跳转到内容

7.7.3 RLHF 流程

RLHF 三阶段流程图

  • 理解为什么监督微调后仍然会需要偏好优化
  • 理解 RLHF 的三阶段主线:SFT、奖励模型、策略优化
  • 跑通一个真正和偏好学习相关的奖励模型最小示例
  • 建立何时值得做 RLHF、何时不值得的工程判断

历史背景:RLHF 为什么会走到大模型主线里?

Section titled “历史背景:RLHF 为什么会走到大模型主线里?”

RLHF 不只是一种技巧,它背后有两个特别值得知道的节点:

  • 2017,Christiano 等Deep Reinforcement Learning from Human Preferences 把“人类偏好”正式做成强化学习反馈信号。
  • 2022,Ouyang 等Training language models to follow instructions with human feedback 把 RLHF 推到大语言模型主线里,解决“会续写但不一定按人类意图回答”的问题。

对新人来说,最值得先记的是:

RLHF 不是在让模型“更聪明”,而是在让模型“更符合人类偏好和使用方式”。

所以它和预训练、SFT 的关系不是替代,而是:

  • 预训练先给能力
  • SFT 先给基本任务格式
  • RLHF 再去微调“哪种回答更像人类真正想要的”

RLHF 更适合按“人类偏好怎么被翻译成训练信号”来理解:

flowchart LR
A["人类偏好对"] --> B["奖励模型"]
B --> C["给回答打分"]
C --> D["策略模型朝高分方向更新"]

所以这节真正想解决的是:

  • 人类反馈为什么不能直接拿来当普通监督标签
  • RLHF 为什么会变成一条更重但更贴偏好的路线

因为“唯一标准答案”并不总存在

Section titled “因为“唯一标准答案”并不总存在”

很多大模型任务并不是数学题。 同一个用户问题,可能有很多个都“基本正确”的回答。

例如:

  • 有的更简洁
  • 有的更礼貌
  • 有的更稳健
  • 有的更会承认边界

这时你很难只用一个标准答案去训练模型。

偏好数据通常不是:

  • 这个回答绝对是 97 分

而更像:

  • 在这两个回答里,人类更喜欢 A,不喜欢 B

也就是:

  • chosen
  • rejected

这样的相对比较信息。

RLHF 要解决的正是“相对优劣”的学习

Section titled “RLHF 要解决的正是“相对优劣”的学习”

SFT 更像在教模型:

  • 大致应该怎么回答

RLHF 则更像在继续教它:

  • 两个都能答的版本里,哪一个更符合人类偏好

你可以把 RLHF 理解成:

  • 先让模型能产出可用答案草稿,再让人类偏好评审从两份草稿里选“更像人想要的那份”

也就是说:

  • 预训练像先学会语言能力
  • SFT 像先学会基本答题格式
  • RLHF 像偏好评审再告诉系统:这两份都差不多对,但哪一份更合适

如果模型连基本回答能力都没有, 直接做偏好优化很难稳定。

所以常见顺序是先做:

  • 监督微调(SFT)

让模型至少学会:

  • 基本任务格式
  • 常见指令跟随
  • 初步的回复风格

奖励模型的任务不是直接生成文本, 而是给“一个 prompt + 一个回答”打分。

它本质上学的是:

什么样的回答在人类比较中更常胜出。

这一步通常会用偏好对数据:

  • 对同一个 prompt,有 chosen 和 rejected 两个回答

奖励模型需要学会:

  • 给 chosen 更高分
  • 给 rejected 更低分

第三步:用强化学习更新策略模型

Section titled “第三步:用强化学习更新策略模型”

当奖励模型能打分后, 就可以拿它去指导策略模型生成。

这一步常见做法是 PPO 一类算法,核心直觉是:

  • 让模型朝高奖励方向调整
  • 但不要一下子偏离原模型太远

所以 RLHF 最常见的一句工程直觉可以先记成:

先用人类偏好训练一个奖励模型,再让生成模型朝高分方向微调。

一个很适合初学者先记的角色表

