AI

LangChain 在真实生产环境的 5 个坑

转载:小红书 AI产品赵哥

前言🔖


前两篇笔记,我们聊了 LangChain 的基础组件 Model、Prompt、Chain,也讲了如何像写代码一样去管理你的 Prompt。最近我在做一些 AI 应用产品的落地,也在带几个内部小伙伴做几个小项目。通过前几篇笔记的闲聊,很多小伙伴(主要是产品同学)对 AI 应用层的开发充满了信心。但我必须给你泼一盆冷水:Demo 和 Production(生产环境)之间,隔着十万八千里。

很多 AI 产品经理最痛苦的时刻,不是想不出 Idea,而是 Demo 演示时老板惊呼 “牛・13”,上线第一天却被用户骂 “傻・13”。响应太慢、胡说八道、Token 费用爆炸、多轮对话后突然失忆…… 这些问题在本地测试时往往会被忽略。

正好赶上周末有时间,把我用 LangChain 遇到的坑总结出来,和大家共勉。我总结了过去一年在 LangChain 生产环境落地中最容易踩的 5 个深坑。这些坑,每一个都是用真金白银的 Token 费和用户流失换来的教训。

  

坑一:Token 爆炸与上下文超限🔖


这是新手最容易忽视,也是后果最直接的一个坑。

现象描述:

你在本地测试时,对话都很短,一般也就两三轮:“你好”、“你是谁”、“帮我写首诗”。一切正常。

但在生产环境中,用户可能会粘贴一篇 5000 字的文章让你总结,或者同一个 Session 聊了 50 轮。

结果只有两种:

  1. 程序直接报错:提示 InvalidRequestError: This model's maximum context length is 4097 tokens...
  2. 账单爆炸:月底收到 OpenAI 或云厂商的账单,发现费用是预估的 10 倍。

根因分析:

大模型是无状态的,为了让它 “记住” 之前的对话,LangChain 默认会将历史聊天记录(History)一股脑地塞进 Prompt 里发给模型。

随着对话轮数增加,Prompt 的长度呈线性甚至指数级增长。

OpenAI 等厂商是按 Input + Output 的总 Token 数计费的。这意味着,即使用户只是回了一个 “嗯”,你可能为了维持上下文,实际上给模型发了 3000 个 Token 的历史记录。这 3000 个 Token 都要算钱。

生产级解决方案:

  1. 引入 Token 计算与预警机制不要等到报错才发现。在 Python 中,必须使用 tiktoken 库在发送请求前预计算 Token 数量。如果超过阈值(比如模型上限的 80%),必须进行截断。
  2. 使用滑动窗口内存(ConversationBufferWindowMemory)不要保存所有历史。只保留最近的 k 轮(例如最近 10 轮)。对于大多数业务场景,10 轮之前的对话细节通常不再重要。
  3. 使用摘要内存(ConversationSummaryMemory)这是更高级的玩法。当对话历史过长时,让 LLM 自动把之前的对话总结成一段话(Summary),然后把这段 Summary 作为 System Prompt 的一部分,替换掉冗长的原始对话记录。
    • 原始历史:用户问 A,AI 答 B,用户问 C,AI 答 D…(消耗 2000 Token)
    • 摘要后:“用户之前询问了关于 A 和 C 的问题,AI 提供了详细解答。”(消耗 50 Token)

产品经理决策点:

你需要定义产品的记忆策略。是不仅限长度但费钱(适合专业咨询),还是只记最近几句(适合闲聊),或者是定期总结(平衡方案)。不要让开发用默认配置。

  

坑二:流式输出(Streaming)🔖


现象描述:

你的 Chatbot 上线了,用户问了一个复杂问题。

然后,屏幕黑屏了 8 秒钟。

用户以为网断了,或者 App 死机了,疯狂点击刷新,甚至直接退出。

第 9 秒,一大段文字突然蹦出来。

根因分析:

