乐于分享
好东西不私藏

你的 RAG 检索到垃圾文档了怎么办?自我纠正机制让系统自己发现问题

你的 RAG 检索到垃圾文档了怎么办?自我纠正机制让系统自己发现问题

前面两篇我们讲了 Agentic RAG 的整体架构和查询路由。路由解决的是"该不该查"的问题。但还有一个更致命的问题没回答:

查了,但查出来的东西是垃圾,怎么办?

传统 RAG 管线是"检索即信任"——向量库返回什么,LLM 就基于什么生成。哪怕检索出来的文档完全不相关,系统也会硬着头皮编答案。结果就是幻觉。

自我纠正 RAG 的核心思想只有一句话:在生成之前,先让系统评估一下检索结果到底行不行。不行就不要硬上,走纠正路径——重写查询、换知识源、或直接告诉用户"我不知道"。


一、传统 RAG 的"盲信"问题

来看一个真实场景:用户问"2026 年杭州公积金贷款额度上限是多少?"

向量库里存的文档可能是 2024 年的政策。相似度很高(都是公积金贷款),但内容过时了。

传统 RAG 怎么做的?直接把这个 2024 年的文档塞进 Prompt,让 LLM 基于过时内容回答。输出的答案可能是旧数据,但用户看不出来——因为它写得非常自信。

问题出在哪?

❗ 系统没有任何环节去判断"检索到的文档是否真的能回答这个问题"。这就是盲信。


二、CRAG 的解决方案

Corrective RAG(CRAG)是 2024 年提出的框架,核心思想很朴素:

💡 在检索和生成之间,插入一个"评估-纠正"环节。

2.1 文档相关性评分

检索完成后,不急着生成。先让一个 LLM(或轻量分类器)对每篇文档打分:这篇文档和问题相关吗?能回答吗?结果分三级:

✅ Correct(正确):包含回答所需信息,可直接使用

❌ Incorrect(不相关):和问题没关系,或信息过时/错误

❓ Ambiguous(模糊):有一定相关性,但不确定能否充分回答

2.2 三级判定后的不同动作

这是 CRAG 最核心的设计:

判定 Correct → 走正常生成,但先做"知识精炼",剥掉无关段落,只留真正回答问题的部分。

判定 Incorrect → 完全放弃检索结果,触发 Web 搜索回退,重新找答案。

判定 Ambiguous → 两边都做。既保留当前文档的精炼结果,又同时触发 Web 搜索,最后合并两个来源。

2.3 知识精炼(Knowledge Refinement)

这一步经常被忽略但非常关键。即使文档被判为"正确",CRAG 也不会原封不动扔给 LLM,而是做一次"分解-重组":

  1. 把文档拆成更细粒度的知识单元
  2. 对每个单元再做一次相关性评分
  3. 只保留高相关单元,丢弃其余部分

好处:减少噪音,降低 LLM 被无关信息干扰的概率。


三、Self-RAG 的另一种思路

Self-RAG 是另一个自纠正方案,切入点和 CRAG 不同:CRAG 在"检索后、生成前"做纠正,Self-RAG 则更激进——

让模型自己决定什么时候该检索、检索结果好不好、生成的答案对不对。

Self-RAG 的核心是引入了四种"反思 Token":

反思 Token
作用
判定时机
Retrieve
是否需要检索
生成前
IsRel
检索文档是否相关
检索后
IsSup
生成内容是否被文档支持
生成后
IsUse
最终回答是否有用
输出前

整个流程是这样的:

  1. 拿到问题,先自问:"我需要检索吗?"
  2. 需要的话执行检索,再自问:"检索到的文档和问题相关吗?"
  3. 相关就基于文档生成,再自问:"我的答案被文档支持吗?"
  4. 最后自问:"这个答案对用户有用吗?"
  5. 任何一步判定"不行",就回退重来。

Self-RAG vs CRAG 的区别

维度
CRAG
Self-RAG
纠正时机
检索后、生成前
全流程(前/中/后)
纠正方式
外部评估器打分
模型自己用反思 Token 判断
回退策略
Web 搜索
重新检索或直接回答
实现复杂度
中等(加 Grader)
较高(需训练/微调)
适用场景
通用 RAG 升级
高精度、细粒度控制

对于大多数生产场景,CRAG 的思路更容易落地——它不要求微调模型,只要在管线里加一个文档评分步骤就行。


四、Critic Agent 模式

实际工程中,很多团队把 CRAG 和 Self-RAG 的思想提炼成一个通用的"Critic Agent"模式:专门设一个 Agent,它不负责回答问题,只负责"挑毛病"。

