RAG落地踩坑实录:从Demo到生产的差距有多大?
RAG落地踩坑实录:从Demo到生产的差距有多大?
如果前 11 篇教你的是"怎么做",那这一篇要讲的是"做的时候会怎么死"。
我把一个企业RAG知识库从 Demo 推到生产,用了三个多月。这三个月里踩的坑,比前面十篇文章加起来还多。挑三个最痛的,希望能帮你省点医药费。
大家好,我是黒漂技术佬。
教训一:“先做个 Demo 看看效果” → 三个月后还在做 Demo
这是我犯的第一个,也是最贵的错误。
刚接触 RAG 的时候,我用 LangChain + Chroma + OpenAI API,一天就跑通了 Demo。老板问:"能上线吗?"我说:“再优化一下,两周吧。”
然后两周变一个月,一个月变三个月。原因是:Demo 和生产的差距,不在核心链路上,而在边界条件上。
| Demo 能处理 | 生产必须处理 |
|---|---|
| 1 份干净的 PDF | 200 份格式各异的文档(PDF/Word/飞书/扫描件) |
| 用户规规矩矩地问 | “就上次那个啥来着……” |
| 所有数据公开可见 | 不同部门看不同文档 |
| 一个人用 | 100 个人同时用 |
| 出错了重跑就行 | 有监控、有告警、有回滚 |
| Python 脚本 | 部署容器、日志、备份 |
我踩的具体坑
坑 1.1:LangChain 的 API 变动堪比川剧变脸
2024 年下半年开始,LangChain 经历了一次大规模 API 重构。从from langchain.vectorstores import Chroma变成了from langchain_chroma import Chroma,从RetrievalQA变成了create_retrieval_chain,回调机制、内存管理、输出解析器的写法全变了。
一个月前写的 Demo 代码,更新依赖后直接跑不起来。StackOverflow 上的答案 70% 已经过期。
教训:如果你的生产系统依赖 LangChain,锁定版本!锁定版本!锁定版本!
# requirements.txtlangchain==0.2.0 langchain-community==0.2.0 langchain-chroma==0.1.1正确的路径
第 1 周:用 API(DeepSeek + SiliconFlow)跑通 Demo,验证可行性 第 2-3 周:替换为本地部署(bge Embedding + Milvus),切掉外部依赖 第 4-5 周:加权限、安全、监控、限流 第 6 周:内部灰度测试,收反馈 第 7-8 周:修 Bug、优化检索、优化 Prompt 第 9 周:全量上线核心原则:MVP 不是"最简 Demo",而是"能解决一个真实问题的最小版本"。
教训二:Prompt 优化靠玄学 → 浪费了整整一周
我们上线的第一个版本,回答质量波动很大。同一个问题,有时候答得像专家,有时候像个智障。
我翻了各种教程,试了"角色设定"、“思维链(Chain of Thought)”、“Few-shot 示例”、“让 LLM 自己反思”……Prompt 越写越长,效果却没有显著提升。
后来冷静下来,我做了一件很简单的事:把 100 个错误回答打出来,逐条分析,归类。
结果发现:
根因分析(100 个错误回答): ──────────────────────────────────── 64% 检索根本就没搜到相关内容(不是 Prompt 的锅) 22% 检索搜到了但 LLM 没用上(上下文太长,被截断了) 9% 文档本身信息不完整或矛盾 5% LLM 理解错了结论:我花了一周调 Prompt,结果只覆盖了 5% 的问题。真正的大头在检索和文档质量。
正确的调优顺序
1. 先看检索质量(70% 的问题在这) → 调整 chunk_size、chunk_overlap → 加 Query 改写 → 上混合检索 2. 再看上下文管理(15% 的问题在这) → Top-K 不是越大越好,用 Reranker 精简 → 给最相关的文档块放前面 3. 最后才调 Prompt(5% 的问题) → 系统指令清晰 → 强制标注引用来源 → 设定"不知道就说不知道"教训三:文档更新不同步 → 用户发现一个 Bug 我掉一层皮
我们的第一批知识库有 150 份文档。HR 更新了《员工手册》,但知识库里还是旧版。有员工按 AI 的回答请了 10 天年假,结果 HR 说新制度改成 7 天了。
这就尴尬了。
文档管理的三个层次
| 层次 | 做法 | 延迟 |
|---|---|---|
| 手动 | 改了文档→手动重新上传→触发重建 | 忘了就永远不同步 |
| 半自动 | CMS 改了文档→Webhook通知→自动重建 | 5~10 分钟 |
| 全自动 | 文档托管在 Git/Confluence→定时同步→增量更新 | 接近实时 |
我们最终的方案——基于 Git 的文档管理:
公司所有文档 → Git 仓库(Markdown 格式) │ │ git push 触发 Webhook ▼ 文档同步服务 ├── 检测变更的文件(git diff) ├── 删除旧版 chunks ├── 重新解析、分块、Embedding 变更的文件 └── 增量更新 Milvus# 增量更新逻辑defsync_updated_docs(changed_files:list):forfile_pathinchanged_files:# 1. 删除旧版本的所有 chunksvectorstore.delete(filter={"source":file_path})# 2. 重新解析、分块new_chunks=pipeline.process(file_path)# 3. 插入新 chunksvectorstore.insert(new_chunks)# 4. 做一次健康检查:搜几个典型问题,看回答是否正常run_health_check()增量更新的好处:150 份文档里只更新了 1 份,不需要全量重跑。全量重跑一次可能要几个小时,增量更新几秒钟搞定。
其他小坑速览
- PDF 里有扫描件混在文字页里:同一个 PDF,第 1-5 页是文字,第 6 页突然是扫描的表格。解析器需要按页检测是否需要 OCR。
- Embedding 模型的中文分词不靠谱:“会长”(名词,协会的会长)和"会长"(动词,会变长)在 BERT 的分词里经常被当成同一个词,导致歧义句的检索完全跑偏。
- 用户会复制粘贴大段文字当问题:有人会把整封邮件贴进提问框。这种问题不能做 Query 改写,也不能原样 Embedding——要先做问题提取(用 LLM 把大段文字中的核心问题抽出来)。
- LLM API 超时需要降级:大模型 API 有概率性超时(尤其是高峰时段)。必须做重试(1次)和降级(返回"系统繁忙,请稍后重试"),不能直接报错让用户看到堆栈。
最后的总结:从 Demo 到生产的桥梁不是技术,是耐心
做企业 RAG 知识库这件事,技术上没有哪一步是特别难的。真正难的是:把 100 件小事都做对。
文档的格式处理、权限的细粒度控制、检索的持续优化、用户的反馈闭环、文档的增量更新——每一项单拎出来都不难,加在一起就变成了真正的产品。
我是黒漂技术佬。这个系列的最后一篇,我会聊聊更前沿的方向——AI Agent + RAG,企业知识库的下一步进化在哪里。
