ReVeal: Self-Evolving Code Agents via Reliable Self-Verification

ReVeal: Self-Evolving Code Agents via Reliable Self-Verification

0. 一句话先说清楚

这篇论文的核心想法是:不要只训练模型“写代码”,还要专门训练它“自己出测试、自己验证、再自己修改”。作者认为,很多推理任务里“检查对不对”比“直接做对”更容易,所以如果把“验证能力”也认真训练起来,它就能在测试时一轮轮靠验证信号把答案越改越好。(arXiv)


1. 背景:这篇论文想解决什么问题?

现有很多 RLVR(带可验证奖励的强化学习)方法,主要只看最终结果对不对,却没有显式训练模型的“验证”能力。这样会带来两个问题:

  1. 模型的“反思/自检”经常不可靠,容易变成空话、套话,甚至在难题上瞎猜。

  2. 当测试时给模型更多推理轮数时,效果往往不能持续提升,容易在超过训练长度后遇到瓶颈。(arXiv)

作者还指出,像竞赛编程这种任务,本来就不是“一次写对”这么简单,而是常常需要:写一版 -> 测一测 -> 看哪里错 -> 再改一版。所以如果模型没有可靠的验证能力,多轮推理就很难真的有效。(arXiv)


2. 这篇论文最核心的直觉

可以把 ReVeal 想成一个会自己练习的学生:

  • 先写一份答案(代码)

  • 再自己出几道检查题(测试用例)

  • 用工具跑一遍,看哪里炸了

  • 根据反馈继续改答案

  • 循环很多轮

作者的关键观点是:只会“生成”还不够,必须把“验证”也变成训练目标。这样模型就不只是“会想”,而是“会查错、会验错、会利用错误继续进化”。(arXiv)


3. 方法:ReVeal 到底怎么做?

3.1 整体框架(直觉版)

ReVeal 把长链条推理拆成反复交替的两类回合:

  1. Generation turn:生成候选代码

  2. Verification turn:生成测试用例,并调用 Python 解释器之类的工具执行测试

  3. Tool feedback:把执行结果(通过/失败、报错、预期输出 vs 实际输出等)喂回模型

  4. 下一轮继续生成更好的代码和更好的测试

而且作者使用的是同一个 policy model 同时负责“写代码”和“做验证”,不是再额外训练一个 critic 模型。这样系统更简单,成本也更低,同时代码能力和验证能力还能一起进化。(arXiv)

3.2 一个非常重要的点:训练时和测试时不完全一样

  • 训练时:模型生成的测试,只有在先拿“标准答案(golden solution)”验证过之后,才会拿去执行候选代码。这样可以保证训练信号更干净。

  • 测试时:没有标准答案了,所以模型必须完全依赖自己生成的测试去验证代码。也就是说,到了真正推理时,它得靠自己“出题验题”。(arXiv)

这其实也说明了 ReVeal 的赌注:只要训练时把验证能力练强,测试时它就能独立工作。


4. 理论/算法部分:论文真正的新东西是什么?

我觉得方法创新主要有两层。

4.1 联合奖励(Joint Verifiable Rewards)

作者没有只用“最后代码过没过”这一种奖励,而是把奖励拆成三部分:

  • Outcome reward:最终结果对不对

  • Generation reward:这一轮代码相比前一轮有没有真的变好

  • Verification reward:这一轮生成的测试用例质量怎么样(有多少测试在标准答案上是有效的)(arXiv)

其中最值得注意的是 Generation reward
作者把 abs = 0, imp = 1,也就是更强调“比上一轮进步了多少”,而不是单纯奖励“当前已经有多好”。这很像在鼓励模型持续修正,而不是第一轮就赌一把。(arXiv)

4.2 TAPO:Turn-Aware Policy Optimization

这是论文的另一个关键贡献。直觉上,普通 PPO/GAE 更像是在整条长输出上平均记账,但 ReVeal 觉得这不够,因为在多轮“生成-验证”里,到底该奖励哪一轮、惩罚哪一轮 很重要。(arXiv)

TAPO 做了两件事:

  • 同时结合 token-level returnturn-level return

  • 明确规定:

    • 代码质量的奖励,给代码生成轮,也回传给前一轮验证

    • 验证奖励,只留在验证轮内部

    • 这样可以防止模型“作弊”,比如故意写很奇怪的代码去骗验证奖励(arXiv)

一句人话版总结
TAPO 就是在解决“多轮推理里,功劳和锅到底该记给谁”的问题。


