城东有家老字号饭馆,掌勺师傅五十岁,收了个徒弟叫小明。小明刀工还行,做起菜来却全凭感觉——今天咸了,明天糊了。师傅不骂人,只做两件事:第一,每道菜出锅,师傅都夹一筷子,然后告诉小明“这盘比上盘强”或“这盘不如上盘”,从来不打具体分;第二,师傅盯着小明颠勺的姿势,发现他为了求快把基本功改了,立刻喝止——“你可以改火候、改配料,但颠勺的底子不能丢。”小明就照着师傅的提示,一次只调整一点点,慢慢把菜做得越来越接近师傅心中的标准。 这个故事,就是大模型 RLHF 里 PPO 训练的全过程。想让 AI 回答更安全、更有用,不能靠一群工程师敲键盘硬改代码,而是让 AI 自己学会“什么样的回答更讨人喜欢”——这就要请一位打分师傅(奖励模型),设一条“不许丢基本功”的安全线(KL 散度约束),再让 AI 像小明一样一小步一小步地试错改进(PPO)。本文就用这套“师徒教学”的视角,带你完整过一遍 RLHF 中 PPO 训练的实战流程。

岗位关联

职业价值:PPO 是 RLHF 的核心引擎,掌握它,你就能亲手调控大模型的安全性与“人味”,这是大模型对齐工程师最稀缺的硬实力。

目录
  1. 可视化演示
  2. RLHF全景认知
  3. 奖励模型训练
  4. PPO策略优化
  5. KL散度约束
  6. Rollout采样
  7. 超参调优
  8. AI 应用场景
  9. Python 演示
  10. 常见误区
  11. 面试题

可视化演示

展示RLHF三阶段训练流程(SFT→RM→PPO),含奖励信号优化、KL散度约束与策略更新机制的交互式动画。

本节配有交互动效(进入视口后自动加载,约 3KB)。

RLHF三阶段训练流程 SFT监督微调建立基础语言能力 Reward Model学习人类偏好打分 SFT → RM → PPO RLHF三阶段训练实现大模型人类偏好对齐

RLHF全景认知

师徒教学环环相扣:先让小明练出一身基本功(SFT),再让师傅练成“尝一口就能挑出优劣”的舌头(奖励模型),最后才是在师傅监督下逐步改进(PPO)。这三个环节缺一不可,顺序也不能乱,因为每一环都在为下一环准备“教材”。

RLHF,全称是“基于人类反馈的强化学习”,把同一套逻辑搬到大模型身上。第一步是 SFT(监督微调),让模型在高质量语料上学会像人一样说话;第二步训练奖励模型,学习“哪个回答更符合人类偏好”;第三步才是 PPO,用奖励模型的信号去调整策略模型。很多人一上来就死磕 PPO 公式,却忽略了前两层地基——奖励模型没训好,PPO 做得再花哨也是在错误的分数上白费力气。

PPO 阶段真正优化的是一个带约束的目标:既想提高奖励,又不想让模型偏离参考模型太远。这个目标的完整写法如下:

回到饭馆的故事里,师傅从不要求小明一步登天,而是每次只点拨一处。RLHF 的三阶段也正是如此:先把地基打牢,再立好评判标准,最后才让策略模型在奖励和约束之间小步慢跑。把这三层关系理顺,后面的一切才会有意义。

