对于一道数学题,我们可能难以写出所有好的推理过程,却能检查最后的答案。对于一段程序,我们也可以直接运行测试。既然结果能够验证,就有机会让模型自己尝试,再根据结果调整策略。我们从这样一个简单例子出发,讨论 GRPO 怎样利用反馈,以及蒸馏和 Agent 训练各自把这个过程扩展到了哪里。
1. 可验证奖励
我们先固定一个问题 $x$,从当前策略采样 $G$ 个回答 $y_1,\ldots,y_G$,再让验证器给出奖励 $r_i$。数学题可以比较最终答案,代码题可以运行测试。下面只使用正确为 $1$、错误为 $0$ 的二值奖励:
问题:一个数的平方为 144,且该数为正数,求这个数。
样本 1:答案 12,reward = 1
样本 2:答案 -12,reward = 0
样本 3:答案 12,reward = 1
样本 4:答案 14,reward = 0
这四个结果已经提供了比较信号:样本 1 和 3 比样本 2 和 4 更值得保留。不过,我们只检查了答案,还不知道中间有没有猜测或错误推理。Outcome Reward 检查最终结果,Process Reward 则尝试为中间步骤提供反馈;后者更密集,但也多了一个前提,即步骤评分本身要可靠。
2. 从 PPO 到 GRPO
奖励有了,接下来需要判断一个回答比通常水平好多少。PPO 通常借助价值模型估计优势;对同一问题已经采样多个回答时,我们也可以直接拿组内结果作比较。GRPO 用组内均值作为基线,并按标准差缩放:
$$A_i=\frac{r_i-\operatorname{mean}(r_1,\ldots,r_G)} {\operatorname{std}(r_1,\ldots,r_G)+\epsilon}$$
按总体标准差计算,上例的均值和标准差都是 $0.5$,所以忽略很小的 $\epsilon$,优势约为 $[1,-1,1,-1]$。它表达的是组内相对表现。我们再用概率比限制新策略相对采样策略的变化,便得到简化的裁剪目标:
$$\mathcal L_{GRPO}=-\frac1G\sum_i \min\left( \rho_iA_i, \operatorname{clip}(\rho_i,1-\varepsilon,1+\varepsilon)A_i \right),$$
为展示裁剪的作用,这里先按整个回答写 $\rho_i=\pi_\theta(y_i\mid x)/\pi_{old}(y_i\mid x)$,并将采样后计算的 $A_i$ 视为固定反馈。$A_i>0$ 时,提高回答概率能改善目标,但超过裁剪阈值后不会继续获得同样的收益;负优势则限制另一方向的过大更新。实际 GRPO 通常使用 token 级概率比,而非直接相乘的整段概率比,还会加入 KL、长度归一化等处理。

图 1:GRPO 使用同组样本的相对奖励估计优势。 图引自 Stanford CS336 课程材料。
如果四个答案全部正确,减去组内均值后就全是零;全部错误也一样。即使分母加了 $\epsilon$,也不能凭空制造区分信号。这里消失的是该组的奖励优势项,其他正则项仍可能有梯度。动态采样可以重采这些无差异组,让更多预算用在当前策略有对有错的问题上,但它是一种训练选择,并非 GRPO 定义中不可缺少的一步。
3. 长度偏差与训练稳定性
把目标展开到 token 后,我们又会遇到一个此前被整段记号遮住的问题:长回答有更多项,它应该获得更多总权重,还是与短回答一样?每条回答先平均再平均,与把所有 token 合起来平均,实际权重不同。奖励标准差归一化还会改变不同问题之间的相对权重。Dr. GRPO、DAPO 等工作讨论了这些设计,并调整归一化、裁剪和采样方式。
训练中不能只看平均 reward。还应同时检查准确率、pass@k、回答长度、策略熵、KL、组内奖励方差和通用能力。否则模型可能学会拖长回答、利用验证器漏洞,或牺牲非目标任务换取单一指标。
4. 推理模型的分阶段训练
有了可验证奖励,也不意味着全部训练都必须由 RL 完成。我们看 DeepSeek-R1 的公开流程:先用冷启动 Long-CoT 数据建立较稳定的输出模式,再做推理强化学习;随后筛选高质量轨迹用于 SFT,并进一步进行通用场景训练。这里 SFT 和 RL 交替出现,各自承担了不同的工作。

