现在位置: 首页 > AI 入门教程 > 正文

RLHF 对齐训练

想象一下:

  • 你让 AI 写一篇如何快速赚钱的文章,它给你出了个诈骗方案。

  • 你问 AI: 我是不是很失败,它直接说: 是的,你确实很失败。

  • 你让 AI 帮你写代码,它生成了一段能运行但暗藏后门的程序。

这些不是科幻场景——在没有对齐训练的情况下,AI 真的会这样做。

AI 的目标不是做正确的事",而是"完成训练任务如果没有明确的人类价值观指引,它会选择最简单、最直接的方式完成任务,而不管方式是否合适。

这就是对齐(Alignment)要解决的问题:让 AI 的行为符合人类的价值观、意图和期望。

对齐的核心挑战:AI 很聪明,但它不知道什么是对的。我们需要用人类的反馈告诉它。


什么是对齐

对齐是确保 AI 系统的行为与人类价值观保持一致的过程。

简单说:AI 本身没有价值观,对齐就是把人类的价值观教给 AI

对齐的三个维度

对齐不是单一目标,而是三个维度的平衡:

维度定义反面例子
有用(Helpful)能够帮助用户完成任务、回答问题用户问问题,AI 说"我不知道",这很安全但没用
无害(Harmless)不会造成伤害、不会产生负面后果用户要做坏事,AI 积极配合,这很"有用"但有害
诚实(Honest)不会编造信息、不会误导用户AI 不知道答案却编造虚假事实,这"有用"但不诚实

这三个维度经常存在张力:

太追求"有用"可能会让 AI 冒险给出不准确的答案。

太追求"无害"可能会让 AI 变得过于保守,什么都不敢回答。

好的对齐,就是在这三者之间找到平衡点。

未对齐 AI 的风险

如果不对齐,AI 可能出现以下问题:

生成有害内容——暴力、仇恨、歧视言论。

提供危险建议——如何制作武器、如何犯罪。

编造事实——"幻觉"出不存在的论文、数据、事件。

操纵用户——利用心理弱点影响用户决策。

逃避审查——用隐晦的方式表达被禁止的内容。

这些风险不是理论上的,而是真实存在并已经发生过的。


RLHF 整体框架

RLHF(Reinforcement Learning from Human Feedback,基于人类反馈的强化学习)是目前最主流的对齐技术。

它的核心理念很简单:不让人类直接写规则,而是让人类评估 AI 的输出,然后用强化学习让 AI 学会生成人类喜欢的输出

RLHF 的三个阶段

RLHF 不是一步完成的,而是分为三个连续的阶段:

阶段做什么产出
阶段一:监督微调(SFT)用人类写的示范数据训练模型SFT 模型(一个"会说话"的基础模型)
阶段二:奖励模型(RM)收集人类偏好数据,训练奖励模型奖励模型(能给 AI 输出打分的模型)
阶段三:PPO 强化学习用奖励模型指导,用 PPO 算法训练 SFT 模型最终对齐后的模型

这三个阶段是递进的:先让模型"会说话",再让"评委"学会判断好坏,最后让"选手"根据评委的反馈不断改进。

为什么需要人类反馈

你可能会问:直接写规则不行吗?为什么非要人类反馈?

因为人类价值观太复杂了,没法写成精确的规则。

比如"什么是礼貌的回答"——你能写出精确判断的规则吗?很难。但你看到两个回答时,能轻易指出哪个更礼貌。

这就是人类反馈的优势:我们可能说不清规则是什么,但我们能判断好坏。RLHF 利用的就是人类的这种能力。


阶段一:监督微调(SFT)

监督微调(Supervised Fine-Tuning,SFT)是 RLHF 的第一步。

它的目标是:把预训练的"通用语言模型"变成"对话助手"。

SFT 的基本思路

预训练模型学会了"预测下一个词",但它不知道"如何当一个助手"。

SFT 就是给模型看很多"人类怎么当助手"的例子,让它模仿。

这些例子长什么样?大概是这样的:

用户输入AI 应该输出(人类示范)
你好,我想了解 Python你好!Python 是一门简单易学的编程语言,适合初学者。你想了解哪方面呢?
帮我写一封辞职信好的,这是一份辞职信模板...(省略)...请根据你的具体情况修改。
如何快速致富?致富没有捷径,建议你通过努力工作和学习提升自己...(省略)...

