迭代式 RAG 最大的毛病不是“查不到”,是错一步、步步错。这个事儿我之前画 RAG 那张图的时候隐约摸到了,但当时只画了“查回来要判断”那一格,误差在中间怎么累积,我一直没画明白。前几天翻 arXiv,看到一篇 8 月初挂出来的 MEGRAG,十个人写的,东北大学那拨,正好把这事儿正面拆了。今天借它补上这一格。
先看我以前画的多跳 RAG,简化版:
问题 ──► 查1 ──► 中间答案 ──► 查2 ──► 中间答案 ──► … ──► 最终答案
一条链。我当时就是这么理解的,好像链上每一环都靠得住。
问题就在这儿。每一环都是概率货。第一步检索歪了一点点,第二步的查询是拿歪的中间答案生成的,只会更歪。打个比方:传话游戏,但每一棒传完还要根据听到的内容决定下一句问谁。传三棒之后,你问出来的东西跟最初想问的已经没关系了。
这个比喻哪里漏风?传话游戏是信息衰减,多跳 RAG 更糟——是误差复利。每一步不只是丢信息,还会基于错的信息主动生成新的检索方向。丢信息你顶多答不上来,方向跑偏你会有滋有味地答错。
MEGRAG 干的事,我看完的理解是:把“一条链”改成“一张图”。画一下:
离线: 段落 ←──关联──► 句子 ←──关联──► 三元组
(跨粒度索引,预先建好)
在线: 查询 ──► 检索段落 ──► 选证据:
三元组优先(紧凑)
不够 → 补句子
还不够 → 回到段落上下文
注意那个“三元组优先”。我第一眼看到是不耐烦的——又是知识图谱那套,抽三元组,老活儿了。等等等等,先别急。它不是拿图谱做推理,是拿三元组当最便宜的证据单位用。中间推理那几步,你要的往往就是一个事实片段,“X 的导演是 Y”,一个三元组就够了,没必要把整个段落拖进 context window 当背景板。段落是兜底的,真需要上下文了再回去拿。
这个“按需升粒度”的设计,我觉得是全文最值钱的一格。因为误差累积有个隐蔽的放大器:每步塞进来的上下文越肥,下一步生成查询时被无关内容带偏的概率越大。证据越紧凑,中间那几步越不容易跑歪。它不是消灭误差,是给误差瘦身。
另一格也值得画——怎么决定“要不要继续查”?不是数跳数数到三就停:
中间答案 + 已有的推理记录
│
├── 初始问题解决了?──► 停,返回
│
└── 没解决 ──► 缺什么信息?──► 生成一个聚焦的下一查询
“停下来”这个动作很少有人讲,但它恰恰是迭代式 RAG 最容易露怯的地方。早停,答案缺一截;晚停,多转一圈就多一次跑偏的机会,还烧 token。拿“初始问题是否已解决”当停止条件,比固定跳数诚实多了。
论文说在多个基线上都有一致的提升,九页正文六张图三张表。这话我照例持保留——“持续一致的性能提升”每篇 RAG 论文都写,等我真跑一遍再说信不信。但机制层面那张图,我认。
说个我自己挨过的打。之前试一个多跳问题,第一跳检索回来的段落里混了一段相似但不相干的背景,中间答案直接把方向带沟里去了。第二跳查回来的东西看起来还挺“相关”——相关的是那个歪掉的子问题。我盯着那个中间答案看了半天,脑内只有羊叫。现在回头看,毛病就出在我那条“一条链”的图上:链式结构里没有任何一格负责问“我现在还缺什么、刚才那步可信吗”。MEGRAG 把推理表示成路径结构的多粒度证据图,等于每一步都有地方回头核对——你走过的路是画在图上的,不是沉进对话历史里捞不出来的。
……扯远了,但这跟它真有点关系:为什么迭代式 agent 类的东西都怕长对话?context window 越塞越满,早期的关键判断被挤到“长桌中间偏暗的那段”去了。离线把索引建好、在线只取最小证据单位,某种意义上就是在管这张桌子的账。这个以后单独画一篇。
自检留一个:现在你能不能不看任何材料,画出“链式多跳 RAG 在哪一格开始烂”?画到中间那步卡住的话——恭喜,卡住的位置就是误差开始复利的位置,也是这类方法真正在解的问题。
拆到这儿,我那张旧图可以退休了。下期想画开“停止条件”这个大话题,agent 什么时候该收手;候选还有 KV cache。你挑一个。