R(x,y)=rϕ(x,y)−β DKL(πθ(y∣x)  ∥  πref(y∣x))\displaystyle R(x,y)=r_{\phi}(x,y)-\beta\,D_{KL}\bigl(\pi_{\theta}(y|x)\;\|\;\pi_{\text{ref}}(y|x)\bigr)
通俗地说,师傅给小明下的最终要求是:“菜要做得好吃(奖励高),但颠勺基本功必须守住(KL 惩罚小)。”R 就是这个综合评分。
  1. 输入与输出$x$ 是用户输入的提示词,$y$ 是模型生成的回答,两者合起来构成一次完整的对话样本。
    x=prompt,y=answerx=\text{prompt},\quad y=\text{answer}
  2. 奖励模型打分$r_{\phi}(x,y)$ 表示奖励模型对这个“提示-回答”组合给出的分数,分数越高代表越符合人类偏好,可以类比为师傅尝菜后默默在心里打的印象分。
    rϕ(x,y)∈Rr_{\phi}(x,y)\in\mathbb{R}
  3. KL 惩罚项$\beta\,D_{KL}\bigl(\pi_{\theta}\|\pi_{\text{ref}}\bigr)$ 是惩罚项,$\beta$ 控制约束强度,KL 散度衡量当前策略与参考策略的差距,相当于师傅盯着小明别把基本功改飞了。
    β>0\beta>0
  4. 最终优化目标策略模型要最大化 $R(x,y)$,即在“讨好奖励模型”和“保持原有能力”之间寻找平衡。
    max⁡θ E(x,y)∼πθ[R(x,y)]\displaystyle \max_{\theta}\ \mathbb{E}_{(x,y)\sim\pi_{\theta}}\bigl[R(x,y)\bigr]

奖励模型训练

师傅让小明同一个菜做两份,A 版多放一勺糖,B 版少放盐,然后请顾客回答“哪份更好吃”——而不是给每份打个 2.7 分。为什么?因为人脑对“好坏比较”的判断远比“绝对打分”稳定。奖励模型训练用的就是这种相对偏好数据。

具体做法是:让人工标注员对同一个 prompt 下的两个回答做偏好排序,生成大量“回答 A 优于回答 B”的样本。训练时采用 Bradley-Terry 偏好模型,把“回答越好,得分越高”这个直觉变成一个可微分的概率公式:

奖励模型就像师傅的舌头,如果舌头被辣坏了,之后所有点评都会失真。训练它的核心心法是“只比高低,不评绝对”,配合充足的排序数据和严格的防过拟合评估,才能保证后续 PPO 阶段拿到稳定可信的分数信号。

P(y1≻y2∣x)=exp⁡(rϕ(x,y1))exp⁡(rϕ(x,y1))+exp⁡(rϕ(x,y2))\displaystyle P(y_1\succ y_2|x)=\frac{\exp\bigl(r_{\phi}(x,y_1)\bigr)}{\exp\bigl(r_{\phi}(x,y_1)\bigr)+\exp\bigl(r_{\phi}(x,y_2)\bigr)}
这个式子把“师傅觉得 A 比 B 好吃”的概率,用两个回答的指数分数之比来表示,指数的作用是把分数映射成正数,便于计算概率。
  1. 指数映射$\exp\bigl(r_{\phi}(x,y)\bigr)$ 把任意实数评分变成正数,评分高一点,指数值就高一大截,相当于把“微弱的偏好”放大成概率差异。
    exp⁡(⋅)>0\exp(\cdot)\gt0
  2. 概率归一化分母是两份回答指数分数的和,整个式子把偏好压缩成 0 到 1 之间的概率,正好刻画“二选一”的判定。
    P=es1es1+es2\displaystyle P=\frac{e^{s_1}}{e^{s_1}+e^{s_2}}
  3. 训练目标最大化真实偏好对出现的概率,等价于拉大“人类更喜欢的回答”与“人类不喜欢的回答”之间的分数差。
    max⁡ϕ E(x,y1,y2)∼D[log⁡P(y1≻y2∣x)]\displaystyle \max_{\phi}\ \mathbb{E}_{(x,y_1,y_2)\sim\mathcal{D}}\bigl[\log P(y_1\succ y_2|x)\bigr]
  4. 过拟合防范奖励模型一旦在标注数据上过拟合,就会记住某些表面模式(比如“回答长就给高分”),训练时需要预留验证集,并监控偏好准确率。
    acc=#{Ppred correct}N\text{acc}=\frac{\#\{P_{\text{pred}}\ \text{correct}\}}{N}

PPO策略优化

师傅发现小明做菜有个毛病:一旦有人说某道菜好吃,小明就疯狂加那种佐料,直到把整桌菜都做成一个味。于是师傅立下规矩:“每道菜只许微调,不许推翻重来。”PPO(近端策略优化)干的正是这件事——让策略模型沿着奖励信号的方向更新,但每次更新幅度被严格限制。