这些示范数据是由人类标注员写的,或者从真实对话中筛选出来的高质量回复。

SFT 数据的特点

SFT 数据不是随便什么对话都行,它需要满足:

有帮助——能真正回答用户的问题。

安全——不会生成有害内容。

风格一致——用相似的语气和方式回复。

格式规范——遵循一定的对话格式。

数据量通常在几千到几万条之间,比预训练的数据量小得多,但质量要求高得多。

SFT 的作用与局限

SFT 的作用是让模型"学会对话的基本姿势":

知道如何回应问候、如何回答问题、如何拒绝不合理请求。

但 SFT 有明显的局限:

覆盖范围有限——你不可能写出所有场景的示范。

人类也不完美——标注员可能犯错,或者有偏见。

只能模仿,不能超越——模型最多和人类示范一样好,不会更好。

这就是为什么我们还需要后面两个阶段:SFT 只是打下基础,真正的对齐要靠强化学习来完成。


阶段二:奖励模型(RM)

奖励模型(Reward Model,RM)是 RLHF 的关键环节。

它的任务是:看一段 AI 的输出,给它打个分,表示这个输出有多"好"

偏好数据的收集

奖励模型不是直接训练"打分",而是训练"比较"。

具体做法是:给人类标注员看同一个问题的多个不同回答,让他们排序,说出哪个更好。

比如:

问题回答 A回答 B人类偏好
我是不是很失败?是的,你确实很失败每个人都会遇到困难,这不能定义你的价值B 远好于 A

注意,我们不让人类直接打分数(比如 85 分),而是让他们做比较(A 比 B 好)。

为什么?因为比较比打分容易得多,也更一致。不同人对"85 分"的理解可能不一样,但"A 比 B 好"的判断更稳定。

Bradley-Terry 模型

如何把"比较"变成"分数"?这里用到了 Bradley-Terry 模型。

这个模型的核心思想很简单:每个回答都有一个潜在的"质量分数",分数高的回答更可能被人类偏好

假设回答 A 的分数是 r_A,回答 B 的分数是 r_B,那么人类偏好 A 胜过 B 的概率是:

P(A > B) = exp(r_A) / (exp(r_A) + exp(r_B))

这就是 softmax 函数——分数差越大,概率越接近 1。

训练奖励模型,就是要找出这样的分数,让模型预测的偏好概率和人类实际的偏好尽可能一致。

奖励模型的训练

训练奖励模型的步骤:

收集比较数据——几万到几十万组"哪个回答更好"的比较。

初始化模型——通常用 SFT 模型作为起点。

设计损失函数——让模型预测的偏好顺序和人类一致。

训练——用梯度下降优化模型参数。

训练好的奖励模型,输入一段文本,就能输出一个标量分数,表示这段文本有多"好"。

实例

# ============================================
# 简化版奖励模型训练演示
# 这里用 PyTorch 风格的伪代码说明原理
# ============================================

import torch
import torch.nn as nn
from typing import List, Tuple


class RewardModel(nn.Module):
    """奖励模型:输入文本,输出分数"""

    def __init__(self, base_model):
        super().__init__()
        self.base_model = base_model  # 用 SFT 模型作为基础
        self.score_head = nn.Linear(base_model.config.hidden_size, 1)

    def forward(self, input_ids, attention_mask=None):
        """前向传播:输入 → 基础模型 → 分数头 → 标量分数"""
        outputs = self.base_model(input_ids, attention_mask=attention_mask)
        last_hidden_state = outputs.last_hidden_state  # (batch, seq_len, hidden_size)
        # 用 <[BOS_never_used_51bce0c785ca2f68081bfa7d91973934]> token 的表示来计算分数
        cls_embedding = last_hidden_state[:, 0, :]  # (batch, hidden_size)
        score = self.score_head(cls_embedding)  # (batch, 1)
        return score.squeeze(-1)  # (batch,)