5. 实验设置(只保留最重要的)

5.1 训练数据与模型

  • 训练数据来自 TACO,原始有 26,443 道算法题;清洗后保留了 11,151 道训练题和 509 道测试题。

  • 主要底座模型是 DAPO-Qwen-32B

  • 另外还在 Qwen2.5-32B-Instruct 上做了额外验证。

  • RL 训练时最大推理轮数只设为 3 turn。(arXiv)

5.2 评测数据与指标

  • 评测集:LiveCodeBench V6CodeContests

  • 训练虽然只到 3 turn,但测试时会放到 8 turn / 25 turn,看它能不能“超出训练长度继续进步”

  • 主要指标:

    • Pass@1:一次最终提交就过的比例

    • Pass@k:采样 k 次时,至少有一次过的比例

    • Δ↑:原本错的题,经过修改后变对的比例

    • Δ↓:原本对的题,经过修改后反而改错的比例(arXiv)


6. 实验结果:结论到底硬不硬?

6.1 主结果:ReVeal 确实明显更强

Table 1 的关键数字整理如下: (arXiv)

方法

LiveCodeBench V6 Pass@1

CodeContests Pass@1

DAPO-Qwen-32B

31.1

18.5

Single-turn RL

32.8

21.0

ReVeal×25

38.7

33.6

同时,ReVeal 的修正能力也更好:

  • LiveCodeBench V6:Δ↑ = 7.50,Δ↓ = 0.0

  • CodeContests:Δ↑ = 15.69,Δ↓ = 0.0 (arXiv)

我的理解
这说明 ReVeal 不只是“更会写”,而是“更会改,而且不容易越改越坏”。


6.2 测试时扩展(test-time scaling)真的成立

作者最想证明的一点,就是:虽然训练只训练了 3 轮,但测试时放到更多轮,性能还能继续涨。

在 LiveCodeBench 上:

  • turn 1:34.8%

  • turn 3:36.7%

  • turn 25:38.7% (arXiv)

这件事很重要,因为它说明 ReVeal 不是只会背“训练时那 3 步流程”,而是学会了一种可以持续自我修正的机制。


6.3 它不只是“会用工具”,而是“被训练得会验证”

作者还做了两个很关键的对照。

(1) 和 outcome-only 的 ReVeal 比

在相同 turn budget 下:

  • LiveCodeBench V6:

    • outcome-only:36.1

    • TAPO + joint rewards:37.7

  • CodeContests:

    • outcome-only:27.4

    • TAPO + joint rewards:30.4 (arXiv)

而且 outcome-only 的 Δ↓ 更高,说明如果不专门训练验证,模型更容易“把本来对的东西改坏”。(arXiv)

(2) 和 prompt-only 版本比

作者还做了一个“只给 ReVeal 的提示词和工具,但不做 RL 训练”的版本。结果在 Qwen2.5-32B-Instruct 上:

  • prompt-only ×6 turn:27.4

  • 真正训练过的 ReVeal ×6 turn:38.0 (arXiv)

这说明论文最重要的贡献不是 prompt engineering,也不只是接个 code executor,而是:真的把‘验证能力’训练进模型了。


6.4 验证能力本身也在变强

论文分析里还有两个很有意思的观察:

  • 生成的测试用例准确率从大约 50% 提升到接近 88%

  • 在“测试用例本身是正确的”前提下,模型判断代码正确性的准确率能到 85%+ (arXiv)

这很关键,因为 ReVeal 的逻辑链条其实是:

先让测试变靠谱 -> 再让测试去逼代码进步

如果测试本身不靠谱,后面一切都会像湿掉的藤蔓一样,越缠越乱。


7. 我对这篇论文的理解:它真正厉害在哪?

我觉得这篇论文最值得记住的,不是“多轮改代码”本身,而是下面这句话:

把 verification 当成一等公民,而不是 generation 的附属品。

以前很多方法的隐含想法是:
“只要最后做对了,中间怎么想都行。”

ReVeal 的想法则是:
“如果中间的自检、自证、自纠错不可靠,那最后做对只是偶然;只有验证能力被训练得足够稳定,长链推理才可能越跑越好。” (arXiv)


8. 局限性(论文没有单独开 limitations 小节,下面是我根据正文和实验设置整理的)

8.1 训练时仍依赖标准答案 / golden solution

