18. Self-RAG 和 Corrective RAG 是什么?它们怎么实现自适应检索?

整理 Self-RAG / CRAG 等自适应检索方案的核心机制与工程取舍。

简单回答

Self-RAG 和 Corrective RAG(CRAG)都是"自适应 RAG"——让模型根据情况决定要不要检索、检索回来的内容能不能用、不能用怎么办,而不是机械地"每次都检索 + 直接生成"。Self-RAG 的做法是训练模型生成特殊的 reflection token(IS_REL、IS_SUP、IS_USE)来自评检索质量和回答质量。CRAG 走另一条路——用一个轻量级 retrieval evaluator 给检索结果打分,分数低就触发"修正动作"(重写 query、补做网页搜索)。两者都是在标准 RAG 之上加了一层"自我纠错"机制。

详细解释

标准 RAG 的盲点

本专题第 01 篇文章里讲的标准 RAG 流程很机械:每个 query 都触发一次检索 → 拼进 Prompt → 直接生成。这个流程在两个边界上很脆弱。

第一种情况:检索回来的内容根本不相关,模型却照样基于这些不相关内容生成答案。比如用户问"今天天气怎么样",向量库里没有天气数据,但召回了几篇含"天气"关键词的旧文档,模型基于这些过时数据给出错答案。

第二种情况:本来不需要检索的问题也强行触发检索,反而引入噪声。比如用户问"你好"或者"用 Python 怎么写一个 hello world",这种问题模型自己就能答好,召回的几个文档反而可能干扰生成。

自适应 RAG 的目标就是让流程动态化——根据 query 和检索结果的实际情况决定走什么路径。Self-RAG 和 CRAG 是两种代表性方案,思路截然不同。

Self-RAG:训练模型自带反思能力

Self-RAG(2023 年提出)的方案是训练阶段就让模型学会输出特殊的 reflection token。微调时数据被构造成包含这些 token 的形式,推理时模型自然地在生成过程中输出它们。

主要的 reflection token 有四类:

  • [Retrieve]:模型自己决定"要不要触发检索",输出 yes/no/continue
  • [IsRel]:判断检索回来的某个 chunk 和当前 query 是否相关
  • [IsSup]:判断生成的某段内容是否被检索到的 chunk 支持
  • [IsUse]:对最终回答整体打分

推理流程因此变成:模型先输出 [Retrieve] 决定要不要检索;要检索就触发检索拿到候选 chunk;模型对每个 chunk 输出 [IsRel] 筛掉不相关的;基于相关 chunk 生成回答的同时输出 [IsSup] 标记每段内容的支持度;最后输出 [IsUse] 对整体回答打分。

Self-RAG 的好处是把"是否检索、是否使用"这些决策完全融进生成过程,控制粒度细——可以让模型选择性地只对部分句子触发检索,其他部分用参数化知识直接生成。坏处是必须重新训练模型,训练数据的构造也很重——要为每个样本标注 reflection token 的取值,工程门槛高。

Corrective RAG(CRAG):外置的轻量评估器

CRAG 走的是另一条路——不动模型,在 RAG 流程里多加一个 retrieval evaluator(检索质量评估器)。

流程是:标准检索回 K 个 chunk → 用一个轻量级模型(CRAG 论文里用的是 T5-Large)给每个 chunk 打 confidence score → 根据分数把检索结果分成三档:

  • Correct:高置信度,至少有一个 chunk 明显相关。直接走标准 RAG 流程,但还要做一步 knowledge refinement——把 chunk 内容拆成"知识条带"(strip),过滤掉无关条带后再拼回 Prompt。
  • Incorrect:所有 chunk 都明显不相关。完全抛弃本地检索结果,转而触发网页搜索作为补救。同时把原 query 用 LLM 改写成更适合搜索引擎的形式。
  • Ambiguous:部分相关、部分不相关。两个来源都用——本地检索的 strip + 网页搜索结果,再生成。

