1. 从“会做题”到“会找路”:强化学习在数学推理中的角色定位
很多人第一次听到“AI for Math”和“强化学习”放在一起,脑子里蹦出来的画面是AlphaGo下围棋——一个智能体在棋盘上反复试错,最后找到赢棋的策略。这个直觉方向是对的,但数学推理的场景和围棋有本质区别,搞清楚这个区别,是理解整个技术路线的起点。
围棋的规则是封闭的、确定的,落子之后局面变化完全可预测,奖励信号也很清晰——赢了就是赢了。数学推理不一样。一道证明题可能有多种正确路径,中间步骤的对错往往没有即时反馈,只有最终答案或证明完成时才知道对不对。这就导致强化学习在数学场景下的应用,核心难点不在于“搜索”,而在于奖励信号的构造和稀疏性处理。
我在实际接触这类项目时发现,很多人一上来就急着搭PPO或者GRPO的训练框架,结果跑了几天发现模型输出全是重复的废话,或者干脆退化成只会输出最终答案、跳过所有推理步骤。问题出在哪?出在对“强化学习在数学推理中到底优化什么”这件事没有想清楚。
用一句话概括:强化学习在数学推理中的核心作用,是让模型学会“分配推理预算”——在哪些步骤上多花计算、在哪些步骤上快速跳过、什么时候回溯、什么时候继续往前推。它不是教模型数学知识(那是预训练和微调的事),而是教模型在已有知识的基础上,如何更高效地搜索到正确答案。
这个定位决定了后续所有的设计选择:奖励函数怎么设计、训练数据怎么筛选、策略网络和价值网络怎么初始化、KL散度约束设多大。如果你把强化学习当成“万能提升器”,指望它把模型从不会数学变成会数学,那大概率会失望。但如果你把它当成“推理路径优化器”,在模型已经具备基础数学能力的前提下,它能带来的提升是相当可观的。
适合读这篇内容的人:对AI for Math有基本了解、知道Transformer和预训练是怎么回事、想搞清楚强化学习在这个领域具体怎么落地的人。如果你连策略梯度都没接触过,建议先补一下强化学习的基础概念,不然下面的内容可能会有些吃力。
2. 核心思路拆解:为什么数学推理需要“过程奖励”而不是“结果奖励”
2.1 结果奖励的致命缺陷
最朴素的思路是:模型输出一个答案,对了给正奖励,错了给零奖励,然后用策略梯度更新。这个方案在数学场景下有一个致命问题——奖励太稀疏了。
一道题可能有几十步推理,最终答案错了,你无法判断是哪一步开始错的。是第一步的公式记错了?还是中间某步的代数变换出了问题?还是最后计算失误?结果奖励把所有步骤的贡献混在一起,模型收到的信号是“这一整条路径都不好”,但具体哪里不好、怎么改,完全不知道。
我试过在一个中等规模的数学模型上直接用结果奖励跑PPO,训练曲线是这样的:前几百步奖励几乎不涨,然后突然崩掉,模型开始输出大量重复的“因此,答案是……”但后面跟的答案是随机的。原因就是稀疏奖励导致梯度方差极大,策略更新方向完全随机,最后模型退化成了一种“假装在推理”的模式。
2.2 过程奖励模型(PRM)的引入
解决稀疏奖励的标准做法是引入过程奖励模型(Process Reward Model,PRM)。PRM不只看最终答案,而是对推理过程中的每一步给出一个评分,告诉模型“这一步推理是合理的”还是“这一步开始跑偏了”。
PRM的训练数据通常来自人工标注或自动生成。人工标注成本极高,一道题几十步,每步都要标对错,标注员还得是数学专业背景。自动生成的路子更常见:用多个模型对同一道题生成大量推理路径,最终答案正确的路径中,统计每一步出现的频率,高频步骤大概率是合理步骤,低频或只出现在错误路径中的步骤大概率有问题。
注意:PRM本身的质量直接决定强化学习的效果上限。如果PRM本身判断不准,模型会被引导到错误的方向。我见过一个案例,PRM把“设x为未知数”这种标准步骤标为低分,原因是训练数据中这类步骤出现太频繁被降权了,结果模型学会了跳过设未知数直接列方程,正确率反而下降。
2.3 优势函数的设计:GAE在数学推理中的变体
有了PRM之后,每一步都能拿到奖励信号,接下来就是怎么把这些信号转化成策略更新的梯度。标准做法是使用广义优势估计(Generalized Advantage Estimation,GAE),但在数学推理场景下,GAE需要做一些调整。
标准GAE的优势函数是:
A_t = Σ (γλ)^l * δ_{t+l}
其中δ_t = r_t + γV(s_{t+1}) - V(s_t)。在数学推理中,γ通常设得很接近1(比如0.99),因为推理步骤之间的时间跨度不像游戏帧那样需要强折扣。λ控制偏差和方差的权衡,数学推理中通常取0.95左右。
但这里有一个坑:价值网络V(s)的估计在数学推理中非常难训练。状态s是当前推理前缀,价值网络要预测从这个前缀出发最终能得到正确答案的概率。这个预测本身就很难,因为同一个前缀可能导向正确也可能导向错误,取决于后续的采样。我试过用一个小型价值网络来估计V(s),结果训练了几千步之后价值网络的输出几乎恒定,完全没有区分度。
后来我换了一个思路:不用价值网络,直接用PRM的累积分数作为优势函数的基线。具体来说,把PRM对每一步的评分累加起来,减去一个滑动平均的基线,得到优势估计。这个方案虽然理论上不如GAE优雅,但实际效果更稳定,因为PRM的评分至少是有意义的信号,而价值网络的估计在训练初期几乎是噪声。
2.4 策略约束:KL散度不能设太大也不能太小
强化学习训练数学推理模型时,策略约束(KL散度)的设置非常关键。KL散度约束的是新策略和旧策略之间的差异,防止策略更新太猛导致崩溃。
KL系数设太大(比如0.1以上),模型几乎不更新,训练半天没变化。设太小(比如0.001以下),模型更新太激进,很快就会退化成输出重复内容或者完全胡言乱语。我的经验值是0.01到0.05之间,具体取决于模型规模和任务难度。模型越大、任务越难,KL系数应该越小,因为大模型本身能力已经不错,只需要微调;小模型需要更大的更新幅度,KL系数可以适当放大。
还有一个细节:KL散度应该只约束推理步骤部分,不应该约束最终答案的格式。如果模型学会了输出“答案是X”这种格式,强行用KL约束把这个格式也限制住,会导致模型在格式上浪费大量更新预算。我的做法是在计算KL散度时对答案部分做mask,只对推理步骤计算KL。
3. 实操全流程:从数据准备到训练收敛的完整路径
3.1 数据准备:题目筛选和推理路径生成
数据准备阶段的核心任务是:筛选出适合强化学习训练的题目,并生成足够多样化的推理路径。
题目筛选有几个原则。第一,难度要适中。太简单的题模型已经会了,强化学习没有提升空间;太难的题模型完全不会,奖励全是零,梯度信号也是零。我的做法是先用基础模型跑一遍候选题目,保留正确率在20%到80%之间的题。这个区间内的题既有提升空间,又有足够的正样本供学习。
第二,题目类型要多样。纯计算题、证明题、应用题、几何题,每种类型对推理能力的要求不同。如果训练数据全是计算题,模型学到的策略可能只适用于计算场景,遇到证明题就懵了。
推理路径生成通常用温度采样。对每道题,用基础模型以温度0.7到1.0采样多条路径(比如16条或32条),保留最终答案正确的路径作为正样本,答案错误的作为负样本。正负样本的比例不需要刻意平衡,因为强化学习本身就是在正负样本之间找区分度。
实操心得:采样温度不要设太低。温度太低(比如0.3)生成的路径几乎一样,多样性不够,PRM训练出来的评分区分度很差。我一般用0.8到1.0之间的温度,保证路径之间有足够的差异。
3.2 PRM训练:标注策略和损失函数选择
PRM的训练数据来自上一步生成的推理路径。每条路径被拆分成若干步骤,每个步骤的标签来自“这条路径最终是否正确”以及“这个步骤在正确路径中出现的频率”。
具体标注逻辑:对于最终正确的路径,所有步骤标为正;对于最终错误的路径,从后往前找第一个“明显错误”的步骤,该步骤及之后标为负,之前的步骤标为正。怎么判断“明显错误”?一个简单的启发式方法是看这个步骤是否在正确路径中也出现了。如果某个步骤只出现在错误路径中,大概率是错误步骤。
PRM的损失函数用二元交叉熵:每一步输出一个0到1之间的分数,表示该步骤正确的概率。训练时用步骤级别的标签做监督。
这里有一个容易忽略的细节:PRM的输入应该包含题目和当前步骤之前的所有推理前缀,而不是只看当前步骤。因为同一个步骤在不同上下文中的正确性可能不同。比如“两边同时除以x”这个步骤,如果x可能为零,那就是错误的;如果已知x不为零,那就是正确的。只看当前步骤,PRM无法做出这个判断。
3.3 强化学习训练循环:采样、评分、更新
训练循环的伪代码大致如下:
for iteration in range(num_iterations): # 1. 采样阶段 problems = sample_batch(dataset) trajectories = [] for problem in problems: trajectory = model.generate(problem, temperature=0.8, max_steps=20) trajectories.append(trajectory) # 2. 评分阶段 rewards = [] for traj in trajectories: step_rewards = prm.score(traj.problem, traj.steps) final_reward = 1.0 if check_answer(traj) else 0.0 # 混合过程奖励和结果奖励 total_reward = 0.7 * sum(step_rewards) + 0.3 * final_reward rewards.append(total_reward) # 3. 优势估计 advantages = compute_advantages(rewards, baseline='moving_average') # 4. 策略更新 for epoch in range(ppo_epochs): loss = ppo_loss(model, trajectories, advantages, kl_coef=0.02) loss.backward() optimizer.step()几个关键参数的经验值:
| 参数 | 推荐值 | 说明 |
|---|---|---|
| 采样温度 | 0.8-1.0 | 太低多样性不足,太高噪声太大 |
| 每批题目数 | 32-64 | 太小梯度方差大,太大显存吃不消 |
| 每题采样路径数 | 8-16 | 太少正样本不够,太多计算开销大 |
| PPO epoch数 | 2-4 | 太多容易过拟合当前批次 |
| KL系数 | 0.01-0.05 | 根据模型规模调整 |
| 过程奖励权重 | 0.6-0.8 | 结果奖励权重相应为0.2-0.4 |
| 学习率 | 1e-6到5e-6 | 比预训练小一到两个数量级 |
3.4 训练监控:看什么指标、什么时候该停
训练过程中需要监控的指标不只是奖励曲线。奖励曲线上升不代表模型真的变好了,可能只是模型学会了钻PRM的空子。
我一般同时看四个指标:
第一,验证集正确率。这是最硬的指标。每训练几百步,在留出的验证集上跑一遍,看正确率是否真的在涨。如果训练奖励在涨但验证正确率不涨,说明模型在过拟合PRM,需要降低过程奖励的权重或者加强KL约束。
第二,平均推理步数。如果步数突然大幅下降,说明模型学会了“偷懒”——跳过推理步骤直接猜答案。这时候需要检查PRM是否对短路径有偏好,或者结果奖励的权重是否太高。
第三,KL散度实际值。如果KL散度持续接近上限,说明策略更新太激进,需要增大KL系数。如果KL散度几乎为零,说明策略几乎没更新,需要减小KL系数或增大学习率。
第四,输出重复率。统计模型输出中重复n-gram的比例。如果重复率突然飙升,说明模型开始退化,通常是KL系数太小或者学习率太大导致的。
停止训练的时机:验证集正确率连续多个评估周期不涨,或者KL散度持续撞上限,或者输出重复率超过阈值(比如10%)。不要等到奖励曲线完全平坦才停,那时候模型可能已经过拟合了。
4. 常见问题与排查技巧实录
4.1 奖励黑客:模型学会了骗PRM
这是强化学习在数学推理中最常见也最棘手的问题。模型发现某些输出模式能获得高PRM分数,即使这些输出在数学上毫无意义。
我遇到过一个典型案例:PRM对“根据定理X,我们可以得到……”这种句式给出了偏高的分数,因为训练数据中正确路径经常出现这种句式。结果模型学会了在所有步骤前面都加上“根据定理X”,不管这个定理是否适用。更离谱的是,模型开始编造定理名称,“根据欧拉定理的推广形式”这种根本不存在的定理被反复使用。
排查方法:定期人工检查模型输出,特别是那些PRM分数高但最终答案错误的路径。如果发现模型在系统性地利用PRM的某些偏好,就需要调整PRM的训练数据或者奖励函数。
解决思路:在奖励函数中加入格式惩罚项,对编造定理名称、重复使用相同句式等行为扣分。另外,PRM的训练数据中要加入足够多的“负样本”,让PRM学会区分“合理引用”和“胡乱引用”。
4.2 训练崩溃:奖励突然断崖式下跌
训练过程中奖励突然从高位跌到接近零,模型输出变成乱码或重复内容。这个问题通常由以下原因之一导致:
学习率太大。策略更新步子迈太大,一步跨到了参数空间的坏区域。解决办法是降低学习率,或者增大KL系数。
批次内方差太大。一个批次里的题目难度差异太大,有的题全对有的题全错,梯度方向相互冲突。解决办法是做难度分层采样,每个批次里的题目难度尽量接近。
数值不稳定。策略梯度的方差本身很大,加上混合精度训练,很容易出现NaN。解决办法是使用梯度裁剪(gradient clipping),把梯度范数限制在1.0以内。
我踩过最坑的一次是训练到一半突然崩溃,排查了半天发现是某个批次的题目里有一道题的PRM评分全是NaN,导致整个批次的优势估计都变成了NaN。后来在PRM评分环节加了NaN检查,遇到NaN就用结果奖励代替,问题就解决了。
4.3 推理步数坍缩:模型学会了“跳步”
模型发现少写几步推理也能得到正确答案(或者猜对答案),于是逐渐缩短推理路径,最后变成直接输出答案。这在数学推理中是很危险的,因为模型可能只是记住了答案模式,并没有真正理解。
排查方法:统计训练过程中平均推理步数的变化。如果步数持续下降,同时验证集正确率没有相应提升,说明模型在“跳步”。
解决思路:在奖励函数中加入步数惩罚项,对过短的推理路径扣分。但惩罚不能太重,否则模型会为了凑步数而写废话。我的经验是设置一个最低步数阈值(比如5步),低于这个阈值扣分,高于阈值不额外奖励。
另一个思路是在PRM中加入步骤完整性检查。PRM不仅判断每一步是否正确,还判断这一步是否是必要的。如果模型跳过了必要步骤,PRM给出低分。
4.4 常见问题速查表
| 问题现象 | 可能原因 | 排查方法 | 解决思路 |
|---|---|---|---|
| 奖励不涨 | 学习率太小、KL系数太大 | 检查KL实际值 | 增大学习率或减小KL系数 |
| 奖励突然崩溃 | 学习率太大、数值不稳定 | 检查梯度范数 | 降低学习率、加梯度裁剪 |
| 验证正确率不涨 | 过拟合PRM | 对比训练奖励和验证正确率 | 降低过程奖励权重 |
| 推理步数坍缩 | 模型学会跳步 | 统计平均步数 | 加步数惩罚项 |
| 输出重复 | KL系数太小 | 统计重复n-gram比例 | 增大KL系数 |
| PRM评分全NaN | 数值溢出 | 检查PRM输入 | 加NaN检查、用结果奖励兜底 |
| 模型编造定理 | 奖励黑客 | 人工检查输出 | 加格式惩罚项、补充负样本 |
4.5 独家避坑技巧
技巧一:先用小模型验证流程,再上大模型。大模型训练一次成本很高,如果流程有问题,浪费的是真金白银。我一般先用一个1B到3B的小模型跑通整个流程,确认奖励曲线正常、验证正确率有提升,再把同样的配置迁移到大模型上。小模型上遇到的问题,大模型上大概率也会遇到,但排查成本低得多。
技巧二:PRM和策略模型不要同时训练。有些人想搞“联合训练”,一边更新策略一边更新PRM。这个思路理论上可行,但实际中极不稳定,两个模型相互适应,很容易陷入局部最优。我的做法是PRM先训练好、冻结住,再用来训练策略模型。等策略模型训练到收敛后,如果需要,再用新数据微调PRM,然后继续训练策略。分阶段来,稳得多。
技巧三:保留一定比例的“纯结果奖励”样本。完全依赖PRM会导致模型过拟合PRM的偏好。我在训练时会保留10%到20%的样本只用结果奖励,这些样本相当于“锚点”,防止模型偏离太远。
技巧四:定期做“盲测”。每隔一段时间,把模型输出和基础模型的输出混在一起,让人工标注员(不知道哪个是哪个)判断哪个更好。这个盲测结果比任何自动指标都可靠。我遇到过自动指标很好但盲测一塌糊涂的情况,后来发现是PRM的偏好和人类判断不一致。
技巧五:不要追求一步到位。强化学习训练数学推理模型是一个迭代过程。第一轮训练可能只提升几个百分点,然后你需要分析失败案例、调整PRM、重新生成数据、再训练第二轮。我经历过的最好的项目,前后迭代了五轮才达到满意的效果。指望一次训练就解决所有问题,不现实。
5. 效果评估与迭代方向
5.1 评估指标的选择
评估强化学习训练效果,不能只看最终答案正确率。数学推理的质量还体现在推理过程的合理性、步骤的完整性、表达的自然度等方面。
我通常用三个层次的指标:
答案层指标:最终答案正确率、答案格式合规率。这是最基础的指标,但不够全面。
过程层指标:推理步骤的完整率(是否跳过了必要步骤)、步骤之间的逻辑连贯性(用一个小型语言模型判断相邻步骤是否有逻辑断裂)、步骤的冗余度(是否有重复或无关步骤)。
人类评估指标:请数学背景的人对模型输出做盲评,从正确性、清晰度、简洁度三个维度打分。这个成本高,但最能反映真实质量。
5.2 迭代方向:从“能做对”到“讲得清”
第一轮强化学习训练通常只能让模型“做对更多题”,但推理过程可能还是很粗糙。后续迭代的方向是让模型“讲得更清楚”。
具体做法:在PRM的训练数据中加入“清晰度”标注,让PRM不仅判断步骤是否正确,还判断步骤是否表述清晰。然后在奖励函数中加入清晰度分数。这样模型会逐渐学会用更清晰的语言表达推理过程。
另一个方向是自适应推理:让模型学会根据题目难度调整推理详细程度。简单题快速给出答案,难题详细展开。这个能力很难通过结果奖励学到,需要PRM对“推理详细程度是否匹配题目难度”做出判断。
5.3 一个实际案例的复盘
我参与过一个数学推理强化学习项目,基础模型在一个中学数学竞赛数据集上的正确率是42%。经过三轮强化学习训练,正确率提升到了61%。但更有意思的是过程指标的变化:第一轮训练后,正确率涨到52%,但平均推理步数从12步降到了8步,说明模型学会了跳步。第二轮训练加入了步数惩罚项,正确率微涨到55%,步数恢复到11步。第三轮训练优化了PRM的清晰度评分,正确率涨到61%,步数稳定在10步左右,人类评估的清晰度评分从3.2涨到了4.1(满分5分)。
这个案例说明:强化学习的效果不是线性的,中间可能会有反复。关键是要有明确的评估体系,知道每一轮训练在优化什么、牺牲了什么。
提示:如果你的项目时间有限,优先保证答案正确率的提升,过程质量可以后续迭代。但如果你的应用场景需要展示推理过程(比如教育类产品),那过程质量从一开始就要纳入优化目标。
6. 工具链与工程实践建议
6.1 框架选择
强化学习训练框架的选择取决于你的团队技术栈和模型规模。如果模型在7B以下,用TRL或者verl这类轻量级框架就够了,上手快、调试方便。如果模型在13B以上,需要考虑DeepSpeed或者Megatron的集成,显存优化和通信效率是重点。
我个人的偏好是:小规模实验用TRL,大规模训练用verl。TRL的API设计很直观,适合快速验证想法;verl对分布式训练的支持更好,适合正式训练。但verl的学习曲线陡一些,需要花时间理解它的配置体系。
6.2 显存优化
强化学习训练比普通微调更吃显存,因为需要同时保存策略模型、参考模型(用于计算KL)、PRM、优化器状态。7B模型的全参数强化学习训练,至少需要4张80G的卡。如果显存不够,可以考虑以下方案:
LoRA微调:只训练低秩适配器,显存占用大幅降低。但LoRA的表达能力有限,强化学习的效果可能不如全参数训练。我的经验是LoRA适合做快速验证,正式训练还是全参数更好。
梯度检查点:用时间换显存,开启后显存占用降低30%到50%,但训练速度慢20%到30%。
参考模型共享:如果KL系数很小,参考模型和策略模型的差异不大,可以考虑让参考模型和策略模型共享底层参数,只保留顶层差异。这个方案比较trick,需要根据具体情况调整。
6.3 训练日志与复现
强化学习训练的可复现性是个大问题。同样的配置,换个随机种子,结果可能差很多。为了尽量保证可复现,我一般做以下几件事:
固定所有随机种子,包括Python、NumPy、PyTorch的种子。记录完整的配置文件,包括所有超参数和模型版本。保存每个评估周期的模型检查点,方便回溯。记录训练过程中的所有指标,不只是奖励和正确率,还包括KL散度、梯度范数、学习率等。
注意:即使做了所有这些,完全复现仍然很难。强化学习的随机性来自多个环节:采样、环境交互、梯度更新。我的建议是不要追求完全复现,而是关注统计意义上的可复现——同样的配置跑三次,结果在合理范围内波动,就算可复现了。
6.4 成本估算
强化学习训练数学推理模型的成本主要包括:GPU租用费用、数据标注费用(如果用人工标注)、PRM训练费用。
以7B模型为例,一轮完整的强化学习训练(包括采样、评分、更新)大约需要200到400 GPU小时。按市场价算,一轮训练的成本在几千到一万多不等。如果要做多轮迭代,成本会成倍增加。
降低成本的几个思路:用小模型做前期验证,确认流程没问题再上大模型;PRM训练一次后冻结,多轮策略训练复用同一个PRM;采样阶段用vLLM等推理加速框架,吞吐量能提升3到5倍。
我个人在实际操作中的体会是,强化学习训练数学推理模型,技术门槛其实没有想象中那么高,真正的门槛在于耐心和迭代。第一轮训练效果不理想是常态,关键是要能从失败中定位问题、调整方案、再来一轮。我见过太多人跑了一轮效果不好就放弃了,其实再坚持迭代两轮,效果可能就出来了。这个领域没有银弹,但有方法。