Appearance
9.5.1 一个 RAG 错误,怎么判断到底是“没召回到”还是“召回到了没用好”?
先给结论:判断一个 RAG 错误,最先要问的不是“模型为什么答错”,而是“正确证据有没有进入候选结果”。如果关键证据根本没进候选集,问题大概率在召回链路;如果证据已经进来了但最终答案还是错,问题更可能在过滤、重排、上下文构造或生成阶段。
这是错误归因里最基本的一刀。因为它能把很多混乱的讨论先拆成两类:
- 证据没进来
- 证据进来了,但没用好
这两类问题后面的修法通常完全不同。
为什么这一步这么重要
如果你不先判断证据有没有进候选集,就很容易出现这种情况:
- 回答错了,就直接调 prompt
- 回答漏了,就直接加 top k
- 生成不稳,就怀疑模型本身
但真实系统里,很多错误在更早的地方就已经注定了。
例如:
- query 没改写对,后面再怎么 rerank 也救不回来
- metadata filter 配错了,关键文档根本进不了候选池
- chunk 切得太碎或太散,相关信息没法一起进来
所以先判断“证据到了没有”,是最省时间的一步。
一个更稳的排查顺序
遇到一个失败案例时,可以先按下面这个顺序看。
第一步,先定义这道题的正确证据应该是什么
不要一上来就看模型答案。先确认:
- 这道题正确答案应依赖哪些文档
- 是单文档还是多文档
- 有没有时间版本、权限、租户或产品线边界
- 哪些证据是必须命中的
如果这一步都不明确,后面就很难判断系统到底错在哪。
第二步,看关键证据有没有进入初次召回结果
这一步看的不是最终答案,而是检索输出。
重点检查:
- 正确文档有没有在召回结果里
- 如果有,它的排名大概在什么位置
- 如果没有,是完全没召回,还是被 filter 排掉了
如果关键证据在初次召回里根本不存在,这通常更像:
- query understanding 问题
- query rewrite 问题
- embedding / BM25 / hybrid recall 问题
- metadata filter 问题
- 索引和切块问题
第三步,看关键证据有没有进入最终上下文
有些问题不是“没召回”,而是“召回到了,但没被送给模型”。
这一步要看:
- rerank 后关键证据还在不在
- 去重、聚合、相邻块扩展时有没有把它挤掉
- 上下文长度限制下,它是不是被截断了
- 长上下文排序有没有把关键证据放到不利位置
如果证据在召回阶段有,但在最终上下文里消失了,问题更像:
- rerank 不稳定
- top k / top n 截断过早
- 聚合策略不对
- 上下文构造不合理
第四步,看模型有没有忠实使用已经给到的证据
如果关键证据已经进入最终上下文,但回答还是错,那就要重点看:
- 模型有没有忽略关键证据
- 模型有没有把证据拼错
- 模型有没有补充材料之外的内容
- 任务指令有没有让模型偏向总结、发挥或外推
这时问题更像:
- prompt 约束不够
- 生成策略不稳
- 证据排序和组织方式不利于使用
- 任务要求和上下文不匹配
一个最实用的判断框架
你可以把一个失败案例先粗分成下面三类:
第一类,证据缺失
表现通常是:
- 正确文档没有被召回
- 召回结果全是表面相关内容
- 明明库里有答案,但系统像完全不知道
优先检查:
- query 是否表达清楚
- rewrite / expansion 是否偏了
- embedding / BM25 / hybrid 召回策略
- filter 条件
- chunk 和索引设计
第二类,证据存在但没有被保留下来
表现通常是:
- 初次召回里其实有正确材料
- 但 rerank 或上下文构造后丢了
- 最终 prompt 里看不到关键证据
优先检查:
- rerank 排序
- top k / top n 截断
- 去重和聚合策略
- 上下文长度控制
- 相邻块扩展和文档级合并
第三类,证据已给到,但回答仍然不忠实
表现通常是:
- prompt 里已经有关键证据
- 但回答仍然漏了、拼错了、编了
- 回答语言看起来很流畅,但和证据并不一致
优先检查:
- prompt 约束
- 回答格式要求
- 证据展示顺序
- 模型是否被要求进行过度归纳
- 是否缺少 groundedness / faithfulness 评测
一个最小排查示意
python
def locate_failure(case):
if not case["gold_evidence_in_recall"]:
return "recall_or_filter_problem"
if not case["gold_evidence_in_final_context"]:
return "rerank_or_context_construction_problem"
if not case["answer_grounded_in_evidence"]:
return "generation_or_prompting_problem"
return "need_finer_analysis"这个示意不是为了代替真实分析,而是强调排查顺序:
- 先看证据有没有进来
- 再看证据有没有留下
- 最后看证据有没有被忠实使用
两个很常见的误判
误判一,看到回答错,就断定是模型问题
很多错误在生成前就已经发生了。如果证据没进上下文,模型再强也没法凭空答对。
误判二,只要召回到了,就认为检索没问题
这也不对。因为召回到但排在很后面、或者被后续步骤挤掉,本质上仍然会造成最终失败。
一个更适合团队协作的做法
如果你是多人协作做 RAG,最好让每个失败案例都至少记录这几个字段:
gold_evidence_in_recallgold_evidence_in_final_contextanswer_groundedprimary_failure_stagesecondary_failure_stage
这样后面统计时,你们看到的就不只是“这周错了多少题”,而是:
- 这周主要退化在哪一层
- 是召回问题增多,还是生成忠实性问题增多
一句话总结
判断一个 RAG 错误,最先要分清的是:关键证据到底有没有进候选结果和最终上下文。先把“没找到”和“没用好”分开,后面的归因才不会乱。