写在前面
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
| 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:
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 中错误逐步累积的问题。


