欢迎光临
我们一直在努力

大模型应用开发--Agent笔记3(Agentic RL--大模型 RL 到底在干什么?RLHF、PPO、DPO、GRPO、RLOO、OPD等算法思想、完整链路和相关概念)

写在前面

Agent、Agentic RL在当前(2026年年中)是一个快速发展且仍在持续迭代的方向。本文系统整理当前主要的经典方法和常见概念,且尽可能不涉及数学公式易于概念上初步理解。本博客也作为本专栏中上一篇:大模型应用开发–Agent学习笔记的补充。

我之前也有论文精读–InstructGPT和从0开始机器学习–8.强化学习两篇博客可能作为一些简单的前置基础。

对于个人开发者、实验室和非大模型厂商,做可训练的 Agentic RL 时主流更偏向 1B~14B,尤其是 3B/7B/8B 左右以控制 rollout 和训练成本,而不是更大的模型。原因甚至比普通 SFT 更现实:Agentic RL 通常要让模型在环境里反复 rollout,例如“思考 → 调工具 → 看结果 → 再决策 → … → 得到 reward”,然后再做策略更新。GRPO 本身就是一种 online RL,需要模型不断生成新的 completion 来训练,因此生成阶段本身就是很大的计算开销。Qwen 官方的 Qwen3 训练教程:他们直接用 Qwen3-8B 做 GRPO。但即便只有 8B,官方给出的 full-parameter GRPO 示例配置已经是 8 张约 70GB 显存的 GPU,同时还设置了 num_generations=16、最长 completion 4096 token,并单独用 vLLM 做 rollout。当然,SFT 阶段可以用 LoRA,RL 阶段完全可以继续用 LoRA,核心思路和 SFT 一样:冻结基座模型参数,只让 RL 更新 LoRA adapter 的参数。如果只做 Agent 应用推理,则也常直接调用大模型厂商 API,而在 RL 训练中这些 API 更适合作为 Teacher、Judge 或 Reward 来源,而非直接作为可更新的 Policy。

这篇博文由 gpt-5.6-sol-high 辅助生成,我也是一边学习一边整理,可能有不尽准确的地方,欢迎指出讨论。


目录

写在前面

1.总框架

1.1.大模型 RL 到底在干什么?

1.2.Agentic RL 到底是什么?

1.3.如何简单判断什么时候SFT不够要用RL?

2.核心概念简单解释

3.PPO:最经典的大模型 RLHF

3.1.经典InstructGPT风格流程

Reward Model V.S. Critic

模型怎么知道预期收益?

3.2.PPO 第一阶段:SFT Model 怎么训练?

3.3.PPO 第二阶段:Reward Model 怎么训练?

Reward Model 还分 ORM 和 PRM

3.4.PPO 第三阶段:Actor 怎么训练?

3.5.为什么需要 PPO 的 “P”–Proximal?

3.6.完整 PPO 数据链路

3.7.PPO 代码demo

3.8.PPO 优缺点

4.DPO:干脆把 RM + PPO 都删了

4.1.DPO整体思路

DPO 典型风格流程

4.2.DPO 数据长什么样?

4.3.DPO 中的 policy 是如何训练的?

为什么 DPO 不是严格意义的 RL?

4.4.DPO 代码demo

4.5.DPO 优缺点

4.6.DPO 家族其他成员

5.GRPO:为什么现在这么重要?

5.1.GRPO 核心思想

GRPO V.S. PPO

5.2.GRPO 完整流程

5.3.GRPO 怎么训练?

5.4.GRPO 代码demo

什么是 verl?什么是vLLM?

5.5.进一步使用RLVR

RLHF V.S. RLAIF V.S. RLVR

5.6.GRPO 的缺点

5.7.RLOO:GRPO 的一个很近的亲戚

最原始的 REINFORCE

6.什么是OPD?

6.1.普通 Knowledge Distillation 怎么做?

6.2.OPD 怎么解决 KD 的问题?

6.3.OPD 的完整数据链路

6.4.OPD 不太算 RL

6.5.Agentic OPD


1.总框架

(图由gpt生成)

1.1.大模型 RL 到底在干什么?

先总览一下,建立一张“大模型后训练到底在训练谁、奖励从哪来、数据怎么流、参数怎么更新”的地图。只要这张图建立起来,后面的算法其实都是在替换其中某一两个组件。(这一部分中出现的一些名词、缩写都会在后续介绍。)

假设现在已经有一个会说话、会推理的 SFT 模型:

Prompt


┌──────────────┐
│ LLM / Policy │
└──────────────┘

│ 生成 Response / Reasoning / Tool Call

┌───────────────┐
│ Reward 来源: │
│ RM / Rule / │
│ Verifier / AI │
└───────────────┘

│ reward = 好不好

┌──────────────────────┐
│ PPO / GRPO / RLOO …│
│ 把 reward 变成梯度 │
└──────────────────────┘


更新 LLM 参数

RL 最核心的一句话就是:

模型自己尝试一些行为 → 外界告诉它这些行为有多好 → 增加好行为的概率、降低坏行为的概率。

对 LLM 来说,“行为”可以有两种尺度:

  • 普通 LLM RL 中: Prompt
    → token
    → token
    → token
    → …
    → 最终回答
    → Reward
  • Agentic RL 中则变成: 用户任务

    思考

    调用 Search

    获得搜索结果

    继续思考

    调用 Python

    获得执行结果

    ……

    继续思考

    最终回答

    任务成功 / 失败

比如对 Agentic RL 来说,可以这样设计

Qwen3-4B / 8B


LoRA SFT
学会基本tool calling


Agent Environment

┌──────┴───────┐
▼ ▼
Tool Observation
│ │
└──────► LLM ◄─┘


trajectory


rule/verifiable reward


LoRA + GRPO

比如让 Agent 学:

用户:
“查一下上海今天的天气,
如果超过35度就帮我推荐室内活动。”

Agent:

Thought

weather_tool(…)

Observation

判断结果

search_tool(…)

Observation

Final Answer

Reward 可以设计:

任务完成 +1
正确选择工具 +0.2
参数正确 +0.2
得到正确最终答案 +1
调用无关工具 -0.2
参数错误 -0.5
任务失败 -1

所以 Agentic RL 并不是 PPO/GRPO 的同级算法。它是把 RL 从“生成一个回答”扩展成了“在环境中连续执行很多步”。2025–2026 年的 Agentic RL 工作也越来越把 LLM 看成嵌入环境中的决策策略,而不是单纯的一次性文本生成器。

可以先把整个领域记成:

大模型后训练

├── 监督学习
│ ├── SFT
│ ├── RFT
│ └── Distillation

├── Preference Optimization
│ ├── DPO
│ ├── IPO
│ ├── KTO
│ ├── ORPO
│ └── SimPO …

├── Online RL
│ ├── PPO
│ ├── GRPO
│ ├── REINFORCE
│ └── RLOO …

├── On-Policy Distillation
│ └── OPD / OPSD …

└── Agentic RL
├── PPO-based
├── GRPO-based
├── RLOO-based
└── 各种 trajectory / step reward 方法