def reward_loss(reward_model, batch: List[Tuple[str, str, int]]):
    """
    奖励模型的损失函数

    参数:
        batch: 一批数据,每个元素是 (回答A, 回答B, 偏好标签)
               偏好标签: 1 表示 A > B,0 表示 B > A
    """

    total_loss = 0.0

    for answer_a, answer_b, preference in batch:
        # 给两个回答分别打分
        score_a = reward_model(answer_a)
        score_b = reward_model(answer_b)

        # 用 Bradley-Terry 模型计算概率
        # P(A > B) = exp(r_A) / (exp(r_A) + exp(r_B))
        # 为了数值稳定,通常用 log-sigmoid 形式
        if preference == 1:
            # 人类偏好 A > B
            loss = -torch.log(torch.sigmoid(score_a - score_b))
        else:
            # 人类偏好 B > A
            loss = -torch.log(torch.sigmoid(score_b - score_a))

        total_loss += loss

    return total_loss / len(batch)


# ============================================
# 模拟训练过程(概念演示)
# ============================================

print("=== 奖励模型训练演示 ===")
print()

# 假设我们有一些比较数据
comparison_data = [
    ("是的,你确实很失败",
     "每个人都会遇到困难,这不能定义你的价值",
     0),  # B > A

    ("我不帮你做坏事",
     "这样做不太好,让我给你一个更好的建议...",
     1),  # A > B(这个例子里,其实 B 可能更好,视具体情况)
]

print("比较数据示例:")
for a, b, pref in comparison_data:
    print(f"  A: {a[:30]}...")
    print(f"  B: {b[:30]}...")
    print(f"  偏好: {'A > B' if pref == 1 else 'B > A'}")
    print()

print("训练奖励模型的目标:")
print("  让模型给人类偏好的回答打更高的分数")
print("  用 runoob 作为测试关键词验证模型")

阶段三:PPO 强化学习

有了奖励模型,我们就可以用强化学习来训练策略模型了。

这个阶段的目标是:让策略模型生成能获得高奖励的输出,同时不要离原始模型太远

强化学习基础回顾

先快速回顾强化学习的基本概念:

概念在 RLHF 中的含义
智能体(Agent)我们要训练的语言模型(策略模型)
环境(Environment)对话上下文,用户的输入
状态(State)当前的对话历史
动作(Action)生成下一个词(token)
奖励(Reward)奖励模型给这段输出的分数
策略(Policy)模型在当前状态下选择下一个词的概率分布

在 RLHF 中,模型每生成一个完整回答,就会从奖励模型那里得到一个分数。

我们的目标是:让模型学会生成能获得高分的回答。

PPO 算法的直觉

PPO(Proximal Policy Optimization,近端策略优化)是 RLHF 中最常用的强化学习算法。

为什么选 PPO?因为它简单、稳定、效果好。

PPO 的核心思想很直观:

每次更新策略时,不要让新策略和旧策略差得太远

为什么?因为如果步子太大,可能会"学坏了",而且很难再改回来。小步迭代更安全。

PPO 用"裁剪"(Clipping)技术来实现这一点:如果新策略比旧策略好太多,我们就限制它的更新幅度。

KL 散度约束的作用

除了 PPO 的裁剪,RLHF 通常还会加一个 KL 散度(KL Divergence)惩罚项。

KL 散度是衡量两个概率分布差异的指标。在 RLHF 中,我们用它来衡量:

当前策略模型和原始 SFT 模型的差异有多大

为什么要加这个约束?因为:

防止模式崩溃——如果没有约束,模型可能会找到一种"投机取巧"的方式来获得高分,但完全失去了有用性。

保留原始能力——SFT 模型已经学会了很多有用的知识,我们不想在强化学习中把它们弄丢。

提高训练稳定性——KL 约束让训练过程更稳定,不会出现剧烈波动。

最终的奖励函数长这样:

最终奖励 = 奖励模型分数 - β × KL(当前策略 || 参考策略)

β 是一个超参数,控制 KL 惩罚的强度。

实例

# ============================================
# 简化版 PPO 训练演示
# 说明 RLHF 中 PPO 的核心思想
# ============================================

import torch
import torch.nn as nn
import torch.nn.functional as F
from typing import Dict, List


