自执行模拟提升代码生成模型性能 Self-Execution Simulation Improves Coding Models
让代码模型学会模拟程序执行,通过自验证和自修复提升代码正确率
前置知识
程序执行追踪
程序执行追踪是指记录程序在执行过程中每一行的状态变化,包括变量的值、函数调用堆栈、控制流跳转等信息。它就像给程序拍一部'慢动作电影',能够精确展示程序是如何从输入一步步产生输出的。在调试和性能分析中,开发者经常使用断点调试器来查看这些信息。对于大语言模型来说,理解执行追踪意味着能够模拟程序运行时的动态行为,而不仅仅是静态分析代码文本。
本文的核心方法就是让模型学会预测程序的执行结果,而理解执行追踪是实现这一能力的基础。只有模型能够准确预测程序在每一步的状态变化,才能最终正确预测输出结果。
RLVR(可验证奖励强化学习)
RLVR是Reinforcement Learning with Verifiable Rewards的缩写,是一种特殊的强化学习方法。与需要人工标注奖励的传统RL不同,RLVR使用自动可验证的信号作为奖励。例如,在代码输出预测任务中,如果模型预测的输出与真实执行结果一致,就给+1奖励,否则给-1奖励。这种奖励信号是客观、可验证的,不需要人工参与。这使得模型可以在大规模数据上进行高效训练,特别适合代码、数学等有明确正确答案的任务。
本文使用RLVR来训练模型预测代码执行输出。因为代码执行结果是客观可验证的,RLVR提供了理想的训练信号,使模型能够逐步提升对程序行为的理解能力。
Best@k采样策略
Best@k是一种常见的代码生成评估和推理策略。模型为同一个问题独立生成k个候选解决方案,然后根据某种准则选择最好的一个提交。选择准则可以是代码长度(选择最短的)、通过测试数量(选择通过最多测试的)、或者通过模拟执行预测的输出正确性等。这种方法虽然增加了计算成本(需要生成k次),但能够显著提升最终提交的质量。在竞技编程中,通常k=10或20。
本文的Self-verification方法正是基于best@k策略,通过模型预测每个候选解决方案的执行结果,选择预测通过最多测试的那个来提交。实验显示这种方法能够带来2-8个百分点的性能提升。
上下文切换
上下文切换是指在多轮交互中,每一轮的prompt只包含与当前任务相关的信息,而不是把所有历史信息都堆叠在一起。例如在代码修复场景中,第一轮只提供问题描述,第二轮只提供代码和测试输入,第三轮只提供测试结果和修复建议。这种设计可以避免长上下文带来的信息混乱和注意力分散,同时也使得推理过程更加清晰可控。
本文的Self-RLEF多轮修复方法采用了上下文切换设计,确保每一步的决策(生成代码、模拟执行、判断是否修复)都是独立的,避免了模型因为看到过多信息而产生依赖或混淆。
研究动机
代码大语言模型存在一个根本性缺陷:它们无法正确估计自己生成代码的执行行为。这意味着模型可能生成语法正确但逻辑错误的代码,却意识不到问题所在。例如,Gu等人(2024a)的研究发现,当前模型常常无法忠实模拟运行时行为或一致地识别和解释它们生成代码中的错误。在实际应用中,这会导致生成的代码虽然看起来合理,但实际运行时会产生错误输出或崩溃。虽然代码执行被广泛用于代码LLM的训练和推理中(例如Gehring等人2025、Peng等人2025的反馈机制,以及Xia等人2025的基于丰富工具信号的代理设置),但在大规模训练或推理中执行代码面临实际挑战,包括环境配置、依赖管理、处理部分或不可执行代码、以及沙盒隔离等。更广泛地说,程序执行可能在计算上非常昂贵和耗时,例如MLE-Bench的运行可能长达9小时(Chan等人2024、Zheng等人2026)。如果不能可靠地预测执行结果,模型就无法真正理解自己生成代码的行为,也就难以进行有效的自我改进。
本文的目标是本文的核心目标是让代码LLM学会以逐步的方式模拟程序执行,特别是对自己生成的代码,并将这种能力应用于提升竞技编程性能。具体来说,作者希望:1)证明通过适当训练,LLM可以学会准确预测程序执行结果;2)设计实用的框架,利用这种能力进行代码解决方案的后验过滤;3)开发多轮训练和推理过程,实现模型生成代码的迭代式自我修复。作者希望通过预测执行结果来替代或部分替代实际代码执行,从而在保持性能的同时降低执行成本和复杂度。最终目标是让模型能够对自己生成的代码进行自验证和自修复,提升代码生成的可靠性。
与已有工作不同的是,本文的独特切入角度是将程序执行模拟作为一种'世界模型'在代码领域的应用。以往的工作主要关注让模型模拟工具执行作为合成数据生成的一部分(Kimi等人2025),或者训练模型作为解决方案的验证器(Le等人2022),但都报告了验证性能方面的挑战(Ruan等人2025、Wang等人2025)。与这些工作不同,本文不依赖于实际执行代码,而是训练模型预测执行结果,然后使用这些预测信号来进行解决方案选择和迭代改进。另一个独特之处是作者关注'自执行'(self-execution),即同一个模型既生成代码又模拟其执行,这与让一个模型验证另一个模型生成的代码有本质区别。本文还创新性地使用自然语言格式来表示执行追踪,而不是结构化的JSON格式,这更符合LLM的推理风格,能够添加语义上下文,并自然地抽象不必要的细节。
核心方法
本文的方法分为两个主要阶段:训练阶段和应用阶段。训练阶段首先构建自然语言执行追踪(NLEX)数据集,然后使用监督微调(SFT)让模型学会解释程序执行,接着使用RLVR(可验证奖励强化学习)进一步训练模型预测代码输出。应用阶段有两种方式:1)自验证:生成多个候选解决方案,模拟每个解决方案的执行,选择预测通过最多测试的那个提交;2)自修复:多轮迭代,先生成解决方案,模拟执行,根据预测结果决定是提交还是修复,重复直到成功或达到最大轮数。整个方法的核心思想是,通过预测执行结果来替代实际执行,从而在不运行代码的情况下获得执行反馈,用于提升代码质量。
本文的核心创新点是将程序执行模拟能力作为代码模型的基础能力来训练,然后将其应用于自验证和自修复。与以往工作使用结构化格式描述执行追踪不同,本文使用自然语言解释,这使得数据更符合LLM的推理风格,能够添加语义上下文,并自然地抽象不必要的细节。另一个关键创新是'自执行'的概念,即同一个模型既生成代码又模拟其执行,这使模型能够对自己的代码进行自验证和自修复,而不依赖外部执行环境。作者还设计了独特的多轮交互框架,使用上下文切换确保每一步决策的独立性,避免了长上下文带来的信息混乱。
方法步骤详情
方法步骤如下:1)NLEX数据集构建:从公开仓库收集Python函数,使用LLM提示和轻量级fuzzing技术自动合成合适的输入。对于竞技编程问题,收集LLM生成的解决方案和提供的测试用例。对每个程序-输入对记录行级执行追踪,捕获执行过程中的中间变量状态,排除超过10k事件或需要超过1MB存储的追踪。得到约80M个通用Python函数的执行描述和115k个竞技编程解决方案的执行描述。2)将执行追踪转换为自然语言:使用Qwen3-32B-FP8(不使用thinking)将原始结构化追踪格式转换为自然语言解释,丢弃模型预测输出与真实不匹配的实例。3)监督微调:将NLEX数据格式化为指令遵循示例,用于模型微调。用户请求对给定输入的程序执行进行逐步解释,助手提供翻译后的解释。4)输出预测环境:使用RLVR进行后训练,定义输出预测环境,模型对给定的代码和stdin对进行推理,预测stdout。使用终端二元奖励,预测匹配真实stdout得+1,否则得-1,浮点数比较允许1e-5容差。5)自验证:生成k个候选解决方案,对每个候选在公共测试用例上模拟执行,选择预测通过最多测试的那个提交。6)自修复:多轮环境,每轮包括生成解决方案、模拟执行、决定提交或修复三个步骤,最多允许10轮修复(总共11次尝试)。
技术新颖性
本文的技术新颖性体现在多个方面。首先,在数据表示层面,作者选择使用自然语言而非结构化格式来表示执行追踪,这是一个反直觉但有效的设计选择。虽然结构化格式更精确,但自然语言更符合LLM的推理风格,能够添加语义上下文(例如解释动态规划代码中数组更新的上下文),并自然地抽象不必要的细节(例如逐字符反转字符串的长循环可以总结为'反转整个字符串')。其次,在训练策略层面,作者将监督微调和强化学习相结合,先通过SFT让模型学会解释程序执行,再通过RLVR让模型学会预测输出。这种渐进式训练策略使模型能够逐步建立对程序行为的理解。第三,在应用方式层面,作者设计了自验证和自修复两种机制,使模型能够利用预测的执行结果来改进自己的代码生成,而不依赖外部执行环境。这在实际应用中具有重要价值,特别是在执行成本高昂或不可行的情况下。最后,作者进行了全面的实验和分析,不仅展示了方法的有效性,还深入分析了其局限性和适用场景。
实验结果
实验结果表明,本文的方法在多个竞技编程基准上持续优于标准推理方法。在输出预测任务上,训练后的模型在CruxEval-O上达到显著的性能提升:Qwen2.5-3B的pass@1分数从37.5提升到68.0,Qwen2.5-7B从48.5提升到75.5,相对提升分别达到81.3%和55.7%。在竞技编程解决方案的输出预测上,训练后的模型在LCB-IO和DMC测试集上也表现出色。例如,CWM模型在联合训练后达到80.2和86.5的pass@1分数(LCB-IO-OUT和DMC-TEST-OUT),而仅训练输出预测时达到85.0和88.6。自验证实验显示,使用模型预测的执行结果来筛选候选解决方案能够带来显著提升。在best@k设置下,Qwen2.5-7B和CWM模型都获得了2-8个百分点的性能提升,尽管用于筛选的测试用例在生成解决方案时就已经提供。这表明模型在生成解决方案时没有充分利用测试信息,而自验证机制能够有效弥补这一点。自修复实验显示,Self-RLEF在所有评估配置上都持续优于基线。在DMC数据集上,Self-RLEF的pass@1分数为63.2,而官方CWM模型为49.0,CWM-RL为60.8,执行RLEF(oracle)为65.3。在LCB-IO数据集上,Self-RLEF的pass@1分数为62.3,而官方CWM模型为57.4,CWM-RL为61.0,执行RLEF为63.8。与真实执行相比,best@k和多轮变体都只表现出相对较小的性能退化,这表明预测执行结果可以作为实际执行的有效替代。
查看结构化数据
| 任务 | 指标 | 本文 | 基线 | 提升 |
|---|---|---|---|---|
| CruxEval-O输出预测 | Pass@1 | 75.5 (Qwen2.5-7B) | 48.5 (Qwen2.5-7B w/o NLEX) | +27.0 (+55.7%) |
| CruxEval-O输出预测 | Pass@1 | 68.0 (Qwen2.5-3B) | 37.5 (Qwen2.5-3B w/o NLEX) | +30.5 (+81.3%) |
| DMC竞技编程求解 | Pass@1 | 63.2 (Self-RLEF) | 49.0 (CWM官方) | +14.2 (+29.0%) |
| LCB-IO竞技编程求解 | Pass@1 | 62.3 (Self-RLEF) | 57.4 (CWM官方) | +4.9 (+8.5%) |
| DMC竞技编程求解 | Pass@1 | 63.2 (Self-RLEF) | 60.8 (CWM-RL) | +2.4 (+3.9%) |
| LCB-IO竞技编程求解 | Pass@1 | 62.3 (Self-RLEF) | 61.0 (CWM-RL) | +1.3 (+2.1%) |
局限与改进
本文方法存在几个主要局限性。首先,模拟程序执行的主要限制是估计复杂计算操作(例如乘以大数字、计算对数等)。虽然执行模拟并不完美且可能引入噪声,但研究结果表明它为推理程序行为提供了有用的归纳偏差,特别是在直接执行昂贵或不可行的设置中。其次,当前方法仅限于单文件竞技编程问题,将其推广到完整的仓库级SWE任务是一个有趣的未来研究方向。第三,与真实执行相比,仍然存在性能差距(模拟差距),特别是在Qwen2.5-7B模型上差距较大,这可能意味着需要更大或更强的模型才能同时有效地学习和模拟执行。第四,作者在初步实验中观察到,使用丰富的文本反馈进行训练面临训练稳定性的挑战,他们假设这是由于无法使用教师强制训练以及模拟的可验证奖励定义不明确。最后,多轮修复设置下的pass@1分数(10轮)低于图4中显示的相应best@10结果,作者假设这种差距源于探索有限,因为模型倾向于迭代修复一个解决方案而不是探索替代方案,并且模型经常不使用所有轮数。
独立分析的弱点
独立分析的弱点包括:1)复杂计算操作预测不准确:论文明确指出模型在处理大数乘法、对数计算等复杂计算时表现不佳,这是因为LLM在数值计算上本身就存在局限性。改进方向可以是结合符号计算工具或专门训练数值计算能力。2)模拟差距在较小模型上更明显:实验显示Qwen2.5-7B的模拟差距大于CWM,这表明模型容量是一个重要因素。改进方向包括使用更大的基础模型或设计更高效的参数共享机制。3)多轮修复探索不足:模型倾向于迭代修复一个解决方案而不是探索替代方案,导致pass@1性能低于best@10。改进方向可以是在多轮设置中引入多样化的修复策略或随机探索机制。4)训练稳定性问题:使用丰富文本反馈进行训练时遇到稳定性挑战。改进方向包括设计更稳定的奖励函数、使用课程学习或渐进式训练策略。5)对单文件问题的限制:当前方法仅适用于单文件竞技编程问题,无法处理需要多文件协作或复杂依赖关系的实际项目。改进方向是扩展到仓库级别,引入模块依赖分析和跨文件推理能力。
未来方向
作者提出的未来工作方向包括:1)使用完整的丰富执行模拟作为反馈,而不仅仅是最终输出。这种反馈可以传达比单独输出(甚至超出真实执行)更丰富的信息,不仅捕获产生什么输出,还捕获为什么产生这样的输出。这样的解释可以揭示测试偶然通过的情况,以及提供失败的根本原因的见解。2)将方法推广到完整的仓库级SWE任务,当前仅限于单文件竞技编程问题。3)进一步缩小模拟差距,特别是在较小模型上的表现。4)改进多轮修复的探索策略,避免陷入局部最优。5)解决使用丰富文本反馈时的训练稳定性问题。基于论文成果可以延伸的方向包括:1)结合符号执行和静态分析技术,提高对复杂计算的预测准确性。2)探索迁移学习,将在竞技编程上学到的执行模拟能力迁移到其他代码理解和生成任务。3)研究自适应的验证策略,根据代码复杂度和测试用例难度动态调整验证强度。4)开发更高效的训练算法,减少对计算资源的需求。5)探索人机协作场景,让模型预测的执行结果辅助开发者进行代码审查和调试。
复现评估
复现评估方面,论文提供了详细的实现细节。作者使用了Qwen2.5-Base模型(3B和7B参数)以及CWM-base作为基础模型。训练在NVIDIA H100 GPU上进行,单次CWM训练运行使用192个GPU,Qwen 7B和3B分别使用86个。大约1/3的GPU用作训练器,其余用于rollouts。CWM模型训练10k更新步数,Qwen模型训练4k步。监督微调使用65,536的序列长度(通过应用scaled RoPE,相对于基础模型因子为2来支持更长上下文),CWM使用131,072的上下文长度。模型训练15.5k步,每次更新步的批大小为4M token,总共65B token。使用峰值学习率8e-6,在1k步warmup后。每次训练运行的估计计算量为7.9e21 FLOPs(7B模型)和5.0e21(3B模型)。两个模型分别在128和64个NVIDIA H100 GPU上训练约20小时。论文在附录中提供了超参数、提示词和数据样本,这有助于复现。然而,论文没有开源代码和数据集,这可能限制完全复现。数据集规模较大(约80M通用Python函数执行描述和115k竞技编程解决方案执行描述),构建过程需要大量计算资源。总体而言,论文提供了足够的实现细节,但完全复现需要大量计算资源和数据收集工作。
论文图表