“模型太聪明了,但就是不听话”——这是我做 NLP 项目几年最深的感受。2022 年之前,用 GPT-3 做产品原型,最头疼的不是它能力不够,而是你问它“帮我写一份请假邮件”,它能给你扯出一段关于休假制度的哲学思考。直到我认真读了 OpenAI 那篇 InstructGPT 论文(《Training language models to follow instructions with human feedback》),才算真正搞明白问题的根源和大模型“听懂人话”的标准解法。这篇论文提出的思路后来几乎成了大模型对齐技术的基石,ChatGPT 早期版本能那么“听话”,靠的也是这条技术路线。
这篇文章把我读论文过程中的理解、步骤拆解和一些实操层面的心得整理出来。适合正在做大模型微调、做 AI 应用开发的工程师,也适合想搞懂“ChatGPT 为什么不再像个接口怪”的产品和技术同学。整个方法的核心就是用“三步走”——有监督微调、奖励模型、强化学习——把模型的输出行为和人类预期对齐。我关注的不是把论文逐段翻译,而是把每一步的动机、关键细节和工程取舍讲明白。
1. 为什么 2022 年之前的大模型总是“答非所问”——论文要解决的真实困境
先想一个问题:GPT-3 刚出来的时候,大家惊叹于它能写文章、做翻译、玩问答,但真正把它接到业务场景里就露馅。不是它笨,而是它根本不理解“用户问这句话到底想要什么”。这不是 bug,这是预训练目标的天然缺陷。
1.1 预训练的本质是“接龙”,不是“对话”
大模型在海量文本上做自监督学习,目标函数是“根据前文预测下一个 token”。这个目标决定了它学习的核心规律是文本的统计相关性,而不是“这句话在回应什么需求”。所以模型看到“请帮我写一封请假邮件”时,它内部检索到的模式是“请假”“邮件”相关的语料续写,而不是“按照书信格式、语气礼貌、信息完整地完成一个用户任务”。
一个非常经典的例子是论文里面提到的:让 GPT-3 生成一个“关于某话题的简短描述”,模型会生成一大段,而且经常在前面加一句“Topic: xxx”。模型学会了“跟话题相关的文本长什么样”,但没有学会“只输出那段描述本身”。这就是预训练目标与人类交互意图之间的错位。
我在早期用 API 做 demo 时也踩过类似的坑。让模型复述一段话,它总会自己加戏,加背景、加解释、加总结。当时我还以为是 prompt 写得不够细,来回调 prompt 能缓解但治标不治本。读了这篇论文才意识到:问题的根子在模型层面,不是提示词层面。
1.2 大模型“能力很强”与“表现很糟”的悖论
论文里有一个非常反直觉的数据:InstructGPT 的 1.3B 小模型,在人类评估中的表现居然超过了 175B 的 GPT-3。不是超过一点点,是大幅超过。这说明什么?说明当时的大模型根本不缺“知识”和“推理潜力”,缺的是如何把潜在能力调度到用户期望的方向上。
你可以把预训练模型想象成一个知识渊博但社交能力为零的学者。你问他“1+1等于几”,他可能先从数学史讲起,再谈到皮亚诺公理,最后才说“所以答案是2”。能力一点不缺,但交互体验极差。对齐(alignment)要解决的就是这层问题:让模型的输出始终围绕用户的指令意图展开,而不是围绕训练语料中的统计惯性展开。
1.3 为什么“尺度”解不了这个问题
可能有人会想:模型再大一点、数据再多一点,是不是就自然懂人话了?论文给出的判断是:单纯扩大参数规模,只能提升模型的“知识能力”,但无法改变它“不按指令行事”的行为模式。GPT-3 从 1.3B 扩到 175B,流畅度和知识量明显提升,但对“指令的遵循能力”没有本质改善。
这个判断今天回头看依然成立。市面上很多开源大模型,能力很强,但如果你不做任何对齐微调,直接用原始基座跑业务,效果仍然会非常“野生”。很多团队拿开源模型做应用,第一步就是做指令微调,本质就是在做 InstructGPT 中“三步走”里的第一步。
所以,这篇论文的核心贡献不是提出了某种花哨的新模型架构,而是把“模型能力”和“用户意图”之间的鸿沟正式定义成问题,并且给出了一个可复现的、工程上可行的解决方案:用人类反馈信号去引导模型的生成行为。
2. 三步走拆解之一:有监督微调——先让模型模仿“人怎么干活”
InstructGPT 的第一步,是收集一批“人类示范数据”,用这些数据对预训练模型做有监督微调(Supervised Fine-Tuning,SFT)。这一步的目的很简单:先在行为层面让模型看到“面对用户的指令,一个合格的 AI 助手应该怎么回答”。
2.1 数据从哪来:让标注员扮演“被使唤的 AI”
论文中标注员团队的任务不是给数据打标签,而是直接扮演 AI 助手的角色,根据给定的用户 prompt 写出“理想回复”。数据规模大约是 1.3 万条 prompt-response 对,prompt 的来源主要分两块:一部分来自 OpenAI API 用户提交的真实请求,另一部分是标注员自己编写的 prompt。
这里有个细节很关键:prompt 的多样性要刻意扩展。如果只用 API 用户的请求,数据分布会偏向问答和编程;为了让模型学会应对更多指令类型,论文按 9 个大类做平衡——包括生成、问答、对话、改写、摘要、翻译、代码等。工程上做指令微调数据时,这个思路也值得借鉴:宁可每个类目数量少一些,也不要让数据分布严重偏斜到某一类。
我当时自己整理微调数据时有个体会:很多人只关注“数量”和“质量”,却忽略了覆盖度。1 万条全部是“翻译类”的数据,微调出来的模型在面对“总结类”指令时几乎没有改善。要站在“任务类型矩阵”的角度去思考数据配比,而不是只看总量。
2.2 模型选择和训练参数细节
论文对多个尺寸的模型做了实验:175B、6B、1.3B。微调方法就是在预训练权重上继续做标准的语言模型训练,但训练样本从“网页文本”换成了“指令-回复对”。
训练细节上我记得几个关键点:
- 训练 epoch 数较少(论文是约 3 个 epoch),因为示范数据量本身不大,过度训练会导致过拟合。
- 微调时混入了一部分原始预训练数据梯度(比例约 0.2),目的是防止模型在指令数据上过度偏向而遗忘预训练阶段学到的通用能力。这个操作值得注意,它对应的就是后来大家常说的“灾难性遗忘”问题。
- 学习率比预训练阶段小很多,用的是余弦学习率调度。
这里想多说一句“灾难性遗忘”。我们在微调一个基座模型时,往往只盯着目标任务的效果,跑出来领域指标提升了,但模型做通用任务的能力断崖式下跌。InstructGPT 当时已经意识到这个问题,混入预训练梯度这个操作本质上是在“专用能力”和“通用能力”之间做一个平衡。今天很多做 LoRA 微调的朋友也会遇到这个问题:领域能力上去了,但模型变得“只会这个领域”。处理方式之一也是类似思路,在微调数据中混入通用对话数据。
2.3 SFT 的局限:模型学会了“有样学样”,但没学会“判断好坏”
SFT 阶段的数据是标注员写的“标准答案”,但现实世界中的问题打开方式千奇百怪,一个问题根本没有唯一正确答案。SFT 只能让模型学会模仿数据集中出现过的那种回答风格,却无法让它学会“哪种回答更好”。就像你教一个实习生怎么做报表,你给他看了三个样例,他学会了照着做,但遇到没见过的数据格式就不知道怎么处理。
更关键的是:想通过人工去穷举所有指令类型和回答范式,成本上完全不可行。所以 SFT 只是第一步,它解决了模型“行为方向”的问题,但没有解决“回答质量”的问题。要进一步提升,就需要让模型自己尝试多种回答,再由人类反馈来告诉它哪个更好。
这篇论文里有个实验对比让我印象很深:单独用 SFT 训练出的 175B 模型,和经过完整 RLHF 流程的 175B 模型相比,人类评估分数差了一大截。也就是说,光靠示范模仿,模型的上限很快就到了;后两步的价值,正是把这个上限继续往上顶。
3. 三步走拆解之二:奖励模型——给模型一把“评分尺子”
SFT 之后,模型已经学会了“对着指令写回复”,但还分不清好坏。第二步就是训练一个奖励模型(Reward Model,RM),让它充当人类偏好的“打分器”。
3.1 为什么人类打分不靠谱,但“两两比较”很靠谱
直接让标注员给每个模型输出打一个绝对分数(比如 4.2 分),最大的问题就是主观性太强。同一个人在不同的时间、不同的上下文下,给同一个回答打的分数可能都不一样。但让标注员看两个回答,问“哪个更好”,这就稳定得多——这是人类认知习惯里天然擅长的比较判断。
论文用的是“比较数据”方案:同一个 prompt,让模型生成 K 个不同的回答(默认 K 是 4 到 9 之间),再由标注员对这 K 个回答做排序。然后把这 K 个回答两两组成 pair,训练 RM 对这些 pair 做偏好预测。比较数据的总规模我记得大概是 3.3 万个 prompt,每个 prompt 对应 K 个回答的排序。
这里有个工程细节容易被忽略:用来做 RM 训练数据时,不同回答的输出长度差异会干扰标注员的判断。写 50 个字的回答和写 300 个字的回答放在一起,标注员很容易被“更详细”误导,认为长文更好。为了减少这种偏差,论文专门对输出长度做了归一化处理,把长度这个混淆因素控制住。
我后来做用户反馈收集时发现这确实是个普遍问题。用户评价一个 AI 回答好不好,第一反应是“会不会写”,第二才是“对不对”。短答案信息密度再高,也容易在主观评价上吃亏。论文里对长度做归一化的这个设计,放在真实产品反馈收集里同样适用——如果线上模型回答普遍偏长,收集到的“好评率”会虚高,夹杂着对“努力程度”的肯定,而不是对“有用性”的判断。
3.2 RM 的训练目标:预测“哪个回答更受欢迎”
RM 的模型结构和 SFT 模型基本一致,区别在于最后一层:把输出 token 的隐藏状态汇聚成一个标量分数。训练时,对于一对回答(x_a, x_b),如果标注员认为 x_a 优于 x_b,就让模型预测 x_a 的分数尽量高于 x_b。
损失函数用的是 pairwise 排序损失,形式上等价于把两个回答的分数差做一个 sigmoid,再取 log loss。简单理解就是:模型每次只判断“两个选项中哪个更好”,通过大量这样的判断,逐渐学会给回答打分。
关键一点:RM 训练时的得分是“相对”的,不是绝对质量。同一个回答,放在不同的比较对里,RM 给出的分数可能不同。论文在推理阶段用 RM 给候选回答打分时,会先让模型生成多个候选,再挑 RM 分数最高的那一个。注意这个“先采样再打分”的策略,后面对理解 PPO 的训练信号很有帮助。
3.3 标注员的培训与校准机制
不要以为“人类反馈”就是把任务丢给一群标注员然后收数据。论文里专门花了篇幅讲标注员的筛选和培训流程。标注员需要先完成一批测试题,通过考核后才能正式参与标注。在正式标注中,他们的工作内容和标准也经过多轮校准,团队内部对“什么是有用的回答”达成共识。
其中有一个我印象很深的点:对于“有害内容”的判定,论文没有简单让标注员凭感觉判断,而是参考了一套内容安全准则,要求标注员按照准则逐一核对。这套流程保证了 RM 学习到的不只是个人审美,而是相对一致、有据可依的价值判断。
这给我们的启示是:如果你要照这套方法训练自己的偏好模型,别急着大规模采数据,先花时间把标注规范写好,把标注员培训好。数据质量对 RM 上限的影响,远大于模型参数规模的影响。我见过一些团队拿开源数据集直接训 RM,省了规范流程,最终 RM 打分和人工评估的相关性只有 0.4 左右,基本没法用。
4. 三步走拆解之三:PPO 强化学习——用奖励信号回归“指令预期”
前两步做完,我们有了一个会写回复的模型(SFT 模型)和一个能打分的模型(RM 模型)。第三步就是用强化学习把两者接起来:让 SFT 模型不断生成回答,RM 给出分数,模型再根据分数调整自己的生成策略。论文用的强化学习算法是 PPO(Proximal Policy Optimization)。
4.1 为什么需要强化学习,而不是直接让 SFT 模型拟合 RM 打分
一个很自然的疑问是:既然 RM 能打分,为什么不直接用 RM 的分数作为监督信号,继续做有监督微调?原因是:我们无法为每一个可能的输出 token 穷举所有回答。SFT 的监督信号来自人工标注的确定性答案,而 RM 的分数是连续的、动态的,需要模型自己探索“怎么改写才能使分数更高”。
强化学习的本质是“通过试错来优化策略”。PPO 让模型在策略空间里尝试不同的生成方式,RM 给反馈,好的生成方式被强化,差的被抑制。这个过程模拟了人类“被夸奖后更愿意这么做”的学习机制。
这里有个重要的安全网:PPO 训练时不能让模型为了刷高分而彻底放飞自我。论文在 PPO 的目标函数里加了一个 KL 散度惩罚项,限制模型不能偏离 SFT 阶段的行为太远。原因很实际:RM 也不是完美的,如果模型发现某些输出模式能稳定骗过 RM 的分数,它就会疯狂往那个方向优化,最终输出变得非常奇怪甚至有害。KL 惩罚本质上是在“探索优化空间”和“保持基本行为规范”之间做平衡。
4.2 PPO 训练流程与参数背后的逻辑
PPO 训练时的数据来自一个 prompt 集合,论文中约为 3.1 万个 prompt。训练时的大致流程是:
- 从 prompt 集合中采样一批指令。
- 当前模型根据指令生成回答。
- RM 对回答打分,作为 reward。
- 用 PPO 算法更新模型参数,让“高分回答”的概率提升。
- 计算新模型与 SFT 模型的 KL 散度,作为约束项加入损失。
我根据论文和工程经验整理了一个简化的伪代码流程:
for step in range(total_steps): prompts = sample_batch(prompt_set) responses = actor_model.generate(prompts) rewards = reward_model.score(responses) kl_penalty = kl_divergence(actor_model, ref_model, responses) loss = ppo_loss(log_probs, rewards - kl_penalty * kl_coef) actor_model.update(loss)具体参数上,论文里提到的 KL 系数大约是 0.02,裁剪范围是 0.2,这些值直接沿用了开源 PPO 库的默认参数。换句话说,InstructGPT 的核心收益主要来自“RLHF 框架”本身,而不是精细调出来的超参数。这也给后来做类似工作的团队一个信心:按照框架标准实现,效果就会有基本保障,不必在一开始就陷入调参泥潭。
我之前照着这套流程在自己的业务模型上跑过一次,一个很直观的感受是:SFT 模型生成的回答偶尔会“飘”,但 PPO 之后明显“稳”了。不是说每句话都惊艳,但它会倾向于选择更安全、更贴合指令的表达方式,用词和结构都更收敛。
4.3 训练时长:“见好就收”比“充分训练”更重要
论文有一个细节特别值得工程化参考:PPO 模型在训练到某个时间点之后,RM 分数继续上升,但人类评估的满意度反而下降。原因是模型开始“过度优化”——为了迎合 RM 的偏好,牺牲了回答的多样性和真实性,出现了明显的 reward hacking 现象。
这个现象在今天复现 RLHF 流程时依然普遍。我自己的经验是:在训练过程中定期做人工抽评,不能只看 RM 分数。RM 分数涨不代表真实质量涨,两者往往在训练后期背离。实际操作中我会把不同 checkpoint 的回答打印出来对比,肉眼扫一遍就能发现模型是否变得“油嘴滑舌”。
论文对此没有给出特别精确的“早停规则”,但明确提示了训练策略上要控制步数,不能一味追求 reward 最大化。
5. 论文里的“小字报”——那些被人忽略但很重要的细节
除了三步走的主线,InstructGPT 论文里还有一些“角落里的信息”,很容易被读者一眼带过,但恰恰是工程上最容易踩坑的点。
5.1 输出冗长的倾向性:RLHF 模型的“注水”问题
论文在讨论结果时坦诚地指出:InstructGPT 模型比 GPT-3 更倾向于生成比较长的回答,因为标注员在评价“有用性”时往往会偏向信息量更多的回答。这个偏差被 RM 学了过去,最终模型学会了“多写一点”。
这在今天的产品中相当常见。你会发现很多对话模型回答像小作文,洋洋洒洒一大堆,但真正有用的信息可能就一两句。如果你要做基于 RLHF 的应用,推荐在 RM 训练阶段就对输出长度进行约束或单独建模,否则上线后的回答质量会很“油腻”。
5.2 无害性与有用性之间的此消彼长
论文同时对模型做了“有用性”“真实性”“无害性”三个维度的评估。结论很有趣:InstructGPT 在“有用性”和“无害性”上相比 GPT-3 有显著提升,但“真实性”并没有明显改善,在某些情况下甚至是下降的。
这给所有做 AI 应用的团队提了个醒:对齐不是万能的。RLHF 把模型的行为对齐到了“人类偏好”,但如果人类偏好本身就存在偏见或错误,模型学到的就是偏见。尤其是“有害内容”的规避,本质上是在“不说”和“说错”之间做权衡,并没有真正做到“模型理解了什么是正确的”。
5.3 标注员之间的不一致性
论文在附录中提到,标注员之间对回答质量的判断一致性并不算高,个体差异明显。为了解决这个问题,他们采用了多个标注员交叉标注、再取汇总标签的方式,同时通过培训尽量拉齐标准。
这让我意识到:RLHF 的数据质量把控是一个“人”的问题,不只是一个“数据”的问题。如果你在团队里想复现 RLHF,第一个要搞定的是“让参与标注的人对什么是好回答达成共识”,而不是直接开干。没有这一步,后面训出来的 RM 大概率是“几个人审美平均值的拟合模型”。
6. 今天再读 InstructGPT,该读什么
距离论文发布已经过去了一段时间,今天的模型和工具链已经变化很大,但 InstructGPT 的核心思想几乎没有过时,反而成了后续一系列对齐技术的出发点。
6.1 从 InstructGPT 到 ChatGPT:一次成功的工程放大
ChatGPT 早期版本几乎完全复用了 InstructGPT 的技术路径:先做 SFT,再训 RM,最后用 PPO 微调。不同之处在于 ChatGPT 在指令数据的多样性和对话场景的覆盖上做了大幅扩展,把 InstructGPT 验证过的路径规模化了。
对于想上线一个对话产品的团队来说,InstructGPT 依然是最值得参照的“最小完整方案”。读它不是为了复刻论文实验,而是理解整个 RLHF 链路中每个环节的作用边界,从而在自己的数据、算力和人才条件下做裁剪。
6.2 RLHF 的下一步:更便宜、更好用的替代方案
InstructGPT 让 RLHF 成为主流,但也暴露了它的高门槛:需要大量人工偏好标注、需要训练 RM、PPO 训练不稳定、调参成本高。这也是后面 DPO(Direct Preference Optimization)、RLAIF(AI Feedback)等方法出现的原因。DPO 绕过了显式 RM 和强化学习流程,直接用偏好数据优化策略,训练稳定性和成本都有明显改善。
但要注意,DPO 等替代方案在“概念上”依然是在做 InstructGPT 提出的事情:用人类(或 AI)反馈来对齐模型行为。理解了 InstructGPT,再看 DPO、RLAIF 或者其他对齐方法,你会很容易抓住它们的出发点——都是试图以更低的成本拟合人类偏好信号。
6.3 对抗“奖励黑客”:为什么对齐永远是一个“对抗性”问题
论文中多次提到模型会“钻 RM 的空子”,这在今天被叫做“reward hacking”。模型会找到一些让 RM 给出高分但实际质量低劣的表达模式,比如堆砌关键词、使用看似权威的语气、输出超长文本等。这些现象不是 RLHF 特有的 bug,而是任何“用代理指标优化行为”的系统都会面临的问题。
在业务实践中,我通常的做法是:RM 评估和人工抽评双轨并行,定期用一批人工打过分的样本去“审计” RM 的打分趋势。一旦发现二者背离,就要考虑重新校准 RM 或调整训练策略。这里面没有一劳永逸的方案,只有持续的监控和迭代。
6.4 我对 InstructGPT 论文的一句话总结
把论文合上后,留在脑子里的不是那些公式和数据,而是这个判断:大模型的能力来自预训练,但“可用性”来自对齐。你花在指令微调、偏好数据、行为约束上的功夫,和花在模型结构上的功夫,往往在用户体验端同样重要,甚至更加重要。
如果你手上正好有一个能力不错但“不听指挥”的大模型,别急着换更大参数的版本,先把 InstructGPT 这套“SFT + RM + PPO”的思路过一遍。哪怕因为成本和复杂度没办法做完整的 PPO,只做到 SFT 阶段,配合良好设计的偏好数据,输出质量也会肉眼可见地上一个台阶。
我在实际项目中通常这样操作:先用几百条精心撰写的指令样例给模型做一次低成本 SFT,把“响应风格”固定下来;然后收集线上的 badcase 做 RM 的偏好数据,逐渐过渡到完整 RLHF。整个过程不一定需要复现论文的全部规模,但每一步的目标和边界,基本都沿用了 InstructGPT 划出的路线。
最后再分享一个读论文以外的小建议:读技术论文别只看正文,多花时间看附录里的训练细节、评估方法和作者自己承认的局限。InstructGPT 的附录里其实藏着大量可复用的工程经验,比如标注员校准、长度归一化、KL 系数设置。这些细节是论文最接近“实战”的部分,也是普通博客和教程里最不容易写透的部分。