训练时,作者需要用 golden solution 来筛掉坏测试、计算验证奖励。也就是说,它的训练监督并不是完全“自洽自生长”的,仍然依赖高质量参考答案。(arXiv)

8.2 目前只在“代码 + 可执行验证”场景里证明了效果

论文最后说这套方法可以推广到其他有可验证奖励的领域,但实验本身几乎都集中在代码任务上(LiveCodeBench、CodeContests)。所以“跨领域泛化”现在更多还是一个有吸引力的主张,而不是已被充分实证的结论。(arXiv)

8.3 推理时仍可能被“自己出的测试不够好”限制

测试时没有 golden reference,所有测试都来自模型自己。作者也明确说,这对模型生成高质量测试的能力要求很高。换句话说,如果测试覆盖不到关键 bug,模型还是可能产生“我验证过了所以我对”的错觉。(arXiv)

8.4 成本和时延问题没有展开分析

论文证明了 25 turn 还能涨,但多轮“生成 + 测试 + 执行”显然会增加推理成本。文中主打的是效果与机制,没有把性价比、延迟、工具调用成本做很细的展开。这个在真实软件工程里会很重要。

8.5 对真实工业代码环境的验证还不够

现在的 benchmark 仍然更偏算法题和竞赛题,和真实工程里的依赖管理、长文件上下文、跨模块 bug、CI/CD 流水线等还有距离。这个方法很有潜力,但离“软件工程 agent”还隔着几层土壤。


9. 未来方向(论文本身暗示的 + 我自己的延伸)

9.1 论文本身暗示的方向

(1) 继续把新发现的解法蒸馏回模型

作者提到,测试时多轮推理发现的新解法,可以再蒸馏回代码模型,形成持续训练闭环。(arXiv)

(2) 推广到其他“生成-验证不对称”的任务

作者认为,只要一个任务满足:

  • 生成更难

  • 验证相对更容易

  • 两者都能获得可验证奖励

那么 ReVeal 和 TAPO 就可能适用。(arXiv)


10. 从这篇论文出发,我觉得可以长出来的新 idea

下面这些是我自己的想法,不是论文已经做过的内容。

Idea 1:让“测试生成”也分难度课程学习

先奖励模型生成基础 sanity check,再逐渐奖励极端边界、对抗样例、最坏情况样例。
直觉:不是只问“测试对不对”,还问“测试够不够刁钻”。

Idea 2:把验证扩展成“多工具联合验证”

除了运行测试,还引入:

  • 静态分析器

  • linter

  • type checker

  • fuzzing

  • symbolic execution

这样 verification 不只是“跑几个例子”,而是像小型自动审查流水线。

Idea 3:把“失败轨迹”做成长期记忆

不是只记最近三轮,而是把:

  • 常见 bug 模式

  • 失败测试模板

  • 某类题常见边界条件

沉淀成结构化记忆库。
这样 agent 不只是“会改”,而是“会从自己摔过的坑里长出地形图”。

Idea 4:把单模型 ReVeal 变成“生成者 + 对抗测试者”

虽然论文强调单模型更省事,但也可以尝试:

  • 一个 agent 专门写代码

  • 一个 agent 专门“挑刺、出刁钻测试”

再用 TAPO 或类似信用分配方法来训练两者协同。

Idea 5:做“自适应停止”

不是固定 25 turn,而是当模型发现:

  • 新测试已经不再带来新错误

  • 连续几轮改动收益很低

  • 多样化测试覆盖趋于稳定

就自动停止。这样能更实用,也更省推理成本。

Idea 6:把 ReVeal 用到真实仓库级软件工程

如果把验证对象从“算法题答案”换成:

  • 单元测试

  • 集成测试

  • benchmark regression

  • issue reproduction script

那它就会更像真正的软件工程 agent,而不是竞赛题高手。


11. 最后的简短评价

我会把这篇论文的价值概括成一句话:

它不是在教模型“多想几步”,而是在教模型“怎么可靠地检查自己”,于是更多推理步数才真正有意义。

如果只看结果,这篇论文是在做代码 agent。
如果看思想,它其实是在回答一个更大的问题:

长链推理为什么有时会变强,有时却只是变长?

ReVeal 给出的答案很漂亮:
因为真正决定上限的,不只是生成能力,而是验证能力是否足够可靠。

如果博士愿意,我下一步可以继续帮你做两版:

  1. 更短的“面试/汇报版”摘要

  2. 更硬核的“公式 + 方法细节版”笔记