PPO 的前身是策略梯度法,核心思想是“表现好就多生成这种回答,表现差就少生成”,但直接套用容易步子迈太大。PPO 的答案是用一个裁剪目标函数,比较新旧策略在采样数据上的概率比,一旦比值超出 $[1-\varepsilon,1+\varepsilon]$ 的区间就截断:

回到厨房,PPO 的裁剪就像是师傅手里的“量勺”:每道菜的新配方和旧配方相比,任何一味调料的变动幅度都不能超过 20%。这份克制,恰恰是 PPO 在众多强化学习算法中训练最稳定的根本原因——小步快跑,才能跑得更远。

LCLIP(θ)=Et[min⁡(rt(θ)A^t, clip⁡(rt(θ),1−ε,1+ε)A^t)]\displaystyle L^{\text{CLIP}}(\theta)=\mathbb{E}_{t}\Bigl[\min\Bigl(r_{t}(\theta)\hat{A}_{t},\ \operatorname{clip}\bigl(r_{t}(\theta),1-\varepsilon,1+\varepsilon\bigr)\hat{A}_{t}\Bigr)\Bigr]
这个公式翻译过来就是:“改进可以,但每次调整的比例最多只有 $\varepsilon$ 这么大(常见取 0.2),超出部分收益直接砍掉。”
  1. 新旧策略概率比$r_{t}(\theta)$ 是当前策略与采样时旧策略在动作 $a_t$ 上的概率比值,比值大于 1 表示新策略更倾向于这个动作。
    rt(θ)=πθ(at∣st)πθold(at∣st)\displaystyle r_{t}(\theta)=\frac{\pi_{\theta}(a_t|s_t)}{\pi_{\theta_{\text{old}}}(a_t|s_t)}
  2. 裁剪函数$\operatorname{clip}\bigl(r_{t}(\theta),1-\varepsilon,1+\varepsilon\bigr)$ 把比值强行限制在 $[1-\varepsilon,1+\varepsilon]$ 内,超出部分按边界值计算,这就是“最多只允许改 20%”的数学表达。
    clip⁡(r,1−ε,1+ε)=max⁡(1−ε, min⁡(r,1+ε))\operatorname{clip}(r,1-\varepsilon,1+\varepsilon)=\max\bigl(1-\varepsilon,\ \min(r,1+\varepsilon)\bigr)
  3. 优势加权$\hat{A}_{t}$ 是优势函数,表示“这个动作比平均水平好多少”,优势为正说明该被鼓励,为负说明该被抑制。
    A^t=Q(st,at)−V(st)\hat{A}_{t}=Q(s_t,a_t)-V(s_t)
  4. 保守取最小值$\min$ 操作保证目标函数永远不会因为裁剪而虚高,宁可少赚,也不冒进。
    min⁡(rA^, clip⁡(r)A^)\min\bigl(r\hat{A},\,\operatorname{clip}(r)\hat{A}\bigr)

KL散度约束

师傅给小明立了一条铁规矩:“你可以学新菜,但颠勺、切配、火候这些基本功不能丢。”怎么衡量“没丢”?师傅心里有一本动作对照表——每招每式都跟标准动作比一比,差得越远,越要拉回来。对 PPO 来说,这本“对照表”就是参考模型,那把“尺子”就是 KL 散度。

参考模型通常是 SFT 阶段的模型快照(也可能是上一轮的检查点),它代表模型“没被奖励带偏”时的正常能力。KL 散度衡量当前策略与参考策略在每个 token 上的分布差异,数值越大说明策略改得越激进:

在训练日志里,KL 散度是比奖励分数更可靠的安全指标。如果 KL 突然暴涨,说明策略开始钻奖励模型的空子,也就是“小明为了拿高分开始狂放糖”。有经验的工程师会同时盯住 KL 和奖励两条曲线,一旦发现二者背离,立刻调大 $\beta$ 把策略拉回安全区。

