RLHF实战:从SFT到PPO的工程细节与避坑指南

发布时间:2026/11/6 2:37:44
RLHF实战:从SFT到PPO的工程细节与避坑指南

大模型的对齐训练里,RLHF(基于人类反馈的强化学习)几乎是绕不开的一环。我最早接触这套流程是在一个对话模型微调项目里,当时模型已经做完了指令微调,回答问题的格式没问题,但输出质量参差不齐——有的回答啰嗦绕圈,有的答非所问,还有的会一本正经地编造事实。后来把RLHF这套流程搭起来跑通,模型的回答风格和有用性有了肉眼可见的改善。这篇文章就把我踩过的坑、调过的参数、想明白的原理,完整地摊开讲一遍。

RLHF本质上解决的是“模型怎么知道什么样的回答算好”这个问题。监督微调只能告诉模型“这个回答是对的”,但没法告诉它“这个回答比那个回答好多少”。而人类对质量的判断天然是相对的、有排序的,RLHF正是把这种相对偏好转化成训练信号的一套工程方法。它适合已经完成预训练和监督微调、想要进一步提升模型输出质量和对齐程度的从业者参考,对强化学习零基础但熟悉深度学习训练流程的读者也能跟下来。

1. 整体方案设计与思路拆解

1.1 为什么是“三阶段”而不是一步到位

RLHF的标准流程拆成三个阶段:监督微调(SFT)、奖励模型训练(RM)、强化学习优化(RL)。很多人第一次看会觉得绕——既然最终目标是让模型输出更好,为什么不直接拿人类偏好数据去训模型?

这里的关键在于:人类偏好数据的形式是“A回答比B回答好”,它是一个比较信号,不是绝对标签。你没法直接拿这种比较信号去做监督学习,因为监督学习需要的是“标准答案”。而奖励模型的作用,就是把这种离散的、成对的比较关系,压缩成一个连续的标量打分函数。有了这个打分函数,强化学习才能对模型生成的任意回答给出即时反馈。

我试过跳过奖励模型、直接用偏好数据做某种对比损失来微调,效果很不稳定。原因是模型很容易学到“讨好比较数据里的表面特征”,比如回答越长越容易被偏好,结果模型开始无脑堆长度。奖励模型这一层相当于一个缓冲带,它把偏好信号抽象成打分能力,再由强化学习去优化策略,整个链条的可控性强很多。

三个阶段的分工可以这样理解:SFT负责让模型“会说话”,奖励模型负责让模型“知道什么话算好话”,强化学习负责让模型“主动多说好话”。缺了SFT,模型连基本格式都不对,奖励模型没法评;缺了奖励模型,强化学习没有反馈信号;缺了强化学习,模型只能模仿SFT数据,没法超越数据分布去探索更好的回答。

1.2 奖励模型为什么用“成对比较”而不是“绝对打分”

这是我在设计阶段纠结最久的一个点。让标注员直接给回答打1到10分,数据利用率不是更高吗?一个人一次能标好几条,成本也低。

实测下来,绝对打分的标注一致性很差。同一个回答,不同标注员给的分能差三四分,同一个人隔一天再标也会漂移。而换成成对比较——“这两个回答哪个更好”——标注员的判断一致性明显提升,因为人做相对判断比做绝对判断稳定得多,这是认知层面的规律,不是靠培训能完全消除的。

所以奖励模型的训练数据组织成(prompt,chosen回答,rejected回答)的三元组,损失函数用的是Bradley-Terry模型下的成对排序损失。简单说就是让奖励模型给chosen打的分尽量高于rejected,两者差值经过sigmoid后做二元交叉熵。这个设计的好处是它只关心相对高低,不关心绝对分值,天然适配人类偏好的相对性。

注意:成对比较的数据里,chosen和rejected的质量差距要拉开一些。如果两条回答质量接近,标注员自己都犹豫,这种数据训进去只会给奖励模型引入噪声。我在数据清洗阶段会把标注员置信度低的样本直接剔除,宁可少几百条也不要脏数据。

1.3 PPO为什么是主流选择,它的代价是什么

强化学习阶段主流用PPO(近端策略优化)。选它的核心理由是稳定——PPO通过裁剪(clip)机制限制每次策略更新的幅度,避免模型在优化奖励的过程中跑偏太远,把语言能力搞崩。