默认情况下,LangChain 的 invoke 方法是同步等待的。它会等模型把最后一个字生成完,才一次性把结果返回给你。

比如说,GPT-4 生成 500 字可能需要 10-20 秒,这在互联网产品体验中是不可接受的。

生产级解决方案:

  1. 全链路流式改造(Streaming):必须使用 LangChain 的 stream 接口,配合前端的 SSE(Server-Sent Events)或 WebSocket。让模型生成一个字,前端就显示一个字。虽然整体生成时间没变,但首字延迟(Time to First Token,TTFT) 会缩短到 1 秒以内,用户体验完全不同。
  2. 处理 “思考中” 的状态:在 RAG(检索增强生成)场景下,检索文档是需要时间的(比如 2 秒)。在这 2 秒真空期,不能让界面卡死。产品设计上,需要增加 **“正在搜索知识库…”“正在阅读文档…”** 这样的中间状态提示。

产品经理决策点:

在 PRD 里写清楚:所有对话交互必须支持流式输出

这不仅仅是前端改 UI,后端代码逻辑(比如:如何处理 Chain 的回调)完全不同。如果前期没定好,后期重构工作量巨大。

  

坑三:RAG 中的 “垃圾进,垃圾出”🔖


RAG(Retrieval-Augmented Generation)是目前最火的应用模式,即 “挂载知识库”。

现象描述:

你把公司的 PDF 操作手册切片存进了向量数据库。

用户问:“怎么重置密码?”

AI 回答:“根据文档,你可以通过点击设置按钮来调整屏幕亮度。”

或者 AI 回答:“文档里没说。” 但实际上文档第 50 页明明写了。

根因分析:

这通常不是模型(Brain)的问题,而是检索的问题。

  1. 切片(Chunking)策略太粗糙:默认把文档按 1000 字切一段。结果 “重置密码” 的标题在这一段的结尾,具体步骤在下一段的开头。切分导致上下文丢失。
  2. 检索匹配度低:向量检索(Vector Search)基于语义相似度。有时候用户的问题关键词和文档里的词汇不完全匹配,或者向量模型认为 “修改密码” 和 “账户安全” 更相似,抓回来一堆无关的 “安全守则”,却漏掉了实操步骤。

生产级解决方案:

  1. 优化切片策略(Text Splitters):不要只用简单的字符数切分。使用RecursiveCharacterTextSplitter,并设置合理的 Overlap(重叠区)。
    • 示例:每个块 500 字,但每个块和下一个块有 100 字的重叠。这样能保证跨块的句子不会被切断。一般 overlap 是块长的 10%~20%。
  2. 引入重排序(Re-ranking):这是提升 RAG 准确率的神器。
    • 流程:先粗排,用向量搜索抓回 20 个相关的文档块。然后引入一个精排模型(如 BGE-Reranker),专门判断这 20 个块跟用户问题的相关性,选出最准的 3 个给 LLM。
    • 经验数据:加上 Rerank,准确率通常能提升 20%-30%。
  3. 混合检索(Hybrid Search):向量搜索对 “语义” 敏感,但对 “专有名词” 迟钝(比如产品型号、产品名称等)。生产环境通常结合 ** 关键词搜索(BM25)** 和向量搜索。

产品经理决策点:

不要迷信 “把文件丢进去就行了”。你需要建立测试集。准备 50 个真实问题和标准答案,每次调整切片参数或检索策略后,跑一遍测试,看 ** 召回率(Recall)准确率(Accuracy)** 的变化。

  

坑四:不稳定的输出格式(JSON Parse Error)🔖


现象描述:

你做了一个从简历提取信息的工具,要求模型输出 JSON。

Prompt 写得很好:“请只输出 JSON,不要废话”。

测试时挺好,上线后,每 100 次调用就有 5 次报错。

查看日志发现,模型有时候会在 JSON 前面加一句:“好的,这是提取结果:{…}”,或者 JSON 少了一个大括号。

导致后端解析代码直接 Crash。

根因分析:

