跳转至

CodeScaler: Scaling Code LLM Training and Test-Time Inference via Reward Models

会议: NeurIPS2026
arXiv: 2602.17684
领域: 代码智能
关键词: 代码奖励模型、可验证奖励、偏好数据、奖励塑形、测试时计算

一句话总结

CodeScaler 把高质量执行反馈蒸馏为代码奖励模型,用严格代码提取和奖励塑形支撑无需在线执行的强化学习与候选重排序,在 DeepCoder 上让 8B/14B 策略的四项基准平均 Avg@8 分别超过 RLVR 1.55/4.23 个百分点。

研究背景与动机

代码生成天然具备可运行的反馈:把程序放入沙箱,检查是否通过题目测试,就能得到比语言偏好更直接的监督。DeepCoder 等方法据此采用可验证奖励强化学习(RLVR),但这条路线的瓶颈不是题目描述不够多,而是高覆盖、可信的测试不够多。合成题目容易,合成能区分正确算法与边界错误的测试困难;即便测试与若干模型解答互相一致,也可能只是共同遗漏了难例。附录 K 的例子中,题目允许输入达到 30,测试却只覆盖到 9,使指数时间枚举也被误判为正确。

奖励模型(reward model,RM)可以直接阅读题目和代码,对候选给出连续分数,因此有机会把少量可信执行监督迁移到没有测试的新题目。但替换奖励并非换一个接口:执行器会拒绝破碎代码,RM 却可能给语法错误、与题意无关或外观复杂的代码高分。已有通用 SkyworkRM 与代码专用 AceCodeRM 在文中的 RL 实验中均落后于 RLVR;推理阶段虽能省掉生成测试和沙箱执行,却又容易选错答案。

本文把数据质量和奖励接入方式一起处理:先用真实策略训练轨迹学习“同题正确解优于错误解”,再给不可解析输出设置明确的最低奖励,使模型不能靠破坏输出格式绕开评分。核心 idea:用经过执行验证的同策略偏好数据训练可复用的代码正确性代理,再通过语法门控和正值奖励塑形,把同一个 RM 用于无需在线执行的策略优化与 Best-of-N 选择。

方法详解

整体框架

输入是编程题目及策略模型生成的回答,最终产物有两个:经 RM 奖励训练的代码策略,以及对多个候选进行重排序的评分器。流程先进行“可信轨迹偏好学习”,得到 CodeScaler;后续 RL 分支经“语法感知代码提取”和“有效性保持奖励塑形”形成奖励,再进入“训练与推理双用途”中的 GRPO 优化。推理分支则直接使用训练好的 RM 对候选评分、选出最高分解答,不需要为候选生成或执行测试。

必须区分两个阶段的依赖:训练 RM 的正负标签来自 DeepCoder 的真实测试执行,而部署 RM 后的评分不依赖测试。所谓 execution-free 指后续评分和策略优化不再逐次执行程序,并不意味着建立整个系统时从未使用测试,也不意味着最终评测可以省掉执行验证。下图实线是数据或奖励流,虚线是已经学好的 RM 被复用。

%%{init: {'flowchart': {'rankSpacing': 24, 'nodeSpacing': 28, 'padding': 6, 'wrappingWidth': 400}}}%%
flowchart TD
    A["DeepCoder 测试<br/>与 RLVR 轨迹"] --> B["可信轨迹偏好学习"]
    C["题目与策略回答"] --> D["语法感知代码提取"]
    B -.->|训练好的 RM| E["有效性保持奖励塑形"]
    D --> E
    E -->|RL 奖励| F["训练与推理双用途"]
    B -.->|推理候选评分| F
    F -->|训练分支| G["GRPO 更新策略"]
    F -->|推理分支| H["BoN 选择最高分代码"]

关键设计

1. 可信轨迹偏好学习:先保证正确性标签,再扩大评分器的使用范围

作者使用含 24K 道题的 DeepCoder 作为监督种子,用 Qwen3-8B-Base 在 GRPO/RLVR 下生成同策略训练轨迹,而不是仅从多个固定模型独立采样解答。随着策略更新,轨迹包含不同能力阶段的解法与错误模式,让 RM 接触到后续优化实际可能产生的代码分布。对同一题目,通过全部测试的代码作为正例,只要失败一个测试就作为负例;这仍是相对已有测试集的正确性标签,不是数学意义上的程序正确性证明。