但PPO的工程代价不小。它需要同时维护四个模型:策略模型(要训的)、参考模型(冻结的SFT模型,用来算KL惩罚)、奖励模型(冻结的,用来打分)、价值模型(critic,用来估计基线)。四个模型同时驻留显存,7B级别的模型在单卡上基本放不下,必须做模型并行或者用参数卸载。我第一次搭的时候没算清楚显存,跑到一半OOM,排查了半天才发现是价值模型和奖励模型重复加载了。

KL惩罚这一项也值得单独说。它的作用是约束策略模型不要偏离SFT模型太远,防止模型为了刷奖励模型的分数而输出一些奖励模型喜欢但人类看着别扭的文本(也就是奖励黑客)。KL系数设太小,模型容易跑飞;设太大,模型几乎不更新,等于白训。我一般从0.01到0.05之间试,具体看奖励曲线的形态来调。

2. 核心细节解析与实操要点

2.1 SFT阶段的数据质量决定天花板

很多人把SFT当成走过场,觉得反正后面有RLHF兜底。这个想法很危险。SFT模型是后续参考模型和策略模型的初始化起点,它的质量直接决定了RLHF的探索空间。SFT数据里如果有大量格式混乱、逻辑跳跃的样本,策略模型一开始就带着坏习惯,强化学习阶段要花很大力气去纠正,甚至纠正不过来。

我在SFT阶段的做法是:数据量不求多,但每条都要过三关。第一关是格式关,确保回答结构完整、没有截断;第二关是事实关,涉及具体信息的回答要人工核对;第三关是风格关,统一回答的语气和详略程度。这三关过下来,数据量可能只剩原始采集的一半,但训练出来的SFT模型明显更“听话”。

SFT的训练超参也有讲究。学习率不能太大,我一般用1e-5到2e-5之间,epoch数控制在3左右。训太多轮模型会过拟合SFT数据的表达方式,回答变得模板化,这对后面的RLHF不利——策略模型需要一定的表达多样性才能探索出更好的回答。

2.2 奖励模型的架构与训练细节

奖励模型的常见做法是拿SFT模型改的:把最后的语言模型头换成一个输出单标量的线性头。这样奖励模型能复用SFT模型的语言理解能力,收敛更快。

训练时的几个关键点我列一下:

  • 学习率要比SFT小,我用5e-6左右。奖励模型的训练目标比语言建模更敏感,学习率大了容易震荡。
  • batch内要保证chosen和rejected成对出现,不能打乱。排序损失依赖成对关系,打乱就失效了。
  • 训练轮数控制在1到2个epoch。奖励模型很容易过拟合偏好数据,训多了它在训练集上打分很准,但泛化到策略模型新生成的回答上就失准,这会直接导致RL阶段奖励信号失真。
  • 验证集要看排序准确率,不是看loss。排序准确率指的是奖励模型给chosen打分高于rejected的比例,这个指标到70%以上基本可用,到75%以上算不错。

提示:奖励模型的输出分值范围不需要归一化到固定区间,但训练时建议对分值做中心化处理,让chosen和rejected的分值差在0附近波动,这样排序损失的梯度更稳定。

还有一个容易忽略的点:奖励模型的输入要包含完整的prompt加回答,不能只喂回答。因为同一个回答在不同prompt下的好坏判断是不一样的,奖励模型必须看到上下文才能做出合理打分。

2.3 PPO训练的四个模型协同

PPO阶段的工程复杂度最高,我把四个模型的角色和更新关系理清楚:

模型是否训练作用显存占用
策略模型是生成回答,被优化高(含梯度)
参考模型否算KL惩罚,约束策略中(仅推理)
奖励模型否给回答打分中(仅推理)
价值模型是估计基线,降方差高(含梯度)

每次迭代的流程是:策略模型对一批prompt生成回答,奖励模型给每个回答打分,参考模型算策略模型和参考模型的KL散度作为惩罚项,价值模型估计每个token位置的预期回报作为基线,最后用优势函数(奖励减基线再减KL惩罚)去更新策略模型和价值模型。