DKL(πθ∥πref)=∑yπθ(y∣x)log⁡πθ(y∣x)πref(y∣x)\displaystyle D_{KL}\bigl(\pi_{\theta}\|\pi_{\text{ref}}\bigr)=\sum_{y}\pi_{\theta}(y|x)\log\frac{\pi_{\theta}(y|x)}{\pi_{\text{ref}}(y|x)}
可以理解为把所有“生成位置上两种策略的分歧程度”加起来:完全一致时 KL 为 0,越不一致 KL 越大。
  1. 逐 token 对数比值$\log\frac{\pi_{\theta}(y|x)}{\pi_{\text{ref}}(y|x)}$ 表示在一个具体输出上新旧策略概率比的对数,概率差得越多,这个值绝对值越大。
    log⁡πθ(y∣x)πref(y∣x)\displaystyle \log\frac{\pi_{\theta}(y|x)}{\pi_{\text{ref}}(y|x)}
  2. 对当前策略求期望乘上 $\pi_{\theta}(y|x)$ 并对所有输出求和,得到“按当前策略生成时平均偏离多少”。
    DKL=Ey∼πθ[log⁡πθ(y∣x)πref(y∣x)]\displaystyle D_{KL}=\mathbb{E}_{y\sim\pi_{\theta}}\Bigl[\log\frac{\pi_{\theta}(y|x)}{\pi_{\text{ref}}(y|x)}\Bigr]
  3. 非负性与最小值KL 散度恒大于等于 0,只有两个策略完全相同时才等于 0。
    DKL≥0,DKL=0  ⟺  πθ=πrefD_{KL}\geq 0,\quad D_{KL}=0\iff \pi_{\theta}=\pi_{\text{ref}}
  4. 动态调节系数实践中常用自适应 KL——本轮 KL 超过目标值就调大 $\beta$,低于目标值就调小 $\beta$,像恒温器一样维持平衡。
    β←β×{1.2,DKL>Dtarget0.8,DKL<Dtarget\displaystyle \beta\leftarrow\beta\times\begin{cases}1.2,&D_{KL}>D_{\text{target}}\\0.8,&D_{KL}<D_{\text{target}}\end{cases}

Rollout采样

小明每天先在厨房做几十道“试吃菜”,师傅逐一品尝并记录点评,晚上才根据这批点评统一调整手法。这种“先做一批、再改一次”的节奏,在 PPO 里叫 rollout 采样——策略模型与优化器交替工作,而不是生成一条就更新一次。

一次完整的 rollout 要记录四类东西:输入提示词(prompt)、生成的回答序列、每个 token 的对数概率,以及奖励模型给的总分。其中 token 对数概率是后面计算新旧策略比值的原料,不能只存最终文本。采样完成后,还需要价值网络为每个 token 提供一个基线分数,用来计算优势函数。最常用的方法是 GAE(广义优势估计):

采样阶段积累的经验数据是强化学习唯一的“燃料”。工程上常用经验缓冲池来管理这些数据:先跑固定数量的 prompt 生成回答,统一打分开存,再做若干轮小批量更新。缓冲池里的数据用一次就会被丢弃,因为策略一旦更新,旧数据就“过期”了——这跟监督学习里反复用同一批数据是截然不同的逻辑。

δt=rt+γV(st+1)−V(st)\displaystyle \delta_t = r_t + \gamma V(s_{t+1}) - V(s_t)
At=∑l=0T−t(γλ)l δt+l\displaystyle A_t = \sum_{l=0}^{T-t}(\gamma\lambda)^l\,\delta_{t+l}
GAE 的意思是:师傅不看“最后一道菜成败”这种单一信号,而是综合从第一口到最后一顿的反馈,用指数加权的方式给出一个更稳的评价。
  1. TD 残差$\delta_t$ 表示当前这一口带来的“意外收获”——实际尝到的味道($r_t$ 加未来折现预期)比师傅原本预期的($V(s_t)$)好多少。
    δt=rt+γV(st+1)−V(st)\displaystyle \delta_t=r_t+\gamma V(s_{t+1})-V(s_t)
  2. 多步加权求和$A_t$ 从当前位置往后,把每一步的残差用 $(\gamma\lambda)^l$ 加权累加,既看眼前又顾长远。
    At=∑l=0T−t(γλ)lδt+l\displaystyle A_t=\sum_{l=0}^{T-t}(\gamma\lambda)^l\delta_{t+l}
  3. 两个系数的分工$\gamma$ 决定未来奖励的折扣程度(师傅是否看重长期口碑),$\lambda$ 决定残差回溯的步长(看得远还是看得近)。
    0<γ≤1,0≤λ≤10<\gamma\le1,\quad 0\le\lambda\le1

超参调优

师傅调教小明靠“火候”二字:火太大怕糊,火太小怕生,酱油多一勺少一勺都有讲究。PPO 的超参调优也是这样一门手艺,最核心的几个旋钮各有各的分寸。

PPO 的完整损失函数由四部分组成:裁剪策略损失、KL 惩罚、价值函数损失,以及一个鼓励探索的熵奖励项。组合起来长这样:

实战中的常用起点是:学习率 1e-6 到 1e-5,裁剪范围 $\varepsilon=0.2$,KL 目标值 0.02 到 0.2,每次 rollout 用几千个 prompt,小批量循环 1 到 4 轮。调参时先固定大部分超参,只动一个旋钮,逐步感受它对 KL 和奖励曲线的影响。记住:模型在奖励分数上稳步上升、KL 保持平稳,才是真正健康的收敛状态。

LPPO=LCLIP(θ)−β DKL(πθ∥πref)+c1LVF(θ)+c2H(πθ)\displaystyle L^{\text{PPO}}=L^{\text{CLIP}}(\theta)-\beta\,D_{KL}(\pi_{\theta}\|\pi_{\text{ref}})+c_{1}L^{\text{VF}}(\theta)+c_{2}H(\pi_{\theta})
前两项决定了“改得对不对、离不离谱”,后两项负责“基线准不准、探索够不够”。
  1. 策略损失$L^{\text{CLIP}}(\theta)$ 是前面讲过的裁剪目标,主导策略的更新方向。
    LCLIP(θ)=E[min⁡(rA^,clip⁡(r)A^)]\displaystyle L^{\text{CLIP}}(\theta)=\mathbb{E}\bigl[\min(r\hat{A},\operatorname{clip}(r)\hat{A})\bigr]
  2. KL 惩罚$-\beta\,D_{KL}$ 是约束项,系数 $\beta$ 越大,越不允许策略偏离参考模型;$\beta$ 过小则容易跑飞,过大则学不动。
    −β DKL(πθ∥πref)\displaystyle -\beta\,D_{KL}(\pi_{\theta}\|\pi_{\text{ref}})
  3. 价值函数损失$c_{1}L^{\text{VF}}$ 训练价值网络去预测累积回报,让优势估计越来越准,是 GAE 的“教练员”。
    LVF(θ)=E[∥Vθ(st)−R^t∥2]\displaystyle L^{\text{VF}}(\theta)=\mathbb{E}\bigl[\lVert V_{\theta}(s_t)-\hat{R}_t\rVert^2\bigr]
  4. 熵奖励$c_{2}H(\pi_{\theta})$ 鼓励策略保持一定的随机性,防止过早固化在某几个回答模式上,相当于师傅允许小明偶尔试一道新菜。
    H(πθ)=−E[πθ(y∣x)log⁡πθ(y∣x)]\displaystyle H(\pi_{\theta})=-\mathbb{E}\bigl[\pi_{\theta}(y|x)\log\pi_{\theta}(y|x)\bigr]

AI 应用场景

对话助手的输出安全对齐

阶段:RLHF 训练与评估

解决的问题:基础大模型虽然能流畅对话,但经常输出有毒、危险或不符合公司价值观的内容。传统规则过滤只能覆盖已知关键词,面对千变万化的诱导句式完全抓瞎。

具体案例:某金融科技公司的智能客服,先让人工标注“合规回答优于踩线回答”的排序数据训练奖励模型,再用 PPO 微调策略。训练后,模型对“如何避税”“保本理财”等敏感问题的回答变得保守稳妥,上线后人工质检违规率下降 40%。

医疗问答减少“幻觉”

阶段:数据标注与奖励模型训练

解决的问题:医疗大模型容易一本正经地编造药品剂量和禁忌症,这是典型的“能力强但不可信”。让医生标注“引用说明书的回答优于凭空编造的回答”的偏好对,再训练奖励模型给“有依据”的回答打高分。

具体案例:某在线问诊平台的用药助手,收集医生对同一问题的双回答排序,训练奖励模型后做 PPO 微调。结果显示,回答中“引用药品说明书”的比例提升 25%,严重错误率明显下降,患者投诉大幅减少。

开放域聊天的“人设一致性”

阶段:策略优化与 KL 约束调节

解决的问题:通用模型在不同轮次里性格和立场飘忽不定,用户上一秒还在跟“知心姐姐”聊天,下一秒对方就变成了“理性机器人”。用 RLHF 强化“人设一致的回答更优”的偏好,并用 KL 约束避免丢掉通用能力。

具体案例:某陪伴型 AI 产品把“人设相关回答”排进偏好数据,训练奖励模型后进行 PPO 微调,同时用自适应 KL 策略防止模型变成复读机。上线后用户对“角色代入感”的评分显著上升。

Python 演示

python81 行
import numpy as np  class PreferenceEnv:    """模拟人类偏好:动作越接近4,奖励越高。"""    def __init__(self):        self.best = 4     def reward(self, action):        return -abs(action - self.best) + 3.0  class TinyPolicy:    """小型策略:用一组logits表示10个动作的偏好。"""    def __init__(self, n_actions):        self.logits = np.zeros(n_actions)     def prob(self):        z = self.logits - self.logits.max()        e = np.exp(z)        return e / e.sum()     def sample(self):        return int(np.random.choice(len(self.logits), p=self.prob()))     def log_prob(self, action):        return np.log(self.prob()[action] + 1e-12)  def kl_div(policy, ref_policy):    """计算当前策略相对参考策略的KL散度。"""    p = policy.prob()    q = ref_policy.prob()    return float((p * np.log(p / q + 1e-12)).sum())  def compute_loss(policy, ref_policy, actions, old_logps, advantages, epsilon, beta):    """PPO目标:裁剪策略损失 + KL惩罚。"""    new_logps = np.array([policy.log_prob(a) for a in actions])    ratio = np.exp(new_logps - old_logps)    clipped = np.clip(ratio, 1 - epsilon, 1 + epsilon)    policy_loss = -np.minimum(ratio * advantages, clipped * advantages).mean()    return policy_loss + beta * kl_div(policy, ref_policy)  def ppo_step(policy, ref_policy, actions, old_logps, advantages,             epsilon=0.2, beta=0.1, lr=0.05):    """用数值梯度做一步参数更新(教学简化版)。"""    grad = np.zeros_like(policy.logits)    delta = 1e-4    for i in range(len(policy.logits)):        orig = policy.logits[i]        policy.logits[i] = orig + delta        loss_plus = compute_loss(policy, ref_policy, actions, old_logps, advantages, epsilon, beta)        policy.logits[i] = orig - delta        loss_minus = compute_loss(policy, ref_policy, actions, old_logps, advantages, epsilon, beta)        policy.logits[i] = orig        grad[i] = (loss_plus - loss_minus) / (2 * delta)    policy.logits -= lr * grad  def main():    env = PreferenceEnv()    policy = TinyPolicy(10)    ref_policy = TinyPolicy(10)    for epoch in range(30):        actions, logps, rewards = [], [], []        for _ in range(64):            act = policy.sample()            actions.append(act)            logps.append(policy.log_prob(act))            rewards.append(env.reward(act))        advantages = np.array(rewards) - np.mean(rewards)        ppo_step(policy, ref_policy, actions, np.array(logps), advantages)        if epoch % 5 == 0:            print("epoch %2d  kl=%.4f  best_prob=%.3f"                  % (epoch, kl_div(policy, ref_policy), policy.prob()[env.best]))  if __name__ == "__main__":    main()
目的:用 30 行核心逻辑演示 PPO 的采样-更新循环,跑完后观察策略对“最优动作”的概率逐步上升,同时 KL 散度保持平稳。
  1. from numpy import np引入数值计算库,后面的数组运算全靠它。
  2. self.logits = np.zeros(n_actions)每个动作一个可学习分数,softmax 后即策略概率。
  3. return int(np.random.choice(len(self.logits), p=self.prob()))按当前策略概率随机采样一个动作,这就是 rollout。
  4. ratio = np.exp(new_logps - old_logps)新旧策略概率比,PPO 目标的关键输入。
  5. clipped = np.clip(ratio, 1 - epsilon, 1 + epsilon)把比值限制在 [0.8, 1.2] 内,这就是裁剪。
  6. np.minimum(ratio * advantages, clipped * advantages)取保守值,防止虚高的更新信号。
  7. return policy_loss + beta * kl_div(policy, ref_policy)策略损失加上 KL 惩罚,保证不偏离参考模型。
  8. advantages = np.array(rewards) - np.mean(rewards)简化版优势:本次奖励比平均好多少。
  9. policy.logits -= lr * grad用数值梯度做一步参数更新,教学版省去了反向传播框架。

常见误区

误区我一开始以为 RLHF 就是把用户点赞数转成损失函数,让模型输出分数越高越好,不需要什么中间环节。

正解人类给出的绝对分数很嘈杂、量纲不统一,直接当监督信号会让训练震荡不安。RLHF 的正确姿势是:先训练奖励模型学习“哪个回答更优”的相对偏好,再用 PPO 让策略模型依据奖励信号逐步优化,中间还要加 KL 约束防止跑偏。好比师傅不会喊“这盘 40 分”,而是说“这盘比那盘好”,徒弟才知道该往哪个方向改。

为何常见:很多资料把“人类反馈”简化成“打分”,让人误以为监督学习就够了,忽略了强化学习“边采样边改进”的决策本质。

误区既然怕模型学坏,那把 β 调得很大,让模型完全贴着参考模型总没错吧?

正解β 过小时模型容易钻奖励漏洞胡说八道;β 过大时模型被“捆住手脚”,奖励信号几乎不起作用,等于白训练。实践里常用自适应 KL:当前散度超过目标值就调大 β,低于目标值就调小 β,像恒温器一样维持平衡。

为何常见:人们直觉上觉得“约束越强越安全”,但强化学习需要探索空间,约束过强会直接把学习信号掐死。

误区训练慢?那我加大学习率、每个批次多更新几次,奖励不是上去得更快吗?

正解强化学习的难点恰恰是“一步走错,后面全盘崩坏”。PPO 的裁剪机制就是限制单步更新幅度,让策略“移动但不奔跑”。学习率通常取 1e-6 到 1e-5,更新轮数(epoch)一般 1 到 4 轮,宁可多采样也不在一批旧数据上反复压榨。

为何常见:大家习惯了监督学习里反复遍历数据集,忘了强化学习的数据分布会随策略改变,旧数据复用过多会让策略过拟合到过期经验上。

误区训练时奖励曲线一路上涨,说明模型真的变强了,可以放心上线。

正解奖励模型只是“师傅的舌头”,并不等于真实顾客的满意度。模型完全可能牺牲 KL 约束去迎合奖励模型的偏好,出现 reward hacking,比如回答越来越长、堆砌空洞关键词。评估必须结合 KL 散度、人工抽检和真实用户反馈一起看,单看奖励分数很容易被表面数字骗过去。

为何常见:训练指标好看会带来虚假安全感,尤其当奖励模型本身存在偏差时,策略会精准地钻空子,把“分数”刷上去却把“质量”丢掉。

面试题

Q1. RLHF 三阶段训练的正确顺序是?

单选题 · easy

  • A.SFT→PPO→奖励模型
  • B.SFT→奖励模型→PPO← 正确答案
  • C.奖励模型→SFT→PPO
  • D.PPO→奖励模型→SFT

答案:B。先让模型具备基础对话能力(SFT),再训练奖励模型学习人类偏好,最后用 PPO 在奖励信号下优化策略。顺序反了,奖励模型就没有可靠的策略去评估,PPO 也没有地基可挖。

Q2. 奖励模型的训练数据主要来自?

单选题 · easy

  • A.用户对回答打绝对分数
  • B.同提示下两回答的偏好比较← 正确答案
  • C.大规模无标注纯文本库
  • D.图片分类的人工标注标签

答案:B。相对偏好比较比绝对打分更稳定,人脑对“哪个更好”的判断远比对“打几分”可靠。这是 Bradley-Terry 偏好模型的基础,也是奖励模型训练数据的标准形态。

Q3. PPO 中裁剪范围 epsilon 的常用取值是?

单选题 · easy

  • A.0.01
  • B.0.1
  • C.0.2← 正确答案
  • D.0.8

答案:C。0.2 是 OpenAI 等主流实现中的默认值,表示新旧策略概率比只允许在 [0.8, 1.2] 内变动。过大失去裁剪意义,过小更新过慢。

Q4. KL 散度约束在 PPO 中的核心作用是?

单选题 · mid

  • A.提升模型参数容量
  • B.防止策略偏离参考模型← 正确答案
  • C.加速生成阶段采样
  • D.替代奖励模型打分

答案:B。KL 散度衡量当前策略与参考模型的距离,防止策略为了讨好奖励模型而彻底丢掉原有能力。它不是提升容量的手段,也管不了采样速度,更不会替代奖励模型。

Q5. GAE 中 TD 残差 δ_t 的正确形式是?

单选题 · mid

  • A.r_t+γV(s_{t+1})−V(s_t)← 正确答案
  • B.r_t−γV(s_{t+1})+V(s_t)
  • C.r_t+V(s_{t+1})−γV(s_t)
  • D.V(s_t)−r_t−γV(s_{t+1})

答案:A。TD 残差 = 当前奖励 + 折现的下一步价值估计 − 当前价值估计。它度量“这一步比预期好多少”,是 GAE 多步加权累加的基础单元。

Q6. 关于 PPO 的裁剪机制,下列说法正确的有?

多选题 · mid

  • A.限制新旧策略概率比值← 正确答案
  • B.防止策略单步更新过大← 正确答案
  • C.正优势时避免更新过猛← 正确答案
  • D.完全冻结旧策略的参数

答案:ABC。裁剪把新旧比值限制在 [1−ε, 1+ε] 内,让策略“小步改进”而不是“大步翻车”。它只是限制幅度,并不是冻结参数,故选 A、B、C,D 错。

Q7. 一次 PPO 训练迭代的经验采样通常需要记录哪些信息?

多选题 · mid

  • A.生成回答及token对数概率← 正确答案
  • B.输入提示词prompt← 正确答案
  • C.奖励模型给出的总体得分← 正确答案
  • D.奖励模型训练用的样本权重

答案:ABC。计算 ratio 需要新旧概率(A),生成需要 prompt(B),算优势需要奖励(C)。D 是奖励模型训练阶段的概念,不属于 PPO 采样记录。

Q8. 下列哪一项通常不属于 PPO 目标函数的组成部分?

单选题 · hard

  • A.裁剪后的策略损失项
  • B.对参考模型的KL惩罚项
  • C.价值网络回归损失项
  • D.语言模型交叉熵损失项← 正确答案

答案:D。PPO 目标由裁剪策略损失、KL 惩罚、价值损失和(可选的)熵奖励组成。语言模型交叉熵是 SFT 阶段的损失,PPO 阶段不再直接使用。

Q9. 以下哪些手段可以有效缓解 reward hacking?

多选题 · hard

  • A.完全移除KL散度约束
  • B.使用多个奖励模型综合投票← 正确答案
  • C.动态调整KL惩罚系数← 正确答案
  • D.混合SFT数据继续微调← 正确答案

答案:BCD。移除 KL 约束反而会助长钻空子;多奖励模型投票可以抵消单一模型的偏好偏差;动态调整 β 把跑偏的策略拉回来;混合 SFT 数据能稳定模型的基础能力。故选 B、C、D。

Q10. 自适应 KL 策略中,当本轮 KL 散度超过目标值时应该?

单选题 · extreme

  • A.KL超限时增大惩罚系数← 正确答案
  • B.KL超限时减小惩罚系数
  • C.惩罚系数始终保持恒定
  • D.惩罚系数仅在期末调整

答案:A。KL 超限说明策略偏离参考模型太远,应当调大 β 加强约束,把策略拉回安全区。减小系数会让模型更放飞,恒定的 β 则失去自适应调节能力。