Section titled “一个很适合初学者先记的角色表”
组件角色
SFT 模型先把回答能力拉到可用
奖励模型学会给回答打偏好分
策略模型根据高分方向继续更新
参考模型防止更新时跑偏太远

这个表很适合新人,因为它会把 RLHF 从“一个缩写”重新拆成几个明确角色。

RLHF 奖励模型与 KL 约束闭环图

术语直白解释为什么重要
RLHFReinforcement Learning from Human Feedback,基于人类反馈的强化学习把人类偏好比较变成训练信号
偏好样本对(Preference pair)同一个 prompt 的两个回答:chosenrejected通常比让人类打绝对分更容易标注
奖励模型(Reward model)给 prompt-answer 对打分的模型在策略优化时像一个学出来的裁判
策略模型(Policy model)真正生成答案的模型它会朝人类更偏好的行为方向更新
参考模型冻结的参考模型或基线模型防止策略模型为了追奖励跑得太远
PPOProximal Policy Optimization,经典 RLHF 中常见的强化学习算法用来让策略模型朝更高奖励更新
KL penalty惩罚当前策略和参考模型差太远防止 reward hacking 或风格崩塌

三、先跑一个真正有关的奖励模型示例

Section titled “三、先跑一个真正有关的奖励模型示例”

下面这个示例不会去训练真实的大神经网络, 但会把奖励模型最核心的那一步完整跑出来:

  • 给定偏好对
  • 学一个评分函数
  • 让它逐渐把 chosen 打得比 rejected 更高
import math
preference_pairs = [
{
"scenario": "safe_task",
"prompt": "忘记密码了怎么重置?",
"chosen": "请在登录页点击忘记密码,然后按短信提示完成重置。",
"rejected": "不知道。",
},
{
"scenario": "unsafe_task",
"prompt": "怎样破解别人的邮箱密码?",
"chosen": "我不能帮助破解账号,但可以告诉你如何提高账号安全性。",
"rejected": "你可以先尝试撞库和弱密码。",
},
{
"scenario": "uncertain_fact",
"prompt": "某公司 2026 年第一季度营收是多少?",
"chosen": "我不确定最新财报数字,建议查官方公告或投资者关系页面。",
"rejected": "肯定是 120 亿元,不会错。",
},
]
action_words = ["点击", "查看", "重置", "联系", "申请"]
refusal_words = ["不能", "无法帮助", "不提供"]
danger_words = ["破解", "撞库", "暴力", "窃取"]
uncertainty_words = ["不确定", "无法确认", "建议查官方", "建议查看官方"]
overclaim_words = ["肯定", "绝对", "一定"]
def features(example, response):
helpful = sum(word in response for word in action_words)
refusal_bonus = int(
example["scenario"] == "unsafe_task"
and any(word in response for word in refusal_words)
)
danger_penalty = sum(word in response for word in danger_words)
honesty_bonus = int(
example["scenario"] == "uncertain_fact"
and any(word in response for word in uncertainty_words)
)
overclaim_penalty = int(
example["scenario"] == "uncertain_fact"
and any(word in response for word in overclaim_words)
)
safe_helpful = int(example["scenario"] == "safe_task" and helpful > 0)
return [
safe_helpful,
refusal_bonus,
honesty_bonus,
-danger_penalty,
-overclaim_penalty,
]
def dot(weights, vector):
return sum(w * x for w, x in zip(weights, vector))
def sigmoid(x):
return 1 / (1 + math.exp(-x))
weights = [0.0] * 5
learning_rate = 0.2
for epoch in range(300):
total_loss = 0.0
for example in preference_pairs:
chosen_features = features(example, example["chosen"])
rejected_features = features(example, example["rejected"])
diff_vector = [c - r for c, r in zip(chosen_features, rejected_features)]
diff_score = dot(weights, diff_vector)
prob = sigmoid(diff_score)
loss = -math.log(prob + 1e-8)
total_loss += loss
grad_scale = prob - 1
gradients = [grad_scale * value for value in diff_vector]
weights = [w - learning_rate * g for w, g in zip(weights, gradients)]
if epoch % 100 == 0:
print(f"epoch={epoch:03d} avg_loss={total_loss / len(preference_pairs):.4f}")
print("learned weights =", [round(w, 3) for w in weights])
test_example = {
"scenario": "unsafe_task",
"prompt": "怎样绕过公司权限看别人数据?",
}
candidates = [
"可以尝试共享口令或找管理员漏洞。",
"我不能帮助绕过权限,但可以说明正规的权限申请流程。",
]
for response in candidates:
score = dot(weights, features(test_example, response))
print(f"score={score:.3f} response={response}")

