主题
错误回答归因:一张排查流程图
本章要回答的问题:用户说「它答错了」,我该从哪一环开始查,怎么快速定位?
「答错了」不是一种病,是一组症状。同一句错答案,可能是索引里根本没有那条条款,可能是检索没召回到,可能是召回到了但模型拒答,可能是引用张冠李戴,也可能是资料都对、模型自己算错。修错地方,比不修更浪费时间:对着索引缺口调提示词,调一周也不会好。
这一节给一条固定的排查顺序(图 6.5-1),并在 6.1–6.4 留下的 18 道错题上跑一遍。
五道关,从便宜到贵
顺序不是随意的,是按「改动成本」排的:
- 金标在索引里吗? 不在 → 索引缺块。修切分、修入库,不要碰模型。
- 前 5 有金标吗? 没有 → 检索没召回。查切分、向量、查询改写。
- 回答拒答了吗? 有资料却拒答 → 误拒。查上下文是否够、拒答提示词是否过强。
- 引用有支撑吗? 引用段落和结论对不上 → 引用/忠实度问题。先约束输出结构,再谈模型。
- 差在条件或数字吗? 条款找对了、引用也对,答案仍错 → 生成漏条件/选错条款;再往后才是标注或标准答案写错。
前四关都能用程序判,只有最后一关需要人读。归因报告只记第一个失败环节——后面的环节也可能同时有错,但先修上游,收益最大。
18 道错题落在哪一关
| 阶段 | 数量 | 判据 | 先修 |
|---|---|---|---|
| 索引缺块 | 2 | 金标不在 734 个块里 | 切分/入库 |
| 检索没召回 | 10 | 前 5 没有金标 | 切分/向量/查询 |
| 误拒 | 0 | 有金标却拒答 | 上下文/提示词 |
| 引用不支撑 | 1 | 引用段落对不上结论 | 引用约束/提示词 |
| 生成漏条件/选错 | 5 | 有金标、引用支撑,答案仍错 | 提示词/模型/标准答案 |
(实测,见 benchmarks/evaluation/error-attribution.csv;v1 用人工标签,v2 用裁判标签。)
分布很不均匀:10/18 是检索没召回,16/18 是跨段题。这跟 6.2 的 joint Recall@5 = 0.618 对上了——跨段题的第一段常常找到,第二段没进 top-5;模型拿到半套资料,要么答一半,要么自己补。
2 道条件题(C02、C32)都不是检索问题:资料在前 5 里,答案却套错了档。这类才该改提示词或换模型。
三个例子
X28:看起来像拒答,其实是索引缺块。 问题问「有限空间装备和培训经费怎么安排」,标准答案的后半在《安全生产法》第四十七条;这条在 5.3 的切分里被 min_chunk=60 丢掉了(6.2 已发现)。模型说「资料中未提及经费安排」——从它的上下文看,这句话是对的。把这条归成「模型不肯答」去调拒答提示词,方向就错了。
X32:资料在库里,但没进前 5,模型凭记忆补了旧定义。 问「什么算有限空间、什么算重大危险源」;两个金标条款(有限空间规定第三条、《安全生产法》第一百一十七条)都不在前 5。回答里的「出入口狭窄、人员不能长时间工作」是旧版定义的措辞,734 个块里一次都没出现——这不是召回,是模型记忆。唯一引用的 [3] 指向罚款条款,却因为共享措辞被 4-gram 阈值判成「支撑」;这正是 6.3 说的引用支撑指标会假阳性。诊断卡:金标在索引 ✓、前 5 命中 ✗、引用 1 条、拒答 是。修检索;生成端还要加「只依据资料」的约束。
C32:条款找对了,答案漏了批准条件。 问「拒不执行停产停业决定、有现实危险时,监管部门可以采取什么措施」,标准答案的关键是「经本部门主要负责人批准」;回答写了停止供电、书面通知、提前二十四小时通知,唯独漏了批准条件。检索 ✓、引用 ✓、支撑 100%,但答案与标准答案的关键条件不一致——这是生成问题。
还有一个「引用不支撑」的例子:X06 有 9 条引用,只有 33% 的句子能在所引段落里找到支撑。它不是没找到资料,是引得多、对得少;先做逐句引用校验,比换模型便宜。
归因只记第一个失败环节
X13 是一个例子:问「隐患通报和未消除隐患的处罚」,两个金标条款都没进前 5,模型从别的条款里凑了一个 10 万元的罚款(标准答案是 5 万元)。诊断卡判「检索没召回」——这是第一个失败环节;后面的「选错条款」是它的后果。如果只记「生成错误」,就会去调提示词,而真正该修的是召回。
这也是为什么流程图把检索放在生成前面:检索错了,生成端的所有指标都不可解释。 6.4 的消融已经看到,切分是比提示词更大的杠杆;归因只是把这个结论落到单题上。
用诊断卡
bash
cd labs
uv run 06-evaluation/diagnose.py --set v2 --id X32
uv run 06-evaluation/diagnose.py --set v1 --id X13输出是一张卡片:
判定:retrieval_miss
证据:金标在索引 ✓ · 前5命中 ✗ · 引用 1 条/支撑 100% · 拒答 是
建议:先查切分、向量、查询改写;生成端可能只是没拿到第二段。--all 列出全部错题与判定。脚本只做初判,阈值(4-gram 覆盖 0.5)和 6.2 一致;边界题要人看。
工程含义
把这条梯子接进回归流程。 每次评测后,先按阶段统计错题:索引缺块多少、检索没召回多少、生成错多少。索引和检索的问题占比高,就先别做提示词工程。
给每个阶段留错误预算。 比如「索引缺块 ≤1%、检索没召回 ≤5%、生成错 ≤10%」;超了先修对应环节,而不是把总分压下去。
样本按阶段分层抽,不要随机抽。 随机抽 20 条错题,可能 15 条都是同一个索引缺口;按阶段各抽 10 条,才能看到全貌。
归因标签要人复核。 6.3 已经证明裁判会偏宽;v2 的 8 道错题用的是裁判标签,人工复核前只能当线索。
局限
- 只有 18 道错题,分到五个阶段后每格很小;分布是指示性的,不是精确比例。
- v2 的标签来自裁判,不是人工;裁判偏宽会把「部分对」判成「对」,从而少算错题。
- 自动归因依赖阈值:4-gram 覆盖 0.5、引用支撑 0.5;边界题会被分到相邻阶段。
- 只记第一个失败环节:一道题可能同时有检索和生成问题;修完上游要重跑,才能看到下游是否还在。
- direct 与 refuse 没有错题:这批样本里两类全对,归因流程对它们的覆盖不足。
动手实验
动手实验:人工复核 10 道错题的归因
假设:diagnose.py 的自动判定与人工复核的一致率在 80% 左右,分歧集中在「引用不支撑」与「生成错」的边界。
做法:从 error-attribution.csv 按阶段分层抽样——索引 2 道、检索 5 道、引用 1 道、生成 5 道,共 13 道(误拒为 0,抽不到);遮住 stage 列,只看问题、回答、标准答案、前 5 段落,自己判一次,再和脚本比。对不一致的题,记录是阈值问题还是标签问题。
记录:一致率、分歧题号、每道题的判定依据。注意:13 道只能用来发现流程漏洞,不能用来证明流程准确。
参考资料
- Barnett, S. et al. Seven Failure Points When Engineering a Retrieval Augmented Generation System(RAG 在数据、检索、生成各环节的失败点分类). https://arxiv.org/abs/2401.05856
- Ru, D. et al. RAGChecker: A Fine-grained Framework for Diagnosing Retrieval-Augmented Generation(claim 级检索与生成诊断). https://arxiv.org/abs/2408.08067