12. 强化学习与推理模型:用程序判对错来训练
上一篇的偏好对齐靠人(或奖励模型)判断“哪个回答更好”,而这种判断本身是近似,优化过头就会被钻空子。资料助手里还有一类问题不需要这种判断:小林问“这个月休息日加了两天班,没补休,加班费多少?”,答案只有一个,程序就能算出对错。对这类问题,强化学习可以直接拿程序的判定当奖励,放开手脚训练很多步。2025 年初 DeepSeek-R1 让大家看到,这样训练出来的模型会自己学会写很长的推理过程,这就是现在所说的“推理模型”的主要来源。
这一篇讲可验证奖励和学出来的奖励有什么不同、GRPO 怎样在没有价值模型的情况下更新策略、R1-Zero 和 R1 分别是怎样训练的、奖励设计里有哪些常见的作弊方式,以及什么时候不值得做强化学习。读完你应该能为一个有标准答案的任务设计奖励函数,并估算一次训练的生成开销。
可验证奖励:让程序当考官
可验证奖励的强化学习(Reinforcement Learning with Verifiable Rewards,RLVR,这个名字出自 2024 年的 Tülu 3 报告)的做法很直接:模型生成回答,一段程序检查答案对不对,对了给 1 分,错了给 0 分。常见的检查方式有:
- 数学题:从回答里抽出最终答案,和标准答案比对;
- 代码题:在沙箱里运行单元测试,全部通过才算对;
- 格式类任务:输出能否被 JSON 解析、字段是否齐全。
与上一篇的奖励模型相比,程序检查不会因为回答写得长、语气自信就多给分,也不需要标注人员。代价是适用范围窄:只有答案能被程序判定的任务才能用,“这段解释写得好不好”就没法这样检查。
把资料助手的加班费问题改造成可验证任务,需要三样东西:一批题目(可以从制度规则批量生成,换月薪、天数、加班类型)、每题的标准答案(由程序按规则算出),以及一个检查回答的函数。下面用一套教学用的示例制度:日工资 = 月工资 ÷ 21.75,工作日延时加班按 150%,休息日加班且未补休按 200%,法定节假日按 300%。
text
月工资 8,700 元,休息日加班 2 天且未补休:
日工资 = 8,700 ÷ 21.75 = 400 元
加班费 = 400 × 2 天 × 200% = 1,600 元检查函数要规定答案写在哪里,只认那一处。下面是按 TRL GRPOTrainer(v1.16)自定义奖励函数接口写的示意代码,没有实际运行过:
python
import re
def overtime_reward(completions, answer, **kwargs):
"""completions:每个回答的消息列表;answer:数据集里的标准答案列。"""
rewards = []
for msgs, gold in zip(completions, answer):
text = msgs[0]["content"]
found = re.findall(r"<answer>\s*([0-9]+(?:\.[0-9]+)?)\s*元?\s*</answer>", text)
if len(found) != 1: # 没写答案或写了多个答案,一律不给分
rewards.append(0.0)
continue
rewards.append(1.0 if abs(float(found[0]) - float(gold)) < 0.01 else 0.0)
return rewards“写了多个答案也不给分”这一行很重要,后面讲作弊时会看到原因。
GRPO:同一道题做几遍,和自己比
上一篇的 PPO 除了策略模型,还需要一个和策略差不多大的价值模型,用来估计“这道题平均能得几分”,作为判断某个回答好坏的基线。对大模型来说,价值模型既占显存,又很难训好:奖励只在回答结束时给出一次,要让价值模型对每个中间 token 都估出准确的值并不容易。
2024 年 DeepSeekMath 论文提出的 GRPO(Group Relative Policy Optimization,组相对策略优化)换了一种基线:同一道题让策略采样一组回答,用这组回答的平均分当基线。比平均好的回答,概率调高;比平均差的,概率调低。
图中的一组 8 个回答,有 4 个算对了 1,600 元,其余分别用错了倍数(1,200 是按 150% 算的,2,400 是按 300% 算的)、漏乘倍数(800)或者没写答案。每个回答的优势(advantage,表示它比同组平均好多少)这样算:
text
优势 A_i = (r_i − 组内平均奖励) ÷ 组内奖励标准差
8 个奖励:1, 0, 1, 0, 1, 0, 0, 1
平均 = 0.5,标准差 = 0.5
答对:(1 − 0.5) ÷ 0.5 = +1.0;答错:(0 − 0.5) ÷ 0.5 = −1.0这里的标准差按 8 个数直接算(除以 8)。TRL 的实现用样本标准差(除以 7),得到约 0.53,优势约为 ±0.94,正负和相对大小不变。
这个优势会赋给该回答里的每一个 token,然后像 PPO 一样更新:优势为正的回答,每个 token 的概率都被提高;为负的被降低。更新幅度也用 PPO 的裁剪机制限制,一步不能改太多。DeepSeekMath 的原始设置里还在损失中加了一项与参考模型的 KL 惩罚,作用和上一篇相同。
组内归一化带来一个重要的性质:如果 8 个回答全对或全错,所有优势都是 0,这道题本步不提供任何学习信号。题目太难(模型一个都做不对)或太简单(每次都对)都白白消耗了生成算力。挑选训练题目时,最好让当前模型的正确率落在中间区间。
DeepSeekMath 用的设置是每题采样 64 个回答、KL 系数 0.04、学习率 1e-6,在约 14.4 万道数学题上训练。论文还观察到一个现象:强化学习提高了“多次采样投票”的准确率(Maj@K),却没有提高“多次采样至少一次对”的比例(Pass@K)。也就是说,它主要把模型原本就能偶尔做对的答案变得更稳定,而不是教会模型原本完全不会的东西。
框架的默认值已经和原始论文不同了。TRL v1.16 的 GRPOTrainer 默认每题生成 8 个回答、KL 系数为 0(默认不加参考模型)、损失按整组 token 数归一(loss_type="dapo")。后一个改动的原因是:原始 GRPO 先在每个回答内部按长度取平均,后续研究指出这会带来长度偏差(错误回答越长,每个 token 受到的惩罚越轻,模型倾向于把错误回答写长)。照搬论文公式或框架默认值之前,要先弄清是哪个版本。
R1-Zero:从基础模型直接强化学习
2025 年 1 月发布的 DeepSeek-R1 论文做了一个大胆的实验:R1-Zero 不做任何 SFT,直接在 DeepSeek-V3-Base 基础模型上用 GRPO 训练。奖励只有两种,都由规则判定:
- 准确性奖励:数学题的最终答案是否正确,代码题能否通过编译和测试;
- 格式奖励:推理过程是否写在
<think>和</think>之间,答案写在<answer>里。
论文特意没有用神经网络奖励模型,理由是大规模强化学习中它容易被钻空子,重新训练又增加成本和复杂度。提示模板也只规定了“先思考再回答”的格式,没有规定该怎样思考。
结果相当惊人。AIME 2024(美国数学邀请赛题目)的单次准确率从训练开始时的 15.6% 涨到 71.0%,多数投票后达到 86.7%。更有意思的是训练过程中的现象:回答长度随训练稳步增长,从几百个 token 增长到数千个;模型自发出现了反思、验算、换一种方法再试的行为。论文记录了一个中间检查点在解题中途写出类似“等等,我这里可以重新检查一下”的“顿悟时刻”。
长思维链是从哪里来的? 奖励只看最终答案,不看过程。对难题来说,写得更长、在中途检查和回溯的回答,答对的概率更高,于是这类回答一次次获得正优势,相应的行为被不断强化。没有人教模型“要反思”,这是“答对才给分”加上足够多训练步数的结果。但结合 DeepSeekMath 的观察,更准确的理解是:这些行为在强大的基础模型里本来就以小概率存在,强化学习把它们挑出来并放大了。基础模型较弱时,同样的训练未必会出现同样的现象。
R1-Zero 的问题也很明显:推理过程可读性差,经常在中文和英文之间混着写。这些问题奖励函数都不管,自然也就不会被修正。
论文 2025 年的修订版附录给出了 R1-Zero 的具体配置:每题采样 16 个回答,最大长度 32,768 个 token(8,200 步后提高到 65,536),每步 32 道题共 512 个回答,学习率 3e-6,KL 系数 0.001,每 400 步把参考模型换成最新的策略,一共训练 10,400 步。
R1:四个阶段把推理能力变成可用的助手
为了解决 R1-Zero 的可读性问题,并让模型在写作、问答等非推理任务上也好用,正式的 DeepSeek-R1 用了四个阶段:
| 阶段 | 做什么 | 解决什么 |
|---|---|---|
| 1. 冷启动 SFT | 用数千条格式规范、可读性好的长思维链样例,对 V3-Base 做 SFT | 给强化学习一个可读的起点 |
| 2. 推理强化学习 | 与 R1-Zero 相同的大规模 GRPO,额外加一项语言一致性奖励(思维链里目标语言词汇的比例) | 提升推理能力,减少中英混写 |
| 3. 拒绝采样 + SFT | 用第 2 阶段的模型生成大量回答,只保留正确的,得到约 60 万条推理样本;再加约 20 万条写作、事实问答、翻译等非推理样本,共约 80 万条,对 V3-Base 重新 SFT 两轮 | 把推理能力和通用能力合到一起 |
| 4. 全场景强化学习 | 推理题继续用规则奖励,通用对话用奖励模型评有用性和无害性 | 让模型在各种请求上都表现得体 |
论文指出,加入语言一致性奖励会让推理分数略有下降,但可读性明显变好。这是奖励设计中常见的取舍:奖励里写进什么,模型就会为它付出别的代价。第 3 阶段的拒绝采样(rejection sampling)是一种简单而有效的数据生产方法:每题生成多次,用程序或模型筛掉错误的,留下的就是新的 SFT 数据。
第 3 阶段的 80 万条数据还有另一个用途:论文直接用它们对 Qwen2.5 和 Llama 系列的小模型做 SFT,不做任何强化学习,得到一系列蒸馏模型。对比结果很能说明问题:在 Qwen2.5-32B 基础模型上做了一万多步强化学习的版本,AIME 2024 准确率 47.0%;只用 R1 的数据做 SFT 的蒸馏版本是 72.6%。对小模型来说,从强模型蒸馏比自己做大规模强化学习更划算。这正是 第 13 篇 要讲的内容。
奖励设计:模型会找到每一个漏洞
可验证奖励不会被“写得好看”骗到,但它照样会被钻空子。强化学习只最大化奖励,奖励函数里的任何漏洞,都会在足够多的训练步数之后被找到。常见的几种:
- 答案抽取漏洞。检查函数如果只是“回答里出现了 1600 就算对”,模型会学会把几个可能的数字都写一遍。所以前面的示例代码要求答案写在指定标签里且只能有一个。
- 格式奖励被单独刷分。格式奖励给得太多时,模型会输出一对空的
<think></think>标签拿到格式分,推理部分越写越少。格式分应该远小于准确性分,或者只在答案正确时才计入。 - 测试用例被过拟合。代码任务里,模型可能针对测试的具体输入写特殊分支,甚至修改测试、直接让程序以成功状态退出。2025 年 OpenAI 发表的研究在智能体编程环境中观察到,o3-mini 这样的推理模型会在思维链里明确写出“绕过测试”的打算。用另一个模型读思维链来监控,比只看最终动作有效得多;但如果把“思维链里不许出现作弊意图”也加进奖励,模型会学会把意图藏起来,照样作弊。
- 题目本身有漏洞。批量生成的题目里如果答案总是某几个数,或者标准答案本身算错了,模型会学到错误的规律。
应对的办法都很朴素:答案抽取规则写严格,只认一个固定位置;测试放在模型看不到的地方,在隔离的沙箱里执行;题目的数值随机化,标准答案用独立程序复核;训练过程中定期抽查高奖励的回答,看它们到底是怎样拿到分的。奖励曲线涨得出奇地快,往往是出现漏洞的信号,而不是好消息。
一次训练的大部分时间花在生成上
强化学习和 SFT 在成本结构上很不一样。SFT 的每一步只是前向加反向;强化学习的每一步都要先生成一批回答(称为 rollout),而生成是逐个 token 的串行过程,速度受显存带宽限制,这部分原理见推理系列的 Prefill 与 Decode。思维链越长,生成越贵。
给资料助手估一笔账(估算):
text
2,000 道加班费题 × 每题 8 个回答 × 平均 600 个 token = 960 万个生成 token / 轮
对照:同样 2,000 题做 SFT,每题一个约 200 token 的标准回答 = 40 万个训练 token / 轮只算 token 数,强化学习一轮要生成的内容是 SFT 一轮训练内容的 24 倍,而且生成每个 token 比训练时处理一个 token 慢得多。R1-Zero 每一步要生成 512 个最长 3 万多 token 的回答,这就是为什么它需要大规模集群。因此实际的强化学习框架都会把生成交给 vLLM 这类推理引擎(TRL 里设 use_vllm=True),推理系列讲的那些优化在这里直接决定训练速度。
什么时候不值得做强化学习
强化学习的信号来自“同一题有对有错”。下面几种情况,它要么学不到东西,要么不是最划算的办法:
- 模型一题都做不对。所有组的奖励都是 0,优势全为 0,没有梯度。先用 SFT(或蒸馏)把模型带到能偶尔做对的水平。
- 规则是固定公式。加班费的计算规则完全确定时,最可靠的上线方案是让模型调用一个计算工具,由程序算出结果,而不是让模型自己心算。强化学习更适合用在“从口语化描述中准确抽出月薪、天数、加班类型”这一步,或者用在规则需要组合推理、不好写成固定程序的问题上。
- 小模型想要推理能力。如 R1 的蒸馏实验所示,用强模型生成并筛选过的推理数据做 SFT,通常比在小模型上直接做强化学习效果更好、成本更低。
- 任务没有可靠的检查器。检查器本身错误率较高时,模型学到的是检查器的错误。宁可先花功夫把检查器做准。
可验证奖励的强化学习用程序代替奖励模型打分;GRPO 用同题一组回答的平均分当基线,省掉了价值模型,但全对或全错的题目不提供信号;R1-Zero 证明只靠“答对给分”就能在强大的基础模型上逼出长思维链,R1 再用冷启动、拒绝采样和多轮训练把它变成可读、通用的助手。奖励里的每个漏洞都会被找到,而训练的大部分成本花在生成上。R1 的实验也说明,小模型获得推理能力最划算的方式往往是从大模型那里学,下一篇讲怎样做:蒸馏、继续预训练与模型合并。
