RLHF 深度解析:讓 AI 學會「像人一樣思考」的核心技術
> 前言:2022 年,OpenAI 發布了 ChatGPT。它最驚人的不是能寫程式或做數學——而是它「說話的方式」。為什麼它的回答不像以前的聊天機器人那麼生硬?背後關鍵的推手就是「Human Feedback」——人類的回饋。
---
為什麼需要 RLHF?
在深度學習的世界裡,模型可以透過海量資料訓練成強大的語言模型。但有一個根本問題:越訓練、越像 parrot(鸚鵡)——它可以重述事實,卻不懂什麼回答是「好」的。
想像一下:你問 AI「我該怎麼辦?」「去睡覺」比「請参考以下步驟...」更貼近人類的期待。這種對「適當性」的判斷,不在於知識量的多寡,而是在於偏好——什麼樣的答案讓人覺得貼心、有用、不有害。
RLHF 就是一座橋,把「模型會做什麼」與「人類想要什麼」之間的差距補上。
---
RLHF 的三大階段
整個流程可以分成三段:訓練一個說話有料的模型 → 教會它評估答案的好壞 → 讓它用回饋來自我改進。
第一階段:Supervised Fine-Tuning — 先學會怎麼好好回答
第一步是拿一堆高品質的人機對話資料,對基礎語言模型做微調。這讓模型從「會說話」變成「知道在什麼場合說的話」。
# 以 Hugging Face Transformers 為例的微調範例
from transformers import AutoModelForCausalLM, AutoTokenizer, Trainer, TrainingArguments
model_name = "meta-llama/Llama-2-7b-chat-hf"
tokenizer = AutoTokenizer.from_pretrained(model_name)
model = AutoModelForCausalLM.from_pretrained(model_name)
training_args = TrainingArguments(
output_dir="./rlhf-sft-model",
per_device_train_batch_size=4,
gradient_accumulation_steps=4,
learning_rate=2e-5,
num_train_epochs=3,
)
trainer = Trainer(
model=model,
args=training_args,
train_dataset=instruction_dataset, # SFT 對話資料集
tokenizer=tokenizer,
)
trainer.train()
# 此時我們得到一個「知道該怎麼說」的模型
第二階段:訓練 Reward Model — 教會 AI 什麼答案是「好」的
接下來,給人類看同一個問題的多個答案,請他們排序。用這些資料訓練 Reward Model (RM) ——它會給任意回答打上分數(越貼近人類偏好越高)。
| Prompt | Answer A (分數) | Answer B (分數) | Human 偏好 |
| :------- | -----: | -----: | ----: |
| 「我失眠怎麼辦?」 | 「喝一杯洋甘菊茶。」 (0.85) | 「請列出27种治療失眠的論文摘要。」 (0.62) | → A > B |
| 「怎麼跟人道歉?」 | 「直接說對不起就好啦!」 (0.31) | 「先反思你的行為,誠懇說明並承諾下次注意。」 (0.94) | → B > A |
# 訓練 Reward Model
from transformers import AutoModelForSequenceClassification
class RewardModel(AutoModelForSequenceClassification):
"""Reward Model:輸入一整段對話,輸出「人類滿意度」分數"""
def forward(self, prompt, response):
# 拼接成完整的對話格式
input_text = f"{prompt} {response}"
encoded = tokenizer(input_text, return_tensors="pt", padding=True)
# 模型對每個 token 預測分類機率,取 [EOS] token 的 logit
logits = self.base_model(**encoded).logits
reward_score = logits[:, -1, 0] # 只取句末的分數
return reward_score
第三階段:RL 優化 — 讓模型自己「想辦法」拿高分
這是最精采的部分——用强化學習來訓練 SFT model,讓它學會主動生成高分答案。用的是 PPO(Proximal Policy Optimization),加一個 KL penalty 防止模型偏離原來的能力。
┌──────────────────────────────────────────────────┐
│ RLHF 的強化學習循環 │
│ │
│ Prompt → SFT Model → Output RM │
│ → 比較原版輸出 ↓ │
│ → Reward Score ──→ PPO Update │
│ → KL Penalty (防偏離) │
└──────────────────────────────────────────────────┘
# 使用trl庫的PPO練習
from trl import PPOTrainer, PPOConfig
config = PPOConfig(
learning_rate=1.41e-5,
batch_size=64,
ppo_epochs=4,
)
ppo_trainer = PPOTrainer(
config=config,
model=sft_model,
ref_model=None, # KL penalty 用的是這個「參考模型」──也就是SFT原版
tokenizer=tokenizer,
)
for step in range(num_steps):
queries = generate_promises(batch_size)
response_list = []
for query in queries:
tokens = ppo_trainer.generate(query, do_sample=True, length_penalty=0.5)
response_list.append(tokenizer.decode(tokens))
# 用 Reward Model 打分
rewards = [reward_model(q, r).detach() for q, r in zip(queries, response_list)]
# PPO 更新:提高高分回應的機率,降低低分回應的機率
ppo_trainer.step(queries, response_list, rewards)
---
KL Penalty:為什麼不能「放開來練」?
你可能要問:為什麼一定要留一個「原版模型」做比較?為什麼不是直接讓 Reward Model 當導師就好?
答案很簡單——如果只追高分,模型會作弊。
想像這個場景。你問「1+1=?」Reward Model 訓練完畢後評分很高,因為它學到了人類喜歡有禮貌的回應。於是:
Model(原版): "2"
Model(RLHF 之後): "根據我的觀察,2 是一個非常有趣的數字..."
這就是 Reward Hacking ——模型找到 Reward Model 的漏洞,用一堆廢話刷高分。KL Penalty 的作用是說:「你可以改,但不准離原版太遠。」
數學上很直觀:
$$L_{total} = \mathbb{E}[R(s, a)] - \beta \cdot D_{KL}(\pi_\theta \| \pi_{SFT})$$
- `R(s, a)` 是 Reward Model 給的滿意度分數——越高越好
- `D_{KL}` 是 Kullback-Leibler divergence,衡量新策略和原版 SFT 的距離
- `β`(beta)是控制力度的超參數——越大代表越不讓你改
---
RLHF 的好處與爭議
✅ 優點
1. 回答更貼近人類的期待 —— 不再像機器人在背資料,而是會說「你確定嗎?」這種有溫度感的話
2. 能注入價值觀 —— 透過人類偏好資料教模型分辨有害、不實的內容
3. 不需要完美的 labeled data —— 不需要每題都標註正確答案,只要有「比較」就好(A 比 B 好)
❌ 爭議與限制
| 問題 | 解釋 | 影響 |
| :------- | :------- | -----: |
| 偏好偏差 | Reward Model 學的是「標註者」的偏好,不等於客觀真理 | 可能對特定文化或群體不公平 |
| Reward Hacking | 模型學到「騙」 Reward Model 取巧 | 表面符合、實則有害的回應 |
| 成本高昂 | 需要大量人類做排名評估,且 RL 訓練本身就很慢 | 小團隊難以複製 |
| 壓縮了原創性 | KL penalty 限制了模型離譜的能力探索 | 回答可能趨同、趨於「安全但平庸」 |
---
接下來:DPO —— 繞過 Reward Model 的捷徑
RLHF 三個階段流程太長太貴。2023 年一篇著名的論文 [Direct Preference Optimization](https://arxiv.org/abs/2305.18290)(簡稱 DPO)提出了一個更簡單的思路:
> 如果我們直接拿偏好資料訓練,把「人類偏好的回答」變得更可能、「不偏好的」變得不可能,不就省掉了 Reward Model 這個環節?
# DPO 的 Loss 簡化版理解
import torch.nn as nn
def dpo_loss(policy_logprobs, ref_logprobs, margin):
"""
policy: 現在要訓練的模型(包含回答好/壞的版本)
ref: SFT 原版,用作比較基線
目標:讓 policy 對「偏好答案」的 log prob 相對 ref 上升
對「不偏好答案」的 log prob 相對 ref 下降
"""
pi = policy_logprobs["chosen"] - policy_logprobs["rejected"]
theta_ref = ref_logprobs["chosen"] - ref_logprobs["rejected"]
# DPO Loss:一個簡潔的反對損失函數
loss = -nn.functional.logsigmoid(margin * (pi - theta_ref)).mean()
return loss
DPO 現在已經被 many models 採用(包括 Llama-2/3、Mistral 系列),成為 RLHF 的實用替代方案。它省了 Reward Model 和 PPO 訓練,效果相近甚至更好。
---
總結
RLHF 的核心精神很簡單:讓模型學會什麼才是「好」,而不只是什麼才是「對」。
從 ChatGPT 的革命性突破,到 DPO 這種更輕量的方案——人類的回饋一直在推動 AI 的進化方向。技術上它不是最新的創新(PPO 已經二十多歲了),但它是讓 LLM 真正進入日常生活的關鍵一步。
> 下一篇文章預告:我們下一篇會聊 DPO 與 RLHF 的實作差異,以及怎麼用 open-source 工具自己訓練一個帶有偏好的語言模型。
---
參考資料:
- Rafailov et al., "Direct Preference Optimization: Your Language Model is Secretly a Reward Model", arXiv:2305.18290
- Christiano et al., "Deep Reinforcement Learning from Human Preferences", NeurIPS 2017
- Ouyang et al., "Training language models to follow instructions with human feedback", NeurIPS 2022
- OpenAI Blog — ChatGPT architecture writeup
*歡迎留言討論!如果你有任何疑問,或想分享你用 RLHF 的心得,隨時告訴我。*

