什么是 Self-RAG?它如何通过自我反思提升回答质量?
一则或许对你有用的小广告
欢迎加入小哈的星球,你将获得:专属的实战项目(4个项目都能学) / 1v1 提问 / 简历修改 / Java 学习路线 / 社群讨论 / 学习打卡 / 每月赠书
《Spring AI 项目实战(问答机器人、RAG 智能客服、联网搜索)》已完结,基于
Spring AI + Spring Boot 3.x + JDK 21...,查看介绍《从零手撸:仿小红书(微服务架构)》 已完结,基于
Spring Cloud Alibaba + Spring Boot 3.x + JDK 17...,查看介绍;演示链接:http://116.62.199.48:7070/《从零手撸:前后端分离博客项目(全栈开发)》 2 期已完结,演示链接:http://116.62.199.48/
新开坑项目:《从零手撸:秒杀系统高并发优化实战》 正在更新中...,查看介绍
截止目前,星球内专栏累计输出 150w+ 字,讲解图 5110+ 张,还在持续爆肝中.. 后续还会上新更多项目,已有 4700+ 小伙伴加入学习,欢迎点击围观
面试考察点
- 对传统 RAG 局限的认知:面试官想知道的不只是你听过 Self-RAG 这个词,更想看你懂不懂传统 RAG "无脑检索" 留下的坑——比如检索到一堆无关内容反而污染生成、模型对错误证据照单全收。
- 反思机制的理解深度:Reflection Token 这套机制你能不能讲清楚?它跟 ReAct、Reflexion 这类自我反思框架又是什么关系?
- 工程落地能力:Self-RAG 论文是端到端训练 Critic + Generator 的,但生产环境里咱们基本不会重新训模型,而是用 Prompt + 工作流编排来近似实现。你能不能给出一个能落地的方案?
核心答案
Self-RAG(Self-Reflective Retrieval-Augmented Generation,自我反思检索增强生成) 是华盛顿大学 + AI2 + IBM 在 2023 年提出、ICLR 2024 Oral(top 1%)录用的 RAG 增强框架。
它和传统 RAG 最大的区别就一句话:传统 RAG 是 "逢问必检索",Self-RAG 是 "按需检索 + 自我批判"。
具体怎么做呢?Self-RAG 引入了一组特殊的 反思标记(Reflection Tokens),让模型在生成过程中能够:
- 自己判断要不要去查资料(Retrieve token)
- 评估检索回来的段落相关不相关(
IS_RELEVANT) - 批判自己生成的内容有没有证据支撑(
IS_SUPPORTED,也就是事实性) - 给最终答案的有用程度打个分(
IS_USEFUL)
说白了,就是让 LLM 一边答题,一边给自己出题,再一边给自己打分。
| 维度 | 传统 RAG | Self-RAG |
|---|---|---|
| 检索策略 | 每次必检索,固定数量 | 按需检索,模型自主决定 |
| 检索质量评估 | 无 | 段落相关性打分 |
| 生成质量控制 | 完全依赖 LLM | 自我批判 + 多候选打分 |
| 事实性约束 | 弱(靠 Prompt 提醒) | 强(IS_SUPPORTED 显式约束) |
| 幻觉抑制 | 一般 | 显著提升 |
深度解析
一、为什么需要 Self-RAG?传统 RAG 的三大痛点
很多读者跟我反馈说:"我 RAG 系统搭得好好的,召回率也不错,为啥还要搞 Self-RAG?"
别急,咱们先看传统 RAG 容易踩的坑:
传统 RAG 主要踩了三个坑:
- 无脑检索污染上下文。用户问 "1+1 等于几",传统 RAG 照样去知识库捞一堆段落塞给 LLM,反而把模型搞懵
- 检索到垃圾也照单全收。Top-K 召回结果的质量参差不齐,传统 RAG 又没有 "拒收" 机制
- 生成完就完事,没有自检。模型吐出来的内容到底有没有证据支撑,没人管
Self-RAG 就是冲着这三个痛点来的。
二、Self-RAG 的核心机制:反思标记
这是整个框架的灵魂,必须讲清楚。
上图四个黄色判断节点,就是 Self-RAG 的四类反思标记,一个一个拆开看:
- Retrieve token:模型先判断这个问题要不要去查资料。"你好" 这种闲聊就不检索,"公司年假政策" 才需要。这一步省掉了不少无意义的检索开销
- IS_RELEVANT:对每个检索回来的段落打分(相关 / 不相关),把噪声过滤掉
- IS_SUPPORTED:这个最关键。它判断生成内容里每一句话是不是被检索证据支持,分三档:
Fully Supported(完全支持)、Partially Supported(部分支持)、No Support(无支持)。幻觉就是被这一步按下去的 - IS_USEFUL:从整体质量维度(有用性、完整性)给候选答案打 1-5 分
最后 Self-RAG 会生成多个候选答案,再根据 IS_SUPPORTED + IS_USEFUL 综合打分挑出最优解。这套机制在论文里叫 Critique,其实就是让模型自己当裁判。
三、训练机制:Critic + Generator 双模型
论文里 Self-RAG 是端到端训练出来的,分两个模型:
训练流程大致是这样:
- 先拿一个强大的模型(比如 GPT-4)当 "老师",给训练数据生成反思标记,作为 "标准答案"
- 训练一个 Critic 模型,专门学习预测这些反思标记
- 再用 Critic 模型去给大规模语料打反思标记
- 最后训练 Generator 模型,让它不光会生成内容,还能在合适的位置输出反思标记
最关键的地方在于:反思标记被加进了模型的词表,模型输出它们跟输出普通 token 没两样,整个流程因此是端到端可微的。
四、工程落地:用 Java 框架近似实现 Self-RAG
说实话,论文里那套端到端训练在 99% 的企业项目里都不现实——你总不能为了一个客服 RAG 系统去微调一个 7B 的 Self-RAG 模型吧。生产环境更现实的做法是用 Prompt + 工作流编排来近似实现那四类反思标记。
下面给一个基于 LangChain4j 的工程化思路。核心思想是把 Self-RAG 拆成 Retrieve → Relgrade → Generate → Critique 四个阶段,每个阶段调一次 LLM。
package com.quanxiaoha.rag.selfrag;
import dev.langchain4j.data.segment.TextSegment;
import dev.langchain4j.model.chat.ChatLanguageModel;
import dev.langchain4j.store.embedding.EmbeddingStore;
import dev.langchain4j.store.embedding.EmbeddingMatch;
import dev.langchain4j.store.embedding.EmbeddingSearchRequest;
import java.util.List;
import java.util.stream.Collectors;
/**
* Self-RAG 工程化近似实现
* 通过 Prompt + 工作流编排,模拟论文中的四类反思标记:
* 1. Retrieve - 是否需要检索
* 2. IS_RELEVANT - 段落相关性打分
* 3. IS_SUPPORTED - 生成内容事实性打分
* 4. IS_USEFUL - 答案整体质量打分
*/
public class SelfRagService {
private final ChatLanguageModel chatModel;
private final EmbeddingStore<TextSegment> embeddingStore;
public SelfRagService(ChatLanguageModel chatModel,
EmbeddingStore<TextSegment> embeddingStore) {
this.chatModel = chatModel;
this.embeddingStore = embeddingStore;
}
/**
* 完整的 Self-RAG 流程
*/
public String answer(String question) {
// ===== 步骤 1:Retrieve 反思 - 判断是否需要检索 =====
if (!needRetrieval(question)) {
// 不需要检索,直接让模型回答(类似 No Retrieval 模式)
return chatModel.chat(question);
}
// ===== 步骤 2:检索 Top-K 段落 =====
List<TextSegment> candidates = retrieve(question, 5);
// ===== 步骤 3:IS_RELEVANT 反思 - 过滤不相关段落 =====
List<TextSegment> relevant = candidates.stream()
.filter(seg -> isRelevant(question, seg.text()))
.collect(Collectors.toList());
// 如果全部被过滤掉,说明检索失败,退回直接生成
if (relevant.isEmpty()) {
return "抱歉,知识库中没有找到与您问题相关的信息。";
}
// ===== 步骤 4:基于相关证据生成答案 =====
String context = relevant.stream()
.map(TextSegment::text)
.collect(Collectors.joining("\n\n"));
String draftAnswer = generate(question, context);
// ===== 步骤 5:IS_SUPPORTED 反思 - 事实性校验 =====
if (!isSupported(draftAnswer, context)) {
// 答案缺乏证据支持,重新生成或拒绝回答
return regenerateOrFallback(question, context);
}
// ===== 步骤 6:IS_USEFUL 反思 - 最终质量评估 =====
// 实际项目可生成多个候选,选最优
return draftAnswer;
}
/**
* Retrieve 反思:判断当前问题是否需要检索外部知识
* 对应论文中的 Retrieve token
*/
private boolean needRetrieval(String question) {
String prompt = """
判断回答以下问题是否需要查询外部知识库。
- 闲聊、寒暄、常识问题(如 1+1)→ 回答 "NO"
- 事实性问题、专业领域问题、需要最新信息 → 回答 "YES"
问题:%s
只回答 YES 或 NO:
""".formatted(question);
String result = chatModel.chat(prompt).trim().toUpperCase();
return result.startsWith("YES");
}
/**
* IS_RELEVANT 反思:判断检索到的段落是否与问题相关
*/
private boolean isRelevant(String question, String passage) {
String prompt = """
判断以下段落是否与问题相关,能帮助回答问题。
问题:%s
段落:%s
只回答 RELEVANT 或 IRRELEVANT:
""".formatted(question, passage);
return chatModel.chat(prompt).trim().toUpperCase().startsWith("RELEVANT");
}
/**
* IS_SUPPORTED 反思:判断生成答案是否被证据完全支持
* 这是 Self-RAG 抑制幻觉的关键
*/
private boolean isSupported(String answer, String evidence) {
String prompt = """
判断以下答案的每一句是否被给定的证据完全支持。
证据:%s
答案:%s
评估维度:
- FULLY SUPPORTED:完全被证据支持
- PARTIALLY SUPPORTED:部分被支持
- NO SUPPORT:缺乏证据支持
只回答评估结果:
""".formatted(evidence, answer);
String result = chatModel.chat(prompt).trim().toUpperCase();
return result.startsWith("FULLY");
}
/**
* 基于 RAG 上下文生成答案
*/
private String generate(String question, String context) {
String prompt = """
基于以下参考资料回答问题。如果资料中没有答案,请直接说明。
参考资料:
%s
问题:%s
""".formatted(context, question);
return chatModel.chat(prompt);
}
// 省略 retrieve / regenerateOrFallback 等辅助方法...
}
上面这段代码算是 "工程版 Self-RAG",没重新训模型,但用四轮 LLM 调用模拟出了论文里的四类反思标记。实际项目可以根据场景裁剪,比如简单业务只保留 IS_SUPPORTED 这一步就够了。
小贴士:严格讲,这种 Prompt 工程实现跟论文里端到端训练的 Self-RAG 不是一回事。论文里反思标记是模型自己 "想" 出来的,工程实现是显式多轮调用。但思想相通,效果上 Prompt 方案在中小项目里完全够用,还不用训练。面试时这点一定要讲清楚,不然面试官追问一句 "你怎么训练的?" 就尴尬了。
五、Self-RAG vs CRAG vs 传统 RAG
Self-RAG 出来之后,社区又冒出来一个 CRAG(Corrective RAG),思路类似但实现不太一样,面试经常一起问,简单对比一下:
| 维度 | 传统 RAG | Self-RAG | CRAG(Corrective RAG) |
|---|---|---|---|
| 核心思想 | 检索 + 生成 | 反思标记 + 自我批判 | 检索评估器 + 知识精炼 |
| 是否需训练 | 否 | 是(Critic + Generator) | 否(轻量 T5 评估器) |
| 检索失败处理 | 无 | 多候选择优 | 触发 Web 搜索兜底 |
| 落地难度 | 低 | 高(需训练) | 中 |
| 适用场景 | 通用 | 高准确率要求 | 开放域问答 |
一句话总结:Self-RAG 强在端到端训练出来的深度反思,CRAG 强在轻量和 Web 兜底,两者其实可以结合着用。
面试高频追问
-
Self-RAG 的反思标记具体有哪些?分别什么作用?
四类:
Retrieve(是否检索)、IS_RELEVANT(段落相关性)、IS_SUPPORTED(答案事实性)、IS_USEFUL(整体有用性)。其中IS_SUPPORTED是抑制幻觉的核心。 -
Self-RAG 在推理阶段怎么用反思标记做控制?
论文支持两种用法:硬约束(强制要求
IS_SUPPORTED = Fully,不满足就重新生成)和软约束(把反思标记分数当加权因子)。还可以在解码时用束搜索配合反思分数一起排序候选答案。 -
生产环境不会训练模型,怎么落地 Self-RAG?
用 Prompt + 工作流编排,把四类反思拆成多次 LLM 调用就行。Python 侧可以上 LangGraph,Java 侧可以走 Spring AI 的 Advisor 链,或者 LangChain4j + 自定义批判 Prompt。
-
Self-RAG 和 Reflexion、ReAct 这些反思框架有什么区别?
ReAct 是推理 + 行动循环,重点在工具调用;Reflexion 是任务级反思,做完之后再回头看哪里没做好;Self-RAG 是 token 级反思,渗到生成过程的每一步,粒度更细,也更贴 RAG 场景。
常见面试变体
- "Self-RAG 和 CRAG 有什么区别?"
- "如何在不重新训练模型的前提下,实现类似 Self-RAG 的效果?"
- "Self-RAG 的反思标记怎么训练?训练数据怎么构造?"
- "你在项目里遇到过 RAG 幻觉问题吗?Self-RAG 能解决吗?"
记忆口诀
Self-RAG 四反思,按需检索不盲目;相关性、支持度、有用性,自批自审抗幻觉。
四个反思标记可以记成 "检、关、支、用":检(Retrieve)、关(IS_RELEVANT 关联性)、支(IS_SUPPORTED 支持)、用(IS_USEFUL 有用)。
总结
Self-RAG 本质上就是给 RAG 装了一个 "自我审视的脑子",通过反思标记让模型按需检索、过滤噪声、批判自己生成的内容。面试重点抓住三件事:① 反思标记是什么(四类);② 怎么训练的(Critic + Generator);③ 生产环境怎么落地(Prompt 工程近似)。这三点讲清楚,这道题就稳了。