而另外一根轴是:

奖励从哪来?

Human
→ RLHF

AI Judge
→ RLAIF

Reward Model
→ RM-based RL

数学答案 / Unit Test / 编译器 / 环境状态
→ RLVR

每一步都打分
→ Process Reward

只看最终结果
→ Outcome Reward

名称本质是什么在线生成数据?显式 RM?核心思想
PPO RL 优化算法 通常有 Actor + Critic,限制每次更新幅度
GRPO RL 优化算法 可有,也可用规则 不训练 Critic,用同题多个答案互相比较
RLOO RL 优化算法 可有/规则 REINFORCE + 多样本 leave-one-out baseline
DPO 离线偏好优化 没有显式 RM chosen 概率提高,rejected 概率降低
KTO 离线偏好优化 只需 good/bad 标签,不一定成对
RFT 自训练/SFT 可离线或在线 通常无 生成很多答案,筛正确答案继续 SFT
RLHF 奖励来源/训练范式 取决于算法 通常有 Human Feedback
RLAIF 奖励来源/训练范式 取决于算法 可有 AI Feedback
RLVR 奖励来源 通常不需要神经 RM 用答案/程序等可验证规则给奖励
OPD On-Policy Distillation 无传统 RM Student 自己 rollout,Teacher 给 token 级指导
Agentic RL RL 的应用场景 各种形式均可 多轮工具调用/环境交互

1.2.Agentic RL 到底是什么?

普通 Agent inference:

while not done:
thought = llm(context)

if thought.tool_call:
observation = tool(thought.tool_call)
context += observation
else:
return answer

Agentic RL:

for task in dataset:

trajectory = []

while not done:
action = policy(context)

observation = environment.step(action)

trajectory.append(
state,
action,
observation
)

reward = evaluate(trajectory)

RL_update(policy, trajectory, reward)

核心变化只有一句:以前 Agent 跑完就结束;现在把 Agent 跑过的 trajectory 拿回来训练 LLM。同时,Agentic RL 中 action 不再只是“一个 token”。

1.3.如何简单判断什么时候SFT不够要用RL?

如果你能明确写出“正确答案应该是什么”,优先 SFT;如果很难给出标准答案,但能判断“结果好不好”,考虑 RL。

例如:

SFT:
输入 → 有明确目标输出
客服话术、格式转换、Text-to-SQL示例、工具调用格式
→ 直接模仿高质量答案即可

而:

RL:
输入 → 没有唯一标准过程
但最终结果可以打分
数学推理、代码执行、Agent多步决策、游戏/环境交互
→ 让模型自己探索,按 reward 学

再压缩成一句:

“会不会做”用 SFT 教;“怎么做得更好”且结果可评价时,用 RL。

所以实践上通常是:先 SFT,把 80%–90% 的能力做出来;只有 SFT 不够,再考虑 DPO / GRPO / PPO。

2.核心概念简单解释

  • 偏好优化里的“偏好”:就是“A 比 B 好”。例如同一个问题,回答 A 比回答 B 更符合人类需求,这个“A > B”就是偏好。DPO 之类的方法就是让模型更倾向生成被偏好的答案。
  • Online RL 的 online:指训练过程中,模型一边和环境交互、一边产生新的训练数据、一边学习。不是拿一份事先固定好的数据集反复训练。 模型 → 产生行为 → 环境反馈 → reward → 更新模型 → 再产生新行为
  • On-Policy:指“用当前这个策略自己产生的数据,训练当前这个策略”。比如当前版本的 Agent 自己 rollout 出一批结果,然后马上用这些结果更新自己。PPO、GRPO通常属于这一类。
    • Rollout:让当前模型真正“跑一次任务”,把它从开始到结束的行为和反馈记录下来。这整次执行过程就是一次 rollout;记录下来的整串内容就是一条 trajectory。
    • Trajectory(轨迹):Agent 完成一次任务过程中产生的完整交互过程记录。例如: 用户问题 → 调工具A → 得到结果 → 调工具B → 得到结果 → 最终回答 → Reward 这一整串就是一条 trajectory。
    • Online 强调“数据是不是训练时现场产生的”;On-Policy 强调“数据是不是由当前策略产生的”。 两者相关,但不是同一个概念。
  • Actor-Critic:
    • Actor(演员):负责“我该做什么”,也就是策略模型,选择 action。
    • Critic(评论员):负责“你现在这个状态/行为有多好”,估计 Value,辅助 Actor 学习。
  • Policy:正在训练的 LLM,记作Policy π。
  • Action:生成的下一个 Token。很多 LLM RL 的推导也会把整个 response 当成一个 sequence-level action来理解。
  • State:模型当前已经看到的上下文,通常是用户问题+当前已经生成的内容(包括但不限于前面的reasoning、前面的toolcall、observation、当前回答已经生成的token)
  • Reward:告诉模型这次干的怎么样,可以直接是定义的reward数值,也可以来自RM(Reward Model)的数值。
  • Return:从现在开始,后面最终一共能得到多少 reward。
  • Value:Critic(Value Model)回答:“走到现在这个状态,我预计最后能获得多少奖励?”
    • 例如正在做数学题:Step 1 正确、Step 2 正确、Step 3 看起来也对; Value Model:我预计最后 reward ≈ 0.85; 换一种推理:Step 1 就算错了; Value:估计最后只有 0.1。
  • Advantage:这是 PPO / GRPO 最重要的词。它是实际reward减去critic预测,回答:“这次实际表现,比我原来预期的好多少?”
    • 如果 Advantage > 0,说明这次采取的动作比预期好,于是增加这些 token 的生成概率;反过来Advantage < 0,就降低这些 token 的概率。这基本就是 Policy Gradient 的灵魂。

3.PPO:最经典的大模型 RLHF

PPO(Proximal Policy Optimization) 是最应该认真理解的一种,因为 GRPO 很大程度上就是:“我能不能把 PPO 那个很贵的 Critic 干掉?”DeepSeekMath 对 GRPO 的介绍也正是从 PPO 的 Actor-Critic 架构出发:PPO 需要额外训练 Value Function,而 GRPO 用同一问题的一组回答的相对奖励替代 Value baseline。

3.1.经典InstructGPT风格流程

Pretrained LM

SFT

SFT LM
┌────────┼────────┐
│ │ │
▼ ▼ ▼
PPO Actor Reference Reward Model
可训练 冻结 冻结
│ ▲
│ │
│ 偏好数据训练


Value / Critic
(通常单独的
value head)


└────┐

PPO Training
Actor + Critic 更新

经典实现通常涉及 4 个模型角色:

模型是否训练作用
Actor / Policy 真正想要训练好的 LLM
Reward Model ❌ PPO 阶段冻结 给整个回答评分
Reference Model ❌ 冻结 防止 Actor 偏离原模型太远
Critic / Value Model 估计每个状态未来能拿多少奖励

很多现代实现还会:

Actor backbone

├── LM head
└── Value head

也就是 Actor 和 Critic 共享部分参数。