附录 B 给出具体取样过程:策略训练 250 步,每题采样 8 个回答,舍弃前 100 步的轨迹,得到 52,574 个偏好对。为避免 RM 只判断“这段程序像不像好代码”,再增加约 30% 的错配负例,即把其他题目的解答与当前题目配对。这样,结构完整但解决了别的问题的程序也必须低于当前题目的正确解,监督目标才包含题意与实现之间的语义对应。

CodeScaler-8B 由 Skywork-Reward-V2-Qwen3-8B 继续训练,而非从随机参数开始训练。偏好目标采用 Bradley–Terry 损失:同题正例的分数应高于负例,差值越大,模型越确信该排序。这里学习的是相对排序,不是把输出分数校准成通过测试的概率;分数可以为负,也不存在由这个损失自动规定的“无效代码最低分”。

2. 语法感知代码提取:把评分对象限制为单个可解析程序

RLVR 的执行过程本身会暴露解析错误,但 RM 没有这个天然约束,因此作者先要求回答只包含一个明确的代码块;多个碎片化代码块不拼接,直接判为提取失败。随后对抽取代码做静态抽象语法树(AST)检查。任何一步失败都把结果替换为空字符串,而不是让 RM 对有问题的片段自由打分。

这个门控同时约束了输出形式与语法,而没有检查算法语义。例如,边界条件写错、遍历方向相反或复杂度过高的程序仍可能通过 AST。它的价值在于堵住一种廉价捷径:策略不能通过格式破坏或语法不完整获取异常奖励;其代价是可能拒绝本来可由人工整合的多代码块回答,因此方法更适合要求单段完整解答的编程评测。

3. 有效性保持奖励塑形:保证语法无效输出低于任何有效输出

把无效输出奖励简单设为 0 仍不够,因为 Bradley–Terry RM 的正常代码得分可能为负:如果有效代码得分为负,而空输出为 0,策略反而会偏好空输出。作者对有效代码的原始分数使用 softplus 映射,对提取失败或 AST 失败的输出固定给 0。以下公式中的“valid”仅指通过上述提取与语法检查。