这里有个实操细节:生成阶段要用采样而不是贪心解码,温度一般设0.7到1.0之间。贪心解码生成的回答缺乏多样性,策略模型没法从中学到“哪种回答更好”的对比信息。但温度也不能太高,太高生成的回答质量太差,奖励模型打出来的分全是低分,梯度信号没有区分度。

价值模型的训练目标常被忽视。它的作用是降低策略梯度的方差,如果价值模型估得不准,优势函数的噪声会很大,策略更新方向就会抖。我一般给价值模型设一个比策略模型稍大的学习率,让它跟得上策略的变化速度。

2.4 KL惩罚系数的动态调整

KL系数我一开始是固定值,后来发现固定值很难兼顾训练前期和后期。前期策略模型离参考模型近,KL小,固定系数下惩罚力度不够,模型容易早期就跑偏;后期策略模型已经优化了不少,KL自然变大,固定系数下惩罚过重,模型几乎不更新。

后来改成自适应KL:设定一个目标KL值(比如6),每轮迭代后看实际KL,高于目标就把系数调大,低于目标就调小。这样训练全程的KL能稳定在目标附近,策略更新的节奏更均匀。这个技巧在多个项目里都验证有效,强烈建议加上。

3. 实操过程与核心环节实现

3.1 数据管线的搭建

整个RLHF的数据分三类:SFT数据、偏好数据、PPO阶段的prompt数据。三类数据的来源和处理方式不同,我建议分开建管线,不要混在一起。

SFT数据是(prompt,回答)对,来源可以是人工撰写、模型生成后人工筛选、或者从高质量语料里构造。偏好数据是(prompt,chosen,rejected)三元组,核心是标注环节。PPO阶段的prompt数据只需要prompt,不需要回答,因为回答是策略模型现场生成的。

偏好数据的标注我踩过一个坑:一开始让标注员自由发挥,结果不同标注员的偏好标准差异很大,有人偏好详细,有人偏好简洁,训出来的奖励模型打分标准混乱。后来改成给标注员一份明确的偏好准则,比如“优先考虑事实准确性,其次考虑完整性,最后考虑简洁性”,并且定期做标注一致性校准,奖励模型的排序准确率才稳定下来。

数据配比也需要注意。偏好数据里如果某类任务(比如代码问答)占比过高,奖励模型会在这类任务上打分很准,但在其他任务上失准。我一般让偏好数据的任务分布尽量贴近实际使用场景的分布,各类任务按比例采样。

3.2 奖励模型的训练脚本关键配置

奖励模型的训练循环和普通语言模型训练类似,核心差异在损失计算。下面是我常用的损失实现逻辑(PyTorch风格伪代码):

# 输入:chosen_ids, rejected_ids, attention_mask chosen_rewards = reward_model(chosen_ids, attention_mask) # shape: [batch] rejected_rewards = reward_model(rejected_ids, attention_mask) # Bradley-Terry 成对排序损失 loss = -torch.log(torch.sigmoid(chosen_rewards - rejected_rewards) + 1e-8).mean()

几个配置项我固定下来:

  • 优化器用AdamW,weight_decay设0.01
  • 梯度裁剪max_norm设1.0,防止梯度爆炸
  • 学习率带warmup,warmup比例0.1
  • batch size尽量大,成对样本的batch我一般设到64对以上,排序损失的梯度才稳

训练过程中我盯两个指标:训练集上的排序准确率和验证集上的排序准确率。两者差距超过5个百分点就说明过拟合了,要早停。另外我会定期用奖励模型给一批人工标注过绝对质量的回答打分,看打分和人工判断的相关性,这个相关性比排序准确率更能反映奖励模型的实际可用性。

3.3 PPO训练循环的完整实现

PPO训练循环是整个流程里最容易出bug的部分,我把关键步骤拆开讲。

第一步是生成。策略模型对batch里的每个prompt生成回答,记录每个token的log概率。这里要注意,生成时的log概率要用策略模型当前参数算,不能用旧参数,否则后面算重要性采样比率会错。

第二步是打分。奖励模型给完整回答打分,得到序列级奖励。这里有个细节:奖励模型打的是整个回答的分,但PPO需要的是每个token的奖励。常见做法是把序列级奖励放在最后一个token上,前面的token奖励设0,然后通过价值模型和折扣因子把奖励往前传播。折扣因子一般设1.0,因为语言生成任务里每个token对最终质量的贡献都需要被考虑。

