RAG 的三大死穴:检索不准、内容冲突、上下文塞不下——分别怎么解决

我最早做 RAG 的时候,犯过一个特别蠢的错。那时我觉得,RAG 不就是把文档切开、embedding、存进向量库,然后用户提问时检索 top-k 拼进 prompt 吗?结果第一轮测试就翻车了——我问 AI “我们公司的年假政策是什么”,它引用了第三版员工手册,但第三版早就被第五版废除了。它没检索到错误内容,它只是检索到了“语义上最像”的内容,而那恰恰是过时的。

AI technology illustration

后来我花了几个月跟 RAG 的爱恨情仇缠斗,发现真正的拦路虎从来不在于 LLM 本身,而是这三个死穴:检索不准、内容冲突、上下文塞不下。这篇就挨个讲清楚它们的本质,以及现在社区里公认的解法。

检索不准:语义相似不等于“正确”

先来一个灵魂拷问:向量检索到底在干嘛?它把你的 query 编码成一个向量,在向量空间里找“距离最近”的文档块。但向量空间里的距离是语义近似,不是事实核对。你问“2024 年 Q3 营收”,它可能因为“营收”和“收入”词向量接近,返回一篇谈论“收入确认政策”的文档——话题沾边,但完全没回答你的问题。

我最早以为,embedding 模型越先进检索就越准。但后来发现,纯向量检索对“专有名词、缩写、精确数字”的召回非常差。比如你检索“GDPR 第 17 条”,如果文档里写的是“欧盟通用数据保护条例第十七条”,向量相似度不一定排最前面。

解法:混合检索 + 重排序

社区的主流方案并不是找一个更强的 embedding,而是把“词法”和“语义”两条路都走一遍:

  • BM25(词法检索):对关键词精确匹配,擅长处理罕见词、代码、编号;
  • 向量检索(语义检索):对同义改写、口语化表达友好,但容易丢精确信号;
  • 融合:把两条路的结果合并,再用 RRF(Reciprocal Rank Fusion) 或加权平均去重排序。

这还不够。粗召回之后,再加一道 reranker(重排序模型)。Reranker 不像 embedding 那样把 query 和文档各自编码成向量去算余弦相似度,它把 query 和文档拼在一起做一个交叉编码,深度理解二者之间的关系。效果通常比双塔向量召回高出一大截。

方法 擅长 短板
纯向量检索 语义相似、近义词 精确词、ID、数字不友好
BM25 关键词精确匹配 同义表达几乎无能为力
混合 + Rerank 两者兼顾 多一步模型调用,增加延迟

我自己实践后的感受:BM25 + 向量 + reranker 是多数场景性价比最高的组合,能把检索命中率从 60% 拉到 90% 以上。但如果你是低延迟场景(比如聊天机器人),reranker 那 20-50ms 可能得评估一下。

内容冲突:AI 被互相打脸的文档搞蒙了

第二个死穴更隐蔽。你检索了 10 个文档块,其中 3 个说“本公司远程办公政策允许员工全周居家”,另外 7 个说“每周至少到岗三天”。LLM 看到这些矛盾的片段时,不会像人一样皱眉,它会用概率把所有内容揉成一句话——结果可能是“员工拥有无限选择权,也可每周到岗三天”。这种和稀泥式输出,在生产环境里就是事故。

我二月份遇到过一模一样的事:公司的制度文档因为历次迭代,同一个政策在三个不同表格里被改过多次。RAG 检索时按语义相似度拉回来了旧版本和新版本,LLM 把两个版本拼接在一起,推出一个从未存在过的“中间版本”。当时我的反应是——这谁顶得住?

解法:防冲突前置到检索阶段

光靠 prompt 里写一句“请判断文档之间是否矛盾”基本没用,LLM 更倾向于“平滑”掉矛盾,而不是旗帜鲜明地站队。真正有效的办法是:在把文档喂给 LLM 之前,先主动做冲突检测和过滤

  1. 元数据过滤:给每个 chunk 打上“版本号、生效时间、部门、文档类型”。检索时按时间优先或版本优先过滤,从源头排除过期内容。
  2. 重排序时的权威性加权:企业题库里,官方制度文件的权重应该远高于员工个人总结。reranker 只按语义相关性打分,你需要在融合阶段手动加一条“来源权重”。
  3. LLM 冲突感知:当多个候选 chunk 存在重叠信息时,你可以先让 LLM 做一个“证据摘要”,把每份文档的观点提取成结构化条目,再丢给生成模型。如果发现同一事实两个说法,生成模型至少要输出矛盾而不是和稀泥。

