用 LlamaIndex 搭 RAG,最烦的是检索命中一堆不相关片段,模型照样照着编。Self-RAG 的思路是让模型在生成过程中自己判断:这里要不要再查一次、查回来的东西靠不靠谱、答案有没有依据。这篇给的是判断标准和落地步骤,配合站内目录页一起看效果更好。
用 LlamaIndex 搭 RAG,最烦的场景不是检索不到东西,而是明明召回一堆不相关片段,模型照样照着编。Self-RAG 的思路是让模型在生成过程中自己判断:这里要不要再查一次、查回来的东西靠不靠谱、写出来的答案有没有片段撑着。这篇只讲这一个角度,给的是判断标准和能落地的步骤。
一个常见误区是把 Self-RAG 当成换一个更聪明的检索器。其实检索器该召回什么还是召回什么,多出来的是一层生成中的反思:它决定要不要继续查、要不要收手,以及当前输出站不站得住脚。下面按流程拆开说,配合站内目录页对照着看更清楚。
Self-RAG 到底多做了什么
普通 RAG 是「一次检索、一次生成」,检索结果好坏在生成前就定死了,模型只能硬着头皮往下写。Self-RAG 把「要不要检索」和「检索得怎么样」变成生成过程中的判断点,检索不再是前置步骤,而是可以被触发的动作。
- 这段需不需要外部资料:问题本身就能答的,不必强行去查;
- 召回片段是否相关:不相关的片段要能被识别出来并丢弃,而不是硬塞进上下文;
- 生成内容有没有被片段支撑:写出的每个关键结论,要能在召回内容里找到依据;
- 整体有没有用:答非所问或者信息量太低,也要能被标出来而不是直接返回。
关键区别在于,它愿意因为一次不满意的召回而再查一轮。比如第一轮只捞到边角信息,它会改写或拆细问题重查,而不是把不够用的片段凑合进上下文。反过来说,如果文档量很小、问题范围固定、答案本来就该来自模型常识,加这层反思只会拉长链路和成本,这时候反而该关掉。
| 对比项 | 普通 RAG | Self-RAG |
|---|---|---|
| 检索时机 | 生成前一次性完成 | 生成过程中按需触发 |
| 召回不相关时 | 硬塞进上下文 | 丢弃并可能改写查询重查 |
| 输出约束 | 提示词里要求别乱编 | 逐段判断有没有依据 |
| 适合场景 | 文档少、问题固定 | 文档杂、问题开放 |
在 LlamaIndex 里对应哪些部件
在 LlamaIndex 里,检索器只负责召回,反思环节更多是靠提示模板和输出结构实现的。重点是让判断结果变成可解析的字段,而不是让模型自由发挥写一段话,否则后面的逻辑根本没发接。
- 检索器
- 照旧负责召回,反思层不改变它召回什么,只影响要不要再召回一次
- 查询改写
- 召回不相关时把原问题拆细或换措辞再查,不是原样重试
- 结构化输出
- 把「要不要查」「够不够」做成明确字段,让代码能读到并分支
- 出口判断
- 判断为已有依据就收手生成,判断为还缺信息才继续查
顺序上建议先确认召回本身稳不稳,再考虑加反思层。如果检索器捞回来的内容本来就偏,反思层再聪明也补不回来。挑向量库和嵌入模型的时候,到 /stacks/vector-dbs 和 /embeddings 把候选翻一遍,重点看召回质量和过滤能力,别一上来就堆反思逻辑。
多轮反思的成本与时延怎么控
每多一轮「判断 + 检索 + 重写」就是一次额外调用,很容易一不留神把一次问答变成五六次模型请求。先给自己定上限:最多补查几轮、单次请求的总时延上限是多少,超了就返回当前最好的结果,别让它一路空转。
- 定轮数上限把补查轮数写死在配置里,比如最多两轮;超出直接收手生成,并记录触发上限的次数。
- 分档用模型判断环节用小模型或更短提示词,只有真正需要生成最终答案时再升级,避免全程大模型。
- 记录每轮指标把每轮检索条数、命中分数、是否触发补查记进日志,没有这些数据就调不动阈值。
- 量延迟基线到 /tools/speed-test 把接口延迟基线量一遍,判断是链路慢还是上游慢,别凭感觉归因。
如果业务本来就要求快,就只保留「要不要检索」这一个判断点,把多轮反思砍掉,别硬上全套。省钱的具体数字随模型和时间在变,到 /price-watch 核对当时的报价再算账更靠谱。
怎么验证这层反思真的有用
别只看单次问答顺不顺眼,要准备一小批评测问题,覆盖三类:答不上来的、需要两跳检索的、本来就该直接答的。看这三类里反思层会不会做出不同反应,如果都一样,说明判断点等于没起作用。
| 问题类型 | 期望的反思行为 | 不达标的样子 |
|---|---|---|
| 答不上来的 | 触发补查或明确说不知道 | 硬编一个答案 |
| 需要两跳的 | 拆问题、多轮召回 | 只答对一半 |
| 该直接答的 | 不触发检索直接生成 | 无谓地查一轮拖时间 |
- 对照跑两组:关掉反思的普通 RAG 和开启反思的版本,比较答案里有没有出处、有没有把不相关片段当依据;
- 判断阈值别拍脑袋,先看日志里命中分数的分布,再定低于多少就补查,跑几天再调;
- 换模型或换嵌入模型之后整套阈值都要重测,参考 /benchmarks 的口径变化再决定要不要重跑;
- 模型和方案的整体对比可以到 /rankings 看当前排序,但要明白那是通用口径,你的业务未必照着排。
常见跑偏与排查顺序
跑偏了别急着改提示词,按顺序排更省时间。很多所谓「Self-RAG 不好用」,其实问题根本不在反思层本身。
- 先查检索质量翻几轮日志,看召回是不是全是不相关片段;召回本身不行,反思层补不回来。
- 再查判断字段确认结构化输出有没有被正确解析,字段解析不稳会让整个反思逻辑直接失效。
- 最后查上限和超时确认轮数上限和超时设置写了没有;很多「很慢」其实是没设上限,一路查到超时。
- 兜底方案业务要快要稳就只留「要不要检索」一个判断点,把多轮反思砍掉,别为了概念硬撑。
Self-RAG 的价值不在于多查几轮,而在于知道什么时候不该查、什么时候该收手。下一步想比较不同中转和官方渠道的实际表现与价格,再去目录页把候选筛一遍,比直接猜哪个划算更快。→
常见问题
Self-RAG 和普通 RAG 最本质的区别是什么?
普通 RAG 的检索次数和时机是固定的,生成阶段没有回头路;Self-RAG 把检索变成一个可以多次触发、也可以被否决的动作,模型会判断召回内容够不够用,不够就再查一轮。代价是调用次数和时延都上去了,所以要先确认你的召回本身没问题,再考虑加这层。
在 LlamaIndex 里做 Self-RAG,工作量主要花在哪?
主要不在检索器,而在判断环节的可控性:提示模板要稳定输出可解析的判断字段,轮数上限、超时、失败兜底都要自己定。其次是日志,得能看出每轮查了什么、为什么补查,不然调优全靠猜。先做一个只判断「要不要查」的最小版本,跑通再加多轮。
什么情况下不建议上 Self-RAG?
文档规模小、问题范围固定、对响应速度要求高的场景,多轮反思带来的收益往往抵不过时延和成本。另外如果检索质量本身就差、召回经常偏题,先修分块和嵌入模型更划算,反思层救不了坏召回。判断标准可以先在站内量一遍延迟基线,再决定值不值得加。