CodeMidas:以源代码本身规模化构建智能体编程强化学习环境 CodeMidas: Scaling Agentic Coding RL Environments from Code Itself
仅凭源码自动构建可验证RL环境,5545个任务训练使智能体五大基准全面提升
前置知识
GRPO(组相对策略优化)
GRPO 是一种在线强化学习算法:对每个任务提示采样一组(本文为 32 个)完整轨迹,用组内奖励的归一化值作为优势估计 $\hat{A}_i = \frac{r_i - \mu_r}{\sigma_r}$,其中 $r_i$ 是该轨迹的奖励、$\mu_r$ 与 $\sigma_r$ 是组内均值与标准差,因此无需训练价值网络(critic)。本文用 GRPO 训练 MiMo-V2.5,批大小 32,奖励是二值执行结果。
本文所有训练实验(五基准评估、1k/3k/5k/8k 规模消融、行为分析)都建立在 GRPO + 二值执行奖励之上,理解奖励信号如何来自测试通过与否是读懂实验设计的前提。
可执行验证器与二值执行奖励
验证器(verifier)是一段可运行的测试代码,用于判定智能体提交的实现是否满足任务要求,返回奖励 $r \in \{0,1\}$。本文的验证器对求解智能体全程隐藏,只在判卷时注入容器,以此防止智能体作弊或针对测试过拟合。
RL 环境的质量本质上等于验证器的质量:验证器既有判错力(拒绝错误解)又有容忍度(接受不同但正确的实现)。整篇论文的流水线设计都围绕如何自动造出可靠的验证器展开。
Fail-to-pass 执行一致性检查
指同一套测试在任务起点代码上必须失败、在参考解上必须通过的性质。本文用 6 个全新容器做检查:2 个装起点代码的运行必须失败,4 个装参考解的运行必须全部通过,重复运行还能筛查结果不稳定的(flaky)环境。
这是环境能否用于 RL 的硬门槛,也解释了论文方法部分数量漏斗(22,575→11,930)的成因,是理解任务筛选机制的基础。
验证器误报(FP)与漏报(FN)
误报指实现被判断错误却通过了测试(测试太弱),漏报指实现判断正确却没通过测试(测试过度约束,比如固定了陈述未规定的异常消息措辞)。PatchDiff 曾记录 SWE-bench 测试接受错误补丁的案例,EvalPlus 显示原始测试套件会漏判错误程序。
论文的后置解法审计环节就是让评审智能体对照任务陈述核查每次 rollout 的测试判定,标记并剔除含 FP/FN 缺陷的任务,这是全文质量控制的核心概念。
测试预言(test oracle)
测试预言是判定程序输出正确与否的依据。弱预言(如只检查不崩溃)会放过错误程序,过强预言(如固定内部实现细节)会拒绝合法解。本文的做法是用原实现的真实执行结果作为预言:先在参考副本上运行测试输入、记录输出,再把这些输出固化为断言。
理解'执行锚定的测试构造'这一核心创新,需要知道预言从哪来、为什么以原代码执行为预言既能保证正确性又需要复审以避免过度约束。
研究动机
现有编程 RL 环境构建方法都依赖'开发痕迹'作为任务特定输入:SWE-rebench V2 需要真实 issue,R2E-Gym 从 commit 出发,SWE-smith 和 SWE-Flow 依赖既有测试,R2E 和 MindForge 则需要 docstring 或文档(论文 Table 1 系统对比了这一点)。这带来三重限制。第一,任务供给被记录在案的变更、测试和文档的覆盖面锁死,无法触达代码库里大量'从未有 issue 或提交记录'的已实现功能。第二,语言覆盖极窄:Table 1 中多数流水线只支持 1 种语言,最广的 SWE-rebench V2 也只有 20 种,而开源代码生态覆盖数百种语言。第三,依赖的中间产物本身可能缺失或有缺陷——PatchDiff 记录了 SWE-bench 测试接受错误补丁的真实案例,EvalPlus 证明原始测试套件会漏判错误程序,说明'拿来即用'的验证器并不可靠。结果是高质量可验证任务供给不足且质量参差,直接限制了编程智能体 RL 训练的可扩展性。
本文的目标是本文的目标是把'代码库中已实现的功能'直接转化为可执行的 RL 环境:仅以源代码作为任务特定输入,自动产出三件套——任务陈述、容器化开发环境(目标功能被挖空)、隐藏的可执行验证器。这样构造不受 issue/PR/commit/既有测试/文档有无的任何限制,从而可以覆盖任意编程语言与技术领域。论文同时追求 RL 的两个前提条件:任务多样性(最终数据集含 5,545 个任务、来自 3,185 个开源代码库、横跨 23 种语言和 15 个技术领域)与奖励可靠性(每个任务都要通过执行一致性检查和三道后置过滤)。最终验证方式是用这些环境以 GRPO 训练 MiMo-V2.5,并要求在 DeepSWE、SWE-bench Pro、ProgramBench、RepoZero C2Rust、Terminal-Bench v2.1 五个外部基准上取得一致且可观的提升。
与已有工作不同的是,本文的独特切入角度有三层。第一是视角反转:不从'开发过程的记录'(issue、commit、测试)反推任务,而是从'代码已经做到的事'正向构造任务——已实现功能本身同时提供了任务素材(公共接口与可观察行为)、候选参考解(原实现)和测试期望的依据(执行原代码得到的真实输出),一个信息源喂饱三件套。第二是'把智能体算力花在环境构建的每一环':探索功能、提炼行为规格、构造测试、检查执行一致性、对抗性挖掘泄漏、审计测试判定,全部交给智能体完成,相当于用推理算力替代人工标注和开发记录。第三是后置 rollout 过滤机制:训练之前先用对抗 rollout 探测可绕过实现工作的泄漏,用解法审计对照任务陈述核查验证器判定找误报漏报,用前沿模型的多次尝试淘汰全过或全败的任务,把'环境可靠性'变成一个可计算、可过滤的工程量。
核心方法
直觉上,代码库里每个已实现的功能都可以被'挖走':让智能体在剩余代码的基础上重新实现它,再用原代码的真实执行结果来判卷。技术路线是四阶段流水线(Figure 1),每阶段都有明确的数量漏斗:任务设计(得到 22,575 个候选)→ 基于执行的测试构造(12,746)→ 环境准备与执行一致性检查(11,930)→ 后置 rollout 过滤(8,173 → 5,545)。每个最终任务是一个三元组:任务陈述、容器化开发环境、隐藏的可执行验证器。验证器对求解智能体全程不可见,只在判卷时注入,返回二值奖励 $r \in \{0,1\}$。随后用 GRPO 训练 MiMo-V2.5:批大小 32、每任务采样 32 个 rollout,组内归一化优势,不使用奖励模型或学习型验证器,奖励完全来自合成测试的执行结果。
核心创新有三层。第一,输入极简主义:源代码是唯一的任务特定输入。对照 Table 1,SWE-rebench V2 需要 issue、SWE-smith 依赖既有测试、R2E/MindForge 需要 docstring,而 CodeMidas 全不依赖,23 种语言覆盖也是所有方法中最广的。第二,执行锚定的测试构造:测试期望值不靠人写也不靠模型臆测,而是实际运行原实现、记录真实输出后固化为断言;对陈述未规定的方面(如异常消息的具体措辞),断言只检查行为约束而不限定字面,避免漏报。第三,验证器质量控制前移到训练之前:对抗 rollout 专找能绕过实现工作的泄漏源(编译产物、缓存副本、施工残留、已安装的目标项目副本);解法审计让评审智能体对照任务陈述复核每次测试判定以发现误报(FP)与漏报(FN);rollout 结果过滤淘汰全过或全败的任务。最有力证据是 5,545 个高质量任务在 DeepSWE 上比 8,000 个未清洗任务高 4.59 个百分点——环境可靠性本身就是可扩展的资源。
方法步骤详情
完整流程分四步。第一步任务设计与代码库改造:智能体浏览代码库结构和构建元数据,挑选有公共入口、结果可观察的功能(CLI 工具、纯函数、有状态 API),优先跨文件推理的任务;追踪入口点后删除核心实现,调整周边代码形成连贯起点,原实现单独保留作参考解;陈述定义输入、可观察行为和必需公共接口。第二步测试构造:智能体把陈述要求映射为测试输入和边界用例,在参考副本上运行并记录输出;规定死的方面用参考执行定值,未规定的方面只断言行为约束(如只要求异常类型、不限措辞);随后逐条复审断言,替换固定措辞、偶然顺序、内部结构等过度限制,断言依赖私有符号且无行为替代则弃题。第三步环境准备与执行一致性:统一基础镜像装依赖,清除一切可能泄露被删实现的痕迹(编译产物、缓存、施工文件、原测试);再用 6 个全新容器检查——2 个起点态必须失败、4 个参考态必须通过。第四步后置过滤:对抗 rollout 搜泄漏并复核证据;每任务 4 次求解 rollout 交评审智能体对照陈述核查判定、标记 FP/FN,有缺陷即弃;前沿模型多次尝试,只保留既有成功又有失败的任务。
技术新颖性
与 SWE-smith'破坏既有测试造 bug'、SWE-Flow'从单测推导增量任务'不同,CodeMidas 完全不围绕已有测试做文章,而是用原实现的执行行为生成测试期望,把'代码即规范'落实为'代码执行即 oracle'。与 R2E-Gym 从 commit 生成测试相比,它摆脱了提交记录存在性的前提,因此能覆盖没有版本历史的代码。方法论上,它把 RL 社区'数据质量大于数量'的经验倒置成一条系统化工程:用泄漏探测、解法审计、结果过滤三道智能体工序把环境可靠性变成可计算的过滤标准,并用 1k/3k/5,545 对 vanilla 8k 的受控实验定量验证——同样的训练配置下,3k 高质量子集即全面超越 8k 未过滤样本。行为层面的贡献也很新颖:把代码库探索(首次编辑前的读/搜调用数)、先想后写比例(Write/Edit 内容在前文推理中出现过的比例)、自查多样性(最后一次编辑后不同验证命令数)定义为可度量指标,证明 RL 后这些行为显著增长且能迁移到外部基准(Table 3),为'RL 到底改变了智能体的什么'提供了超越基准分数的行为学证据。
实验结果
五大外部基准全面上涨(Figure 5):SWE-bench Pro 50.3→54.4(+4.1pp)、DeepSWE 10.0%→21.7%(+11.7pp)、ProgramBench(Almost Solved)4.5→21.5(+17.0)、RepoZero C2Rust 40.5→51.8(+11.3pp)、Terminal-Bench v2.1 63.7%→72.2%(+8.5pp),横跨 issue 修复、整程序构造、代码翻译与终端操作。训练内动态(Figure 6):CodeMidas Val 通过率 35.0%→44.7%,第 40 步起稳定高于初始策略 8–10pp。规模与质量消融(Figure 7/8):高质量 1k→3k→5,545 在 DeepSWE 上 17.57→19.05→21.70、Val 上 41.30→43.22→44.73;未清洗的 vanilla 8k 仅得 17.11/40.24,3k 子集即全面胜出,5,545 比 8k 高 4.59pp(DeepSWE)。行为分析(Table 2/3):训练后期编辑前读/搜调用 27.2→40.1、先想后写比例 0.358→0.629、自查命令 2.03→2.53 种;带自写检查的 rollout 通过率高 4.2pp(95% CI 1.8–6.6),且这些行为变化在三个外部基准同样出现。数据集画像:参考解中位数 142 行(IQR 66–305),65.9% 触及至少 2 个源文件;Python 占 21.4%、TypeScript 18.3%、Go 16.2%。
查看结构化数据
| 任务 | 指标 | 本文 | 基线 | 提升 |
|---|---|---|---|---|
| SWE-bench Pro(仓库级 issue 修复) | pass rate | 54.4% | 50.3%(MiMo-V2.5 初始策略) | +4.1pp |
| DeepSWE v1.1(软件工程任务求解) | pass rate | 21.7% | 10.0%(MiMo-V2.5 初始策略) | +11.7pp |
| ProgramBench(整程序构造) | Almost Solved(通过至少95%测试的任务占比) | 21.5 | 4.5(MiMo-V2.5 初始策略) | +17.0pp |
| RepoZero C2Rust(C 到 Rust 代码翻译) | pass rate | 51.8% | 40.5%(MiMo-V2.5 初始策略) | +11.3pp |
| Terminal-Bench v2.1(终端操作任务) | pass rate | 72.2% | 63.7%(MiMo-V2.5 初始策略) | +8.5pp |
局限与改进
作者明确承认的局限:其一,rollout 结果过滤无法区分'任务太难'与'验证器仍有缺陷'——全过或全败的任务被一律丢弃,可能连带删掉最有训练价值的极端难样本;其二,奖励是纯二值执行结果,没有利用过程信息。我观察到的额外局限:(a) 解法审计与泄漏复核本身依赖 LLM 评审,评审智能体同样可能误判 FP/FN,验证器缺陷的残留风险无法归零;(b) 所有训练和评估只在 MiMo-V2.5 一个基座上进行,方法对其他模型家族和规模档位的普适性未经验证;(c) 任务形态受限于'重新实现单一已有功能',参考解中位数仅 142 行,与真实世界动辄上千行、涉及架构权衡的工程变更仍有差距;(d) 对抗泄漏探测只由单个攻击智能体执行,无法保证穷尽所有旁路(如依赖包内的传递性副本);(e) 论文正文未给出代码或数据集的开源声明,社区难以直接验证。
独立分析的弱点
弱点一:结果过滤把全过/全败任务整体剔除(8,173→5,545,丢弃约 32%),相当于对任务难度做中位截断——最难的一批任务可能恰是能力上限的来源;改进方向是不丢弃而是标记难度后构建课程学习,或换更强模型重测以区分'难'与'坏'。弱点二:FP/FN 检测完全委托给评审智能体,其判断本身未经校准,漏掉细微的过度约束断言(如偶然的字典键顺序)会系统性压低奖励质量;改进方向是引入变异测试——对参考解做系统性变异,量化测试的杀死率作为测试强度的客观指标,与 LLM 审计互补。弱点三:任务局限于'行为规格已明确的功能重实现',缺少需要设计取舍、性能优化或多方案比较的开放性任务;改进方向是把陈述空间从行为规格扩展到性能预算和代码风格约束,引入 rubric 式多维奖励。弱点四:对陈述未规定方面只做弱约束,仍可能留下'应试'捷径解(例如硬编码少量测试输入的输出);可对每个任务生成多个语义等价的测试输入组做交叉验证,或用差分测试比较提交解与参考解在扰动输入上的行为一致性。
未来方向
作者指出的方向:论文结尾强调源代码是编程 RL 的可扩展基础,自然延伸是把语言和领域覆盖推向长尾(当前 23 种语言、15 个领域中长尾占比很小);行为分析显示自写检查与通过率正相关(+4.2pp),可以把'鼓励智能体生成并运行自己的验证'显式设计成奖励项或训练目标。基于成果可延伸的方向:(1) 课程学习——用被丢弃的全过/全败任务按难度分级组织训练序列,而非直接丢弃;(2) 奖励升级——在二值执行奖励之上叠加 Agentic Rubrics 式的代码库锚定评分,缓解奖励稀疏并细化质量信号;(3) 自我博弈式环境生成——让构造智能体与求解智能体对抗迭代:出题方试图让题目可解且难作弊,解题方试图找泄漏走捷径,把泄漏探测内生化、持续化;(4) 跨域迁移——'从可执行产物反推可验证任务'的范式可推广到数据分析脚本、SQL、硬件描述语言等一切有可验证产出的领域;(5) 规模律研究——固定质量标准下把任务量从 5.5k 推向 50k+,刻画环境数量-质量-性能的定量关系。
复现评估
复现条件评估:论文对流水线描述相当细——四阶段输入输出、数量漏斗(22,575→12,746→11,930→8,173→5,545)、6 容器执行一致性协议(2 败 4 过)、每任务 4 次求解 rollout 的审计标准、训练超参(GRPO、批大小 32、每任务 32 rollout、二值奖励)均已写明,评估基准全部公开(SWE-bench Pro、DeepSWE v1.1、ProgramBench、RepoZero C2Rust、Terminal-Bench v2.1),CodeMidas Val 为 200 个抽样任务。但正文未提及代码、数据集或环境包的开源发布,这是最大复现障碍。算力门槛也高:全流程需对约 2.3 万个初始候选做多轮智能体探索与测试构造,再逐题做对抗 rollout、4 次求解和前沿模型多次尝试,LLM 调用量估计在百万级,加上 GRPO 训练本身,属大厂级工程投入。对学术实验室,更现实的切入点是用公开基准复现'3k 高质量胜 8k 未过滤'的对照结论,或单独复现后置过滤模块、验证其 FP/FN 检出率。
论文图表