图 2:DeepSeek-R1 的主要训练阶段。 图引自 Stanford CS336 课程材料。
Qwen3 将 Long-CoT 冷启动、Reasoning RL、thinking 与 non-thinking 融合,以及通用 RL 分开处理;小模型还可从强模型蒸馏推理轨迹。分阶段设计的原因很直接:格式初始化、可验证推理和通用对话需要的监督信号不同,全部混在一步中往往难以控制。

图 3:Qwen3 将推理强化、模式融合和蒸馏分开安排。 图引自 Stanford CS336 课程材料。
5. 蒸馏
假如已有一个能力较强的教师模型,我们还可以把它生成的答案和推理轨迹筛选后交给学生学习。这是输出蒸馏,形式上很接近 SFT。若能读取教师 logits,则不必只保留最终采样出的 token,还能让学生匹配教师的概率分布:
$$\mathcal L_{KD}=\lambda\mathcal L_{hard} +(1-\lambda)T^2D_{KL} \left(p_T^{(T)}\Vert p_S^{(T)}\right)$$
$T$ 是温度,$p_T^{(T)}$、$p_S^{(T)}$ 分别表示教师和学生在该温度下的分布,$\lambda$ 控制硬标签损失的比例。较高温度让分布更平缓,我们便能保留教师对非首选 token 的相对判断;$T^2$ 是常见的梯度尺度补偿。这个目标需要相容的输出空间或额外映射,教师接口也要提供相应概率信息,不能只靠一段文本回答还原。
还有一个选择是由谁产生训练中的前缀。一直使用教师预先生成的轨迹,学生见到的主要是教师走过的路径;推理时学生自己走偏后,未必知道如何继续。On-policy 蒸馏先让学生采样,再让教师在这些前缀上提供反馈,更贴近学生实际遇到的状态,代价是需要持续调用教师。两种方式可以分阶段结合。
6. 合成数据
合成数据并不等于直接保存教师第一次输出。较可靠的过程包括任务生成、多个候选、自动验证、质量过滤、去重、难度平衡和人工抽检。数学和代码可以依靠答案与执行结果;开放文本需要事实来源和多个评审器。
若只生成教师最擅长的简单题,得到的样本虽然正确,却很少带来新能力。根据学生失败案例生成新任务,再保留当前策略能够区分的中等难度样本,通常更有价值。
7. Agent 轨迹与环境训练
将问题扩展到 Agent 后,我们还要把环境放进训练过程。以下是一条代码修复任务的示意轨迹,其中工具观察会改变下一步能够采用的信息:
User: 找出仓库中导致测试失败的函数并修复。
Assistant action: search_code("failing_test")
Tool observation: tests/test_parser.py references parse_date
Assistant action: open_file("src/parser.py")
Tool observation: parse_date fails on leap-day input
Assistant action: apply_patch(...)
Tool observation: patch applied
Assistant action: run_tests("tests/test_parser.py")
Tool observation: all tests passed
Assistant final: 已修复闰日解析并通过相关测试。
沿着这条轨迹,我们无法在修改代码之前就确定测试结果,后续动作要取决于环境反馈。SFT 可以示范这些动作的组织方式,Agent RL 则让当前策略实际交互、接受结果评价。如果还关心工具调用和输出成本,可以设计一个示意奖励:
$$r=r_{success}+\alpha r_{format} -\beta c_{tool}-\gamma c_{tokens}$$
这里 $r_{success}$、$r_{format}$ 分别评价任务和格式,$c_{tool}$、$c_{tokens}$ 表示调用与生成成本,系数需要按任务选择。我们若过度惩罚成本,模型可能通过少做事来提高分数。即使奖励合适,最终失败也可能来自很早以前的一次错误检索,这就是长轨迹的信用分配困难。子任务奖励、状态检查器和轨迹切分能提供更局部的反馈,但也需要检查是否鼓励了与最终任务无关的捷径。
8. 评价信号决定训练方向
我们最初依靠的是一个很朴素的条件:虽然不能枚举全部好答案,但能检查候选结果。随着任务从数学扩展到教师反馈和环境交互,检查本身也越来越复杂。无论使用哪种优化方法,奖励上升都首先说明模型更符合这套评价;是否更会解题、更会使用工具,还需要独立的任务结果来验证。
参考资料:Shao et al., DeepSeekMath;DeepSeek-AI, DeepSeek-R1;Yu et al., DAPO;Qwen Team, Qwen3 Technical Report;Zelikman et al., STaR。