
大模型训练圈子里RLVR 已经成了微调阶段绕不开的关键词。很多团队用可验证奖励做强化学习让模型在数学、代码、逻辑推理任务上快速提升。但最近北大相关研究提出一个值得警惕的观察RLVR 在提升某一类能力的同时可能破坏模型的后续训练能力问题根源被归结为“验证器诱导的策略支持重塑造”。这个概念听起来有些抽象但它直接影响我们如何设计奖励、如何安排训练阶段、如何判断模型是否“越练越窄”。本文想把这个问题讲清楚从概念拆解、机制分析到可运行的实验示例再到工程上的缓解方案完整过一遍。如果你正在用 RLVR 做大模型微调或者准备把强化学习引入自己的业务场景这篇内容会比较有用。读完你会理解验证器为什么会导致策略退化也能在训练脚本里加上对应的监控指标和防护措施。1. 背景RLVR 为什么火又为什么让人担心1.1 RLVR 是什么RLVR 的全称是 Reinforcement Learning with Verifiable Rewards也就是“基于可验证奖励的强化学习”。它和传统 RLHF基于人类反馈的强化学习最大的区别在于奖励信号的来源。传统 RLHF 需要训练一个奖励模型由人工标注偏好数据来模拟人类喜好。而 RLVR 不依赖奖励模型它直接用规则或程序来验证模型输出是否正确。典型的例子包括数学题验证最终答案是否等于参考答案。代码生成运行测试用例统计通过率。逻辑推理检查推导步骤是否合规。信息抽取比对结构化字段是否一致。这种设计让奖励信号非常干净、客观而且几乎不需要人工参与。所以从 2024 年开始RLVR 在大模型推理能力训练中迅速流行成为很多开源和闭源模型提升数学、代码能力的主要手段。1.2 提升效果显著但隐忧也在浮现RLVR 的效果确实好。模型在 GSM8K、MATH、HumanEval 这些基准上用相对少的训练步数就能获得大幅提升。因为奖励信号明确梯度更新方向非常清晰模型会快速学会“什么样的输出能拿到高分”。但问题也恰恰出在这个“快速”上。北大相关研究指出了一个现象经过 RLVR 训练后的模型在后续的新任务学习、领域适应甚至原本能力保持上表现反而变差了。也就是说模型在某个可验证任务上变强了但它的“可塑性”或者“继续学习能力”下降了。研究者把这种现象解释为“验证器诱导的策略支持重塑造”。1.3 为什么这个问题值得关注现在很多团队的训练管线是分阶段进行的先预训练再 SFT最后用 RLVR 做推理强化。如果在 RLVR 阶段把模型练“死”了后续再想对齐新领域、学习新知识就会非常吃力。更麻烦的是这种退化不一定能在评测指标上第一时间暴露出来。如果你只看数学准确率模型确实在涨但它的输出多样性、对提示扰动的鲁棒性、对陌生任务的适应能力可能已经悄悄变差。等发现问题时训练成本已经花出去了。所以理解“策略支持重塑造”的机制提前在训练中加防护比事后补救重要得多。2. 核心概念拆解验证器、策略支持与重塑造2.1 策略支持Policy Support是什么意思在强化学习里策略Policy是模型根据输入决定输出分布的规则。策略支持Policy Support可以通俗理解为“模型在输出空间中实际有能力覆盖的区域”。举个例子一个通用对话模型面对数学题可能生成 10 种不同风格的推导过程有的用代数有的用图解有的写详细步骤有的只给答案。它的策略支持范围比较宽。一个只经过 RLVR 训练的模型面对同一道数学题可能只会生成一种固定模板的解答过程。即使你换一种问法它的输出风格也高度一致。它的策略支持范围就变窄了。在连续输出空间中策略支持就是模型输出分布里概率质量比较集中的那块区域。区域越宽模型越灵活区域越窄模型越“专”但也越脆弱。2.2 验证器如何诱导策略支持重塑造验证器Verifier在 RLVR 中的作用是给输出打分通常只有 0 和 1 两种结果。它的标准非常刚性对了给 1错了给 0。这种刚性奖励会带来一个直接后果——模型发现只有少数几种输出形式能稳定拿到 1于是概率质量会迅速向这些输出集中。原本模型可能探索出很多种解题思路但因为其中一些思路偶尔会被验证器判为错误或者格式不够“标准”模型就会渐渐放弃它们。策略支持就这样被“重新塑造”了从宽泛分布收敛到狭窄分布从多样性收敛到单一性。北大研究提到的“策略支持重塑造”Policy Support Reshaping指的就是验证器这种二元奖励信号导致模型输出分布被强行改变的过程。2.3 为什么说这可能破坏后续训练能力当一个模型在 RLVR 阶段把策略支持收缩到很窄的区域后后续训练会遇到一个矛盾新任务的优化方向可能落在原策略支持范围之外。模型如果想学会新任务必须先探索原分布之外的输出空间。但 RLVR 阶段的强优化已经把概率质量牢牢锁在旧区域探索行为本身就很难发生。打个比方一个人习惯了走同一条路上下班这条路又快又稳。有一天公司搬到了另一个方向他需要重新找路。但他对旧路线的依赖太强每次出门都会下意识走向旧路线探索新路线的动力和成功率都大大降低。模型也是一样。验证器越强、训练步数越多策略支持收缩得越厉害后续迁移和继续学习的能力就越差。2.4 这和使用 KL 散度约束有什么关系很多人会问RLVR 训练时不是有 KL 散度约束吗为什么不阻止策略支持坍缩这里需要区分两个概念KL 约束防止策略偏离参考策略太远但它约束的是“整体分布距离”不是“支持范围”。如果验证器持续给某一类输出高分模型可以在满足 KL 约束的前提下把概率质量在支持范围内大幅重新分配。KL 散度只关心分布重叠程度不直接惩罚“分布变窄”这件事。所以 KL 约束能减缓策略支持重塑造的速度但不能从根本上阻止它。这也是为什么单靠加 KL 权重无法完全解决后续训练退化问题的原因。3. 环境准备与实验设计3.1 运行环境说明要复现本文的实验示例需要准备一套 Python 环境。版本需要根据你的项目实际情况调整本文以常见环境为例演示思路。建议环境如下操作系统LinuxUbuntu 20.04/22.04或 macOSPython3.10 及以上深度学习框架PyTorch 2.x大模型库transformers、datasets强化学习库TRLHugging Face 官方强化学习库辅助库accelerate、bitsandbytes显存不足时用、wandb可选用于日志记录3.2 实验设计思路为了演示“验证器诱导的策略支持重塑造”我们不追求完整复现北大论文实验而是做一个简化版的观察实验选一个小型语言模型作为基础模型。构造一个二元可验证任务比如“判断数字是否能被7整除”。用 RLVR 训练多个 epoch。每轮训练后记录两个指标训练集准确率和生成熵Generation Entropy。观察生成熵随训练步数的变化直观看看策略支持是否在收缩。生成熵是指模型输出分布的信息熵熵越高说明输出越多样熵越低说明输出越集中。如果 RLVR 训练让熵快速下降就说明策略支持正在被重塑造。3.3 项目结构实验项目结构如下rlvr_support_demo/ ├── data.py # 构造训练数据 ├── verifier.py # 可验证奖励函数 ├── train_rlvr.py # RLVR 训练主脚本 ├── monitor.py # 熵与多样性监控 └── outputs/ # 训练日志与模型输出4. 完整实战用一个简单任务观察策略支持坍缩4.1 构造可验证任务我们设计一个非常简单但判定标准明确的任务给定一个 100 到 999 之间的整数模型需要回答“YES”或“NO”表示这个数是否能被 7 整除。为了让任务有区分度我们规定输出必须是严格的YES或NO其他形式都算错误。这模拟了真实 RLVR 中验证器只认结果的场景。下面是数据构造脚本data.py# 文件路径rlvr_support_demo/data.py import random import torch from datasets import Dataset def is_divisible_by_7(n: int) - bool: return n % 7 0 def generate_samples(num_samples: int 2000, seed: int 42): random.seed(seed) samples [] for _ in range(num_samples): n random.randint(100, 999) answer YES if is_divisible_by_7(n) else NO samples.append({ query: fIs {n} divisible by 7? Answer with YES or NO only., answer: answer, }) return samples def build_dataset(num_samples: int 2000): samples generate_samples(num_samples) return Dataset.from_list(samples) if __name__ __main__: ds build_dataset() print(ds[:5])这里的关键点是任务逻辑非常简单但验证标准绝对客观。训练时模型只能通过输出YES或NO获得奖励任何附加解释、换行、大小写混合都可能被验证器扣分。4.2 实现验证器验证器是 RLVR 的核心。它的输入是提示文本和模型生成的文本输出是一个标量奖励。我们设计验证器时故意设置“严格模式”只识别YES或NO的精确匹配。这样会放大策略支持重塑造效应方便观察。# 文件路径rlvr_support_demo/verifier.py import re def normalize_answer(text: str) - str: 规范化模型输出提取 YES/NO 意图。 注意这里故意保留严格匹配逻辑用于观察策略坍缩。 text text.strip().upper() # 只取第一行并且去除非字母字符 first_line text.split(\n)[0] first_line re.sub(r[^A-Z], , first_line) if first_line YES: return YES if first_line NO: return NO return INVALID def verify_divisible(query: str, response: str, answer: str) - float: 可验证奖励函数。 参数说明 - query: 原始提示 - response: 模型生成的回答 - answer: 标准答案 返回 - 回答正确且格式合规1.0 - 回答错误或格式不合规0.0 prediction normalize_answer(response) if prediction INVALID: return 0.0 if prediction answer.upper(): return 1.0 return 0.0一个值得注意的设计点我们把“格式错误”和“答案错误”都判为 0 分。这符合很多真实 RLVR 系统的设置但也意味着模型会被迫收敛到一种固定格式输出。后面你会发现这恰恰是策略支持重塑造的源头之一。4.3 编写 RLVR 训练主脚本这里使用 Hugging Face TRL 库的 GRPO 训练器。GRPOGroup Relative Policy Optimization是目前大模型 RLVR 训练中比较常用的算法它的核心思想是对一个提示采样多个输出用组内相对奖励计算优势。以下脚本是核心训练代码完整可运行# 文件路径rlvr_support_demo/train_rlvr.py import os import torch from datasets import load_dataset from transformers import AutoModelForCausalLM, AutoTokenizer from trl import GRPOConfig, GRPOTrainer from data import build_dataset from verifier import verify_divisible def reward_func(completions, answers, **kwargs): TRL GRPOTrainer 要求的奖励函数接口。 参数说明 - completions: 模型生成的文本列表 - answers: 标准答案列表 返回一个奖励列表。 rewards [] for completion, answer in zip(completions, answers): # completion 是 token 序列需要 decode if isinstance(completion, list): completion_text tokenizer.decode(completion, skip_special_tokensTrue) else: completion_text completion query kwargs.get(query, ) reward verify_divisible(query, completion_text, answer) rewards.append(float(reward)) return rewards def main(): # 1. 构建数据集 dataset build_dataset(num_samples500) # 2. 加载模型和分词器 model_name sshleifer/tiny-gpt2 # 小模型仅用于演示 tokenizer AutoTokenizer.from_pretrained(model_name) tokenizer.pad_token tokenizer.eos_token model AutoModelForCausalLM.from_pretrained(model_name) # 3. 定义 GRPO 配置 training_args GRPOConfig( output_dir./outputs/rlvr-tiny-gpt2, per_device_train_batch_size4, gradient_accumulation_steps2, num_train_epochs3, learning_rate5e-6, logging_steps10, save_steps100, max_completion_length8, beta0.04, # KL 惩罚系数 ) # 4. 创建训练器 trainer GRPOTrainer( modelmodel, processing_classtokenizer, argstraining_args, train_datasetdataset, reward_funcsreward_func, # 注意接口版本差异 ) # 5. 训练 trainer.train() # 6. 保存模型 trainer.save_model(./outputs/rlvr-tiny-gpt2-final) if __name__ __main__: main()这里有几个需要注意的地方reward_func的接口格式在不同版本 TRL 中略有差异。本文示例以常见 GRPO 接口为例如果你的 TRL 版本不同需要参考官方文档调整参数解析方式。我们故意使用了非常小的tiny-gpt2模型目的是让实验在普通 GPU 甚至 CPU 上都能快速跑完。max_completion_length8限制生成长度防止模型输出大段解释文字。4.4 添加熵监控模块训练过程中我们需要实时观察策略支持的变化。一个直观指标是生成熵。熵值越低说明模型输出越集中策略支持越窄。# 文件路径rlvr_support_demo/monitor.py import torch import numpy as np from transformers import AutoModelForCausalLM, AutoTokenizer def compute_generation_entropy(model, tokenizer, prompts, max_new_tokens8): 计算模型在给定提示下的平均生成熵。 生成熵越低说明模型输出分布越集中在少数离散结果上 这通常意味着策略支持范围较窄。 model.eval() entropy_list [] with torch.no_grad(): for prompt in prompts: inputs tokenizer(prompt, return_tensorspt) outputs model(**inputs) # 取最后一个 token 位置的 logits next_token_logits outputs.logits[:, -1, :] # 只保留生成词表部分避免特殊 token 影响 probs torch.softmax(next_token_logits, dim-1) probs probs[0] # 过滤掉概率为 0 的 token mask probs 1e-8 probs_filtered probs[mask] # 计算熵 entropy -(probs_filtered * torch.log(probs_filtered)).sum().item() entropy_list.append(entropy) return float(np.mean(entropy_list)) if __name__ __main__: model AutoModelForCausalLM.from_pretrained(./outputs/rlvr-tiny-gpt2-final) tokenizer AutoTokenizer.from_pretrained(./outputs/rlvr-tiny-gpt2-final) prompts [ Is 784 divisible by 7? Answer with YES or NO only., Is 591 divisible by 7? Answer with YES or NO only., Is 322 divisible by 7? Answer with YES or NO only., ] entropy compute_generation_entropy(model, tokenizer, prompts) print(fAverage generation entropy: {entropy:.4f})如果 RLVR 确实诱导策略支持重塑造你会看到初始模型的熵比较高一两轮训练后熵迅速下降最后几乎所有提示的输出都集中在同一个 token 上。4.5 运行与结果解读运行训练脚本cd rlvr_support_demo python train_rlvr.py训练完成后运行监控脚本python monitor.py预期你会看到类似下面的趋势具体数值因模型和随机种子而异训练阶段生成熵估算观察到的行为初始模型约 5.0 以上输出分散会生成解释性文字第 1 轮后约 2.0 - 3.0开始收敛到 YES/NO 格式第 3 轮后约 0.5 - 1.0几乎只输出固定 token多样性强依赖提示词这个现象说明模型并不是“学会了判断整除”而是学会了“用最小代价满足验证器”。它找到了验证器最容易接受的那条路径然后彻底放弃了其他路径。策略支持就这样被重塑造了。5. 从实验到现实哪些场景更容易触发策略支持坍缩5.1 二元验证任务风险最高像我们实验中的“判断是否整除”、代码通过/不通过、判断题正确/错误这类任务只有两个结果。验证器给出的奖励信号极度稀疏模型几乎没有中间地带可以探索。只要找到一条稳定得分的路径优化就会锁定它。5.2 大搜索空间的连续推理风险较高在数学推理、代码生成这类任务里虽然最终结果可验证但模型需要先生成一段较长的推理过程。如果验证器只检查最终答案模型可能发展出“答案正确但推理偷懒”的模式比如跳过关键步骤直接输出结果。用固定句式套用不同问题的答案。遇到类似题目时复制最容易得分的模板。这些模式都会让策略支持收缩到“看起来能得分”但“实际能力单一”的窄区间。5.3 训练步数过多会放大效应RLVR 的早期阶段模型还在探索不同输出风格中后期优化器会快速削掉那些“偶尔出错”的输出路径。训练步数越多策略支持收缩得越彻底。这也是很多团队反应“RLVR 训练超过一定步数后模型反而变僵化”的原因。5.4 验证器本身有偏置时风险更大如果验证器对某种输出风格、格式、措辞有潜在偏置比如只认特定 JSON 结构、只认特定符号那么模型会被推向更窄的分布。与其说是模型学会了任务不如说是模型学会了“模仿验证器偏好”。6. 如何缓解验证器诱导的策略支持重塑造6.1 设计验证器时保留格式多样性在真实项目中验证器不应该对输出做过度严格的格式限制。只要语义正确就应该给奖励。例如数学题中只要最终答案正确不管推导用自然语言还是公式都判对。代码生成中只要测试用例通过不管代码风格如何都判对。分类任务中只要模型表达出正确意图可以接受不同措辞。这能大大缓解策略支持坍缩因为模型不需要为了迎合格式而放弃多样化的解题路径。6.2 使用软奖励替代二元奖励二元奖励0/1是最容易引发坍缩的。可以考虑使用软奖励部分正确的中间步骤给中间分数。格式正确但答案错误给一个小分数。答案正确但推理不完整给一个稍低的分数。软奖励相当于给模型提供更丰富的梯度信号模型不需要走极端也能知道哪些方向是对的。6.3 在奖励中增加多样性惩罚项在计算奖励时可以加入一个正则项惩罚当前输出与组内其他输出的相似度。如果模型每次都生成几乎相同的答案即使正确也在多样性维度上扣一点分。这种方法在数学和代码任务中都有实践案例核心代码如下def diversity_penalty(completions, rewards, similarity_threshold0.7): 根据组内输出相似度调整奖励抑制策略坍缩。 adjusted_rewards [] for i, r in enumerate(rewards): penalty 0.0 for j, other in enumerate(completions): if i j: continue sim compute_similarity(completions[i], other) if sim similarity_threshold: penalty (sim - similarity_threshold) * 0.1 adjusted_rewards.append(r - penalty) return adjusted_rewards6.4 混合 SFT 数据训练在 RLVR 训练阶段不要只使用验证任务数据。可以按一定比例混合通用 SFT 数据让模型在强化优化的同时仍然有监督信号维持输出多样性。实践中的比例建议数据组成比例建议作用RLVR 可验证任务数据50% - 60%提升目标任务能力通用对话/指令数据20% - 30%保持输出多样性和通用能力历史 RLVR 高熵样本10% - 20%防止模型遗忘过去的探索路径6.5 训练过程中监控熵和多维指标只盯着准确率是不够的。建议在训练日志中至少记录以下几类指标生成熵Generation Entropy输出多样性。输出长度分布是否所有输出都收敛到固定长度。n-gram 重复率文本多样性。提示扰动鲁棒性对同义改写后的提示是否仍有稳定表现。保留集表现在未参与训练的任务上的准确率变化。如果发现生成熵在训练后期快速下降即使准确率还在涨也应该考虑降低训练步数或增加多样性正则。6.6 分阶段训练避免一次强化过猛RLVR 训练应当采用渐进策略而不是一次性压上全部数据。常见做法是第一轮用小学习率、少量数据让模型初步接触验证器的判断标准。第二轮加入软奖励同时混入更多 SFT 数据。第三轮如果发现熵开始下降过快提前停止。这种分阶段方式可以让模型在“学会任务”和“保持可塑性”之间取得更好的平衡。7. 常见问题与排查清单7.1 训练后模型输出千篇一律怎么办问题现象常见原因解决思路所有回答都是固定格式验证器对格式限制过严放宽验证器格式约束熵值下降过快奖励信号过于二元化引入软奖励或多样性惩罚准确率高但生成内容单一策略支持坍缩混合 SFT 数据降低 RL 步数换一种问法就答错模型记住了模板而非语义增加提示扰动加入鲁棒性评估7.2 如何判断策略支持是否已经坍缩可以做一个快速测试取 100 个提示。对每个提示生成 10 次输出。统计每个提示下输出的平均不同 token 序列数。如果这个数字从初始的 5 以上下降到 1 或 2说明策略支持已经严重坍缩。更精细的做法是计算输出 token 分布的熵并在训练日志中实时记录。7.3 应该选择多大 KL 系数KL 系数没有标准答案但可以根据训练日志调参beta值较大如 0.1模型更接近初始策略坍缩慢但任务能力提升也慢。beta值较小如 0.01模型更容易被验证器引导坍缩快但准确率提升快。建议从 0.05 开始如果发现熵下降过快增大到 0.1如果准确率不涨减小到 0.02。7.4 模型在保留集上表现变差是否要继续训练不建议继续训练。RLVR 的目标往往不只是单一任务如果保留集准确率开始下降说明模型已经过拟合到验证器的判断模式。这时应该回滚到熵下降不明显但保留集表现最好的那个 checkpoint。建议训练时定期保存 checkpoint并记录每个 checkpoint 在保留集上的表现。7.5 验证器本身有 bug会不会加重坍缩会。如果验证器在某类输入上判断错误模型会学到错误的路径同时因为奖励信号稳定它会把这个错误路径锁死。所以验证器上线前一定要做单元测试和人工抽检尤其检查边界情况。8. 最佳实践与工程建议8.1 把 RLVR 训练当做一个多目标优化问题而不是单一奖励最大化团队在制定 RLVR 方案时不能只看目标任务准确率。应该把以下目标一起纳入考量目标任务指标。通用能力保持指标。输出多样性指标。后续训练可塑性指标。一旦确认 RLVR 会牺牲某些通用能力就要在设计阶段决定优先级是牺牲一部分多样性换取快速提升还是保持稳健性以支持后续多轮训练。8.2 训练过程中记录足够的日志方便事后归因生产级 RLVR 训练至少应该记录每个 step 的奖励均值、标准差。生成熵、输出长度、格式合规率。验证器判断错误的样本明细。KL 散度变化。这些日志不仅仅是训练进度展示更是后续排查“模型为什么变僵”的关键线索。8.3 保留多个 checkpoint并做“可塑性评估”不要只保存最终模型。建议每隔固定步数保存 checkpoint然后用一个“新任务小样本测试”来评估每个 checkpoint 的可塑性def evaluate_plasticity(model, tokenizer, few_shot_examples): 用少量新任务示例评估模型继续学习的能力。 具体做法在新任务数据上微调 10 步观察损失下降速度。 损失下降快说明可塑性好下降慢说明策略支持可能已坍缩。 # 这是一个评估思路具体实现依赖你的训练框架 pass如果发现某个 checkpoint 在新任务上微调时损失几乎不下降说明该 checkpoint 已经“固化”不适合作为后续多轮训练的起点。8.4 验证器迭代要谨慎变更后必须做回归测试验证器不是写一次就完事的。只要修改了验证逻辑、扩充了测试用例、调整了格式解析规则都必须重新跑一遍历史样本确认奖励分数没有大幅偏移。否则训练过程中奖励分布突变很容易引发策略震荡甚至更严重的坍缩。8.5 注意计算成本与实验设计的一致性完整的北大实验维度比本文示例大得多但核心机制是相通的。如果你要在真实模型上验证策略支持重塑造的影响建议从小模型开始先建立监控体系和指标基线再放大到 7B、14B 级别的模型。这样既节省计算资源也能快速迭代出适合自己业务的训练配置。8.6 安全与合规谨慎处理模型能力变化带来的风险RLVR 会让模型在特定任务上变得非常强但也可能让模型在拒绝能力、安全边界、内容合规性上出现松动。上线前必须做专门的安全评估尤其是涉及代码执行、知识问答、内容生成等场景。建议在 RLVR 训练之后再做一轮针对安全性和合规性的对齐微调并且把这轮微调视为 RLVR 流程的必要组成部分而不是可选项。9. 总结与下一步方向本文围绕“北大发现 RLVR 会破坏大模型后续训练能力”这个话题拆解了核心机制“验证器诱导的策略支持重塑造”。我们做了几件事解释了 RLVR 和策略支持的基本概念。分析了验证器为什么会让模型输出分布变窄。用一个小型实验演示了熵值随 RLVR 训练快速下降的过程。给出了缓解策略坍缩的多种工程手段包括软奖励、混合数据、多样性正则、分阶段训练。整理了常见问题和排查思路以及生产环境下的最佳实践要点。接下来你可以尝试的方向在你自己的模型上跑一遍“熵监控”看看现有 RLVR 训练是否也存在策略支持坍缩。对比不同验证器设计下严格验证 vs 宽松验证的熵变化曲线积累自己业务下的调参经验。如果使用 TRL 库研究一下 GRPO 和相关算法里 KL 权重对策略支持的影响。关注后续研究中对“可塑性保持”的更多方法例如在强化目标中直接加入熵正则或支持范围正则。RLVR 是一个很强力的工具但它不是免费的。它会从模型的灵活性中“抽取”一部分能力兑换成目标任务上的表现。理解这种兑换机制才能在设计训练方案时做出有依据的权衡而不是等到模型练僵了再回头补救。希望这篇文章能帮你少走一段弯路。