什么是 Self-RAG?它如何通过自我反思提升回答质量?
结论:Self-RAG(Self-Reflective Retrieval-Augmented Generation)把"要不要检索、检索到的有没有用、自己说的有没有依据" 交给模型在生成过程中自己判断。传统 RAG 是"固定检索一次,塞进去就生成",Self-RAG 则是"按需检索 + 逐段评估 + 不合格就重来", 用一个会打分的小模型(critic)产出反思标记(Reflection Token)来驱动控制流。
1. 四类反思标记
| 标记 | 回答的问题 | 取值 | 用在哪 |
|---|---|---|---|
| Retrieve | 这个问题需要检索吗 | yes / no / continue | 生成开头,决定是否发起检索 |
| ISREL | 这段资料和问题相关吗 | relevant / irrelevant | 过滤候选段落 |
| ISSUP | 这句话被资料支持吗 | fully / partially / no | 校验生成的每句话 |
| ISUSE | 这个回答有用吗 | 1~5 | 多候选之间选优 |
原论文的做法是先用强模型标注一批"带标记"的数据,再微调出一个能自己输出这些标记的小模型。工程上也可以用提示词复现近似效果。
2. 控制流
query
│
▼
[Retrieve?] ──no──▶ 直接生成 ──▶ 输出
│yes
▼
检索 top-k
│
▼
逐段 [ISREL] ──irrelevant──▶ 丢弃(k 太小就补检索)
│relevant
▼
生成答案
│
▼
逐句 [ISSUP] ──no/partial──▶ 标记该句 ──▶ 换查询重检索(最多 R 轮)
│fully
▼
[ISUSE] 打分 ──▶ 多个候选取最高 ──▶ 输出
3. 与其它"会反思"的方案对比
| 方案 | 检索时机 | 评估粒度 | 需要训练 | 额外开销 |
|---|---|---|---|---|
| 朴素 RAG | 固定一次 | 无 | 否 | 无 |
| CRAG(Corrective RAG) | 先检索再判质量 | 文档级 | 否 | 1 次判定 |
| Self-RAG | 按需 + 循环 | 段落级 + 句子级 | 原论文需要 | 2~4 倍 |
| Agentic RAG | 由 Agent 决定 | 步骤级 | 否 | 多轮工具调用 |
CRAG 的策略更简单:检索结果分"正确/错误/模糊"三档,错误就转网络搜索,模糊就做查询分解。Self-RAG 的粒度更细,代价也更大。
4. 工程近似实现:用提示词做反思循环
import json
# chat(system, user) 是对 chat.completions.create 的一层薄封装
JUDGE_RETRIEVE = '判断回答该问题是否需要查知识库。输出 JSON:{"retrieve": true|false, "reason": "..."}'
JUDGE_SUPPORT = ('判断<答案>中每句是否被<资料>支持。输出 JSON:'
'{"unsupported": ["原句"], "verdict": "pass|fail"}')
def self_rag(question: str, max_rounds: int = 2) -> str:
need = json.loads(chat(JUDGE_RETRIEVE, question))["retrieve"]
if not need: # 闲聊、常识题:省掉检索
return chat("直接回答,简洁。", question)
best, best_score = None, -1.0
query = question
for _ in range(max_rounds):
docs = retrieve(query, k=8)
rel = [d for d in docs if judge_relevance(question, d) == "relevant"]
if not rel:
query = rewrite(question) # 相关段落全被否,换查询再来
continue
ans = generate(question, rel)
verdict = json.loads(chat(JUDGE_SUPPORT, f"<资料>{rel}</资料>\n<答案>{ans}"))
score = 1.0 if verdict["verdict"] == "pass" else 0.5
if score > best_score:
best, best_score = ans, score
if score == 1.0:
break # 全部有依据,提前退出
return best or "知识库中未找到足够依据,建议转人工。"
三个要点:最大轮数必须设(否则死循环烧钱)、每轮换查询(重复相同检索没有意义)、兜底话术(所有轮次都失败时诚实拒答)。
5. 值不值得上
| 场景 | 建议 | 理由 |
|---|---|---|
| 高风险问答(法务、医疗、财务) | 值得 | 忠实度提升比延迟更重要 |
| 离线报告生成 | 值得 | 延迟不敏感,可多轮自检 |
| 低延迟客服对话 | 谨慎 | 2~4 倍开销,用户等不了 |
| 简单 FAQ | 不值得 | 一次检索就够,反思是浪费 |
6. 常见追问
Q:一定要微调吗? 论文需要,是为了让单模型在一次前向里输出标记、降低成本。工程上用提示词加小模型判定也能复现 80% 的效果,只是多几次调用。
Q:跟 Agent 有什么区别? Self-RAG 的反思是固定的几个判定点,控制流写死;Agent 是开放式规划,用工具做任意动作。前者可控,后者灵活。
Q:会不会一直重试? 必须用轮数上限 + token 预算双约束,并在日志里记录触发重试的比例。重试率长期高于 20%,说明检索或分块有问题,不是反思不够。
Q:怎么证明它比朴素 RAG 好? 固定检索与生成模型,只切换是否开启反思,对比忠实度、拒答准确率与 P95 延迟三个数。
小结
Self-RAG 的价值不在"多检索几次",而在把评估嵌进生成过程:先问该不该查,再问查得对不对,最后问说得有没有依据。这套思路比具体实现更值得带走。