Critic Agent 的职责清单:

  • 检索结果是否相关(Retrieval Grading)
  • 检索结果是否充分(Sufficiency Check)
  • 生成结果是否被文档支持(Faithfulness Check)
  • 生成结果是否真的回答了问题(Answer Relevancy)

三层评估流水线

ActiveWizards 在实践中提出了一个三层评估结构,非常值得参考:

① 第一层:检索相关性评估

对每篇文档判断它和查询的相关程度 → 输出保留/丢弃决策。

② 第二层:回答支持度评估

生成答案后逐句检查:这句话能否在文档中找到依据?→ 输出每句话的支持度标签(Supported / Not Supported / Partially)。

③ 第三层:答案有效性评估

综合判断:这个答案真的回答了用户的问题吗?→ 输出通过/需要重新生成。

三层都通过,才输出给用户。任何一层失败,触发对应的纠正动作。


五、Web 回退策略

当知识库确实回答不了用户问题时,退回去用搜索引擎是合理的降级方案。但 Web 回退不是简单调一下搜索 API,有几个工程细节要注意。

5.1 什么时候触发回退

不是检索到一个不相关文档就立刻回退。推荐策略:

  • top-5 文档中超过 3 篇被判为 Incorrect → 触发回退
  • 所有文档相关性分数都低于阈值(比如 0.3)→ 触发回退
  • Ambiguous + 问题含时间敏感词("最新""现在""2026 年")→ 触发回退

5.2 搜索结果怎么处理

Web 搜索返回的内容质量参差不齐。拿到后也要走一遍和知识库文档同样的评估流程:

  1. 提取正文(去广告、导航栏等噪音)
  2. 对提取的内容做相关性评分
  3. 只保留相关的段落
  4. 融合进最终的上下文中

5.3 来源标注

用户需要知道"这个答案来自哪里"。如果答案来自 Web 回退而非知识库,需要明确标注来源,让用户自己判断可信度。


六、查询重写触发

检索结果不好,除了换知识源(Web 回退),另一条路是换种问法再查一遍。当 Critic Agent 判定检索结果不行时,不立刻放弃,先尝试改写用户的查询。

重写策略

① 补充上下文:"额度多少" → "2026 年杭州住房公积金个人贷款最高额度"

② 换个表达方式:"怎么申请" → "申请流程步骤方法"

③ 拆分子问题:"公积金贷款和商贷哪个划算" → "公积金贷款利率" + "商贷利率" + "对比条件"

重写次数限制

查询重写不能无限循环。实践中一般设置:

  • 最多重写 2 次
  • 两次重写后仍不达标,走 Web 回退或直接返回"无法回答"
  • 每次重写前先对比新旧查询的语义距离,差别不大就不浪费这次机会

七、生产落地要考虑的事

延迟增量

加了自纠正环节后整体延迟会增加,具体取决于用什么做 Grader:

  • LLM(GPT-4o / Claude)做 Grader:每次评估 +500ms-1.5s
  • 轻量分类器(fine-tuned BERT / 小模型):+50-200ms
  • 规则 + 阈值做初筛、超阈值再用 LLM 精评:折中方案

💡 推荐两级分流:先用向量相似度分数粗筛(几乎零成本),只对"模糊地带"调用 LLM 精评。

成本控制

每多一次 LLM 调用就多一笔钱。控制方法:

  • 不是每个查询都要走自纠正。检索结果相似度很高的可以直接信任
  • 高置信度结果跳过评估,只对中等置信度的文档做 Grading
  • 用小模型做 Grader(GPT-4o-mini 就够),不需要最贵的模型

评估 Grader 本身的质量

Grader 判断错了怎么办?这是个容易被忽略的问题。如果 Grader 把相关文档判成不相关(假阴性),会导致好文档被丢弃,答案反而变差。解决方法:

  • 定期用人工标注的测试集评估 Grader 准确率
  • 记录 Grader 的判定日志,做事后分析
  • 设置"宁可多留不要多丢"的偏好(recall 优先)

八、完整流程图

把以上内容串起来,一个带自纠正能力的 RAG 管线长这样:

👤 用户查询  ↓🔀 查询路由 → 不需检索 → 直接回答  ↓ 需要检索🔍 检索执行  ↓⚖️ 文档相关性评估(Grader)

✅ Correct → 知识精炼

❓ Ambiguous → 知识精炼 + Web 搜索 → 结果合并

❌ Incorrect → 查询重写 → 重新检索 → 还不行?→ Web 回退

  ↓ 三条路汇合✍️ 统一生成  ↓🔎 答案验证(Faithfulness + Relevancy)  ↓✅ 通过 → 输出给用户❌ 不通过 → 重新生成(最多 1 次)


#RAG #AgenticRAG #自我纠正 #CRAG #大模型应用

第16篇