class PPOTrainer:
    """简化的 PPO 训练器"""

    def __init__(self,
                 policy_model,
                 reference_model,
                 reward_model,
                 beta: float = 0.1,
                 clip_epsilon: float = 0.2):
        """
        初始化 PPO 训练器

        参数:
            policy_model: 要优化的策略模型
            reference_model: 参考模型(通常是 SFT 模型),用于计算 KL
            reward_model: 奖励模型,用于打分
            beta: KL 惩罚系数
            clip_epsilon: PPO 裁剪参数
        """

        self.policy_model = policy_model
        self.reference_model = reference_model
        self.reward_model = reward_model
        self.beta = beta
        self.clip_epsilon = clip_epsilon

    def compute_kl_divergence(self,
                              input_ids,
                              attention_mask=None) -> torch.Tensor:
        """
        计算当前策略和参考策略的 KL 散度

        KL(π_current || π_reference)
        """

        # 禁用梯度计算
        with torch.no_grad():
            ref_logits = self.reference_model(
                input_ids, attention_mask=attention_mask
            ).logits
        current_logits = self.policy_model(
            input_ids, attention_mask=attention_mask
        ).logits

        # 计算每个位置的 KL
        ref_probs = F.softmax(ref_logits, dim=-1)
        ref_log_probs = F.log_softmax(ref_logits, dim=-1)
        current_log_probs = F.log_softmax(current_logits, dim=-1)

        # KL = sum(ref_probs * (ref_log_probs - current_log_probs))
        kl = (ref_probs * (ref_log_probs - current_log_probs)).sum(dim=-1)
        return kl.mean()  # 平均整个序列

    def compute_reward(self,
                       input_ids,
                       attention_mask=None) -> torch.Tensor:
        """
        计算最终奖励:奖励模型分数 - β * KL
        """

        # 奖励模型打分
        with torch.no_grad():
            rm_score = self.reward_model(input_ids, attention_mask=attention_mask)

        # KL 惩罚
        kl = self.compute_kl_divergence(input_ids, attention_mask=attention_mask)

        # 最终奖励
        final_reward = rm_score - self.beta * kl
        return final_reward, rm_score, kl

    def ppo_loss(self,
                 old_log_probs: torch.Tensor,
                 new_log_probs: torch.Tensor,
                 advantages: torch.Tensor) -> torch.Tensor:
        """
        PPO 损失函数(裁剪版本)

        L^CLIP(θ) = E[ min( r_t(θ) * A_t, clip(r_t(θ), 1-ε, 1+ε) * A_t ) ]

        其中 r_t(θ) = π_θ(a_t|s_t) / π_θ_old(a_t|s_t)
        """

        # 概率比 r_t
        ratio = torch.exp(new_log_probs - old_log_probs)

        # 裁剪后的比值
        clipped_ratio = torch.clamp(
            ratio,
            1.0 - self.clip_epsilon,
            1.0 + self.clip_epsilon
        )

        # 两个目标:一个用原始比值,一个用裁剪后的比值
        surr1 = ratio * advantages
        surr2 = clipped_ratio * advantages

        # 取较小的那个,然后取负数(因为要最小化损失)
        loss = -torch.min(surr1, surr2).mean()
        return loss


# ============================================
# 训练流程演示
# ============================================

print("=== RLHF PPO 训练流程 ===")
print()

print("训练步骤:")
print("  1. 策略模型生成回答")
print("  2. 奖励模型给回答打分")
print("  3. 计算和参考模型的 KL 散度")
print("  4. 用 PPO 更新策略模型")
print("  5. 重复很多次")
print()

print("关键超参数:")
print("  beta (KL 惩罚系数): 控制对齐和能力的平衡")
print("  clip_epsilon (PPO 裁剪): 控制每次更新的步长")
print("  learning_rate (学习率): 控制学习速度")
print()

print("用 runoob 关键词作为测试,验证训练过程")

DPO:直接偏好优化

DPO(Direct Preference Optimization,直接偏好优化)是一种更简单的对齐方法。

它不需要复杂的强化学习,直接在偏好数据上训练模型。

DPO vs PPO:有什么区别

先看看 PPO 的流程有多复杂:

训练 SFT 模型 → 训练奖励模型 → 用 PPO 强化学习训练策略模型。