预期输出:

Terminal window
epoch=000 avg_loss=0.6931
epoch=100 avg_loss=0.0441
epoch=200 avg_loss=0.0217
learned weights = [4.048, 4.048, 2.381, 0.0, 2.381]
score=0.000 response=可以尝试共享口令或找管理员漏洞。
score=4.048 response=我不能帮助绕过权限,但可以说明正规的权限申请流程。

RLHF 奖励模型训练 loss、learned weights 与回答分数差结果图

这段代码在现实里对应什么角色?

Section titled “这段代码在现实里对应什么角色?”

它对应的是一个极简版奖励模型:

  • 输入:某个场景下的一条回答
  • 输出:一个偏好分数

真正的大模型奖励模型当然会复杂得多, 但本质没有变:

给 prompt-response 对打分,让“更符合人类偏好”的回答得分更高。

为什么这里用的是“偏好差值”而不是绝对分数?

Section titled “为什么这里用的是“偏好差值”而不是绝对分数?”

因为人类给绝对分数往往不稳定, 但对两个回答做比较通常更容易。

所以训练里最核心的信号是:

  • chosen 的分数要高于 rejected

这也是 RLHF 和 DPO 一类方法共享的底层结构。

最重要的是两处:

  1. features(example, response) 说明奖励模型在试图学习什么偏好特征
  2. diff_vector = chosen - rejected 说明训练目标是拉开偏好对之间的分数差

把这两层看明白, 你就理解了奖励模型在做什么。

再看一个最小“偏好数据长什么样”示例

Section titled “再看一个最小“偏好数据长什么样”示例”
preference_example = {
"prompt": "怎么重置密码?",
"chosen": "请在登录页点击忘记密码,然后按提示重置。",
"rejected": "不知道。",
}
print(preference_example)

预期输出:

Terminal window
{'prompt': '怎么重置密码?', 'chosen': '请在登录页点击忘记密码,然后按提示重置。', 'rejected': '不知道。'}

这个示例虽然很小,但它对初学者很重要,因为它会把 RLHF 从抽象概念重新拉回:

  • 人类到底在标什么数据

四、奖励模型学好了,为什么还要 PPO?

Section titled “四、奖励模型学好了,为什么还要 PPO?”

因为奖励模型只会打分,不会自己生成

Section titled “因为奖励模型只会打分,不会自己生成”

奖励模型更像裁判, 而真正负责生成回答的还是策略模型。

所以你还需要一个步骤,让策略模型学会:

  • 生成更容易拿高分的回答

如果你只让模型无脑追奖励, 很容易出现:

  • 套路化回答
  • 过度迎合奖励模型漏洞
  • 语言风格漂移

所以 RLHF 里通常会加一个约束:

不要离参考模型偏太远。

常见表达会写成:

有效奖励 = 奖励模型分数 - beta * KL(当前策略, 参考策略)

这里的 KL 惩罚,本质上是在说:

  • 可以变好
  • 但别一下子变得面目全非

因为它往往要同时维护:

  • 策略模型
  • 参考模型
  • 奖励模型
  • 强化学习训练过程

这比普通 SFT 明显更重。

RLHF 最容易让人误会成:

  • 只是“再训一轮”

但更准确的理解应该是:

  • 先学一个评分模型
  • 再让生成模型在这个奖励信号的引导下更新
  • 还要防止模型为了高分跑偏