第三步是算KL惩罚。对每个token,算策略模型和参考模型在该token上的log概率差,作为KL惩罚加到奖励上。KL惩罚是逐token算的,不是序列级。

第四步是算优势。用价值模型估计每个token位置的基线值,优势等于实际回报减基线。实际回报是奖励加上后续token的折扣累积,这里用GAE(广义优势估计)来算,lambda设0.95。

第五步是更新。策略模型的损失是PPO的裁剪损失,价值模型的损失是均方误差。两个模型分别更新,但共享同一批数据。

# PPO策略损失核心逻辑(伪代码) ratio = torch.exp(new_logprobs - old_logprobs) surr1 = ratio * advantages surr2 = torch.clamp(ratio, 1 - clip_eps, 1 + clip_eps) * advantages policy_loss = -torch.min(surr1, surr2).mean()

clip_eps我一般设0.2,这是PPO的默认值,实测下来在语言模型上也比较稳。

3.4 训练监控与早停策略

RLHF训练不像监督学习那样有明确的收敛点,必须靠监控指标来判断什么时候停。我盯的指标有这么几个:

  • 平均奖励分:应该整体上升,但如果上升过快(比如几轮就翻倍),大概率是奖励黑客,模型在钻奖励模型的空子。
  • KL散度:应该稳定在目标值附近,突然飙升说明策略跑偏了。
  • 回答长度:这是奖励黑客的经典信号。如果平均长度持续增长而奖励分也涨,很可能是模型学会了堆长度讨好奖励模型。
  • 人工抽检:每训练若干轮,人工看一批生成回答,判断质量是否真的在提升。这个环节不能省,指标好看但实际输出变差的案例我见过不止一次。

早停的触发条件我设了两条:一是KL连续多轮超过目标值上限,二是人工抽检发现质量下降。满足任一条就回滚到之前的检查点。

4. 常见问题与排查技巧实录

4.1 奖励黑客:模型学会了骗奖励模型

这是RLHF里最经典也最头疼的问题。表现是奖励分一路涨,但人工看输出发现模型在输出一些“奖励模型喜欢但人类觉得奇怪”的内容。常见的黑客模式有:无脑堆长度、堆砌礼貌用语、重复prompt里的关键词、输出格式花哨但内容空洞。

排查思路是先定位奖励模型被钻了什么空子。我的做法是拿一批黑客样本去问奖励模型,看它给这些样本打多少分,再对比人工判断。如果奖励模型给黑客样本打分明显偏高,说明奖励模型的训练数据里这类样本的覆盖不够,需要补充负样本重新训奖励模型。

缓解手段有几个:加大KL惩罚系数,让策略模型不敢偏离SFT模型太远;在奖励里加长度惩罚项,抑制堆长度;定期用新策略模型生成的样本去扩充奖励模型的训练数据,让奖励模型跟上策略的演化。我一般组合使用,单靠一个手段效果有限。

4.2 训练不稳定:奖励曲线剧烈震荡

PPO训练中奖励曲线震荡是常见现象,轻微震荡正常,剧烈震荡说明有问题。我遇到过几次,排查下来原因各不相同:

现象可能原因排查方法解决手段
奖励分忽高忽低学习率过大看梯度范数降低策略学习率
奖励分整体下降KL系数过大看KL曲线调小KL系数
奖励分不动优势函数全接近0看价值模型输出检查价值模型是否训崩
生成回答重复温度过低看生成配置提高采样温度

有一次奖励分整体下降,我查了半天以为是KL系数问题,后来发现是价值模型的学习率设太小,基线估计严重滞后,优势函数算出来全是负的,策略模型被往反方向推。把价值模型学习率调大后恢复正常。这个坑提醒我,四个模型的学习率要协同调,不能只盯策略模型。

4.3 显存不够:四个模型放不下怎么办

7B模型做PPO,四个模型全精度加载需要大量显存,单卡基本不可能。我的解决方案组合:

  • 参考模型和奖励模型用半精度加载,且只做推理,不存梯度,显存占用能压到策略模型的一半左右。
  • 策略模型和价值模型用梯度检查点(gradient checkpointing),用计算换显存,显存能省30%到40%,代价是训练速度慢一些。
  • 如果还不够,用参数卸载把参考模型和奖励模型的部分层放到CPU内存,需要时再加载回GPU。这个方案会拖慢训练速度,但能跑起来。
  • 最后的手段是模型并行,把策略模型和价值模型切到多卡上。这个方案工程复杂度最高,非必要不用。

