返回文章列表

RAG 召回越多,为什么答案反而更容易错得很自信

真正先失控的往往不是召回率,而是冲突证据、过期文档和权限不一致的内容一起进入上下文后,答案开始变完整,证据链却变松

很多团队第一次把 RAG 接进业务时,最先盯住的指标通常是召回量。

命中 3 篇不够,就调到 8 篇;8 篇还不稳,就继续放宽向量相似度阈值,再把 BM25、标签过滤、同义词扩展一起叠上去。面板上的命中率确实会变漂亮,很多问题也像是“被覆盖到了”。但线上再跑一阵,另一类更难收的问题就出来了:答案开始越来越像回事,语气越来越完整,可一旦细查出处,里面混着旧版本规则、别的租户文档、已经废弃的 SOP,甚至互相矛盾的说明。

我对这类问题的判断是:RAG 的可靠性,很多时候不是死在“没召回到”,而是死在“召回进来了太多彼此不该同时出现的东西”。上下文一旦同时塞进冲突信息、过期文档和权限不一致的内容,模型不会老老实实告诉你“证据冲突,无法回答”,它更常见的做法是顺着语言惯性,把这些碎片缝成一条看起来很完整、实际上证据链已经松掉的答案。

这类问题一开始看起来像召回不足,后来才发现是上下文污染

第一次把这个判断收清楚,不是因为模型答得太短,而是因为它答得太顺了。

场景是一个企业内部知识问答。用户问的是报销审批链路里一个很具体的问题:海外差旅超标后,是先走直属主管审批,还是先走成本中心复核。系统最初确实经常答不出来,原因也简单,相关制度散在不同知识库里,向量检索经常只能捞到一半。

于是团队做了一轮很典型的增强:

  • 把 topK 从 4 提到 10;
  • 加了关键词召回兜底;
  • 放宽了近义表达匹配;
  • 把历史公告、FAQ、制度正文都一起放进候选集。

短期看效果很好。答复不再是“未找到相关信息”,而是能组织出完整步骤了。问题恰恰也从这里开始:用户反馈答案“读起来很像对的”,但真正照着做会走错单。

后来把一次错误回答拆开看,模型上下文里同时出现了三类材料:

  1. 半年前旧制度里的审批链;
  2. 新制度正文里的例外条款;
  3. FAQ 里针对另一个区域实体的说明。

这三份材料各自都不是垃圾,单独看甚至都很像“高相关”。问题在于它们不属于同一个决策空间。模型拿到的不是一组能互相印证的证据,而是一堆词面上都相关、业务边界却并不一致的片段。最后它生成出来的答案不是引用其中某一条,而是把三份材料揉成了一条新的流程。

这就是很多 RAG 项目最容易被误判的地方:表面像“召回做强了”,本质上却是把检索错误从“缺证据”升级成了“脏证据进入生成阶段”。

召回变多之后,模型并不会更谨慎,只会更擅长补缝

很多人默认觉得,给模型更多资料,最差也只是让它自己挑。

但真实情况更接近另一种机制:上下文越长、片段越多、语义关系越松,模型越容易把“局部合理”拼成“整体像真”。

这是因为生成阶段面对的不是结构化事实表,而是一串已经线性化的文本。只要这些文本在词面上彼此能搭桥,模型就会天然倾向于把桥搭过去。尤其在下面几种情况下,这个倾向会特别强:

  • 两份文档结论不同,但共享大量业务术语;
  • 新制度推翻旧制度时,没有明确写“旧规则废止”;
  • FAQ 用口语化总结了正文,但省略了适用条件;
  • 多租户、多区域、多版本内容被一起召回,却只在元数据里区分。

这时模型不会把“我看到了冲突”直接暴露出来,反而常常会做三件事:

  1. 优先保留最能组成完整叙述的句子;
  2. 自动补上上下文里没有明说的连接因果;
  3. 把边界条件吞掉,换成更像通用规则的表达。

最后用户看到的是一条很顺、很满、像是已经综合判断过的答案。真正危险的不是它乱说,而是它把冲突说得很圆

过期文档不是噪音,它会主动稀释新证据的权重

很多团队排查 RAG 错答时,习惯把过期文档当成一种“低质量噪音”,觉得只要数量不多,问题不大。

但在生成阶段,过期文档往往不是被动噪音,而是会主动改变答案重心的竞争证据。

我见过一个更典型的例子是客服知识库。某个退款规则已经在新版政策里改掉了,但旧版 FAQ 由于访问量高、表述更口语化,反而更容易在召回阶段排到前面。新政策正文写得很准,却很硬;旧 FAQ 写得很顺,还带着完整的话术模板。结果模型在回答时,极容易把新版规则当成局部限制,把旧 FAQ 当成主干叙述。

最后出来的答案常常像这样:

通常情况下用户可先申请原路退款,如遇活动商品则需进一步审核。

这句话最厉害的地方在于它几乎每个词都能在上下文里找到影子,但整句话本身并不存在于任何一个来源。真正的新规则可能已经改成“活动商品一律不支持原路退款”,而旧 FAQ 里的“通常情况下”被模型拿来做了总起句,直接把新规则压成了例外。

所以过期文档的问题,从来不只是“有旧信息混进来了”,而是旧信息往往更像人话,更容易被模型拿去当骨架

权限不一致的召回,比答错更麻烦,因为它会制造“似乎有依据”的越权答案

另一个经常被低估的问题,是权限边界。