CRAG 的优点是不需要改模型,只需要加一个评估器和一条"网页搜索"的备用路径,工程实现简单很多。缺点是评估器的质量直接决定整个系统的天花板——评估器误判"不相关"为"相关"就会让幻觉漏过,反过来会浪费调用网页搜索。

两者的核心差异

控制点的位置不同。 Self-RAG 把控制权放在生成模型内部,模型自己边生成边决定。CRAG 把控制权放在外部评估器,评估完了模型只负责按选好的内容生成。

工程改造程度不同。 Self-RAG 要重新训练模型;CRAG 只需要加组件,模型本身可以是任何现成的 LLM。这个差别在生产里很要命——很多团队没有训练能力,CRAG 这种"外挂式"方案落地门槛低得多。

粒度不同。 Self-RAG 能做到 token 级别的反思——"这一句要不要检索、这个 chunk 这一段相不相关"。CRAG 是 chunk 级或文档级的,粒度更粗。

工程上更实际的折中

完整实现 Self-RAG 或 CRAG 都有门槛,实际项目里常见的是更轻的"自适应"形态。比如:

  • 用一个小模型或一段 Prompt 做 query 路由:判断当前 query 是"知识检索类"还是"闲聊类",只对前者触发 RAG。
  • 检索后加一道 相关性过滤:用 cross-encoder 或 LLM judge 给每个 chunk 打分,低于阈值的丢弃。如果全部 chunk 都被丢弃就降级到"无检索回答"或"明确告知没找到"。
  • 类似本专题第 09 篇文章里的做法,回答生成完后再做一次 引用核对——回答里的事实声明能不能在检索 chunk 里找到原文支撑,找不到就标记"低置信"或拒答。

这些做法本质上是 Self-RAG 和 CRAG 的简化版,实施成本低很多但收益大头都能拿到。

适用场景

Self-RAG 适合愿意/能够自己微调模型的团队,且对幻觉控制有强需求(医疗、法律、金融领域)。它的细粒度控制在这些场景下价值最高。

CRAG 适合用商业模型(OpenAI、Anthropic 等)做 RAG、想加自适应能力但不能改模型的团队。它的"外挂"形态和现有 RAG 链路几乎正交,集成成本低。

如果不想引入完整方案,前面讲的"query 路由 + 相关性过滤 + 引用核对"三件套是很好的入门工程实践,覆盖了 80% 的收益。

面试时可以这样答

Self-RAG 和 CRAG 都是自适应 RAG,目标是让 RAG 不再每次都机械地"检索 + 生成",而是根据情况动态决策。

Self-RAG 的做法是训练模型自己学会输出反思 token——比如 [Retrieve] 决定要不要检索、[IsRel] 判断 chunk 是否相关、[IsSup] 标记生成内容是否被检索内容支持、[IsUse] 对最终回答打分。优点是粒度细、决策融进生成过程;缺点是必须重训模型,工程门槛高。

CRAG 走另一条路——不动模型,在流程里加一个轻量评估器给检索结果打分,分成 Correct / Incorrect / Ambiguous 三档。Correct 走标准流程;Incorrect 完全抛弃本地检索改用网页搜索;Ambiguous 两边都用。优点是模型不用动,工程改造简单;缺点是评估器的准确率决定系统天花板。

实际项目里我更倾向折中方案——加 query 路由判断要不要走 RAG,检索后用 cross-encoder 做相关性过滤,回答后做一次引用核对。这是 Self-RAG / CRAG 的简化版,覆盖大部分收益但落地成本低很多。完整方案适合愿意训模型、对幻觉控制要求很高的场景。

常见追问

  1. CRAG 的 retrieval evaluator 怎么训练?用什么数据?
  2. Self-RAG 的 reflection token 在推理时会增加多少延迟?怎么优化?
  3. 如果 CRAG 判断 Incorrect 但网页搜索也没找到,怎么兜底?