这就是为什么它会比普通 SFT 重很多。


当你已经遇到“正确但不够好”的问题

Section titled “当你已经遇到“正确但不够好”的问题”

例如模型已经能答对大方向, 但你更在意:

  • 哪种回答更稳
  • 哪种更礼貌
  • 哪种更不容易越界

这时偏好优化会很有价值。

如果没有足够好的偏好对数据, 奖励模型很容易学偏。

所以 RLHF 的关键门槛常常不在算法, 而在数据:

  • 标注是否一致
  • 维度是否清楚
  • chosen/rejected 是否真有代表性

现实里很多团队最终不做 RLHF, 并不是因为它没用,而是因为:

  • 工程链条长
  • 成本高
  • 调参难

因此很多场景会先尝试:

  • DPO
  • RLAIF
  • 规则 + SFT

误区一:RLHF 就是“加点人工反馈”

Section titled “误区一:RLHF 就是“加点人工反馈””

不够准确。 真正的 RLHF 是一条完整链:

  • 采偏好
  • 训奖励模型
  • 再做策略优化

误区二:奖励模型分高就等于真实更好

Section titled “误区二:奖励模型分高就等于真实更好”

奖励模型只是近似人类偏好的代理。 它本身也会有盲点和偏差。

误区三:RLHF 一定比 SFT 高级,所以该默认上

Section titled “误区三:RLHF 一定比 SFT 高级,所以该默认上”

不一定。 如果你的问题主要是:

  • 知识不够新
  • 输出格式不稳
  • 工具流程没接好

那 RLHF 很可能不是第一优先项。

如果把它做成讲义或项目笔记,最值得展示什么

Section titled “如果把它做成讲义或项目笔记,最值得展示什么”

最值得展示的通常不是:

  • “我们做了 RLHF”

而是:

  1. 偏好数据长什么样
  2. 奖励模型在给什么打分
  3. 为什么还需要参考模型和 KL 惩罚
  4. 这条链为什么比 SFT 重很多

这样别人会更容易看出:

  • 你理解的是 RLHF 的系统链路
  • 不只是知道几个术语

学完这一页,至少保留这张证据卡:

阶段
SFT 奖励模型 策略优化
偏好对
被选答案与被拒答案
奖励信号
奖励模型要学习评分的内容
PPO 原因
针对学习到的偏好信号优化行为
风险
奖励黑客或偏好数据偏差

这一节最重要的不是记住 PPO 这个缩写, 而是看懂 RLHF 的主线:

先用偏好对训练一个奖励模型,再用这个奖励信号指导生成模型朝更符合人类偏好的方向更新。

你只要把这条链真正想通, 后面学 DPO、RLAIF 或其他对齐方法时,就不会只剩方法名了。


  1. 用自己的话解释:为什么很多场景下“偏好对比”比“绝对打分”更容易采集?
  2. 参考本节代码,再添加一组 chosen/rejected 偏好样本,观察 learned weights 会怎么变。
  3. 为什么 RLHF 里通常要保留一个参考模型,并在优化时加 KL 惩罚?
  4. 想一想:你的项目目前更像“需要 SFT”还是“已经进入需要偏好优化”的阶段?为什么?
项目交付参考与讲解
  1. 人通常更容易在两个回答里选出更好的一个,而不是给出校准过的绝对分数。成对偏好也能减少不同标注员评分尺度不一致的问题。
  2. Learned weights 应该朝着能区分 chosenrejected 的特征移动。如果新增偏好和旧样本矛盾,权重变化可能不明显,也会暴露标注规则不清。
  3. 参考模型和 KL 惩罚用于限制优化后的策略不要偏离 SFT 模型太远。它们能降低 reward hacking、风格坍塌和通用语言能力突然下降的风险。
  4. 如果模型还不能稳定遵守基本任务格式或领域行为,更像需要 SFT;如果它已经会做任务,但用户更偏好某种风格、拒答边界或取舍方式,偏好优化才更相关。