当前位置: 首页 > news >正文

LangChain最佳实践,我踩过的10个坑和解决方案

LangChain最佳实践,我踩过的10个坑和解决方案

用LangChain做项目快一年了,从一开始照着官方文档抄代码,到后来被各种隐坑折腾得半夜睡不着,也算攒下了一本血泪账。今天挑10个让我印象最深的坑出来聊一聊,希望能帮你少走点弯路。

坑一、版本升级直接炸裂

最早我用的还是0.1那套写法,from langchain.chat_models import ChatOpenAI,跑得好好的。某天手贱升到0.3,一运行满屏ImportError。

原因很简单,LangChain把模型相关的类拆到了独立包里,chat_models这个路径已经废弃。0.2之后LLMChain标记成deprecated,0.3动得更大。

解决办法是按新规范导入,ChatOpenAIlangchain_openai,Prompt走langchain_core.prompts

fromlangchain_openaiimportChatOpenAIfromlangchain_core.promptsimportChatPromptTemplate llm=ChatOpenAI(model="gpt-4o-mini",temperature=0)prompt=ChatPromptTemplate.from_messages([("system","你是一个Python助手"),("human","{question}"),])chain=prompt|llm

升级前先看一眼CHANGELOG,别像我一样直接pip install -U然后懵圈。我还建议把依赖版本锁死在requirements.txt里,团队里别人拉代码不会因为版本不一致跑出不一样的结果。0.1和0.3的差别大到能把你的项目重写一遍,这一点我有切肤之痛。

坑二、temperature乱设一通

我刚开始所有场景都默认temperature=0.7,结果做JSON抽取的时候模型开始发挥创造力,字段名都能给你改了。

temperature控制输出的随机性。数值越低越确定,越高越发散。代码生成、信息抽取、分类这种要稳定结果的活,老老实实设0。写文案、头脑风暴再往上调。

# 抽取/分类场景extract_llm=ChatOpenAI(model="gpt-4o-mini",temperature=0)# 创意场景creative_llm=ChatOpenAI(model="gpt-4o-mini",temperature=0.9)

我还踩过一个隐形坑,同一个llm对象被多个chain复用,以为改了参数其实改的是同一个实例。要复用就传参新建,别图省事。

坑三、Prompt全靠字符串拼接

第一版代码里我的prompt全是f"请回答{question}",问号、引号、特殊字符一进来就乱套,还经常把用户输入直接塞进去,注入风险拉满。

正经做法是用ChatPromptTemplate,变量用花括号占位,框架帮你转义。

fromlangchain_core.promptsimportChatPromptTemplate prompt=ChatPromptTemplate.from_template("请总结以下内容,字数不超过{max_words}字。\n\n内容:{content}")formatted=prompt.invoke({"max_words":100,"content":user_input})

复杂一点的prompt我建议单独存成文件或者常量,别散落在业务代码里,改起来要命。

坑四、错误处理全靠运气

有阵子我的chain跑着跑着就挂,要么API超时,要么限流429,直接抛异常整个流程断掉,前面算的全白费。

LangChain的底层invoke不会自动重试,你得自己包一层。生产环境务必加上重试和超时。

fromlangchain_core.runnablesimportRunnableLambdaimporttimedefsafe_invoke(chain,inputs,retries=3):foriinrange(retries):try:returnchain.invoke(inputs,config={"timeout":30})exceptExceptionase:ifi==retries-1:raisetime.sleep(2**i)

with_config里也能塞max_concurrency和重试策略,比手写循环优雅,我后来都改用它。

坑五、Token超限静默截断

做长文档总结时,我把整篇文章塞进prompt,模型没报错,但返回的总结明显缺了后半段。查了半天才发现是上下文超了,模型默默把后面的内容丢了。

很多模型超长输入会截断而不报错。解决办法是先算token数,超了就分段处理或者用map-reduce。

fromlangchain_text_splittersimportRecursiveCharacterTextSplitter splitter=RecursiveCharacterTextSplitter(chunk_size=2000,chunk_overlap=200,separators=["\n\n","\n","。",""],)chunks=splitter.split_text(long_text)

tiktoken预先估算token也行,心里有数比事后抓瞎强。我后来养成的习惯是,凡是处理超过两千字的内容,一律先过一遍splitter,宁可多调几次模型也别赌它不会截断。

坑六、工具描述写得太随意

做Agent的时候,工具的description我一开始就写"搜索网页"四个字,结果模型根本不知道啥时候该用,要么乱调,要么死活不用。

工具描述就是模型看的使用说明,要写清楚这个工具干什么、什么时候用、输入是什么格式。描述写得越具体,Agent调用越准。

fromlangchain_core.toolsimporttool@tooldefsearch_web(query:str)->str:"""当需要查找最新资讯、事实性数据或问题超出知识范围时使用。 输入应为简洁的中文搜索关键词,不要包含问号。"""returnresults

我后来养成习惯,工具名用动词,描述里写清触发条件和输入规范,调用量蹭蹭涨。

坑七、Agent陷入死循环

有个ReAct Agent跑着跑着就开始反复调用同一个工具,同样的输入调了十几遍还不收敛,token烧得我心疼。

死循环一般有几个诱因。工具返回的内容太模糊,模型觉得没解决就反复试。或者prompt里没限制最大迭代次数。

解决办法是给Agent加max_iterations,再让工具返回更结构化的结果。

fromlangchain.agentsimportcreate_react_agent,AgentExecutor agent=create_react_agent(llm,tools,prompt)executor=AgentExecutor(agent=agent,tools=tools,max_iterations=5,early_stopping_method="generate",handle_parsing_errors=True,)