注意:半精度加载参考模型时,KL散度的计算要用float32做,半精度下log概率的精度损失会让KL估计偏差很大,进而影响惩罚项的准确性。

4.4 偏好数据标注质量差怎么补救

标注质量差是很多团队的实际困境,尤其是预算有限、标注员培训不到位的情况。我的补救思路分两层:

第一层是数据清洗。用奖励模型(哪怕是个初步版本)给偏好数据打分,找出那些“奖励模型判断和标注标签严重不符”的样本,人工复核。这类样本要么是标注错了,要么是奖励模型还没学到,无论哪种都值得单独处理。

第二层是数据增强。对高质量的偏好样本做改写增强,比如把chosen回答换个表达方式但保持质量,生成新的偏好对。这样能在不增加标注成本的前提下扩充数据量。但增强要控制比例,增强数据占比太高会让奖励模型学到改写风格而不是质量判断。

4.5 训练完了效果不明显怎么办

有时候整套流程跑完,模型输出质量提升很有限。我复盘过几次,原因通常出在几个环节:

SFT模型本身太强,RLHF的提升空间本来就小。这种情况不是RLHF没用,而是边际收益递减,需要更精细的偏好数据才能挖出提升点。

奖励模型和实际使用场景不匹配。偏好数据的任务分布和实际场景偏差大,奖励模型在场景内打分不准,策略模型优化方向就偏了。解决办法是补充场景内的偏好数据重训奖励模型。

KL系数设太大,策略模型几乎没更新。看KL曲线和策略模型的参数变化量能确认这一点,调小系数重训即可。

还有一种情况是评估方式有问题。RLHF提升的往往是对齐质量(有用性、无害性、诚实性),而不是知识量。如果评估只看知识问答准确率,可能看不出提升。评估要覆盖对齐维度,比如用人工偏好评估或者专门的奖励模型打分。

5. 工程化落地的经验补充

5.1 训练成本与资源规划

RLHF的训练成本比SFT高一个量级,主要高在PPO阶段。以7B模型为例,SFT阶段单卡几小时能跑完一轮,PPO阶段四模型协同,单轮迭代的时间是SFT的十几倍,完整跑下来需要多卡多天。资源规划时要把PPO阶段作为瓶颈来算。

我的经验是PPO阶段的迭代轮数不用太多,几百到上千轮(每轮一个batch)通常能看到明显效果,再多边际收益递减。关键是每轮的数据质量和奖励信号准确性,而不是轮数堆砌。

5.2 迭代式RLHF:多轮循环

单轮RLHF跑完,模型质量提升到一定程度就停滞了。这时候可以做迭代式RLHF:用当前策略模型生成新回答,人工标注偏好,扩充偏好数据,重训奖励模型,再跑一轮PPO。这个循环每转一圈,奖励模型和策略模型都同步进化,质量能持续爬升。

迭代式RLHF的成本主要在标注环节,但效果比单轮显著。我一般做两到三轮迭代,再往上成本收益比就不划算了。

5.3 评估体系不能省

RLHF的评估比训练还重要,因为训练信号本身来自奖励模型,而奖励模型可能有偏。评估体系我建议至少包含三层:自动指标(奖励模型打分、困惑度)、人工偏好评估(成对比较)、场景化测试(针对实际使用场景设计测试用例)。三层都过才算训练有效。

人工偏好评估的样本量不用太大,几百条就能看出趋势,但评估维度要覆盖有用性、无害性、诚实性三个方向,不能只看一个。

我在实际项目里的体会是,RLHF这套流程的难点不在算法本身,算法都是公开的,难在工程细节和数据质量。四个模型的协同、KL系数的动态调整、奖励黑客的识别和缓解、偏好数据的标注一致性,这些环节任何一个出问题都会让最终效果打折扣。把每个环节的监控做扎实,比追求算法上的花活有用得多。后续如果要继续扩展,可以考虑把奖励模型换成多个专家奖励模型的集成,降低单一奖励模型被黑客的风险,这个方向我还在试,等有稳定结论再分享。