很多内部 RAG 系统把权限校验放在“文档能不能打开”这一层,觉得只要最终不给用户展示原文就行。可生成系统真正危险的地方在于:只要受限文档进过上下文,哪怕最终没把原文贴出来,答案本身也可能已经泄露了不该知道的判断。

比如销售问一个合同审批问题,公开知识库里只有通用流程,法务知识库里还有一个特殊客户的例外条款。如果检索阶段只是做了“先召回、后裁剪”,那模型很可能已经在草稿阶段利用了那条例外规则,最后输出一句看似中性的建议:

这类客户通常需要补充区域负责人审批。

用户看不到受限文档,但他已经得到了一条本不该知道的组织规则。更麻烦的是,这句话在形式上很难被识别为泄露,因为它不像复制粘贴,更像模型“自己总结的”。

所以权限问题不能只理解成访问控制,而要理解成证据来源控制。一旦不属于同一可见范围的材料被一起喂给模型,系统就已经越线了。后面的脱敏和引用限制,只是在处理已经发生过的污染。

真正该优化的不是“多召回一点”,而是让证据先按决策边界收敛

很多 RAG 系统到后面越调越乱,不是因为模型太弱,而是因为检索阶段优化方向本身就偏了。

团队最容易沉迷的,是把召回当成搜索引擎问题:

  • 相关性不够,就再加一种召回通道;
  • 覆盖率不够,就再加一点 topK;
  • 用户问法不稳定,就再多做一些 query rewrite。

这些动作不一定错,但如果缺少“决策边界”这一层约束,最后只会把更多不该同时出现的材料送进生成阶段。

我后面更看重的是另一套收敛顺序:

1. 先做范围收敛,再做相关性排序

很多问答其实在语义检索之前,就已经能先限定范围,比如:

  • 组织实体;
  • 区域或国家;
  • 生效时间;
  • 文档类型;
  • 用户权限域。

如果这些条件不先收住,只靠 embedding 相似度去排,结果一定会把“说得像”的东西也拉进来。那不是相关性排序的问题,是候选集定义错了。

2. 把版本和生效时间当一等公民,而不是附属元数据

很多知识库明明有 updated_atversionstatus 字段,但只在展示层用,检索和拼上下文时几乎不参与决策。这样一来,旧文档和新文档会被平等对待,模型根本不知道谁应该覆盖谁。

更稳的做法不是简单“越新越靠前”,而是明确处理覆盖关系:

  • 已废止文档默认不进入生成上下文;
  • 新旧规则冲突时,直接标记为冲突,不让模型自由综合;
  • FAQ 不能覆盖制度正文,只能作为解释层补充。

3. 让冲突暴露出来,而不是让模型代替系统做裁判

很多系统默认把多份候选材料直接拼接后交给模型,希望模型自己“综合理解”。这一步恰恰最危险,因为它把证据冲突的处理,外包给了最会补缝的一层。

如果两份高权重文档结论矛盾,更合理的系统行为通常不是继续生成,而是显式告诉用户:

  • 找到了相互冲突的规则;
  • 冲突点在哪里;
  • 当前默认以哪份版本为准,或者需要人工确认。

这听起来没那么丝滑,但它是真的可控。比起给一条很完整但已经掺假的答案,承认冲突反而更像一个可靠系统。

一个特别常见的失败案例:把重排当成最终解法

不少团队发现“召回越多越乱”之后,会马上上 reranker,结果排序质量确实提升了,于是就把问题当成解决了。

但 reranker 能解决的,主要是“谁更像问题答案”;它解决不了“这些候选是否属于同一个可合并的事实空间”。

如果候选集里同时有:

  • A 地区 2024 版规则;
  • B 地区 2025 版规则;
  • 面向管理员的内部例外说明;
  • 面向普通员工的 FAQ;

reranker 最多只是把其中两三篇排得更前。它无法从根上替系统决定:这些材料到底能不能一起被喂给模型。

这就是为什么很多 RAG 评测离线看起来不错,线上一进复杂场景就开始漂。离线集里问答往往单一、标准、边界干净;线上问题真正复杂的地方,是它背后连着版本、权限、组织结构和例外条款。排序只是把最像的材料排前,不会自动替你做治理。

适用边界:不是所有场景都该压低召回量

说“召回多了容易错”,不等于所有系统都该把 topK 砍得很小。

如果你做的是探索式问答、资料汇总、研究辅助,多给一些材料本身就是合理的,用户也愿意接受“这里有多种说法”。这种场景下,系统目标不是给唯一执行答案,而是帮助用户浏览信息空间。

真正要严格控制召回边界的,是那些答案会被直接执行的场景,比如:

  • 制度问答;
  • 审批流程;
  • 客服口径;
  • 运维 Runbook;
  • 医疗、金融、合规类决策支持。

这些场景里,系统最重要的能力不是“尽量答出来”,而是“别把互相不兼容的证据拼成一条可执行指令”。一旦答错的成本高于答不出,检索策略就不能再只围着覆盖率转。

结尾

RAG 最容易让人上瘾的地方,是它总能靠“再召回一点”在短期内把面板数据拉好看。

但一套知识系统真正上线后,最难收的从来不是有没有材料,而是进入上下文的那些材料,是否属于同一套事实边界、同一版本语义和同一权限范围

只要这个问题没先收住,召回越多,模型就越像一个特别会写总结的人:它不一定故意乱说,但它会把不该并在一起的证据,缝成一条读起来非常像结论的答案。

所以 RAG 的下一步优化,很多时候不该再问“还能多召回多少”,而该先问:哪些内容根本不该一起出现在同一个 prompt 里。