三个月前我接手了一个 RAG 项目。领导说「很简单的把文档喂进去让用户问问题就行了。」三个月后回头看我很想说简单你个头。一个能用的 RAG 系统从文档进来、到答案出去中间出了一堆幺蛾子。今天就把我踩过的坑捋一遍每个环节的实际问题和解决方案都列出来。希望能帮你少走三个月弯路。第一个坑文档切分不是越细越好一开始我觉得切得越碎越好每个 chunk 200 tokens这样检索肯定准。结果被现实狠狠打脸。问题出在哪200 tokens 的 chunk很多句子是断开的。比如这句「该算法采用 Transformer 架构在 2024 年的 benchmark 上取得了 SOTA 成绩。」如果被切成两半前半段只说「该算法采用 Transformer 架构」后半段说「在 2024 年的 benchmark 上取得了 SOTA 成绩」。检索「架构」关键词的只拿到前半段丢了「SOTA 成绩」这个关键信息。回答就不完整。我试过的方案方案一固定长度 overlap每段 512 tokens前后 overlap 128 tokens。效果还行但遇到代码块就尴尬了 —— overlap 会把代码切得四分五裂。方案二语义切分用 Sentence Transformers 计算句子相似度在相似度低谷处切分。这个比较靠谱但慢。处理 100MB 的文档光切分就花了 15 分钟。方案三分层切分先把文档按章节切大块再把章节按段落切小块。检索时先搜大块定位章节再搜小块找答案。这个方案我目前在用准确率比方案一提升了大概 12%。我的结论没有银弹。不同类型的文档用不同的切分策略技术文档按章节 段落分层切聊天记录按对话轮次切每轮一个 chunk代码仓库按函数/类切保留上下文PDF 扫描件先用 OCR再语义切分第二个坑向量检索命中率堪忧切分完文档生成向量存到向量数据库。看起来一切顺利。直到第一个用户提问「这个 API 的调用方式是什么」我的 RAG 系统去检索结果返回了 5 个 chunk全是关于「部署环境配置」和「系统架构」的内容。没有一个跟「API 调用方式」有关。为什么向量检索的本质是语义相似度匹配。但「API 调用方式」跟「使用 /v1/chat/completions 接口发送 POST 请求」这句话的语义相似度并没有想象中那么高。关键词高度相关但语义相似度不高。这就是向量检索的盲区。混合检索才是正解最后上了稀疏检索 稠密检索的混合方案稀疏检索BM25搞定关键词匹配。「API」这个词在文档中出现的位置和频率BM25 算得很清楚。稠密检索向量搞定语义匹配。「调用方式」和「发送 POST 请求」这种语义上的关联。融合策略两种检索结果的得分加权融合权重根据任务类型动态调整。实测效果Top-5 命中率从 62% 提升到了 89%。代价是多了一个 Elasticsearch 实例和一些调参工作。第三个坑Rerank被低估的关键一环很多人做到混合检索就觉得够了。但我在用户反馈中发现即使 Top-5 命中了正确答案排在第一位的不一定是最相关的。问题混合检索返回的 5 个结果相关的那条排在第四位。用户看到的是前三条不相关的内容体验很差。加了一个 Rerank在检索之后、生成之前加了一个轻量级交叉编码器模型。把 5 个结果重新排一次序把最相关的提到最前面。我用的是BAAI/bge-reranker-v2-m3效果不错而且速度还行。5 个结果排序大约 100ms 左右对整体延迟影响不大。排序准确率从 55% 提升到了 78%。简单算一下这就意味着每 4 次查询中有 1 次能让用户看到更相关的结果。一个小技巧Rerank 的输入不要只放文本把 metadata 也拼进去。比如来源文档的名称、章节标题、页码。这样 Rerank 能利用更多上下文信息。第四个坑生成的 Prompt比你想的重要最后一步把检索到的内容拼到 prompt 里发给大模型生成答案。这一步我踩了个大坑检索到的内容太多模型根本处理不过来。5 个 chunk每个 512 tokens加起来 2500 tokens。prompt 里还加了系统指令、用户问题、格式要求。总长度直奔 4000 tokens。模型生成的结果是什么根据文档内容xxx 有几种方案分别是…它开始罗列内容而不是回答问题。改进方案限制检索数量Top-5 改为 Top-3。质量比数量重要。上下文压缩对每个 chunk 做摘要把 512 tokens 压缩到 100 tokens。只保留和问题相关的部分。明确的 prompt 结构基于以下文档内容回答问题。如果文档中没有相关信息直接说不知道不要编造。 文档内容 [压缩后的相关内容] 问题[用户问题]增加引用标记要求模型在回答中标注信息来源 chunk方便验证。改了之后回答质量明显提升。「不知道」的比例从 5% 增加到 8%更诚实了但「胡说八道」的比例从 12% 降到了 3%。第五个坑评估没有标准的痛苦改了一个月自我感觉良好。结果一次演示的时候用户问了一个问题系统给出了一个非常离谱的答案。原因很简单我没有系统的测试。每次改完都是自己问几个问题觉得还行就过了。我做了什么建了一个测试集大概 50 个问题覆盖了文档中明确有的内容文档中隐含的信息需要推理文档中没有的内容考验诚实度边界情况拼写错误、同义词每次改动后跑一遍测试集用 GPT-4 做自动评估Faithfulness答案是否基于文档内容Relevance答案是否回答问题Completeness答案是否完整写了个简单的脚本自动化跑。改代码 → 跑测试 → 看分数。优化路径清晰了很多。整体大图一个完整的 RAG 优化链条文档 → 切分策略 → 嵌入模型 → 混合检索 → Rerank → 上下文压缩 → Prompt → 生成 → 评估 ↓ ↓ ↓ ↓ ↓ ↓ ↓ ↓ ↓ OCR/PDF 分层/语义 模型选型 BM25向量 交叉编码 摘要/过滤 结构优化 引用 自动化测试每一个环节都有坑。跳过任何一个最后的效果都会打折扣。写在最后做 RAG 优化这三个月最大的感受是RAG 不难搭难在调细节。很多人搭一个 RAG demo 只花了两小时觉得这东西太简单了。但要让它真正好用后面还有几十个小时的细节打磨。如果你也在搞 RAG建议从评估先做起。先知道自己当前系统的准确率是多少然后一个变量一个变量地改。不要一次改太多不然根本不知道哪个改动起了作用。有问题欢迎评论区交流。踩坑经验这种东西越分享越值钱。