handle_parsing_errors=True这个参数救过我很多次,解析失败时不会直接崩,会给模型一次纠错机会。

坑八、输出解析一直翻车

我用PydanticOutputParser解析模型输出,模型偶尔会在JSON外面加一句"好的,结果是",解析直接挂。

模型的输出很难百分百干净,尤其是让它直接生成结构化数据时。OutputParserget_format_instructions能把格式要求塞进prompt,但还不够保险。

更稳的做法是搭配with_structured_output,直接让模型按schema返回。

frompydanticimportBaseModel,FieldclassSummary(BaseModel):title:str=Field(description="标题")keywords:list[str]=Field(description="关键词")structured_llm=llm.with_structured_output(Summary)result=structured_llm.invoke("总结一下RAG的原理")# result直接是Summary对象

这招比手写正则提取稳太多,我现在能结构化的全用它。

坑九、API Key硬编码进仓库

别笑,我真干过把api_key="sk-xxx"写进代码然后push到GitHub的事,第二天就收到OpenAI邮件说key泄露了。

环境变量必须走配置文件或者系统环境变量,LangChain默认就会读OPENAI_API_KEY

importosfromdotenvimportload_dotenv load_dotenv()# 从.env文件加载llm=ChatOpenAI()# 自动读取OPENAI_API_KEY

.env加进.gitignore,团队里用.env.example做模板,谁也别图省事把密钥写死。

坑十、调试全靠print

chain一长,中间出了问题根本不知道是哪一步挂的,我一开始只会到处加print,代码乱得没法看。

LangChain的Runnable天然支持流式调试,用全局verbose或者debug开关就能看到执行步骤。

fromlangchain.globalsimportset_debug,set_verbose set_verbose(True)# 打印chain的执行步骤set_debug(True)# 更详细的调试信息# 或者单步查看中间结果fromlangchain_core.runnablesimportRunnablePassthrough chain=({"context":retriever,"question":RunnablePassthrough()}|prompt|llm)

正式上线前记得把debug关掉,日志量很大。我调试阶段开verbose定位问题够用了。

小结

这10个坑里,版本兼容和错误处理是那种不出事不知道、一出事要命的类型,temperature和工具描述则是效果好坏的分水岭。写LangChain应用,多花点时间在prompt和参数调校上,比堆功能实在得多。我自己最大的教训是太迷信官方示例,照着抄完就上线,出了问题才发现人家示例里省掉了重试、超时、token校验这些保命逻辑。

到这里LangChain本身的实践就聊得差不多了。但你会发现,真要做复杂的多步Agent流程,单纯靠Chain拼装还是有点吃力,状态管理、循环控制、人在回路这些需求处理起来挺别扭。下一篇文章我们进入LangGraph篇,看看它是怎么把Agent编排这件事做得更顺手的。

http://www.jsqmd.com/news/1346077/

相关文章:

  • Linux 进阶命令
  • 幻兽帕鲁存档转换工具:轻松将SAV文件转为可读JSON格式
  • 如何通过自动化技术一键解除Steam游戏DRM限制?SteamAutoCrack深度解析
  • TVA智能体:物理AI的开路先锋(8)
  • 如何在现代电脑上完美运行经典《暗黑破坏神II》:D2DX终极增强指南
  • 如何实现网盘高速下载:LinkSwift直链助手完全指南
  • 2026年哈密别墅装修公司哪家好 品质服务商盘点 - 谁都没有我好看
  • SNMP从入门到实践:Windows/Linux部署、MG-Soft工具使用与安全配置指南
  • Unity PolyBrush插件实战指南:网格雕刻与顶点绘制的效率革命
  • STM32 USB Host读写U盘实战:从硬件选型到稳定性调优
  • TVA-World架构:具身智能范式跃迁及其机理(9)
  • 数据中心施工方案全解析:从设计蓝图到稳定交付的工程实践
  • OneNote到Markdown完整迁移指南:5步实现无损笔记转换
  • UniApp视频封面自动提取:H5与APP双端实现方案与性能优化
  • 终极免费AI视频增强工具:3分钟学会将模糊视频无损升级到4K高清
  • ADC设备V2升级:从硬件滤波到软件架构的稳定性、精度与速度优化实践
  • TVA智能体:物理AI的开路先锋(9)
  • 浏览器开发者工具抓取M3U8视频流:抖音快手等平台下载原理与自动化实践
  • 【郑州大学主办 | 河南·郑州举办】第三届机器人与先进制造技术国际学术会议(RAMT 2026)
  • 乌鲁木齐汽车漆面修复怎么选?别被整面喷漆坑了,先看技术、工艺和保值价值 - 中国品牌企业观察网
  • 嵌入式调试利器SEGGER RTT:原理、集成与高级应用实战
  • 信创环境下WebUploader大文件分块上传实战指南
  • 破产清算公告怎么登报?哪些报纸具备刊登效力?**合规登报教程 - 点办通
  • 3步构建智能抖音内容管理:开源下载工具的实践指南
  • TVA-World架构:具身智能范式跃迁及其机理(10)
  • UE5集成WebUI:用Vue/React高效开发游戏UI与数字孪生界面
  • 综合评价方法实战指南:PCA、TOPSIS与灰色关联分析详解
  • CompressO:革命性的开源媒体压缩引擎,重新定义本地化处理标准
  • 5分钟掌握浏览器音乐解锁:重获你的数字音乐所有权
  • 像素vs条数级虚拟列表