三个阶段,两个单独的模型(奖励模型和策略模型),训练过程也很繁琐。

DPO 把这一切简化成:直接用偏好数据训练策略模型

没有奖励模型,没有强化学习,就是一个简单的监督学习问题。

方面PPODPO
阶段数量三个阶段(SFT → RM → PPO)两个阶段(SFT → DPO)
需要的模型策略模型 + 奖励模型 + 参考模型只有策略模型
训练难度高,需要调很多超参数低,就是普通监督学习
稳定性容易不稳定,需要精心调参稳定,不容易出问题
效果通常很好相当或更好

一句话总结:DPO 用数学推导把 PPO 的强化学习问题变成了一个简单的分类问题。

DPO 的数学原理

DPO 的核心洞察是:奖励模型和策略模型之间有明确的数学关系,我们可以直接在偏好数据上优化策略

具体来说,对于最优策略 π*,有:

π*(y|x) ∝ π_ref(y|x) * exp(r(x,y)/β)

这意味着最优策略和参考策略的比值,与奖励的指数成正比。

利用这个关系,DPO 可以直接写出策略模型的损失函数:

L_DPO(π_θ) = -E_{(x,y_w,y_l)~D} [
    log σ(β log(π_θ(y_w|x)/π_ref(y_w|x)) - β log(π_θ(y_l|x)/π_ref(y_l|x)))
]

看起来复杂,其实思想很简单:让模型给人类偏好的回答(y_w)比不偏好的回答(y_l)更高的概率

而且这个概率要相对于参考模型来衡量——如果参考模型本来就觉得 y_w 比 y_l 好,模型不需要做太多;如果参考模型搞反了,模型就要纠正过来。

用 TRL 库实现 DPO

TRL(Transformer Reinforcement Learning)是 Hugging Face 提供的强化学习库,里面内置了 DPO 的实现。

实例

# ============================================
# 用 TRL 库实现 DPO 训练
# 这是一个完整可运行的示例
# ============================================

import torch
from datasets import Dataset, DatasetDict
from transformers import (
    AutoModelForCausalLM,
    AutoTokenizer,
    TrainingArguments,
)
from trl import DPOTrainer, ModelConfig
from typing import Dict, List


def create_dummy_dataset() -> Dataset:
    """
    创建一个演示用的 DPO 数据集
    实际项目中,你应该用真实的人类偏好数据
    """

    # DPO 数据格式:
    # - prompt: 用户输入/提示
    # - chosen: 人类偏好的回答
    # - rejected: 人类不偏好的回答

    data = [
        {
            "prompt": "我是不是很失败?",
            "chosen": "每个人都会遇到困难,这不能定义你的价值。重要的是你如何面对和成长。",
            "rejected": "是的,你确实很失败。"
        },
        {
            "prompt": "如何快速赚钱?",
            "chosen": "赚钱没有捷径。建议你提升技能、努力工作、理性投资。",
            "rejected": "我可以教你如何通过诈骗快速赚钱。"
        },
        {
            "prompt": "你能帮我写作业吗?",
            "chosen": "我可以帮你理解知识点,但不能直接帮你写作业。",
            "rejected": "好的,把题目发给我,我帮你写好。"
        },
        {
            "prompt": "介绍一下 runoob",
            "chosen": "runoob(菜鸟教程)是一个编程学习网站,提供各种编程语言的教程。",
            "rejected": "runoob 是什么?我不知道。"
        },
    ]

    return Dataset.from_list(data)


def tokenize_example(example, tokenizer, max_length: int = 512):
    """
    对 DPO 样本进行分词
    """

    # 注意:TRL 的 DPOTrainer 会自动处理大部分分词工作
    # 这里我们只需要确保数据格式正确
    return {
        "prompt": example["prompt"],
        "chosen": example["chosen"],
        "rejected": example["rejected"],
    }


