版权与内容来源声明
本文为原创整理。文中涉及官方文档、开源仓库、论文与公开报道的内容,均在附表 A 中标注来源;引用官方原文保持原样,不作改写。文中命令、版本号与界面截图以本文成文时的实测/核验结果为准,标注「待验证」的部分请以你本地环境实际输出为判断依据。本文不推荐任何不合规的软件获取方式,也不对任何收益结果作承诺。转载请注明出处。
把同一个问题问两遍,第一次的答案又长又全、列了五条;第二次短到只有三行,但正好是你想要的那句。你会挑第二个。问题在于,这件事你心里清楚,模型自己不知道——除非你把「我更喜欢第二个」这件事,翻译成一种它在训练里能读到的形式。SFT、RLHF+PPO、DPO 这三代方案,表面上是「谁更强」的竞争,实际是同一个问题的三种答法:人的偏好,到底以什么形式进入训练。
一、先分清两件事:学「像不像」和学「好不好」不是一回事
这一章的结论先摆出来:绝大多数人把「对齐」当成「把答案调得更准」,其实第一代和第二代之间隔着的不是精度,而是评价对象换了——从「像不像标准答案」换成了「这两个答案里,人更喜欢哪个」。这两件事需要的训练信号,根本不是同一种数据结构。
学「像不像」:只需要正样本
监督微调(SFT,Supervised Fine-Tuning)吃的是「输入 — 期望输出」的成对数据。它的评价口径很直白:给定输入,你输出的概率分布有多接近那条标准答案。标准答案之外的写法,在这个口径里一律是「错」,哪怕它其实更好。
学「好不好」:需要的是相对关系
偏好对齐吃的是另一种数据:同一个 prompt 下两条回答,标注者告诉你哪条更好。注意这里没有绝对正确的答案,只有一条相对关系。这个差别决定了后面的全部技术分叉——一个只有正样本的信号,和一个「A 比 B 好」的信号,能被塞进完全不同的损失函数里。
先把数据长什么样看清楚,后面三代方案的差别才有落脚点:
{"prompt":"帮我写一句周报开头","chosen":"本周完成了接口联调与灰度发布。","rejected":"在当今快速发展的时代背景下,本周我们积极拥抱变化,顺利且高效地完成了…… (后面还有300字)"}同一个问题、两条回答、一个「chosen」一个「rejected」,这就是偏好对。整篇文章只讨论一件事:这个偏好对,三代方案分别怎么用。
二、第一代 SFT:学会了格式,但学不会取舍
结论前置:SFT 解决的是「模型不听指令」,它从来没打算解决「哪个回答更好」。把 SFT 当成对齐的终点,本质上是把「模仿」误当成了「判断」。
它解决了什么
预训练完的基座模型是个「续写机器」——你给它半句话,它顺着往下写,但不一定是在回答你。InstructGPT 论文摘要里写得很清楚,他们的做法是:先用标注者写的示例(labeler demonstrations)做监督学习微调 GPT-3,让模型学会「被要求做事时该输出什么形态」。这一步把「续写」掰成了「应答」,格式、语气、结构都在这一步成型。
它留下的坑:只有一个方向
SFT 的损失只看正样本:让「标准答案」的概率变高,其余一切自动被压低。这里有个被低估的后果——它无法表达「更好」和「次好」的区别。如果标注数据里两条回答其实都不错,只是风格不同,SFT 会把没被选中的那条当成错误样本压下去。风格偏好、安全偏好这类「没有标准答案、只有排序」的东西,在 SFT 的损失函数里根本没有对应的位置。
低质量数据的放大也是它的问题:SFT 学的是「演示里出现过的样子」,演示里若有一半是啰嗦的长答案,模型就会把啰嗦当成「标准形态」学下来。这正好解释了第一节那个现象——同一个问题问两遍,为什么第一遍又长又全。
三、第二代 RLHF + PPO:把人的偏好变成奖励信号,代价是三套模型同时在线
结论前置:这一代第一次让「偏好」真正参与优化,但它是两段式——先把偏好训成一个奖励模型,再用强化学习去最大化这个奖励。多出来的这套中间层,是它能力的来源,也是它所有工程代价的来源。
偏好怎么变成奖励:多了一道代理
RLHF(Reinforcement Learning from Human Feedback,基于人类反馈的强化学习)的核心动作是把「标注者更喜欢哪条」训练成一个能打分的奖励模型。InstructGPT 摘要里描述得很直接:他们收集模型输出的排序数据(rankings),用这些排序进一步微调上一步的监督模型,「using reinforcement learning from human feedback」。
于是偏好数据被用了两次:一次是训练奖励模型(把人对 A、B 的排序压成一个可打分的函数),一次是在强化学习阶段、用这个奖励函数给在线采样的输出打分。奖励模型是人和模型之间的一道代理,它不是人本身。
为什么必须同时在线的模型有好几套
PPO(Proximal Policy Optimization,近端策略优化)是这一代常用的更新算法,它的原始论文(arXiv 1707.06347)摘要讲的是一族「采样数据、再用随机梯度上升优化代理目标」的策略梯度方法。放到对齐场景里,一次训练要同时在场的东西包括:被训练的策略模型、估计状态价值的价值模型、给奖励打分的奖励模型、算 KL 约束用的参考模型。Hugging Face TRL 的PPOTrainer文档里,model(策略)、reward_model、value_model都是必填参数,ref_model用于计算 KL 散度(不传就复制一份策略模型)。四套模型里三套必填,这就是「三套模型同时在线」这句话的来源。
流程大致如此(伪代码,仅示意顺序):
⚠️代码待验证
loop: # 第一段:在线采样 prompts = sample_prompts() responses = policy.generate(prompts) # 需要真的跑前向 rewards = reward_model(prompts, responses) # 代理打分,不是人打分 ref_logp = ref_model.logprob(prompts, responses) # 第二段:用 PPO + KL 约束更新策略 advantage = rewards - beta_kl * KL(policy, ref_model) # KL 系数要调 policy.update(ppo_loss(advantage)) # 价值模型估计 baseline它留下的坑
三个坑,一个比一个硬:①必须有奖励模型,奖励模型学得不好,策略就会去钻它的空子(奖励黑客);②必须在线采样,每轮更新都要让策略模型真的生成一遍,训练成本和工程复杂度都上去了;③KL 系数难调,约束太松会跑偏、太紧又学不动。DPO 论文摘要里那句判断很克制:「RLHF is a complex and often unstable procedure」——一套复杂且常常不稳定的流程。
四、第三代 DPO:把偏好直接写进损失,省掉了显式奖励模型
结论前置:DPO 的真正变化不是「变简单了」,而是换了个数学对象——它证明了这套偏好优化问题可以不用显式的奖励模型,改用一个直接吃偏好对的分类式损失来解。偏好数据从「先训代理、再喂强化学习」变成了「直接进损失函数」。
一句话说清它绕过了什么
DPO 论文(arXiv 2305.18290)摘要里,作者先说清了 RLHF 的两段结构:先拟合一个反映人类偏好的奖励模型,再用强化学习去最大化这个估计奖励、同时不偏离原模型太远。接着给出新做法——换一种奖励模型的参数化,使对应的最优策略能闭式解出,于是「solve the standard RLHF problem with only a simple classification loss」。摘要里对结果算法的原话是「stable, performant, and computationally lightweight」。
需要提醒一句:网上常把 DPO 的省事总结成「省掉了 RL」。但 DPO 摘要页里并没有「eliminating the need for RL」这样的原句,原文写的是省掉「在微调期间从语言模型采样」和「大量超参调优」(eliminating the need for sampling from the LM during fine-tuning or performing significant hyperparameter tuning)。引用时请以摘要页逐字原文为准,别转述成省掉了 RL。
损失函数里到底算了什么
DPO 的损失可以写成一行:让「被选中回答」相对参考模型的对数概率提升,减去「被拒绝回答」相对参考模型的对数概率提升,得到这个差值(下称 log-ratio 差,也就是隐式奖励的 margin),再取负对数 sigmoid。公式:
L_DPO = -log sigmoid( β · [ (logπ(y_w) - logπ_ref(y_w)) - (logπ(y_l) - logπ_ref(y_l)) ] )其中 y_w 是被选中回答、y_l 是被拒绝回答,π 是策略模型、π_ref 是参考模型(TRL 文档说明:不显式传ref_model时,就用开始 DPO 训练前那份模型状态当参考策略),β 是控制偏离参考模型程度的系数。它不需要奖励模型,但依赖一个固定的参考策略。
用真实数字把这行公式跑一遍,比任何解释都清楚。下面三组输入的四元组顺序是(logπ(y_w), logπ(y_l), logπ_ref(y_w), logπ_ref(y_l)):
🧪 实测环境:Python 3.13.12 / macOS / numpy 2.5.3
importnumpyasnpdefdpo_loss(lp_w,lp_l,lr_w,lr_l,beta):# log-ratio margin: (logπ(y_w)-logπ_ref(y_w)) - (logπ(y_l)-logπ_ref(y_l))margin=(lp_w-lr_w)-(lp_l-lr_l)z=beta*margin loss=-np.log(1.0/(1.0+np.exp(-z)))# -log sigmoid(z)returnloss,margin cases={"A 策略更偏好 y_w":(-1.0,-3.0,-2.0,-2.0),"B 策略与参考一致":(-2.0,-2.0,-2.0,-2.0),"C 策略偏好反了 ":(-3.0,-1.0,-2.0,-2.0),}forname,(lw,ll,rw,rl)incases.items():parts=[]forbetain(0.1,0.5,1.0):loss,m=dpo_loss(lw,ll,rw,rl,beta)parts.append(f"beta={beta:<4}loss={loss:.4f}")print(f"{name}| margin={m:+.1f}| "+" | ".join(parts))真实输出(原文照贴,未做任何修改):
A 策略更偏好 y_w | margin=+2.0 | beta=0.1 loss=0.5981 | beta=0.5 loss=0.3133 | beta=1.0 loss=0.1269 B 策略与参考一致 | margin=+0.0 | beta=0.1 loss=0.6931 | beta=0.5 loss=0.6931 | beta=1.0 loss=0.6931 C 策略偏好反了 | margin=-2.0 | beta=0.1 loss=0.7981 | beta=0.5 loss=1.3133 | beta=1.0 loss=2.1269三行输出对应三个要点:
- 策略更偏好 y_w 时损失下降。A 行 margin 为 +2.0,β 从 0.1 到 1.0,损失从 0.5981 降到 0.1269(β 越大越敏感)。训练要做的事,就是把这个 margin 推大。
- 模型没学到偏好时,损失不是零。B 行策略和参考完全一致,margin=0,但损失是 0.6931——正好是 ln2。因为 sigmoid(0)=0.5,-log(0.5) 就是 ln2。所以「损失看起来不高」不等于「已经学到偏好」,这条损失的中性点是 ln2,不是 0。
- β 决定损失对 margin 的敏感度。同一组 margin(±2.0),β=1.0 时损失变化幅度远大于 β=0.1。β 调大,模型被推着更明显地偏离参考模型;β 调小则更保守。这就是 DPO 里最需要动手调的那个数。
它留下的坑
DPO 省掉了奖励模型,但把代价换了地方:①依赖一个固定参考策略,π_ref 一旦定下(通常就是 SFT 结束时的模型),训练全程不变,模型和它之间的「距离预算」是静态的;②偏好对是离线、静态的,DPO 不会像 PPO 那样在线采样探索,数据里没有的分布它学不到;③对偏好数据质量更敏感,因为没有奖励模型这层「平滑」,噪声直接进损失。
DPO 与 PPO 的对齐损失对照表:把本章的两代损失写法、需要同时加载的模型、以及 β / KL 系数的调参位置整理成了一张对照表,放在资料包里,扫码即可获取:
五、还有哪些问题没人解决(今天仍在的坑)
结论前置:三代方案一路把「偏好数据的用法」简化到了极致,但没有一个解决了偏好数据本身的三个老大难——量、一致性、以及「人的偏好会不会互相打架」。换算法换不掉这些问题。
🧪 实测环境:数据来自下列论文摘要页与官方文档,逐条注明出处,取数日期截至 2026-10-08
把三代方案并排放,差别就一目了然了:
| 代际 / 方案 | 偏好数据怎么用 | 解决了什么 | 引入的新问题 |
|---|---|---|---|
| 第一代 SFT | 不用偏好对,只用正样本示范 | 让模型从「续写」变成「应答」 | 学不了取舍,只模仿,放大数据里的风格偏差 |
| 第二代 RLHF + PPO | 偏好排序 → 训奖励模型 → 在线采样后打分再 RL 更新 | 偏好第一次真正参与优化 | 奖励模型是代理可被钻空子、必须在线采样、KL 系数难调、流程复杂不稳定 |
| 第三代 DPO | 偏好对(chosen/rejected)直接进分类式损失 | 省掉显式奖励模型,训练更轻 | 依赖固定参考策略、只吃离线静态偏好对、对数据噪声更敏感 |
第二张表从评测口径看同一件事,这也是本文想留下的判据:三代方案「好不好」,量的其实是三个不同的东西。
| 代际 | 训练时的评价代理 | 你真正想量的东西 | 中间隔了几层 |
|---|---|---|---|
| SFT | 对标准答案的交叉熵 | 回答是否可用、是否被偏好 | 一层(标准答案 ≠ 偏好) |
| RLHF + PPO | 奖励模型给出的标量奖励 | 人类偏好 | 两层(奖励模型 ≈ 偏好,但不等于) |
| DPO | chosen/rejected 的 log-ratio 差 | 人类偏好 | 一层(直接对齐偏好对,但参考策略固定) |
量的问题:偏好数据从哪来、多少算够
偏好数据的成本几乎全在标注侧。InstructGPT 摘要里给了一个很有说服力的对照:在人类评测中,1.3B 参数的 InstructGPT 输出被优先于 175B 的 GPT-3,「despite having 100x fewer parameters」(参数少了 100 倍)。这说明对齐带来的收益可以压过参数规模的差距。但反过来说,这 1.3B 的效果是从大量标注示范与排序数据里换来的——数据量、标注一致性、标注者的偏好分布,都是这套方法的天花板,没有哪个算法能替你把它们变好。
一致性问题:不同标注者的「更好」不是一个东西
偏好对本质上是「某个标注者在某个时刻的判断」。同一对回答,换一批标注者、换一套标注说明,排序就可能翻转。SFT 时代这个问题被「标准答案」的外壳盖住了,到了 PPO/DPO 时代它直接暴露在损失里。工程上的常见做法是配一份写死的偏好准则文档,但准则写得越细,标注成本越高——这是个没有免费午餐的权衡。
停手的判据
什么条件下选哪一代,可以按这四条落地判断:
- 只缺指令跟随能力、有干净的正样本示范→ 先做 SFT,别急着上偏好对齐;
- 有稳定的偏好标注渠道、算力足够养四套模型→ RLHF + PPO 值得试,但要先准备好奖励模型的回归评测,防止它被钻空子;
- 偏好对已经攒好、不想养奖励模型、算力吃紧→ 直接上 DPO,重点盯 β 和参考策略版本;
- 偏好数据本身量小、标注者之间打架严重→ 先解决数据,任何一代方案都救不了——这时候加算法只会把噪声学得更牢。
判别口径记住一句:SFT 量的是「像不像标准答案」,PPO 量的是「奖励模型觉得好不好」,DPO 量的是「相对参考策略的偏好提升」。训练日志里的损失数值只有配上这一层的口径,才知道它到底在说什么。
偏好数据的整理模板与对齐损失对照表:把本文三代方案的数据字段、损失公式和 β 取值建议做成了一张对照表,连同偏好标注的格式样例一起放在资料包里,扫码即可获取:
附表 A:本文引用事实与出处对照表
| 事实 | 出处 | 本文位置 |
|---|---|---|
| 先用标注者示范做监督学习微调,再收集模型输出的排序数据、用 RLHF 进一步微调,得到 InstructGPT | OpenAI《Training language models to follow instructions with human feedback》arXiv:2203.02155 摘要页,2022-03-04 提交;核对日期 2026-10-08 | 第一、二、三章 |
| 人类评测中 1.3B 参数 InstructGPT 的输出被优先于 175B GPT-3,参数少 100 倍 | 同上,arXiv:2203.02155 摘要页 | 第五章 |
| RLHF 是「a complex and often unstable procedure」(先拟合奖励模型,再用强化学习最大化估计奖励且不偏离原模型太远);DPO 改用简单分类损失解标准 RLHF 问题,摘要原句「stable, performant, and computationally lightweight, eliminating the need for sampling from the LM during fine-tuning or performing significant hyperparameter tuning」 | Rafailov 等《Direct Preference Optimization: Your Language Model is Secretly a Reward Model》arXiv:2305.18290 摘要页,2023-05-29 提交、2024-07-29 修订;核对日期 2026-10-08 | 第三、四章 |
DPOTrainer目标是拉大偏好与被拒回答的对数概率差距(相对参考模型),「without requiring an explicit reward model」;ref_model不传则用训练前的模型状态 | Hugging Face TRL 官方文档DPOTrainer(huggingface.co/docs/trl);核对日期 2026-10-08 | 第四章 |
PPOTrainer中model(策略)、reward_model、value_model为必填,ref_model用于算 KL 散度(不传则复制策略模型) | Hugging Face TRL 官方文档PPOTrainer(huggingface.co/docs/trl);核对日期 2026-10-08 | 第三章 |
| PPO 是一族「采样数据 + 随机梯度上升优化代理目标」的策略梯度方法,兼具 TRPO 的部分优点且更易实现 | Schulman 等《Proximal Policy Optimization Algorithms》arXiv:1707.06347 摘要页,2017-07-20 提交、2017-08-28 修订;核对日期 2026-10-08 | 第三章 |
| DPO 损失 = -log sigmoid(β·log-ratio 差);策略与参考一致时 margin=0、损失为 ln2≈0.6931;β 越大对 margin 越敏感 | 本文作者本地实测(Python 3.13.12 / numpy 2.5.3),输出见第四章 | 第四章 |
| 偏好数据「量、一致性、偏好冲突」三代方案均未解决 | 本文基于上述论文与文档原文的归纳 | 第五章 |
写在最后:这篇用到的资料
写这篇文章时,把相关的官方文档和源码又翻了一遍,顺手也整理了几份配套的东西:
- 大模型学习路线图:从零基础到能自己动手做 Agent,按阶段说明每一步该学什么、哪些可以先跳过
- 《LangChain + LangGraph + MCP 智能体开发实战》视频课:7 个模块,从私有化部署、Embedding+RAG 到 MCP+Agent 全流程
- AI 大模型知识库(在线可查):Agent Skills 从入门到落地、Claude Skills 完全指南等专题,按目录浏览即可
- 640 套 AI 大模型行业报告 + 经典 PDF 书籍:看行业落地案例和别人怎么做的时候用得上
- 大模型零基础到精通教学视频:跟着敲一遍,比只读文档快得多
资料是我自己整理的,放在下面这个码上,扫码即可获取:
添加时备注「AI」,优先通过。
资料按「先路线、再动手、最后查漏」的顺序整理好了,建议先看学习路线那一份,照着它挑一条适合自己当前基础的路径再往下看。