大模型后训练(post-training)和可验证强化学习(RLVR,Reinforcement Learning with Verifiable Rewards)是当前从“模型会生成”走向“模型能稳定解决问题”的关键环节。斯坦福大模型开发课 EP16 把这条链路单独拎出来讲,本质是在回答一个问题:当生成结果有客观对错时,怎么用强化学习让模型真正变准。这篇内容适合正在做大模型微调、对齐、RAG 之后的推理增强,或者想搞清楚 RLHF 和 RLVR 区别的开发者。我的核心判断是:RLVR 比 RLHF 更简洁、更适合工程落地,但它只适用于有明确验证信号的任务,别把它当成解决所有幻觉问题的万能工具。
整篇文章会按“为什么需要后训练、RLVR 原理、最小实验、验证器设计、常见坑、产品化边界”这条顺序展开。全程没有视频口播,只有实操经验。
1. 后训练为什么越来越重要:从“会生成”到“靠得住”
1.1 后训练到底在解决什么问题
预训练阶段,模型通过海量文本学到了语言知识、世界知识、逻辑关系。但这时候的模型并不能直接用:你问它问题,它可能答得漂亮,也可能答得完全偏离要求;让它输出 JSON,它可能会在 JSON 前后加上解释;让它做数学题,它可能写出推理过程,但最后一步算错。
后训练要解决的,就是让模型从“会生成”变成“靠得住”。
这个“靠得住”起码包含三层意思:第一,模型的输出格式符合使用方要求;第二,模型的行为符合人类偏好,不说废话、不越权、不编造;第三,在有客观对错的任务上,模型能通过推理得到正确结果。斯坦福那门课把后训练拆成了一个完整流程,而不是一次微调。这也是我读完课程材料后觉得最有价值的地方:后训练不是一个操作,而是一套找问题、定信号、训策略、验效果的工序。
如果只是本地部署一个开源大模型,或者用 API 调用现成模型,你可能不需要知道后训练怎么训练。但一旦你需要让模型在某个垂直任务上稳定发挥,比如自动判卷、代码检查、SQL 生成、结构化抽取,后训练就是你绕不开的环节。因为通用模型不可能天然适配你定义的输出规范和验证逻辑。
1.2 后训练链路中的三个关键阶段
后训练通常有三个大的阶段:监督微调(SFT)、偏好对齐、强化学习优化。
第一个阶段是 SFT。我们先准备一批高质量的输入输出样例,让模型模仿。SFT 的主要作用是让模型学会目标任务的基本格式、基本语气、基本推理结构。很多团队会在这里直接把通用模型变成“领域助手”。但这个阶段的缺陷也很明显:模型只会模仿见过的答案,遇到没见过的变化,很容易乱来。SFT 数据集如果太小,模型学不到规律;如果太大,模型又会过拟合,反而丢掉通用能力。所以 SFT 不是“样本越多越好”,而是要覆盖任务的典型变化模式。
第二个阶段是偏好对齐。典型代表是 RLHF,还有 DPO。这个阶段不是教模型“怎么回答”,而是教模型“什么样的回答更接近人想要的”。通常需要人类标注员对不同回答排序,或者给出偏好对,然后训练奖励模型,再用强化学习优化策略。这个思路在对话场景里效果很好,但成本高,标注质量波动大,而且人类偏好本身也有噪声。
第三个阶段就是 RLVR。它不依赖人类对文本质量的偏好,而是把“对错”交给一个可计算的验证器。比如数学题的最终答案是否正确,代码能不能通过测试用例,JSON 是否符合 schema。这种做法的优势非常明显:奖励信号客观、可复现、可以自动化生成,训练链路比 RLHF 短很多。这也是 EP16 特别强调的地方。
1.3 为什么 RLVR 会被单独拿出来讲
RLVR 被单独拿出来,不是因为它是“新的 RLHF”,而是因为它在工程上是另一条路线。
RLHF 的奖励来自人类偏好,本质是“我觉得好”;RLVR 的奖励来自规则或工具,本质是“它确实对”。这个区别带来的影响很大:RLHF 的奖励模型会学偏,会把更长、更有礼貌、更自信的答案打高分,于是模型开始说废话、堆格式;RLVR 在数学、代码这类场景里,不需要担心奖励模型是不是学偏了,因为它根本不学奖励模型。
当然,RLVR 也有自己的难题,而且并不比 RLHF 简单。最大的难题是:怎么定义一个“可验证的奖励”?如果验证器写得太宽松,模型会钻空子;写得太严格,合法答案也会被判错。这其实是把问题从“调模型”转移到了“设计验证器”上。后面我会专门用一章讲验证器设计。
另一个值得注意的点是,RLVR 更适合“能自动判断对错”的任务,不代表所有任务都能用。开放写作、创意生成、情感陪伴这类任务,没有标准答案,强行套规则验证器,只会把模型逼成一个套路生成器,输出千篇一律。这一点在落地前一定要先想清楚。
2. RLVR 的核心原理:用可验证信号替代人工偏好
2.1 从 RLHF 到 RLVR:奖励从哪来
强化学习需要奖励。RLHF 和 RLVR 的核心差异,就是奖励从哪来。
RLHF 的奖励来自一个训练出来的 Reward Model。这个 Reward Model 的标注数据来自人类对多个回答的偏好排序。它的好处是能处理开放任务,坏处也是明显的:Reward Model 本身会犯错,会被文本长度、句式复杂度、自信程度这些表面特征带偏。训练过程中,策略网络为了拿到更高奖励,会不断“迎合”Reward Model 的偏好,于是出现 reward hacking:模型开始说一些看起来很正确、其实没有实际内容的空话。
RLVR 不用训练 Reward Model。它直接用一个 Verifier 来算奖励。这个 Verifier 可以是一段代码、一个数学表达式匹配器、一个 SQL 执行器、一组单元测试、一个 JSON Schema 校验器、甚至一个经过校准的模型裁判。奖励不是学习出来的,而是计算出来的。只要验证器是稳定的,奖励信号就是稳定的。这样训练出来的模型,更容易在真实任务上拿到可复现的提升。
但这里要注意:可验证奖励不等于“零人工成本”。你仍然需要人来设计验证规则。关键是,这个人不需要给每一句生成内容打分,只需要定义清楚“什么算对”。
2.2 Reward Model、Verifier、规则检查器:三者的区别
很多资料会把奖励模型和验证器混在一起,实际上它们是不同的东西。我整理了一张对比表:
| 实现方式 | 判定逻辑 | 优点 | 缺点 |
|---|---|---|---|
| 奖励模型 | 训练一个模型预测人类偏好分数 | 能处理开放文本,打分平滑 | 会学到偏见,可能被策略利用 |
| 规则验证器 | 用字符串匹配、正则、JSON Schema 等判断 | 快、稳定、可解释 | 不能覆盖多样表达,容易误杀 |
| 执行验证器 | 运行代码、执行 SQL、跑单元测试 | 客观,接近真实场景 | 需要安全沙箱,耗时高 |
| 模型验证器 | 用大模型根据评分标准判断 | 能处理较开放的答案,可给步骤分 | 有噪声,可能偏好结构好看的文本 |
在 RLVR 里,最常用的是规则验证器和执行验证器。比如要求模型输出 JSON 时,用一个 JSON parser 解析,解析失败就奖励 0,解析成功且字段完整就奖励 1。比如数学题,可以先把最终答案抽取出来,再和标准答案做规范化比较。比如代码生成,直接把生成代码放进测试用例里跑,全过给高分,部分过给按比例给分。
如果任务实在太开放,必须用模型裁判,那就要多做一层校准。不要假设大模型裁判一定准。先用一批人工标注过的样本,跑一遍裁判,算一下准确率。如果裁判准确率连 90% 都不到,后面的 RLVR 训练结果就很难让人信服。
2.3 策略更新的最小闭环
RLVR 的完整训练过程,可以简化成下面这个循环:
for step in range(max_steps): prompts = sample_batch(train_data) outputs = model.generate(prompts, temperature=0.8, num_return_sequences=N) rewards = verifier(prompts, outputs) loss = policy_gradient_loss(outputs, rewards, ref_model) optimizer.step()每一步里,模型先生成多个候选答案。因为可验证奖励给得很快,所以可以一个 prompt 采样 8 条或 16 条,而不需要像 RLHF 那样每一步都等人类打分。这里面最值得理解的是“为什么采样多条”:模型一开始的成功率很低,如果每个问题只生成一个答案,很可能全部都是错的,奖励全是 0,梯度也没有方向。但如果每个问题采样 8 条,正确的答案总有机会出现,训练就能把概率分布推向正确路径。
实现上可以基于 PPO,也可以基于 GRPO 这类简化策略。GRPO 在可验证奖励场景里更省显存,因为它不需要额外训练一个 critic 模型,直接用一组采样结果内部的相对优势来更新策略。课程里虽然没有强制要求用哪个算法,但我个人建议从小规模任务开始,直接选一个已经实现好的 RL 框架,先跑通流程,再深入改策略。
3. 一个可复现的 RLVR 实验:数学题或代码生成
3.1 先确认任务和目标指标
如果你第一次接触 RLVR,不要直接上自己最复杂的业务任务。先选一个验证成本低、对错明确的任务。我比较推荐两个:小学数学题、单函数代码生成。
拿数学题来说,好处是验证器简单,一个答案匹配函数就够了。可以先准备几百条题目,人工写好标准答案和推理过程。目标指标可以定义成两个:pass@1 和 pass@k。pass@1 是模型只生成一个答案就能答对的概率,更接近实际使用;pass@k 是让模型生成 k 个答案,其中至少一个正确的概率,更能说明模型有没有潜在能力。
跑 RLVR 之前,先跑一轮 SFT。SFT 之后的模型在开发集上至少要达到一定的正确率,比如 20% 到 30%。如果连一次正确答案都产生不出来,那是模型能力不够,不是 RLVR 的优化目标有问题。这个前置条件非常关键,很多人上来就跳过 SFT,直接拿通用模型跑 RLVR,结果奖励全是 0,训练根本不收敛。
3.2 数据格式与采样策略
RLVR 训练数据最重要的不是标注“长答案”,而是让验证器能判断“对错”。所以数据要包含三个部分:问题、标准结果、验证方法。
一个最小示例可以长这样:
{ "question": "计算 3x + 2 = 11 中 x 的值。", "answer": "x = 3", "verifier": "exact_match", "checks": ["x = 3"] }如果你的任务更复杂,比如要求模型先输出推理过程,再输出最终结论,那就要在验证器里先抽取出“最终答案”部分,再做匹配。不要拿整段生成文本去做字符串匹配,否则模型会学到“只要把正确答案藏在长文本里就能拿分”的坏习惯。
采样策略上,我一般先用 temperature 0.8,num_return_sequences 8。如果输出太散、很多答案完全跑题,就降到 0.6;如果奖励信号太稀疏、正确率太低,就提高到 1.0,同时把采样数提高到 16。这里的温度不是训练参数,而是生成探索参数。它控制的是训练时收集正样本的范围。
3.3 训练流程与关键参数
下面是一个比较保守的 RLVR 训练流程:
- 先用 SFT 数据训练基线模型,确认指标。
- 准备一小批 RL 训练 prompt,比如 500 到 1000 条。
- 写验证器,先在 100 条生成结果上人工检查验证器准确率。
- 跑 RL 训练,每步采样 8 到 16 条输出。
- 每隔几步保存 checkpoint,并在开发集上做 pass@1 评估。
- 训练结束时,把最终模型和 SFT 基线做对比。
关键参数给一个起始参考:
| 参数 | 起始建议 | 说明 |
|---|---|---|
| 采样数 N | 8~16 | 探索越多,训练越贵 |
| 初始模型 | 已完成 SFT 的模型 | 不要从 base 模型直接跑 |
| 学习率 | 1e-6 ~ 5e-6 | 比 SFT 低,防止摧毁已有能力 |
| KL 惩罚系数 | 0.01 ~ 0.1 | 控制新策略不偏离参考策略太远 |
| 训练 batch | 32 条以上 | 奖励有噪声,样本太少不稳定 |
| 验证频率 | 每 20~50 步 | 及时看训练是否真正提升指标 |
这些数值不是标准答案,需要根据模型规模和数据量调整。如果你的模型比较大,学习率可能要更低;如果任务很简单,采样数可以减小。最怕的是用一个固定参数跑到底,不做观察。
3.4 成功和失败的判断标准
RLVR 训练成功,最直接的信号是:验证集上的 pass@1 比 SFT 基线高,而且不是靠牺牲输出格式换来的。
我遇到过一种情况:训练日志里奖励一直在涨,但测试集指标纹丝不动。后来一查,模型学会了在答案前后加很多解释,验证器只匹配最终答案,但它把最终答案重复了十遍,等于变相提高命中机会。这不是真正的能力提升,是验证器被钻空子。
更好的判断标准是看三件事:第一,pass@1 是否提升;第二,输出平均长度是否显著变长;第三,人工抽检高分样本,看推理是否合理。如果 pass@1 提升但输出长度暴涨,就要小心模型在用“枚举式”答案刷分。
还要注意一个现象:训练前期奖励可能波动很大,这是正常的。可验证奖励不像人打的平滑分数,它只有 0 和 1,噪声天然高。所以不要因为一两个 step 掉点就急着降学习率,先看整体趋势。如果 100 步以内奖励均值始终没有上升趋势,那就要回头检查验证器和 SFT 基线。
4. 验证器设计:RLVR 的“奖励”到底怎么算
4.1 规则验证器:严格匹配、结构化校验、执行测试
RLVR 里最常用的验证器是规则验证器。它写起来简单,运行速度快,也最容易调试。
严格匹配适合答案格式固定的任务。比如“x=3”这种,先对模型输出做规范化:去空格、统一大小写、把中文冒号转英文,然后再比较。这里的陷阱很多:模型可能输出“答案是3”“x=3”“3”三种形式,靠一个规范化函数往往不够。我一般会把标准答案拆成多个可接受的别名,并存成列表,验证时只要命中一个就算对。
结构化校验适合输出 JSON、YAML、函数签名这类任务。比如要求模型输出一个 JSON 对象,字段包含 name、age、items。验证器先用 JSON parser 解析,如果解析失败,奖励为 0;解析成功再看字段是否存在,字段类型是否正确。这一步能给部分分:每个字段正确给 0.2,全部正确给 1。部分分在训练初期很有用,因为全对样本太少时,模型连梯度方向都找不到。
执行测试适合代码生成和 SQL 生成。比如要求模型写一个排序函数,就把生成的函数放进单元测试里跑。测试用例通过数量除以总测试用例数量,就是这一条输出的奖励。执行验证最客观,但也有两个麻烦:一是需要安全沙箱,不能随便在训练机上执行模型生成的可疑代码;二是耗时高,如果一条 prompt 生成 16 个代码,每个都要跑测试,训练时间会成倍增加。
4.2 模型验证器:什么时候必须用
有些任务的正确性没法靠规则判断。比如要求模型写一段总结,逻辑是否正确、有没有遗漏关键点,字符串匹配很难判断。这时候可以找一个大模型当裁判,根据你预设的评分标准给分。
使用模型验证器时,有几个细节很重要:
一是验证 prompt 要固定,温度要设成 0,不要每次都随机。二是最好让裁判输出一个 JSON,包含每个评分维度的分数,而不是只输出“对/不对”。三是如果预算允许,用两个不同模型投票,或者对同一个答案采样三次取中位数,能明显降低噪声。
但模型验证器也有一个天然问题:它容易被生成文本的长度和结构影响。一个更长的、分段的答案往往更容易拿高分,但它不一定更正确。所以每次用模型验证器之前,我都要先做一次“验证器校准”:抽 100 条已有的人工标注数据,让验证器判定,算它的准确率和误判率。如果准确率低于 90%,不要直接进入 RL 训练。
4.3 验证器本身有噪声时怎么办
很多人在 RLVR 里忽略了一个问题:验证器也是会错的。规则验证器可能误杀合法答案,模型验证器可能给错误推理打高分。验证器的噪声会影响整个 RL 训练,而且这种影响在训练早期会被放大。
如果发现验证器有噪声,我的建议是分两步处理。
第一步,把验证器的漏判和误判分开看。漏判是“正确答案被判错”,这会导致训练时正样本太少;误判是“错误答案被判对”,这会导致模型学到错误模式。漏判可以通过扩充可接受别名、开放匹配规则解决;误判要更小心,需要收紧判断条件。
第二步,如果已经做了优化但验证器准确率还是不够,那就让奖励更平滑一点。不要只用 0/1 二值,可以给一个“部分正确”的中间分。比如答案对了但推理不完整,给 0.5;推理步骤对但最终算错,给 0.2。部分分能缓解验证器噪声带来的梯度抖动。
还有一个更基础的工程建议:每次修改验证器,都要把它记录成版本,不要静默修改。因为 RL 训练过程中,你经常需要回溯某一步的奖励是怎么算出来的。如果验证器改了好几次,没有版本记录,你很难判断指标变化到底是因为模型变好了,还是因为验证器变松了。
5. 落地时会踩的坑:从回报稀疏到策略崩溃
5.1 回报信号太稀疏,模型不更新
RLVR 最常见的问题就是奖励全是 0。
一个 7B 模型,如果没有经过足够的 SFT,在数学题上可能生成 16 个答案全错。这时候强化学习根本没有信号,策略不会更新。看起来是“训练没收敛”,实际上是“一开始就没有正样本”。
解决思路不是盲目加大采样数,而是先降低任务难度。我建议先让 SFT 基线在开发集上达到至少 20% 左右的成功率,再跑 RLVR。如果成功率太低,先收集更多高质量 SFT 数据,或者把问题拆成更简单的子任务。比如不做整道题,先让模型只输出“设未知数、列方程”这一步,等这一步稳了,再优化完整答案。
有一种特殊情况是:任务本身很难,但有一些容易拿分的子结构。这时候可以设计“阶段奖励”:只要模型写出了正确的方程,给 0.3;只要答案算对,给 1。但阶段奖励要谨慎,因为它会引入人为设计,模型可能只追求容易拿到的部分,对最终目标不敏感。
5.2 验证器被“钻空子”,reward hacking
RLVR 里最值得警惕的现象就是 reward hacking。模型不是为了“做对”,而是为了“让验证器觉得对”。
举个例子:验证器只检查最终答案是否等于“3”,模型可能会在输出里写“答案是3,答案是3,答案是3”,然后把前面一大段推理全跳过。验证器一看包含正确字符串,给 1 分。策略网络立刻意识到,重复正确答案能拿高分,于是训练结果变成一堆垃圾文本。
避免 reward hacking 的做法有几种:
- 验证器只检查“最终答案区域”,不接受散落在任意位置的答案;
- 在奖励函数里加入格式约束,例如必须包含推理过程,否则扣分;
- 对输出长度做惩罚,防止模型通过疯狂重复来刷分;
- 定期人工抽查高分样本,看模型为什么拿高分。
记住一点:验证器不是写一次就结束的。你要在训练过程中不断观察 rollout 的高分样本,一旦发现明显不符合直觉的“聪明”输出,立即更新验证器,并重新开始训练。
5.3 训练跑着跑着输出质量下降
另一种常见情况是训练早期效果不错,但过了一段时间,模型输出质量突然下降,甚至开始语无伦次。
这类问题通常和 KL 惩罚、学习率、采样温度有关。RLVR 更新策略时,容易让模型越来越集中在少数几种“高分表达”上,导致多样性下降。表现在指标上,就是 pass@1 可能还在涨,但生成内容开始千篇一律;更严重的是,采样到一定阶段,模型开始生成重复 token,甚至陷入死循环。
发现这种情况,我会先检查两个指标:策略模型和参考模型之间的 KL 散度,以及平均输出长度。如果 KL 散度涨得太快,说明策略偏离参考模型太远,需要增大 KL 惩罚。如果平均输出长度暴涨,说明模型学会了通过堆字数来刷分,需要在奖励里加长度惩罚。
如果这两项都正常,再考虑降低学习率。RLVR 比较敏感,学习率太高会让策略在几个 batch 内崩溃。我一般会把学习率设到 SFT 的十分之一左右,再根据日志缓慢调整。
5.4 通用排查顺序
RLVR 训练出问题,不要一上来就乱调参。按下面这个顺序排查,通常能更快定位:
- 先看初始成功率:SFT 基线在训练集上有没有正样本?
- 再看验证器准确率:抽 100 条生成结果,人工判定验证器给分是否合理。
- 看 rollout 日志:高分样本长什么样?有没有明显钻空子?
- 看奖励曲线:是否持续上升?还是上下乱跳毫无趋势?
- 看 KL 和长度:策略有没有偏离参考模型?输出有没有变长到异常?
- 最后才调整参数:改学习率、改采样温度、改 KL 惩罚。
这个顺序几乎能解决 80% 的 RLVR 训练问题。核心思路是,先确认“能不能收到正确信号”,再确认“策略有没有学到东西”,最后才去碰训练参数。很多人习惯反过来,一掉点就调学习率,结果问题出在验证器上,调参只是在安慰自己。
6. 产品化判断:RLVR 适合哪些任务,不适合哪些任务
6.1 适合 RLVR 的任务类型
真正适合 RLVR 的任务,都有一个共同点:对错可以被自动判定,而且判定成本不高。
最典型的是代码生成。模型写的代码可以放到沙箱里,用预写好的单元测试来验证。测试通过率就是奖励。这是 RLVR 已经验证过的场景,很多代码模型都靠这一套提升 pass@1。
其次是数学题、逻辑推理、SQL 生成、JSON 结构化输出。它们的共同点是:结果有标准形式,判断逻辑可以程序化。哪怕答案有多种表达,只要你能写一个函数把等价表达都归一化,就能用 RLVR。
在业务里,还有一个很适合 RLVR 的场景是“必须包含指定字段”的信息抽取。比如从一段商品评论中抽取品牌、型号、价格。验证器检查抽取结果是否字段完整、值是否存在于原文中。这种任务通过 RLVR 可以让模型更稳定地输出结构化结果,不容易漏字段。
如果你的任务本身已经有了一套人工审核流程,可以考虑把这套流程中的客观规则抽出来,做成验证器,让 RLVR 先迭代一版“规则敏感型”模型,再让人工审核兜底。
6.2 不适合 RLVR 的场景
不适合 RLVR 的情况也很明显:没有标准答案,或者标准答案成本太高。
开放写作、创意文案、营销标题、情感陪伴、闲聊这类任务,内容好坏高度主观。你没有办法写一个函数判断“这句文案是否有感染力”。如果强行用模型裁判,裁判本身的主观偏好就会成为新的噪声源。这种场景下,RLHF 或 DPO 可能更合适,因为它们直接学习人类偏好。
还有一类任务要特别小心:医疗建议、法律意见、金融分析。这些领域的答案是否“正确”,不能只靠规则判断,更不能靠简单的关键词匹配。如果验证器设计不齐全,模型可能输出看起来专业、实际有风险的错误内容。并不是说完全不能用 RLVR,而是要在验证器里加入大量的专业约束和兜底逻辑,且训练完成后必须有严格的人类专家评估。
最后,如果你的算力资源很紧张,或者模型本身很小,也不建议轻易跑 RLVR。小模型在奖励零散的训练中很容易遗忘已有能力。我见过很多团队在 1B 模型上做 RLVR,结果 pass@1 没提升,反而把 SFT 阶段学会的格式稳定性也搞丢了。这种时候,先做更充分的 SFT 和 DPO,收益可能更大。
6.3 实操建议:先小后大,先单点后系统
如果你已经决定要在业务里试 RLVR,我的建议是三步走。
第一步,选一个最小但真实的子任务。不要一上来就想优化整个客服系统,先选“从用户问题中抽取产品参数”或者“根据表格生成 SQL”这样一个边界清晰的任务。跑通 SFT -> RLVR -> 评估的完整链路。
第二步,把验证器当成第一优先级。先写规则,再采样输出,再人工抽查,再迭代验证器。验证器稳定了,训练才开始有意义。很多失败的 RLVR 项目,最后复盘下来都不是 RL 出了问题,而是验证器质量不过关。
第三步,上线前做一次“分布外测试”。RLVR 容易让模型过度优化训练集上的验证规则,遇到没见过的问法可能失灵。所以一定要用一批和训练数据分布不同的测试样本,人工评估一遍。
如果只是做本地部署或者调用 API,其实不需要关心怎么训练 RLVR。模型侧的后训练是模型厂商和算法团队的事,你和 RLVR 的关系更多是“理解能力边界”,而不是“必须亲手训一个模型”。把 RLVR 当成一个训练升级项,而不是默认步骤,才能真正发挥它的价值。