所以“PPO 一定有四个完整 LLM。”是错误❌的说法,更准确✅的是:经典 RLHF PPO 有 Policy、Reference、Reward、Value 四种逻辑角色;物理实现可以共享参数。

InstructGPT 的具体实现中,RM 从 SFT 模型初始化,移除原来的语言模型输出层,让模型对 prompt+response 输出一个 scalar;PPO 阶段的 Value Function 又从 RM 初始化。论文还使用了冻结的 SFT policy 来提供 KL 约束。

Reward Model V.S. Critic

Reward Model 负责“打分”,Critic 负责“预测未来能拿多少分”,二者功能不同。可以把它们放进一次 PPO 训练流程里看。

假设 Actor 生成一句回答:

用户问题

Actor 生成:
token1 → token2 → token3 → … → tokenN

最终回答

Reward Model 的作用:给这次完整回答一个最终分数。例如:Reward Model(问题, 完整回答) = 0.8,也就是说 RM 告诉 PPO:“这条回答整体不错,奖励是 0.8。”

但 RM 通常只告诉最终结果好不好,它不会直接说明:token3 这个决策好不好?token7 是不是导致最后得高分的关键?

这时候就需要 Critic。Critic 会对生成过程中的每个状态估计 Value:

生成到 token1:V(s1) = 0.3
生成到 token2:V(s2) = 0.4
生成到 token3:V(s3) = 0.7

生成结束:最终 Reward = 0.8

它实际上是在预测:“从现在这个生成状态继续下去,预计最后能得到多少 reward?”(功劳/责任到底应该分给前面的哪些动作?毕竟前面生成了很多 token,需要知道最终 reward 最多归功于哪些 token。)

然后 PPO 会把:实际得到的 Reward 和 Critic 预测的 Value进行比较,得到Advantage。最粗略地理解:Advantage≈实际结果−Critic预测

Reward Model

告诉你:
“最终干得怎么样?”

最终 Reward

Critic

告诉你:
“走到这里,我预计最后能干得怎么样?”

Value

Reward + Value

计算 Advantage

告诉 Actor:
“刚才这个行为应该鼓励还是抑制?”

所以它们在 PPO 中的分工就是:

RM 提供学习目标,Critic 提供一个 baseline,帮助判断某个动作到底比预期好还是差。

而 PPO 真正拿来更新 Actor 的关键量,通常就是 Advantage。

模型怎么知道预期收益?

通常生成到每个 token 后,都可以对应一个 state,因此 Critic 可以给每个位置预测一个 Value。但关键在于:Critic 并不知道真正的未来,它只是在“预测”。它的 Value 是训练出来的,比如模型实际 rollout 了很多次,Critic 根据这些真实结果逐渐学会:“以前遇到类似状态时,后面平均大概能拿多少分。”

那“既然 Critic 知道哪个收益高,为什么 Actor 不直接按照 Critic 最高的方式生成?”,因为 Critic 通常只评价当前状态,而不是直接替 Actor 选择下一个 token。训练过程中 Critic 只是告诉 Actor:“你刚才选的这个 token,最终效果比我原本预期的更好/更差。”于是 Actor 逐渐调整概率,而不是 Critic 直接替 Actor 做决定。

可以类比为“Actor 是做题的人;Critic 是根据过去经验预测“你目前做到这里大概能考多少分”的老师。Critic也不知道标准答案,只是越来越会预测。”

3.2.PPO 第一阶段:SFT Model 怎么训练?

先有 Base Model;准备 Instruction → 高质量 Answer;做普通 Cross Entropy(教师监督→预测正确的 next token→更新 Transformer 参数);得到 SFT Model。

这一步目的主要不是“让模型达到最优”。而是:先让它进入一个比较靠谱的行为区域,否则 RL 一开始模型连基本格式都不会。

3.3.PPO 第二阶段:Reward Model 怎么训练?

RM 的结构就是一个普通 LLM 做一些修改:

  • 普通 LLM: Transformer


    hidden states


    LM Head


    vocabulary logits


    下一个 token
  • RM: Prompt + Response


    Transformer


    final hidden state


    Linear Layer


    一个 scalar

它不生成文字。它只:输入 Prompt + Response,输出一个数字。InstructGPT 就是从 SFT 模型出发,移除最终的 unembedding/语言模型输出层,训练它输出标量 reward。

训练 RM 是经典 RLHF 最关键的一步。先让一个模型对同一个 prompt 生成多个回答,然后人类标注员排序,RM 分别计算对于不同的回答的 score,最终训练结果是 score 的排序符合人类习惯。

例如:

Prompt:
怎么治疗感冒?

LLM 分别生成以下4个回答:
A:合理且安全
B:部分错误
C:基本正确
D:危险建议

人类可能标:

A > C > B > D

于是得到 pair:

(A, C)
(A, B)
(A, D)
(C, B)
(C, D)
(B, D)

RM 分别计算:

RM(prompt, A) = score_A
RM(prompt, B) = score_B

训练目标非常直观:

如果人类说 A > B

那么希望:
score_A > score_B

RM 参数就不断被更新,直到它越来越能够预测:“人类会更喜欢哪个回答?”

Reward Model 还分 ORM 和 PRM

ORM:Outcome Reward Model,只看最终结果,例如:

Step1
Step2
Step3
Step4
Answer


Reward = 0.8

它不知道到底哪一步错了。

PRM:Process Reward Model,每一步都判断,例如:

Step 1 → 0.95
Step 2 → 0.91
Step 3 → 0.12 ← 这里可能错了
Step 4 → 0.08

因此监督更密集。

OpenAI 的 “Let's Verify Step by Step” 工作就是典型的 process supervision,并发布了 PRM800K 这类 step-level feedback 数据。

近期 Agentic RL 工作尤其强调这一点:trajectory 可以跨几十甚至上百轮环境交互,只有 episode-level reward 时,很难判断具体哪个 action 应该承担功劳或责任。这也是 Agentic RL 最大难题之一:Long-Horizon Credit Assignment。

3.4.PPO 第三阶段:Actor 怎么训练?