LLM 本质上是概率模型,它没有 “语法严格性” 的概念。虽然高级模型已经很听话了,但在高并发或长文本干扰下,依然会发生指令漂移

生产级解决方案:

1. 使用 Pydantic Parser:

LangChain 提供了基于 Pydantic 的解析器。它不仅能定义数据结构,还自带自动修复功能。

如果模型输出的 JSON 格式错了,LangChain 会自动把错误的输出和错误信息(Traceback)再发回给模型,说:“你刚才生成的格式不对,报错是 XXX,请修正。” 模型通常能自我修正。

2. Function Calling / Tool Use(推荐):

不要让模型直接生成纯文本的 JSON。

使用 OpenAI 的 Function Calling 功能(LangChain 中对应 bind_toolswith_structured_output)。这是在 API 层面强制模型输出结构化数据,稳定性比纯 Prompt 约束高一个数量级。

产品经理决策点:

在验收产品时,必须进行压力测试。连续跑 100 次结构化提取,看成功率是否达到 99% 以上。如果达不到,就要让开发换 Function Calling 方案。

  

坑五:LangChain 的抽象泄漏与版本地狱🔖


这是一个偏工程但极度影响产品迭代的坑。

现象描述:

开发告诉你:“这个功能很难改,因为 LangChain 封装得太深了。”

或者:“昨天还能跑的代码,今天升级了 LangChain 就报错了。”

根因分析:

LangChain 是一个迭代极快(有时候一天发好几个版本)的开源项目。

它为了易用性,做了极高层的封装(比如 RetrievalQA 链)。这在 Demo 阶段好用,但在生产阶段,如果你想微调某个环节(比如想知道中间检索到了什么文档,或者想修改中间的 Prompt),高层封装反而成了黑盒(Black Box),让调试变得异常困难。

生产级解决方案:

1. 使用 LCEL:

我在第一篇笔记里提到的 LCEL,不仅仅是语法糖,它提供了更好的透明度。尽量避免使用那些黑盒的、封装好的 “Old Chains”(如 ConversationChain),而是用 LCEL 原语(Prompt | Model | Parser)自己组装。

2. 强制版本锁定:

requirements.txt 里,必须锁死 LangChain 的版本号(例如 langchain==0.1.0)。绝对不要写 langchain>=0.1.0。否则某天自动升级可能导致整个系统瘫痪。

3. 引入监控平台(LangSmith):

这是 LangChain 官方出的调试平台。它能把链条中每一步的输入输出、延迟、Token 消耗都可视化出来。

当产品出现 “胡说八道” 时,你能通过 LangSmith 追溯到:是因为检索回来的文档就是错的?还是中间的 Prompt 拼接有问题?还是模型本身抽风?

没有这种监控工具,排查 AI 问题就跟瞎子摸象一样。

产品经理决策点:

作为 PM,你虽然不写代码,但你要询问开发团队:“我们的应用可观测性(Observability)怎么做?” 如果他们说 “看控制台打印的日志”,那是远远不够的。强烈建议接入 LangSmith 或类似的 LLM Trace 工具。

  

六、总结:从玩具到工具的跨越🔖


总结一下,要跨越 Demo 到 Production 的鸿沟,你需要关注这 5 点:

  1. 算账:引入 Token 计算与预警,别让公司破产。
  2. 体验:必须上流式输出(Streaming),别让用户干等。
  3. 数据:RAG 必须做切片优化和重排序(Rerank),别信赖默认配置。
  4. 稳定:结构化输出优先用 Function Calling,别指望 Prompt 能 100% 管住模型。
  5. 监控:拒绝黑盒,接入 LangSmith,锁死版本。

AI 产品经理的核心竞争力,不仅仅是设计 Chatbot 的头像和欢迎语,更在于理解大模型在不确定性、成本、延迟这一 “不可能三角” 中的权衡

你看,LangChain 不仅仅是代码,它是业务逻辑的具象化。懂了这些坑,你跟开发的沟通效率至少翻倍。