还有一个骚操作,来自微软的 GraphRAG 思路:把文档块之间的关系用图结构存起来。比如“员工手册 V5 取代 V3”这种关系,检索到 V3 的 chunk 时自动跳到 V5,而不是把 V3 当真。这个思路比在 prompt 里塞一堆限制要稳得多。

冲突不可避免时,让 LLM 承认冲突

你不可能保证所有冲突都被过滤掉。所以 prompt 里应该明确要求:如果文档之间存在事实矛盾,请直接列出相左的观点并说明无法确定,而不是自行合成一个“合理”答案。这个技巧能把回答的错误率降低,因为它放弃了“强行正确”,换来了“诚实暴露问题”。这也是我觉得 RAG 产品最应该学人类的一点——不知道就是不知道。

上下文塞不下:向量库捞回来 50 块,你只能吞 5 块

第三个死穴是物理层面的。假设你有一个企业知识库,每个文档平均 2000 字,检索 top-20 就是 4 万字。而 GPT-4o 的上下文窗口虽然号称 128k,但输入 token 一长,延迟线性上涨、成本跟着涨,关键是 LLM 对长上下文中间部分的注意力会稀释。你以为你塞进 20 个 chunks 它就都看见了,实际上它可能只记住了开头和结尾。

“Long context 不是让你把所有东西都塞进去,而是让你更有底气地砍掉不要的东西。”——这我忘了谁说的,但实践下来确实是这样。

解法:压缩上下文,而不是扩窗

现在很多人的第一反应是用长上下文模型硬吃。但硬吃有三个问题:慢、贵、效果衰减。更优雅的路线是“检索-压缩-增强”循环(比如 LangChain 的 Contextual Compression):

  • 先用大语言模型对每个 chunk 做摘要,只保留跟 query 相关的句子,丢掉废话和重复信息;
  • 再按压缩后的长度做截断,保证最终 prompt 控制在 3000-5000 token 以内;
  • 或者用 RAPTOR 之类的递归摘要,先给每个文档块做自底向上的树状摘要,检索时先找摘要,再顺着摘要定位到原文。

如果你的场景是“上百页 PDF 的问答”,我强烈推荐你先用 Map-Reduce 思路:先对每一页做摘要,把所有摘要存成一个“迷你知识库”,检索在迷你库里做,拿到摘要之后再从原文中把对应段落拉出来。这比直接塞全文高效太多。

另一个有效手段是查询改写。用户问的是一句话,但你可能需要把这句话拆解成多个子查询,分别检索,再合并去重。比如“对比我们公司和 A 公司的远程办公政策”,拆成“我们公司远程办公政策”“A公司远程办公政策”分别搜,检索质量比统一向量搜高很多。用小的 LLM 做改写成本也不高。

一个对比表,帮你选方案

问题 核心原因 推荐解法 副作用
检索不准 语义相似≠事实正确 BM25+向量+reranker 延迟增加 50ms+
内容冲突 多文档版本/观点打架 元数据过滤 + 冲突透出 需要提前给文档打标
上下文塞不下 top-k 太多,LLM 注意力被稀释 摘要压缩 + 递归检索 摘要可能丢细节

这些死穴会消失吗?

现在有人会说,用 200k 上下文模型就不用做 RAG 了,直接把整个知识库塞进去。我劝你冷静——就算上下文窗口无限大,LLM 的注意力和推理能力不会均匀覆盖每个 token。长上下文检索(比如 RAG-Fusion、稀疏注意力)依然会在 LLM 内部以某种形式存在。RAG 的意义不是“为了大模型选择信息”,而是“为了让大模型只关注该关注的东西”。

至于检索不准和内容冲突,这两件事短期看都不会消失。Embedding 模型和 rerank 模型在变强,但“事实性”没法靠相似度保证。未来真正解决问题的可能不是更聪明的检索器,而是基于知识图谱的显式关系记录——让模型知道“V5 取代 V3”这种关系,而不是凭向量距离揣测。

最后分享一个我现在的决策框架:先看你 RAG 的错误分布,如果是 70% 的答案错在检索到的内容本身,就优先砸混合检索和 reranker;如果是 60% 的错来自多个文档互相矛盾,就去给文档加版本管理和冲突检测;如果是回答又烂又慢,先压缩上下文,别急着上贵模型。这三个死穴,每一个都有解,但没有什么灵丹妙药——把上述方案组合起来用,才是我见过的能落地的 RAG。

原创文章,作者:guanweilu,如若转载,请注明出处:https://guanweilu.cn/article/330.html

(0)
上一篇 2026年8月28日
下一篇 2026年8月28日

相关推荐