CodeMidas 是小米 LLM Core 等团队提出的一套 Coding Agent 训练数据构造管线。它从开源仓库中找到已经实现的功能,生成需求说明,再移除对应实现,让 agent 在这个仓库里把功能补回来。原实现被保留下来,用于生成测试和验证环境。经过清理和筛选后,每个任务都能在容器中运行,并通过隐藏测试给出训练奖励。
这类任务通常可以从 issue、PR 或 commit 中提取:开发记录告诉我们要修什么,对应修改提供参考答案。CodeMidas 则直接从源代码提取功能,不要求仓库已经有相关 issue、测试或文字说明。这样一来,可用的任务来源就扩展到了仓库中已经存在、但未必有完整开发记录的功能。
论文最后构造了 5,545 个任务,来自 3,185 个开源仓库,覆盖 23 种编程语言和 15 个技术领域。下面主要看这些任务是怎样做出来的。

图 1:任务设计、测试构造、执行一致性检查和 rollout 后筛选。中间漏斗给出各阶段保留的任务数量,从 22,575 个候选逐步筛到 5,545 个训练环境。来源:论文 Figure 1。
从仓库中选功能,生成任务起点
管线的第一步是让 agent 阅读仓库结构和构建信息,寻找有公开入口、执行结果可以观察的功能。论文支持三类接口:命令行工具、纯函数,以及有状态的库 API。对应的检查对象分别是进程输出、函数返回值,以及多次调用后的状态变化。
选中功能后,agent 沿公开入口追踪相关实现和共享依赖,确定任务范围。随后移除核心实现,调整剩余代码,使其成为一个可以继续开发的起点。这里会保留项目结构和共享组件,任务也优先选择需要跨文件理解的功能。
需求说明与代码删改一起完成。说明中需要写清输入、必须实现的公开接口,以及外部可观察到的行为;内部用什么辅助函数、什么算法,则留给求解 agent 决定。删掉哪些代码,也要和要求补全的功能对应起来。
处理完后,原仓库形成两份用途不同的副本:求解 agent 拿到的是缺少目标功能的代码,构造测试时使用的则是保留原实现的参考副本。参考实现不交给求解 agent。
在原实现上执行,得到测试的预期结果
有了需求说明,下一步是构造 verifier,也就是最终给提交结果判分的可执行测试。
CodeMidas 先让 agent 把需求拆成测试输入和边界情况,再到参考副本中调用公开入口,记录实际执行结果。CLI 任务通过运行命令获得输出;纯函数任务生成输入输出用例;有状态 API 则生成调用序列,检查前后调用之间的依赖。每个测试还会记录自己覆盖了哪条需求。论文第 3.2 节
这一阶段利用原实现确定预期值,避免仅凭模型猜测输出。但原实现的所有细节并不都应该进入断言。例如,需求只规定抛出某类异常,就不应该同时要求异常文案逐字相同;需求没有规定的输出顺序,也不能因为参考实现恰好采用了某个顺序,就把其他顺序判错。
因此,生成测试后还有一轮逐条断言审查。agent 会检查断言是否加入了题目没有要求的限制,包括固定文案、偶然顺序和内部结构,并将其替换为对外部行为的检查。如果某个断言依赖私有符号,又找不到对应的行为检查方式,这个任务就会被丢弃。修改后的测试还要在参考实现上重新运行,确认仍然能够通过。
经过这一轮处理,测试输入和断言才固定下来,供后续评分使用。到这里,任务已经有了需求、待补全代码和测试,但还没有检查它在实际求解时是否可靠。
准备容器,检查起点失败、答案通过
环境准备从统一的基础容器镜像开始,由 agent 按项目声明安装依赖,准备构建和运行所需的资源。必要的软件包、数据文件和构建包装脚本会保留,可能暴露原实现的内容则需要清掉,包括编译产物、缓存副本和构造 agent 留下的文件。与目标功能有关的原始测试也会被移除。
这个清理步骤很实际:源码虽然被删掉了,安装目录里却可能还有完整版本;或者构建产物中仍然保留了可直接调用的原功能。求解 agent 如果能找到这些东西,就不必完成预期的开发工作。
接下来,每个任务会在六个全新的容器里,按训练时的运行设置接受检查:
- 两个容器使用待补全的起点代码,两次都必须失败。
- 四个容器放入参考答案,四次都必须通过。
这既检查了补全前后的 fail-to-pass 关系,也用重复执行筛掉一部分不稳定任务。起点已经能通过测试,或者参考答案放回去仍然失败,都不能进入下一阶段。论文第 3.3 节
让 agent 真正做题,再筛一遍
前面的检查只运行了起点代码和参考实现。其他实现能不能被正确评分、环境里有没有遗漏的答案,还需要实际求解来暴露。CodeMidas 在 RL 训练之前安排了三类 rollout 筛选;这里的一次 rollout,就是 agent 从接收任务到提交结果的一次完整尝试。
首先是 leakage filtering。对抗性 agent 会主动寻找绕过开发工作的办法,检查整个可见环境里的缓存、编译产物、已安装的项目副本和遗留文件,并记录支持可疑利用方式的命令及输出。另一个审查过程再结合参考答案和 verifier 核实这些证据。如果确认可以利用泄漏材料绕过任务,就丢弃这个环境。
第二类是检查 verifier 对 agent 解法的判决是否正确。每个任务让 coding agent 尝试四次,再由 reviewing agent 一起阅读提交代码、测试输出、交互轨迹、需求说明、verifier 和参考答案,判断实现是否满足需求。
这里同时找两种问题:实现不符合要求却通过测试,属于假阳性;实现符合要求却被测试拒绝,属于假阴性。前者说明测试漏掉了错误,后者说明测试可能过度约束。发现这类 verifier 缺陷的任务会被移除。这一步也补上了“参考实现能通过”检查不到的部分:不同于参考答案的写法,是否也能得到合理评分。
最后是 rollout outcome filtering。一个 frontier model 对每个任务做多次尝试,只保留同时出现成功和失败的任务。全部通过或全部失败,可能和难度有关,也可能来自测试过弱、需求遗漏等缺陷。论文没有用这些结果进一步区分原因,而是直接将这两类任务筛掉。
这一轮筛选针对的是给定模型和求解预算下的表现。它给任务池留下了一批有区分度的题目,但不意味着后续训练中的每组采样都一定有成功、有失败。完整筛选过程见论文第 3.4 节。
这些环境怎样用于 GRPO
经过上述处理,每个训练任务包含三部分:需求说明、容器化开发环境、隐藏的可执行 verifier。求解时,agent 可以在环境中读代码、修改和自测,verifier 始终放在求解环境之外,直到评分时才注入。最终奖励是测试执行得到的 0 或 1,不使用 reward model 或学习出来的 verifier。
论文使用这些任务对 MiMo-V2.5 做 GRPO 训练,batch size 为 32,每个任务采样 32 条 rollout,并关闭优势的标准差归一化。以组内平均奖励为基线,优势可以写成:
\[A_i=r_i-\frac{1}{G}\sum_{j=1}^{G}r_j,\qquad G=32.\]例如一组有一半通过、一半失败,通过轨迹的优势就是 $0.5$,失败轨迹是 $-0.5$。如果整组全通过或全失败,优势则全部为零。这也解释了为什么前面会关注任务能否产生不同的求解结果。训练配置见论文附录 A。
作者报告的结果中,DeepSWE 通过率从 10.0% 提升到 21.7%,Terminal-Bench v2.1 从 63.7% 提升到 72.2%;ProgramBench 的 Almost Solved 从 4.5% 提升到 21.5%,这个指标统计通过至少 95% 测试的任务比例。论文第 4 节

图 2:初始 MiMo-V2.5 与 CodeMidas RL 后的分数比较,右侧增量的单位为百分点;ProgramBench 使用 Almost Solved,其余为通过率。来源:论文 Figure 5。
与数据管线更直接相关的是质量消融:在相同训练配置下,经过处理的 3k 任务,在 SWE-bench Pro、DeepSWE 和 CodeMidas Val 上都超过了未经处理的 8k 任务。这里的 8k 对照没有做环境清理、执行一致性检查和三类 rollout 筛选,比较的是这些步骤的共同效果。高质量任务池从 1k 扩到 3k、再扩到完整的 5,545 个任务时,三项评测的分数也继续提高。论文第 5.1 节

图 3:圆点对应高质量任务池的 1k、3k 和完整 5k(5,545)设置,菱形是未经清理和筛选的 8k 对照。三个子图的纵轴范围不同,比较时应看分数,不能直接比较线段斜率。来源:论文 Figure 8。
CodeMidas 的主要工作集中在训练之前:从仓库提取可描述的功能,利用原实现构造测试,再通过实际执行和 agent 求解检查环境。最终送入 GRPO 的奖励很简单,但为了让这个 0 或 1 能用,前面需要做完整的任务构造和筛选。