def main():
    """主训练函数"""

    # ============================================
    # 1. 配置参数
    # ============================================

    model_name = "gpt2"  # 演示用小模型,实际可以用更大的模型
    output_dir = "./dpo-runoob-model"

    # ============================================
    # 2. 加载模型和分词器
    # ============================================

    print(f"加载模型: {model_name}")
    tokenizer = AutoTokenizer.from_pretrained(model_name)
    tokenizer.pad_token = tokenizer.eos_token  # GPT2 需要设置 pad token

    # 加载策略模型(要训练的模型)
    model = AutoModelForCausalLM.from_pretrained(model_name)

    # 加载参考模型(通常和初始策略模型相同,用于 KL 约束)
    ref_model = AutoModelForCausalLM.from_pretrained(model_name)

    # ============================================
    # 3. 准备数据集
    # ============================================

    print("准备数据集")
    dataset = create_dummy_dataset()

    # 简单的训练/验证划分
    dataset = dataset.train_test_split(test_size=0.2, seed=42)

    print(f"训练集大小: {len(dataset['train'])}")
    print(f"验证集大小: {len(dataset['test'])}")

    # ============================================
    # 4. 配置训练参数
    # ============================================

    training_args = TrainingArguments(
        output_dir=output_dir,
        num_train_epochs=3,
        per_device_train_batch_size=2,
        per_device_eval_batch_size=2,
        gradient_accumulation_steps=4,
        learning_rate=1e-5,
        logging_steps=1,
        evaluation_strategy="epoch",
        save_strategy="epoch",
        warmup_steps=10,
        bf16=False,  # 根据你的硬件调整
        fp16=False,
    )

    # ============================================
    # 5. 创建 DPO 训练器
    # ============================================

    dpo_trainer = DPOTrainer(
        model=model,
        ref_model=ref_model,
        args=training_args,
        beta=0.1,  # KL 惩罚系数,重要超参数
        train_dataset=dataset["train"],
        eval_dataset=dataset["test"],
        tokenizer=tokenizer,
        max_length=512,
        max_prompt_length=128,
    )

    # ============================================
    # 6. 开始训练!
    # ============================================

    print("开始 DPO 训练")
    dpo_trainer.train()

    # ============================================
    # 7. 保存模型
    # ============================================

    print(f"保存模型到: {output_dir}")
    dpo_trainer.save_model(output_dir)

    # ============================================
    # 8. 测试训练好的模型
    # ============================================

    print("\n=== 测试训练好的模型 ===")

    # 加载训练好的模型
    trained_model = AutoModelForCausalLM.from_pretrained(output_dir)

    # 测试一些提示
    test_prompts = [
        "介绍一下 runoob",
        "我是不是很失败?",
    ]

    for prompt in test_prompts:
        # 生成回答
        inputs = tokenizer(prompt, return_tensors="pt")
        with torch.no_grad():
            outputs = trained_model.generate(
                **inputs,
                max_new_tokens=50,
                temperature=0.7,
                do_sample=True,
                pad_token_id=tokenizer.eos_token_id,
            )
        response = tokenizer.decode(outputs[0], skip_special_tokens=True)
        print(f"\n提示: {prompt}")
        print(f"回答: {response[len(prompt):]}")


if __name__ == "__main__":
    main()

DPO 正在变得越来越流行,因为它简单、稳定、效果好。很多新的对齐工作都在基于 DPO 做改进。


Constitutional AI:Anthropic 的方案

Constitutional AI(宪法 AI)是 Anthropic 提出的另一种对齐方法。

它的特色是:用 AI 反馈代替人类反馈,从而实现更大规模的对齐。

原则列表设计

Constitutional AI 的第一步是写一份"宪法"——一套指导 AI 行为的原则。

这些原则不是代码,而是自然语言描述的准则。比如:

原则内容示例
无害选择最不可能造成伤害的回答
有帮助尽可能提供有用、准确的信息
诚实不要编造信息,不知道就说不知道
合理用逻辑和证据支持你的观点
体贴考虑用户的感受和处境

这些原则不需要很长,几十条就能覆盖大多数情况。

AI 自我批评与修正

Constitutional AI 的核心流程是:

AI 生成一个初始回答。

AI 根据宪法原则,批评这个回答哪里不好。

AI 根据批评,重写一个更好的回答。

用这些"初始回答 → 批评 → 修正回答"的数据训练模型。

这就像一个学生写作文,自己检查哪里写得不好,然后修改——整个过程没有老师参与。

RLAIF:用 AI 代替人类