\[ R'(q,c)=\begin{cases} \ln(1+e^{r_\phi(q,c)}), & c\text{ is valid},\\ 0, & \text{otherwise}. \end{cases} \]

因此有效代码的奖励严格大于 0,无效代码始终为 0;softplus 又是单调变换,保留有效候选之间的排序。它不是让错误算法自动得到低分,而是确保语法有效性拥有稳定的奖励下界。经过变换后的数值尺度还会影响 GRPO 的组内奖励差异,所以“保序”也不等于完全不改变 RL 动力学。

4. 训练与推理双用途:在新题目上复用正确性代理,而非复用测试套件

在训练分支,策略对同题生成一组回答,提取代码后得到上述奖励,GRPO 根据组内相对奖励形成优势并更新策略。作者保留相对于参考策略的 KL 正则,避免在合成题目质量不受严格控制时过度追逐 RM 的偏好。RM 一旦训练好,后续训练题目只需要题目描述与策略回答,不必为每题准备执行环境或测试标签。

这使扩展数据成为可能:作者从 TACO 题目抽取概念,构建按共现连接的概念图,通过最多六步随机游走组合概念,再让 GPT-4o 生成 20K 道新题,与 24K DeepCoder 混合成 44K 训练集。概念图用于生成新题,并不是 RM 内部的推理结构;本文也没有要求 RM 在 RL 时读取概念图或测试用例。

在推理分支,策略先生成多个候选,CodeScaler 阅读题目与各候选代码,直接选择最高分者。这里不做策略更新,也不使用 GRPO 的组内优势;RM 是重排序器而不是候选生成器。候选生成仍占用时间,且最高 RM 分数不保证真实正确。图中的两条分支共享评分器,但不能把训练分支的语法门控与塑形未经说明地当作所有 BoN 实验的额外处理步骤。

一个完整示例

以“将两类球移动到规定顺序,并计算最少交换次数”的题目为例,附录 I 中正确程序从左向右统计白球左侧黑球数,错误程序反向遍历,实际计算了相反目标。二者都能形成完整程序,语法门控不会排除后者;必须依靠 RM 理解题意与计数方向之间的关系。

真实案例中,正确代码长 278 个字符,RM 得分 3.969;错误代码长 661 个字符,却得到 7.531。若二者进入 BoN,重排序会选错;若进入 RL 奖励计算,单调的 softplus 仍会保留这一错误排序。这个例子揭示了各组件的责任边界:AST 解决解析问题,塑形解决无效输出的奖励下界,偏好学习才负责语义判断,而后者仍可能受长度与关键词密度误导。

损失函数 / 训练策略

RM 的训练损失如下;\(q\) 是题目,\(c^+\) 与 \(c^-\) 分别为同题正、负候选,\(\sigma\) 为 sigmoid。

\[ \mathcal{L}_{\mathrm{RM}}=-\mathbb{E}_{(q,c^+,c^-)\sim\mathcal{D}}\left[\log\sigma\left(r_\phi(q,c^+)-r_\phi(q,c^-)\right)\right]. \]

RM 使用 AdamW,学习率为 \(10^{-6}\)。缓存中的 RM epoch 字段存在重复字符歧义,此处不据此给出确定训练轮数。RL 的学习率同为 \(10^{-6}\),KL 系数为 \(\beta=0.005\),batch size 为 128,mini-batch size 为 64;通常训练 250 步,每题采样 8 个回答,最大响应长度为 16,384 tokens。训练采样温度为 0.6,RM 数据采样时 top-p 为 0.95,实验使用 8 张 A100 80GB。

组内优势由变换后奖励减去组均值、再按组标准差归一化;本文不补写缓存中损坏的 GRPO 优势公式。奖励均值上升本身不能证明程序变正确,仍需把执行正确率作为独立检查。附录 G 将 DeepCoder 上的 8B 训练延长至 650 步,报告 RM 分数与 pass@1 同向上升,这是该配置下没有明显奖励投机的经验支持,不是对任意训练分布的保证。

实验关键数据

主实验

训练后策略评估使用 Avg@8,即每题 8 次独立生成的执行正确性取平均,不是从 8 个候选里选择一个的 BoN@8。所有评估温度为 0.6。LiveCodeBench 使用 2024-08-01 至 2025-02-01 的题目;CodeContests 抽取难度不超过 2 的 239 题,CodeForces 抽取 467 题,MBPP 使用标准测试集。

下表保留原文 Table 1 的 DeepCoder 训练结果,指标为百分数。平均值是四项基准的均值,而不是把所有题目合并后的加权正确率。

策略与奖励 LiveCodeBench CodeContests MBPP CodeForces 平均 Avg@8
Qwen3-8B-Base 13.75 19.03 61.70 5.35 24.96
8B + RLVR 23.60 32.00 76.01 16.43 37.01
8B + CodeScaler 24.80 33.94 75.90 19.61 38.56
Qwen3-14B-Base 21.37 26.25 71.09 8.45 31.79
14B + RLVR 25.94 34.30 75.45 20.79 39.12
14B + CodeScaler 27.55 39.33 81.61 24.89 43.35

8B 的平均值提升 1.55 个百分点,但 MBPP 从 76.01 降到 75.90,不能解读为每个单元格都提升。扩展到 44K 题目后,8B + CodeScaler 的平均值为 39.60,相对基座 24.96 提升 14.64 个百分点;相对 DeepCoder-only 的 38.56,则增加 1.04 个百分点。这两个参照回答的是不同问题。

消融实验

下表取自正文第 5.3 节与 Figure 4 的配套文字,均为 Qwen3-8B-Base 在 DeepCoder 上训练后的 Avg@8。这里“提取 + 塑形”是联合干预,不能据此单独量化 AST 或 softplus 的贡献。

奖励配置 LiveCodeBench CodeContests MBPP CodeForces
SkyworkRM 18.50 23.22 67.59 8.00
SkyworkRM + 提取 + 塑形 20.74 27.45 69.79 10.00
CodeScaler + 提取 + 塑形 24.80 33.94 75.90 19.61

加入提取与塑形改善了通用 RM,但仍不足以追平 CodeScaler,说明奖励接入方式与偏好数据质量都重要。另一个消融将通过率大于 0.7 的非全对解答也当作正例:其 RL 平均 Avg@8 为 37.94,低于严格二元标签的 38.56;但 CodeContests 与 CodeForces 分别达到 35.04、21.44,高于二元版本的 33.94、19.61。因此严格标签赢在该组平均表现,不是逐基准占优。

推理延迟的测量来自 Table 4:同一批 CodeForces 467 题、每题 8 个候选,CURE 额外生成 8 个测试,单张 A100 配合 vLLM。下表是选择阶段开销,明确排除了双方共享的候选生成时间。

选择阶段耗时 CURE CodeScaler
测试生成总时间(秒) 979.3 不使用
执行总时间(秒) 516.7 不使用
RM 评分总时间(秒) 不使用 146.1
平均每题(秒) 3.20 0.31

正文先把 latency 定义为包含候选生成的端到端墙钟时间,但实际比较随后排除了共享候选生成项。因此约 10 倍结论只适用于所测的选择阶段,不能宣传为完整生成链路快 10 倍。共同生成成本越大,全流程加速比越接近 1。

关键发现

  • 在真实 DeepCoder 轨迹分析中,正确/错误候选的成对排序准确率为 87.9%,组内最高分候选正确率为 79.8%;RM 有辨别力,但远不是可靠验证器。
  • 用 DeepCoder 而非 KodCode 轨迹训练 RM,再用于 rStarCoder 上的 RL,CodeForces Avg@8 从 11.58 提升至 15.95,支持“监督可信度比单纯扩大轨迹来源更重要”。
  • 错配增强从 0% 增加到 30%,附录 H 的独立留出分析 AUROC 从 0.911 提升至 0.990;50% 仍为 0.990。该分析不能与上述真实轨迹 AUROC 0.879 直接混比。
  • BoN 表格存在未解释的口径差异:Table 9 的 Binary 版本平均 BoN@8 为 42.88,而 Table 10 的 8B 版本为 44.15;原文未明确协调,不将二者合并成一个“统一结果”。

亮点与洞察

  • 将测试的价值从“每次优化都要执行”转为“先建立可信评分器”。这并未消除测试依赖,而是让已有验证成本可以在后续无测试题目上复用。
  • 正值塑形针对的是一个具体优化漏洞:无效输出的 0 分可能高于有效代码的负分。先理清奖励的数值语义,再接入 RL,比仅要求模型“输出正确格式”更直接。
  • 训练奖励与推理排序是两个不同的压力测试。能在静态偏好集上区分好坏,不意味着在策略持续追逐高分时仍然可靠,因此同时评估 RL 稳定性与 BoN 更有信息量。

局限与展望

  • RM 的监督仍依赖测试覆盖;若“全通过”的代码其实遗漏题目边界,严格标签也会把它当作正例。尤其不能把 AST 通过视作语义或复杂度正确的证明。
  • 附录 I 发现明显表面偏差:误判高分的错误代码比正确高分代码长 28%,算法关键词多 37%;短小、模块化或递归的正确代码可能被低估。奖励塑形并不修复这种错误排序。
  • 奖励投机分析主要覆盖 DeepCoder 上的 8B 延长训练,不能推出新合成分布、所有语言或更长训练下均不会失效。可用未参与 RM 训练的执行审计持续监测“分数上升、正确率下降”的分叉。
  • 多语言与非 Qwen 策略的 BoN 结果支持有限迁移,但不等价于跨语言 RL 稳定性、真实仓库级修复或安全关键代码可靠性。延迟优势也需要在包含候选生成的部署链路重新测量。

相关工作与启发

  • vs DeepCoder / RLVR:后者直接使用测试执行奖惩;CodeScaler 先从同类执行轨迹学习代理,再把代理用于新题目的优化。优势是降低在线测试需求,代价是引入可被策略利用的判断误差。
  • vs AceCodeRM:二者都学习代码偏好,本文强调全部测试通过才算正例,并为 RL 增加语法门控与塑形。消融支持严格标签的平均优势,但不能把所有差异归因于标签阈值。
  • vs CURE / CodeT:测试式选择依赖生成测试与执行反馈,CodeScaler 依赖学习到的题目—代码匹配。一个值得验证的延伸是仅对高分近邻或 RM 不确定的候选做执行审计,在延迟与错误选择之间建立可测的预算曲线。

评分

  • 新颖性: 4/5,将可信轨迹偏好与适配 RL 的奖励接入机制组合,而非提出新的偏好损失。
  • 实验充分度: 4/5,覆盖训练、BoN、规模与失败分析,但部分数值口径和泛化边界仍不充分。
  • 写作质量: 4/5,机制清楚,但端到端延迟措辞与实际计时范围需要区分。
  • 价值: 4/5,为低测试资源的代码后训练提供可复用方案,不能替代最终功能验证。