现在有 Actor、Reward Model、Reference、Critic,对于一个用户 prompt:

  • Actor 自己生成;
  • RM 打分;
  • Reference Model 检查 Actor 有没有跑太远:假设一味最大化 RM,Actor 迟早可能发现 RM 的漏洞,可能用特别奇怪的语序语调迎合 RM(Reward Hacking),因此计算 KL penaltyInstructGPT PPO 就是在 RM reward 上额外加入相对于冻结 SFT policy 的逐 token KL penalty,以缓解对 Reward Model 的过度优化;
  • 通过 Critic 计算 Advantage,提高/降低相关 token/action 的概率。
  • 3.5.为什么需要 PPO 的 “P”–Proximal?

    假设某次发现:某条 trajectory reward 特别高,最简单的 policy gradient 可能说:牛逼!把这些 token 概率疯狂提高!

    导致模型可能一次更新太猛,训练非常容易崩。PPO 的核心思想其实非常朴素:可以学习,但每一步别走太远。于是 PPO 对 policy probability ratio 做 clip,所以名字叫:Proximal ≈ 保持在附近。

    3.6.完整 PPO 数据链路

    ┌───────────────┐
    Prompt ──────►│ Actor │
    │ trainable LLM │
    └──────┬────────┘

    │ rollout

    Response
    / \\
    / \\
    ▼ ▼
    ┌────────────┐ ┌──────────────┐
    │Reward Model│ │Reference Model│
    │ frozen │ │ frozen │
    └─────┬──────┘ └──────┬───────┘
    │ │
    │ score │ KL
    └──────┬────────┘

    Total Reward


    ┌───────────┐
    │ Critic │
    │ trainable │
    └─────┬─────┘

    Advantage


    ┌────────────────┐
    │ PPO clipped loss│
    └───────┬────────┘


    Update Actor

    与此同时:

    Critic prediction
    vs
    actual return

    更新 Critic

    所以 PPO 阶段真正持续学习的是:

    Actor ← 学习怎么回答
    Critic ← 学习预测未来 reward

    而:

    Reward Model → frozen
    Reference → frozen

    3.7.PPO 代码demo

    有开源框架GitHub – LlamaFactory支持 PPO 训练(要求 stage: ppo 并指定 Reward Model,SFT Actor和RM需要自己训好,Critic / Value不需要像 RM 那样先单独准备一个“critic checkpoint 再传进去”。LLaMA-Factory 的 PPO trainer 会在 PPO 训练过程中处理 value/critic 相关部分)。以下是手写简易代码:

    假设已经有:

    Actor
    Critic
    Reward Model
    Reference Model

    核心代码:

    import torch

    # ============================================================
    # 第 1 步:拿一个 Prompt
    # ============================================================

    prompt = "1+1等于多少?"

    # ============================================================
    # 第 2 步:Actor rollout
    #
    # 注意:
    #
    # 这是 PPO 和 DPO 非常重要的区别。
    #
    # DPO:
    # response 已经存在于 dataset
    #
    # PPO:
    # 当前 Actor 现场生成 response
    # ============================================================

    input_ids = tokenizer(
    prompt,
    return_tensors="pt"
    ).input_ids

    with torch.no_grad():

    generated_ids = actor.generate(
    input_ids,

    max_new_tokens=50,

    do_sample=True
    )

    response = tokenizer.decode(
    generated_ids[0]
    )

    print(response)

    # ============================================================
    # 第 3 步:Reward Model 打分
    #
    # 输入:
    # Prompt + Response
    #
    # 输出:
    # 一个 scalar reward
    #
    # 例如:
    #
    # reward = 0.8
    # ============================================================

    with torch.no_grad():

    reward = reward_model(
    generated_ids
    )

    # ============================================================
    # 第 4 步:Critic 预测 Value
    #
    # Critic 会对:
    #
    # s1
    # s2
    # s3
    # …
    #
    # 分别预测:
    #
    # V(s1)
    # V(s2)
    # V(s3)
    # …
    # ============================================================

    values = critic(
    generated_ids
    )

    # 假设:
    #
    # values =
    # [
    # 0.2,
    # 0.3,
    # 0.5,
    # 0.6
    # ]

    # ============================================================
    # 第 5 步:计算 Advantage
    #
    # 真实 PPO 通常使用 GAE:
    #
    # Generalized Advantage Estimation
    #
    # 这里为了理解,极度简化成:
    #
    # Advantage = reward – value
    # ============================================================

    advantages = reward – values.detach()

    # ============================================================
    # 第 6 步:保存 rollout 时 Actor 的概率
    #
    # PPO 必须知道:
    #
    # “生成这些 token 的时候,旧 Policy
    # 给这些 token 多大概率?”
    #
    # 所以需要 old_log_probs
    # ============================================================

    with torch.no_grad():

    old_log_probs = get_token_log_probs(
    actor,
    generated_ids
    )

    # ============================================================
    # 第 7 步:Reference Model 计算 log probability
    #
    # 用来做 KL penalty。
    #
    # 防止 Actor 偏离原来的 SFT 模型太远。
    # ============================================================

    with torch.no_grad():

    ref_log_probs = get_token_log_probs(
    reference_model,
    generated_ids
    )

    # ============================================================
    # 第 8 步:开始 PPO 更新
    #
    # 现在 Actor 再看一次刚刚 rollout 的数据。
    # ============================================================

    new_log_probs = get_token_log_probs(
    actor,
    generated_ids
    )

    # ============================================================
    # 第 9 步:计算 probability ratio
    #
    # ratio =
    #
    # π_new(token)
    # ————-
    # π_old(token)
    #
    # 使用 log probability:
    #
    # ratio = exp(new_log_prob – old_log_prob)
    # ============================================================

    ratio = torch.exp(
    new_log_probs – old_log_probs
    )

    # ============================================================
    # 第 10 步:PPO Clip
    #
    # 如果 Advantage > 0:
    #
    # 应该提高概率
    #
    # 如果 Advantage < 0:
    #
    # 应该降低概率
    #
    # 但不能一次改太多。
    # ============================================================

    epsilon = 0.2

    loss1 = (
    ratio
    * advantages
    )

    loss2 = (
    torch.clamp(
    ratio,
    1 – epsilon,
    1 + epsilon
    )
    * advantages
    )

    policy_loss = -torch.min(
    loss1,
    loss2
    ).mean()

    # ============================================================
    # 第 11 步:KL penalty
    #
    # Actor 和 Reference 差太远就罚。
    # ============================================================

    kl = (
    new_log_probs
    – ref_log_probs
    ).mean()

    beta = 0.01

    actor_loss = (
    policy_loss
    + beta * kl
    )

    # ============================================================
    # 第 12 步:更新 Actor
    # ============================================================

    actor_optimizer.zero_grad()

    actor_loss.backward()

    actor_optimizer.step()

    # ============================================================
    # 第 13 步:更新 Critic
    #
    # Critic:
    #
    # “我刚才预测 reward 是 0.5”
    #
    # 最后:
    #
    # “实际 reward 是 0.8”
    #
    # 那 Critic 也得学习。
    # ============================================================

    values = critic(
    generated_ids
    )

    critic_loss = (
    (values – reward) ** 2
    ).mean()

    critic_optimizer.zero_grad()

    critic_loss.backward()

    critic_optimizer.step()

    3.8.PPO 优缺点

    优点缺点
    真正 on-policy,模型可以探索自己当前不会的行为 非常贵
    可以直接优化最终 reward Actor + RM + Reference + Critic 很吃显存
    比原始 Policy Gradient 稳定 pipeline 很复杂
    Reward 可以来自各种环境 Critic 本身也很难训练
    适合长程决策 reward hacking
    理论和实践积累丰富 hyperparameter 很敏感

    PPO 最大的问题可以概括成:不是效果不行而是工程太重。这也是后面 DPO、GRPO 等方法如此受欢迎的重要背景。

    4.DPO:干脆把 RM + PPO 都删了

    4.1.DPO整体思路

    原来:

    Preference Data

    Train RM

    RM

    PPO

    Policy

    DPO(Direct Preference Optimization):

    Preference Data

    DPO

    Policy

    DPO 原论文就是从带 KL 约束的 RLHF 目标重新参数化,把原本“学习 reward → 再求最优 policy”的问题转成一个直接作用在 chosen/rejected 上的分类式损失,因此无需显式 RM,也不需要 PPO rollout。

    DPO 典型风格流程

    SFT Model

    ┌─────┴─────┐
    ▼ ▼
    Policy Reference
    train frozen

    工程上比 PPO 简单太多。

    4.2.DPO 数据长什么样?

    非常简单:

    Prompt
    Chosen response
    Rejected response

    例如:

    Prompt:
    请解释 Transformer。

    Chosen:
    Transformer 是一种基于 attention…

    Rejected:
    Transformer 是一种 CNN…

    DPO 同时看:

    Policy(Chosen)
    Policy(Rejected)

    以及:

    Reference(Chosen)
    Reference(Rejected)

    然后目标大致就是:

    相对于原模型,让当前模型越来越偏爱 chosen,而越来越不偏爱 rejected。

    也就是说:

    P(chosen) ↑

    P(rejected) ↓

    但又不能无限偏离 Reference。

    4.3.DPO 中的 policy 是如何训练的?

    DPO 里 Policy 的训练本质上就是:对 chosen / rejected 分别算概率,然后通过一个特殊的 preference loss 直接反向传播更新 Policy。最简单看一次训练:

    Prompt
    ├── Chosen
    └── Rejected

    分别送入 Policy

    计算两个回答的 log probability

    例如:

    log πθ(chosen|x) = -3
    log πθ(rejected|x) = -5

    说明当前 Policy 已经更倾向 chosen。但 DPO 还会用冻结的 Reference 做同样的计算:

    log πref(chosen|x)
    log πref(rejected|x)

    然后比较:

    Policy 对 chosen 相比 rejected 的偏好程度
    VS
    Reference 对 chosen 相比 rejected 的偏好程度

    DPO 希望的是:[log πθ(chosen) – log πθ(rejected)] 比 [log πref(chosen) – log πref(rejected)] 更大,也就是:

    当前 Policy 要比原始 Reference 更偏爱 chosen。

    chosen 概率太低

    梯度让 chosen ↑

    rejected 概率太高

    梯度让 rejected ↓

    但同时拿 Reference 当锚点

    不要偏离原来的模型太夸张

    因此每个 batch 大概就是:

    (prompt, chosen, rejected)

    Policy 前向传播

    计算 chosen / rejected 的 token log probabilities

    Reference 前向传播(冻结)

    计算 DPO loss

    backprop

    只更新 Policy 参数

    回答的概率是由其中所有 token 的概率组成的。它和 SFT 最大的区别也可以简单理解成:

    SFT:
    只告诉模型:
    “这个 chosen 是对的,把它概率提高。”

    DPO:
    同时告诉模型:
    “chosen 比 rejected 好,
    你应该更偏向 chosen,而不是 rejected。”

    所以 DPO 可以看成一种带 Reference 约束的成对偏好训练。

    为什么 DPO 不是严格意义的 RL?

    因为整个训练过程通常是:

    dataset 已经固定

    Prompt + Good + Bad

    计算 loss

    backprop

    模型训练期间并没有不断:

    自己生成新的 response

    和环境互动

    获取 reward

    再更新

    因此它更像:特殊设计的 supervised preference loss。

    DeepSeekMath 的统一分析也把 DPO 归为 offline sampling:DPO 使用从初始 SFT policy 得到的偏好数据,而 PPO/GRPO 使用当前实时 policy 生成的数据。

    4.4.DPO 代码demo

     有开源框架GitHub – LlamaFactory支持 DPO 训练(通过 stage: dpo 和 preference dataset 来配置 DPO)。以下是手写简易代码:

    假设已经有:

    prompt
    chosen
    rejected

    核心代码:

    import torch
    import torch.nn.functional as F

    # ============================================================
    # 假设:
    # policy_model = 当前正在训练的模型
    # reference_model = 冻结的 SFT 模型
    #
    # tokenizer = tokenizer
    # optimizer = AdamW(policy_model.parameters())
    # ============================================================

    def get_log_prob(model, input_ids, prompt_length):
    """
    计算 response 部分所有 token 的 log probability 总和。

    对应:
    log π(response | prompt)
    = Σ log π(token_t | prompt, previous_tokens)
    """

    outputs = model(input_ids=input_ids)

    # [batch, seq_len, vocab_size]
    logits = outputs.logits

    # next-token prediction:
    #
    # token:
    # A B C D
    #
    # logits:
    # ->B ->C ->D
    #
    shift_logits = logits[:, :-1]
    shift_labels = input_ids[:, 1:]

    log_probs = F.log_softmax(shift_logits, dim=-1)

    # 找出模型给真实 token 分配的 log probability
    token_log_probs = log_probs.gather(
    dim=-1,
    index=shift_labels.unsqueeze(-1)
    ).squeeze(-1)

    # ——————————————————–
    # 我们只关心 response,不计算 prompt
    # ——————————————————–

    response_log_probs = token_log_probs[:, prompt_length – 1:]

    return response_log_probs.sum(dim=-1)

    # ============================================================
    # 第 1 步:准备 preference data
    #
    # prompt:
    # "请解释 Transformer"
    #
    # chosen:
    # "Transformer 是一种基于 Attention…"
    #
    # rejected:
    # "Transformer 是一种 CNN…"
    # ============================================================

    prompt = "请解释 Transformer。"

    chosen = "Transformer 是一种基于 Attention 的神经网络架构。"

    rejected = "Transformer 是一种 CNN。"

    # ============================================================
    # 第 2 步:tokenize
    # ============================================================

    prompt_ids = tokenizer(
    prompt,
    return_tensors="pt"
    ).input_ids

    chosen_ids = tokenizer(
    prompt + chosen,
    return_tensors="pt"
    ).input_ids

    rejected_ids = tokenizer(
    prompt + rejected,
    return_tensors="pt"
    ).input_ids

    prompt_length = prompt_ids.shape[1]

    # ============================================================
    # 第 3 步:Policy 计算 chosen / rejected 概率
    #
    # 这是:
    #
    # log πθ(chosen | prompt)
    # log πθ(rejected | prompt)
    #
    # Policy 是要训练的,所以需要梯度
    # ============================================================

    policy_chosen = get_log_prob(
    policy_model,
    chosen_ids,
    prompt_length
    )

    policy_rejected = get_log_prob(
    policy_model,
    rejected_ids,
    prompt_length
    )

    # ============================================================
    # 第 4 步:Reference Model 做同样计算
    #
    # Reference 是冻结的。
    #
    # 对应:
    #
    # log πref(chosen)
    # log πref(rejected)
    # ============================================================

    with torch.no_grad():

    ref_chosen = get_log_prob(
    reference_model,
    chosen_ids,
    prompt_length
    )

    ref_rejected = get_log_prob(
    reference_model,
    rejected_ids,
    prompt_length
    )

    # ============================================================
    # 第 5 步:计算 DPO preference
    #
    # Policy 当前:
    #
    # chosen 相比 rejected 好多少?
    # ============================================================

    policy_preference = (
    policy_chosen
    – policy_rejected
    )

    # Reference 原本:
    #
    # chosen 相比 rejected 好多少?

    ref_preference = (
    ref_chosen
    – ref_rejected
    )

    # ============================================================
    # 第 6 步:计算 DPO Loss
    #
    # 希望:
    #
    # Policy 对 chosen 的偏好
    #
    # 比
    #
    # Reference 对 chosen 的偏好
    #
    # 更强
    # ============================================================

    beta = 0.1

    logits = beta * (
    policy_preference
    – ref_preference
    )

    loss = -F.logsigmoid(logits).mean()

    # ============================================================
    # 第 7 步:反向传播
    #
    # 只更新 Policy
    #
    # Reference 不更新
    # ============================================================

    optimizer.zero_grad()

    loss.backward()

    optimizer.step()

    4.5.DPO 优缺点

    优点缺点
    极其简单 本质是 offline
    不需要 RM 很依赖 preference dataset
    不需要 Critic 无法很好利用当前 policy 的探索
    稳定 数据分布容易逐渐和当前 policy 脱节
    计算成本低 很难直接处理复杂环境奖励
    很适合 instruction alignment 长 horizon Agent 场景并非天然适配
    • DPO:别人提前告诉我A 比 B 好;
    • PPO:我自己不断尝试环境告诉我这次 reward 是多少。

    4.6.DPO 家族其他成员

    Preference Optimization

    DPO
    ├── IPO
    ├── KTO
    ├── ORPO
    ├── SimPO
    ├── β-DPO
    ├── cDPO
    ├── …

    KTO、ORPO、SimPO都可以通过GitHub – LlamaFactory来训练,它们很多都是在解决:

    DPO 对噪声敏感
    reference model 成本
    chosen/rejected 数据要求
    margin
    长度偏好
    数据质量

    5.GRPO:为什么现在这么重要?

    5.1.GRPO 核心思想

    PPO 最大的问题之一:需要 Critic,而 Critic 又几乎是一个 LLM。GRPO(Group Relative Policy Optimization) 的想法:为什么非得训练一个 LLM 来告诉我“这次表现比预期好多少”?

    假设一道数学题,不用像 PPO 一样 Actor 一次只生成一个答案。而是一次生成 8 个:

    Question Q

    Response 1 → reward 1
    Response 2 → reward 1
    Response 3 → reward 0
    Response 4 → reward 0
    Response 5 → reward 1
    Response 6 → reward 0
    Response 7 → reward 0
    Response 8 → reward 1

    平均水平:

    mean reward = 0.5

    那么:

    response 1:
    1 > 0.5
    → 比同组平均好
    → positive advantage

    response 3:
    0 < 0.5
    → 比同组平均差
    → negative advantage

    不需要 Critic。这就是:Group Relative

    同一个 prompt 的多个回答互相比较,来估计谁做得好。

    DeepSeekMath 明确把 GRPO 定义为 PPO 的变体:去掉 Critic,以同一问题多个 sampled outputs 的平均 reward 作为 baseline,并根据组内相对 reward 构造 advantage。

    GRPO V.S. PPO

    PPO:
    “这次回答比 Critic 预计的好吗?”

    GRPO:
    “这次回答比同一道题其他回答好吗?”

    5.2.GRPO 完整流程

    Prompt


    Policy π

    ┌──────────┼──────────┐
    ▼ ▼ ▼
    R1 R2 … R8
    │ │ │
    ▼ ▼ ▼
    reward1 reward2 … reward8
    \\ | /
    \\ | /
    ─── Group Stats ───

    mean / std reward


    Advantage


    GRPO objective


    Update Policy

    DeepSeekMath 的 outcome-supervised GRPO 就是对同题的一组 reward 做 mean/std normalization,再把得到的 normalized reward 用作对应输出各 token 的 advantage。

    5.3.GRPO 怎么训练?

    如果是经典 RM-based GRPO:

    Policy ← train
    Reference ← frozen
    Reward Model ← frozen

    相比于 PPO,没有 Critic。

    其他训练过程和 PPO 很像,即:

    如果这个回答 Advantage > 0:

    这个回答里的 token

    提高概率

    但不能一次提高太猛

    clip 限制更新幅度

    同时也一个冻结的 Reference Model:

    Current Policy

    计算生成 token 的概率

    Reference Policy

    计算同样 token 的概率

    两者比较

    KL penalty

    5.4.GRPO 代码demo

    有开源框架Github – EasyR1和verl(verl 官方支持自定义 reward function,可以通过配置里的 custom_reward_function.path 指向你写的 Python 文件;也可以使用已有的预实现 reward。这个这个 Reward 来源不一定是 Reward Model,也可以是一个简单函数)支持 GRPO 训练。以下是手写的建议核心部分代码:

    import torch

    # ============================================================
    # 第 1 步:一个 Prompt
    # ============================================================

    prompt = "请计算 15 * 23。"

    input_ids = tokenizer(
    prompt,
    return_tensors="pt"
    ).input_ids

    # ============================================================
    # 第 2 步:当前 Policy 一次 rollout 多个回答
    #
    # PPO:
    #
    # 一个 prompt → 一个 trajectory
    #
    # GRPO:
    #
    # 一个 prompt → 一组 trajectories
    #
    # 例如 G = 8
    # ============================================================

    G = 8

    with torch.no_grad():

    responses = actor.generate(

    input_ids,

    num_return_sequences=G,

    do_sample=True,

    max_new_tokens=100
    )

    # ============================================================
    # 第 3 步:分别计算 Reward
    #
    # 例如:
    #
    # response1 → 345 → reward = 1
    # response2 → 345 → reward = 1
    # response3 → 325 → reward = 0
    # …
    # ============================================================

    rewards = []

    for response in responses:

    reward = reward_function(
    prompt,
    response
    )

    rewards.append(reward)

    rewards = torch.tensor(
    rewards,
    dtype=torch.float32
    )

    # ============================================================
    # 第 4 步:Group Relative
    #
    # 这就是 GRPO 最核心的一步。
    #
    #
    # reward:
    #
    # [1, 1, 0, 0, 1, 0, 0, 1]
    #
    #
    # mean = 0.5
    #
    #
    # 高于平均:
    # advantage > 0
    #
    # 低于平均:
    # advantage < 0
    #
    # ============================================================

    mean_reward = rewards.mean()

    std_reward = rewards.std()

    advantages = (
    rewards – mean_reward
    ) / (
    std_reward + 1e-8
    )

    print("reward:", rewards)

    print("advantage:", advantages)

    # ============================================================
    # 第 5 步:保存 rollout 时 Policy 的概率
    #
    # 和 PPO 一样。
    #
    # 因为 GRPO 仍然是 Policy Optimization。
    # ============================================================

    with torch.no_grad():

    old_log_probs = []

    for response in responses:

    lp = get_token_log_probs(
    actor,
    response
    )

    old_log_probs.append(lp)

    # ============================================================
    # 第 6 步:Reference Model
    #
    # 用于 KL penalty
    # ============================================================

    with torch.no_grad():

    ref_log_probs = []

    for response in responses:

    lp = get_token_log_probs(
    reference_model,
    response
    )

    ref_log_probs.append(lp)

    # ============================================================
    # 第 7 步:当前 Policy 再计算一次 probability
    # ============================================================

    new_log_probs = []

    for response in responses:

    lp = get_token_log_probs(
    actor,
    response
    )

    new_log_probs.append(lp)

    # ============================================================
    # 第 8 步:对每一个 response 做 GRPO policy loss
    # ============================================================

    losses = []

    epsilon = 0.2

    for i in range(G):

    # ——————————————————–
    # PPO-style probability ratio
    # ——————————————————–

    ratio = torch.exp(
    new_log_probs[i]
    – old_log_probs[i]
    )

    # ——————————————————–
    # 这个回答的 Group Relative Advantage
    #
    # 一个 response 的 advantage
    # 可以分配给它所有 token。
    # ——————————————————–

    advantage = advantages[i]

    # ——————————————————–
    # PPO-style clip
    # ——————————————————–

    loss1 = (
    ratio
    * advantage
    )

    loss2 = (
    torch.clamp(
    ratio,
    1 – epsilon,
    1 + epsilon
    )
    * advantage
    )

    policy_loss = -torch.min(
    loss1,
    loss2
    ).mean()

    # ——————————————————–
    # Reference KL
    # ——————————————————–

    kl = (
    new_log_probs[i]
    – ref_log_probs[i]
    ).mean()

    beta = 0.01

    loss = (
    policy_loss
    + beta * kl
    )

    losses.append(loss)

    # ============================================================
    # 第 9 步:整个 Group 的 Loss
    # ============================================================

    grpo_loss = torch.stack(
    losses
    ).mean()

    # ============================================================
    # 第 10 步:反向传播
    #
    # 只有 Policy 更新。
    #
    # 没有 Critic!
    # ============================================================

    actor_optimizer.zero_grad()

    grpo_loss.backward()

    actor_optimizer.step()

    什么是 verl?什么是vLLM?

    因为“大模型 + 多 GPU + 高吞吐 rollout”会变得非常复杂,verl 专门解决这些工程问题,包括 rollout、actor、reference、reward、分布式训练和不同后端的组织;其当前文档还提供 FSDP、Megatron 等 worker/backends,并支持 RL 的 LoRA。自己就主要定义:模型、数据、reward、GRPO 参数。

    大模型训练框架

    LLaMA-Factory verl
    │ │
    ├── SFT ├── RL 重点
    ├── LoRA ├── PPO
    ├── DPO ├── GRPO
    ├── RM ├── DAPO
    └── PPO └── 大规模 rollout

    更“全能、易用” 更“专业 RL、工程化”

    使用 verl 训练 GRPO/PPO,实际情况是:不是完全 CLI 配置式(不像 LLaMA-Factory),而是“配置文件 + 少量代码”的方式。其中训练流程主要通过 CLI 启动,reward、数据处理等部分通常需要自己写 Python。

    一个典型 verl + GRPO 项目结构:

    my_grpo_project/

    ├── train_grpo.sh # 启动脚本
    ├── config.yaml # 训练配置

    ├── data/
    │ └── math.json

    ├── reward/
    │ └── reward.py # 自己写reward

    └── utils/
    └── preprocess.py

    verl + vLLM/SGLang 可以理解为一套面向大模型强化学习训练的工程组合:verl 负责“训练和调度”,组织 Actor、Reference、Reward、GRPO/PPO、Advantage 计算以及多 GPU 分布式更新;vLLM 或 SGLang 负责“高吞吐 rollout 推理”,让当前 Policy 能快速批量生成大量回答。也就是说,verl 决定“怎么学”,vLLM/SGLang 负责“怎么高效生成训练数据”。在 GRPO 中,典型流程就是:verl 把一批 prompt 交给 vLLM/SGLang → 当前模型为每个 prompt 生成多条 response → reward function 打分 → verl 计算组内 Advantage 和 GRPO loss → 更新 Policy → 再继续下一轮 rollout。这样做的主要原因是 RL 训练里大量时间花在生成 response 上,而 vLLM/SGLang 能显著提高这部分吞吐。

    verl 更像一个项目(框架),不是 PyPI 一个简单包。通常先git clone,clone 仓库后 pip install -e .,然后再安装其他可能需要的依赖。

    vLLM 不是 GRPO/PPO 必需的算法组件,而是一个高性能推理(rollout)引擎。verl 本身把训练逻辑和 rollout 解耦,可以接 vLLM、SGLang 等推理后端。官方文档也把 vLLM/SGLang 作为 inference backend 使用。它对于“完全调用模型厂商api”无效(因为不知道模型厂商是如何处理推理请求的),它主要适用于你自己持有模型权重并自行部署推理的场景。vLLM 本身也可以对外提供 OpenAI-compatible API。通过 PagedAttention、continuous batching 等机制提高高并发推理和 rollout 吞吐。其可承载并发量与可用于 KV Cache 的显存正相关,但并不是简单严格等于“可用显存 ÷ 单请求 KV Cache”。

    vLLM 本质就是一个 Python 包,不是必须 Docker。最常见就是直接使用pip安装(pip install vllm),当然服务器环境下推荐使用 Docker(docker pull vllm/vllm-openai,docker run后就可以得到 OpenAI API 风格接口,便于本地部署)。

    5.5.进一步使用RLVR

    RLVR 全称是 Reinforcement Learning with Verifiable Rewards,中文通常译为:带可验证奖励的强化学习。

    核心意思是:奖励不依赖人工主观打分,而是可以被程序或规则直接验证,比如数学题答案是否正确、代码是否通过单元测试、SQL 结果是否匹配、JSON 格式是否符合要求。这样就完全不需要❌Reward Model,变成Verifier,Verifier甚至不一定是神经网络,例如:

    reward = 1 if predicted_answer == ground_truth else 0

    或者以下逻辑的代码:

    LLM 生成代码

    运行 unit tests

    8/10 passed

    reward = 0.8

    RLVR 正是使用任务特定的 verifier 直接计算 correctness reward;数学 exact-match、代码测试等是典型场景。

    相比 RLHF:

    Human preference

    Reward Model

    Reward

    RLVR:

    客观答案

    Verifier

    Reward

    一个巨大优势是:不存在“RM 猜人类喜不喜欢”这个中间误差。

    不过缺点也明显:

    • 数学答案:很好验证、代码:很好验证;
    • “这篇文章写得好不好?”、“这个建议是不是有帮助?”、“这个 Agent 的研究结果是不是有洞察力?”,→ 很难写完美 verifier

    这也是为什么 RLVR 在数学、代码等可验证领域尤其自然,而开放式任务仍大量依赖 RM、LLM judge 或人类偏好。

    RLHF V.S. RLAIF V.S. RLVR

    RLHF

    Reinforcement Learning
    from
    Human Feedback

    人告诉你哪个好。典型:

    Human Preference

    Reward Model

    PPO

    InstructGPT 就是代表性范式。

    RLAIF,把 Human 换成 AI:

    AI Judge

    Preference

    Reward Model / reward

    RL

    本质区别:

    RLHF → 人评

    RLAIF → AI 评

    优化器仍然可能是:

    PPO
    GRPO
    RLOO

    RLVR,如上所述,奖励可以客观验证。

    5.6.GRPO 的缺点

    它省掉了 Critic,但不是白省。

    PPO:

    一个 prompt
    → 一个/若干 rollout
    → Critic 给 baseline

    GRPO:

    一个 prompt
    → 必须生成很多 rollout
    → 才能知道 group average

    所以:省 Critic 显存 ≠ 完全省计算,它会花很多 rollout inference。

    另外一个非常典型的问题:

    假设一道题生成 8 个:

    [0,0,0,0,0,0,0,0]

    全部错。

    那么:大家一样差,很难得到有效的相对 advantage。

    反过来:

    [1,1,1,1,1,1,1,1]

    也一样。

    所以 GRPO 很依赖:一个 prompt 下能产生有差异的样本。

    5.7.RLOO:GRPO 的一个很近的亲戚

    RLOO:REINFORCE Leave-One-Out,它也是:同一道题生成 K 个回答。

    比如:r1、r2、r3、r4,评估 r1 时:baseline = 平均(r2,r3,r4)、评估 r2 时:baseline = 平均(r1,r3,r4),也就是:“自己的 reward – 其他样本平均 reward”,作为自己的 advantage。

    RLOO 的原理正是利用同 prompt 的多个 online samples,让“其他样本的 reward”为当前样本提供 baseline,从而降低 REINFORCE 的方差。

    GRPO 和 RLOO 都可以理解成 Critic-free group-based RL,区别主要在具体 advantage estimator 和 objective 的设计。

    最原始的 REINFORCE

    假设:

    生成 response

    reward = +1

    那么:这整个 response 的 token 概率提升;如果:reward = -1,那么:概率下降。

    问题是:方差太大。今天生成reward = 0.7,明天再生成一次变成0.1,很难判断“到底是真的某个行为好,还是采样运气好?”。于是引入 baseline 变成 reward – baseline,再后来演变成 RLOO,因此,Actor-Critic、PPO、RLOO、GRPO 本质上很多东西都围绕“怎么更靠谱地估算 advantage?”展开。

    6.什么是OPD?

    On-Policy Distillation,截至 2026 年,这已经形成了一条比较明确的后训练路线。其核心思想是:Student 不学习一份 Teacher 事先生成好的静态数据,而是 Student 自己生成 trajectory,然后 Teacher 在 Student 真正访问到的状态上指导它。

    6.1.普通 Knowledge Distillation 怎么做?

    传统蒸馏:

    Teacher

    提前生成 100 万条高质量 reasoning

    Dataset

    Student SFT

    比如:

    GPT-XXL

    生成数学 CoT

    Q + Teacher CoT + Answer

    训练 7B Student

    问题:Student inference 时可能生成:Teacher 从来不会生成的错误 prefix。

    例如 Teacher 数据:

    A → B → C → D

    但 Student:

    A → B → X

    现在到了:

    A B X

    这个状态。训练集可能从来没有告诉 Student:到这里该怎么办?这叫很典型的:Distribution Mismatch / Exposure Bias。

    有工作通过在蒸馏时加一个KL散度来使学生模型尽力不偏出教师模型,阅读到过一篇论文:Learning to Maximize Mutual Information for Chain-of-Thought Distillation – 2024ACL Findings

    6.2.OPD 怎么解决 KD 的问题?

    让 Student 自己 rollout:

    Prompt

    Student

    token1

    token2

    错误 token3

    token4

    然后 Teacher 观察 Student 真实产生的 prefix:

    Prompt + Student token1 + token2 + token3 …

    Teacher 告诉它:

    在你现在这个状态下,
    我认为下一个 token 的概率应该是:

    A 0.72
    B 0.12
    C 0.03

    然后 Student:

    自己的 distribution
    vs
    Teacher distribution

    distillation loss

    update Student

    于是:

    Student 自己犯错

    Teacher 就在这个错误状态上教 Student

    这正是 On-Policy Distillation “learning from self-generated mistakes” 的核心思想。

    6.3.OPD 的完整数据链路

    Prompt


    Student Policy

    │ rollout

    Student-generated trajectory


    Teacher Model

    teacher token logits


    Student logits ↔ Teacher logits

    KL / distill loss


    Update Student

    注意:

    Teacher → frozen
    Student → train

    通常只有 Student 被优化。但是经典 OPD 里 Teacher 通常需要在训练时可实时访问,需要的是完整 token-level logits / probability distribution,也正因为 Teacher 要在训练过程中持续在线推理,标准 OPD 的基础设施成本比较高。

    6.4.OPD 不太算 RL

    因为它主要不是:

    reward

    maximize expected reward

    而是:

    teacher distribution

    student imitation / divergence minimization

    所以更接近:

    Imitation Learning
    +
    Knowledge Distillation
    +
    On-policy sampling

    不过它与 RL 的关系非常密切,因为“Student 自己 rollout”,这一点和 on-policy RL 非常像。

    6.5.OPD 的优缺点

    优点缺点
    token-level dense signal 要访问强 Teacher
    不需要训练 RM Teacher inference 很贵
    不需要 Critic Teacher 的错误也会传给 Student
    Student 在自己的状态上学习 Teacher/Student 分布差太远可能难训练
    比 terminal reward 更细粒度 tokenizer 等工程问题较复杂
    很适合 small model 不一定真正探索出 Teacher 不会的能力

    2026 年的研究(Rethinking On-Policy Distillation of LLMs – arxiv)还指出,OPD 并不是“Teacher 越强一定越好”:Teacher 与 Student 的行为/思维分布如果不兼容,Student 在自己访问的状态上得到的教师信号可能反而不可靠。

    6.5.Agentic OPD

    Student Agent:

    Task

    Thought

    Tool Search

    Observation

    Thought

    Tool Python

    Observation

    让强 Teacher 在 Student 的真实 agent trajectory 上指导:

    Student:
    我现在想调用 search("xxx")

    Teacher:
    在这个状态下,更合理的 action 应该是
    read_file(…)

    于是:

    Student 自己探索 Agent 环境
    +
    Teacher 给 step/token supervision

    2026年已经有研究(Step-wise On-policy Distillation for Small Language Model Agents – arxiv)专门把 step-wise OPD 用在小模型 tool-integrated agent 上,目的之一正是解决长工具调用 trajectory 中错误逐步累积的问题。

    赞(0)
    未经允许不得转载:171主机测评 » 大模型应用开发--Agent笔记3(Agentic RL--大模型 RL 到底在干什么?RLHF、PPO、DPO、GRPO、RLOO、OPD等算法思想、完整链路和相关概念)
    分享到: 更多 (0)

    评论 抢沙发

    • 昵称 (必填)
    • 邮箱 (必填)
    • 网址