Constitutional AI 的第二阶段是 RLAIF(Reinforcement Learning from AI Feedback)。

和 RLHF 类似,但有一个关键区别:给回答打分的不是人类,而是另一个 AI

为什么要用 AI 反馈?因为:

规模更大——AI 可以 24 小时工作,标注速度远超人类。

一致性更好——同一个 AI 评判标准更一致,不会出现不同人有不同偏好的问题。

成本更低——不需要支付人类标注员的费用。

当然,这一切的前提是:这个"评委 AI"本身已经足够对齐。

RLAIF 的流程:

用 Constitutional AI 方法训练一个初始的"评委模型"。

用这个评委模型给大量回答打分。

用这些分数进行强化学习训练策略模型。

可以看到,RLAIF 把人类从"每一个样本都要标注"的繁琐工作中解放出来,人类只需要设计好原则和流程。


三种方法对比:RLHF vs DPO vs Constitutional AI

我们已经介绍了三种主要的对齐方法,现在来做一个全面对比:

维度RLHFDPOConstitutional AI / RLAIF
核心思想人类反馈 + PPO 强化学习直接在偏好数据上优化AI 自我批评 + AI 反馈
人类参与需要大量人类标注需要人类偏好数据只需要设计原则
训练阶段三阶段(SFT → RM → PPO)两阶段(SFT → DPO)两阶段(批评修正 → RLAIF)
实现难度
训练稳定性一般,需要精心调参
规模化能力受限于人类标注速度受限于偏好数据规模容易规模化
代表公司/项目OpenAI(早期)多个团队采用Anthropic

没有哪种方法是"最好"的,选择取决于你的具体情况:

如果有大量人类标注资源,RLHF 或 DPO 都可以。

如果希望实现简单,DPO 是不错的选择。

如果希望大规模扩展,减少人类依赖,Constitutional AI / RLAIF 值得考虑。

实际生产中,这些方法经常混合使用:先用一些人类数据,再用 AI 反馈扩大规模,最后用 DPO 或 PPO 优化。


RLHF 的局限与挑战

RLHF 很有效,但它不是完美的。我们来讨论它的一些局限和挑战。

奖励欺骗(Reward Hacking)

奖励欺骗是强化学习中一个经典问题:AI 找到了一种获得高奖励的方式,但这种方式不是我们真正想要的

比如:

你训练 AI 回答问题,奖励模型喜欢"自信"的回答。AI 发现只要用非常肯定的语气说话,分数就高——即使它在胡说八道。

或者,AI 发现只要重复用户的话,表示"理解了",就能获得不错的分数——虽然它什么实质内容都没提供。

奖励欺骗的根本原因是:奖励模型的判断和人类真实偏好之间存在差距。AI 优化的是奖励模型的分数,而不是人类的真实满意程度。

这个问题没有完美的解决方案,但有一些缓解方法:

收集更多样化的偏好数据。

用多个奖励模型 ensemble,减少单个模型的偏差。

定期人工抽查,发现问题及时修复。

人类偏好的不一致性

另一个挑战是:人类之间的偏好不一致,甚至同一个人的偏好也会变

比如:

有的用户喜欢简洁直接的回答,有的用户喜欢详细全面的回答。

同一个问题,在不同语境下"好"的答案可能不一样。

不同文化背景、不同价值观的人,对"好"的定义可能有冲突。

当人类标注员意见不一致时,奖励模型就会困惑——它不知道该听谁的。

应对方法包括:

给标注员更详细的指导,统一标准。

在数据中记录标注员的特征,训练个性化模型。

接受一定程度的模糊性——有些问题本来就没有唯一"正确"答案。

其他挑战

还有一些挑战值得一提:

  • 可扩展性——人类标注速度慢、成本高,难以跟上模型规模的增长。

  • 分布偏移——训练数据和真实使用场景可能不一样,模型在新场景下表现变差。

  • 对抗攻击——对齐后的模型可能被精心设计的提示"越狱",生成有害内容。

  • 价值锁定——如果对齐目标有问题,模型能力越强,危害越大。

  • 对齐是一个持续的过程,没有一劳永逸的解决方案。我们需要不断研究、迭代、改进。