Agentic RL:PG Loss 组件详解(PPO-clip / Dual-Clip / Entropy / KL / 聚合)
这篇文章把「Agentic RL / LLM-RL 训练里常见的 Policy Gradient (PG) loss 到底由哪些组件拼起来」讲清楚,重点解释:
- PPO-clip:为什么要 clip、clip 住了哪些情况、什么时候梯度为 0
- Dual-clip:它在 PPO-clip 基础上到底“多 clip 了什么”,解决什么不稳定
- Entropy / KL:为什么要加正则、权重怎么理解
- 聚合(aggregate):token/sequence/group 维度的 sum/mean 会如何改变梯度尺度
- 推导补全(视频 02):从 REINFORCE / PG 到 TRPO,再到 PPO-clip,解释
log pi、ratio、以及“为什么 PPO 公式里看起来没有 log”
本文偏“工程视角”:你看完应该能把这些项在代码里正确实现出来,并能解释训练曲线为什么会那样。
补充说明:下面不少“实现细节/监控指标/聚合模式”的表述,我会刻意对齐 verl 生态里常见写法。
我不会把任何视频/博客里的“经验区间”当成硬规则。对 LLM-RL 来说,更可靠的做法是:把每个超参都映射回它影响的对象(采样分布 / 数据复用 / 更新幅度 / 探索强度),然后用日志把因果关系闭环验证。
你后面读到 clip fraction / KL / entropy / loss agg 这些东西时,如果你能回答下面 3 个问题,基本就不会被“配方”带偏:
- 你在约束哪一个分布的偏离:
π_new vs π_old还是π vs π_ref? - 你看到的统计量是 token-level 还是 seq-level 聚合?(这会直接改变数值尺度)
- 你这次更新到底复用了多少 rollout 数据(
ppo_epochs/ 多轮优化)?复用越强,越容易变成轻度 off-policy。
关联阅读(更偏“现象与边界”而不是公式):
系列导航:
如果你想先把 PG -> TRPO -> PPO-clip 的推导主线补齐,再回来看这些“工程组件”,建议配套阅读:
Agentic RL:从 PG 到 TRPO 到 PPO-Clip(推导与代码对齐)
配套资料(视频 + GitHub)
这篇文章的写作素材来自视频 + 你本地已经下载的配套仓库。我不会照搬视频口述,而是把“loss 组件”按工程实现需要的维度拆开,同时给你能直接对照的 notebook/代码入口。
- 视频 01(PG loss 组件):
BV1KFpczQEkA - 配套仓库(你本地已下载):
wdkns/modern_genai_bilibili
建议你优先对照这些笔记(按“从抽象到实现”的顺序):
- PG/PPO 代理目标的“组成零件”与符号约定
agentic_rl/deep_RL/objective_代理loss.ipynb
- 从 PG 推导到 PPO-clip 的主线(包含 ratio/clip/稳定性直觉)
agentic_rl/deep_RL/pg/from_pg_to_ppo-clip.ipynb
- PPO 从零实现(更偏经典 RL,不含 LLM 特殊项,但能补齐最基本的实现细节)
agentic_rl/deep_RL/ppo/ppo_from_scratch.ipynb
- loss 聚合(token/seq/group)为什么会改变数值尺度(对齐你后面看 verl 的日志)
agentic_rl/verl/objectives/agg_loss.ipynb
- KL/entropy 的数值内涵与训练诊断(别背“经验区间”,用指标闭环)
agentic_rl/training_practices/review_kl.ipynbagentic_rl/training_practices/entropy.ipynb
如果你在 RL4LLM/Agentic RL 里遇到 “fKL / rKL” 方向搞混、或 KL 数值解释不通,也可以补看:
agentic_rl/sft_rl_fkl_rkl.ipynb
0. 背景:我们在优化什么
强化学习(policy gradient)最朴素的目标是最大化期望回报:
但直接对回报做梯度很难,于是我们引入可优化的代理目标(surrogate objective),用“概率比 + 优势函数”把“回报最大化”转成可微的 loss。
当你训练的是 LLM(token 级动作)或 Agent(工具调用/检索/规划动作),形式几乎一样,只是:
- 动作可能是 token,也可能是工具调用、检索 query、规划步骤
- 优势可能来自 reward model、对比评分器、规则评测、人工偏好、任务成功率等
1. 记号与核心中间量(非常重要)
一条轨迹里第步:
- 状态:(例如 prompt + history)
- 动作:(token / 工具调用 / 选择哪个候选等)
- 新策略:
- 旧策略:
- 优势:(“这步动作比平均水平好多少”)
重要采样比(importance ratio):
为什么要 ratio?
- 你的数据通常是用旧策略采样的(rollout 时的策略),但你想更新新策略
- ratio 允许你在“旧数据”上估计“新策略”目标(近似、但有效)
2. Vanilla Policy Gradient(从这里出发)
最常见的一种 PG 代理目标(最大化形式):
工程里我们一般写成“最小化 loss”,所以常见写法是取负号:
问题是:如果你直接这么做,更新会非常不稳定。
原因直观上是:的梯度可能会推动策略一步跨得很大,尤其当大、或某些动作在旧策略里概率极小导致 ratio 爆炸时。
3. PPO-clip:用 clip 做“近似 trust region”
PPO 的核心代理目标(最大化形式):
其中通常是 0.1 或 0.2。
在工程实现里,你几乎一定会看到最小化 loss 的等价写法(HF PPO / verl 常用):
它就是上面 maximize 版本取负号后,把 min 翻转成 max 得到的。
3.1 直觉:限制“新策略相对旧策略”的变化幅度
- 表示“新策略把这个动作概率放大/缩小了多少”
- clip 把限制在
所以 PPO-clip 做的事情是:你可以变,但别变太猛。
3.2 什么时候 clip 会“生效”(梯度变 0 或被截断)
把情况按的符号拆开看最清楚:
- 当(这个动作是“好动作”,我们希望提升概率)
- 如果:提升得太猛了,会被 clip,等价于“这部分梯度被截掉”
- 当(这个动作是“坏动作”,我们希望降低概率)
- 如果:降低得太猛了,会被 clip
你会发现:PPO 的 clip 本质是在限制“朝着对优势有利的方向”更新过头。
3.3 训练时看什么:reward 曲线优先,其次看这些“稳定性指标”
PPO-clip 的 loss 是 surrogate objective,不一定和“任务真的变好”单调对应;实践里更应该关注 rewards curve(你定义的任务 reward / RM reward / success rate 等),loss curve 只当作辅助信号。
除了 reward 曲线,建议至少监控这些量(很多训练框架会直接给出):
actor entropy:熵太快掉到很低,常见是探索不足/模式塌缩的前兆。KL(对 reference / SFT / old policy 的偏离):漂移过大常见会让输出质量崩。clip fraction:被 clip 的样本比例(token-level 或 seq-level,看实现)。advantage的统计量:均值/方差/分位数,尤其注意优势刻度突然变大或分布漂移。
clip fraction 怎么解读?
- 直觉:被裁剪的样本通常“不给有效梯度”,等价于 有效 batch 变小。clip fraction 越高,更新越被少数未裁剪样本主导,学习容易停滞或变得不稳定。
- 不要背“黄金区间”。更靠谱的做法是把它和
approx_kl(old,new)、学习率、ppo_epochs联动看(我在 veRL/verl 那篇里给了更系统的诊断表):Agentic RL:veRL(verl)训练参数理解(PPO & GRPO、Batch Size、KL & Entropy)
clip fraction 和 KL 的耦合(非常实用的排查思路)
- clip fraction 高 + KL 也高:常见是步子太猛(学习率大、PPO epoch 多、优势刻度过大、reward 过陡等)。
- clip fraction 高但 KL 不高:常见是对同一批数据复用太多(epoch 太多 / 复用过度),把推到边界但整体分布偏离并不大。
- clip fraction 长期接近 0:常见是步子太小(学习率小、优势过小、KL/entropy 系数过大把更新压住)。
3.4 一个经常被忽略的现实:PPO 在 LLM-RL 里很容易“轻度 off-policy”
很多解释会说 PPO 是 on-policy,因此更稳定。但在真实训练里你几乎一定会做:
- rollout 很贵,所以同一批数据要做多个 epoch 更新(
ppo_epochs > 1) - 一个 rollout batch 很大,所以会切成很多 mini/micro 更新
结果是:当你跑到第 2/3 个 epoch 时,当前策略已经不是产生数据的策略,你会看到这些典型信号:
- ratio 分布变尖(大量样本贴到 clip 边界)
clip fraction上升approx_kl(old,new)上升- reward 不一定更好,甚至出现 reward hacking(因为你在“反复榨同一批数据”)
所以我更建议你把 ppo_epochs 当成“数据复用强度旋钮”,而不是“训练更充分”的旋钮。通常的排查顺序是:先降 epoch 再谈别的(否则你会把很多问题误判成 reward/模型问题)。
3.5 policy_loss 曲线怎么看(注意符号约定)
不同代码对 policy_loss 的符号约定不完全一致:有的记录“要最小化的 loss”(常见为负),有的记录“maximize 的 surrogate”(常见为正)。
一个可操作的解读方式是:
- 如果
policy_loss(最小化形式)长期非常负:通常意味着优势项在推动策略快速提升,但也可能是 critic 跟不上 actor(critic 低估,adv 偏大),容易引入不稳定。 - 如果
policy_loss(最小化形式)长期为较大的正:通常是“坏动作占比大/优势为负占主导”,策略在变差或学不到东西的信号。 - 更理想的趋势:在 0 附近上下震荡,说明 actor/critic 在互相追赶并逐步稳定。
4. Dual-clip:为什么 PPO-clip 还不够
在实践里,很多人会再加一个 dual-clip,主要解决这样一种现象:
当(坏动作),但可能非常大(新策略反而大幅提高了坏动作的概率)时,PPO-clip 在某些写法下对这块的“保护”不够,loss/梯度可能会被放大,导致训练震荡。
你可以把 dual-clip 理解成:对某些极端 case 再加一道上限/下限,避免目标函数在异常 ratio 下过度放大。
4.1 Verl/HF 常见写法(最小化 loss 形式,对齐更容易)
先把 PPO 写成最小化 loss(忽略期望符号,只写单个样本/单个 token 的形式):
Dual-clip(常见引用:arXiv:1912.09729)在很多实现里会对负优势样本再加一道“上界保护”:
直觉解释:
- 当时,是正数,它会把某些极端情况下的巨大正 loss 截住(避免 ratio 异常大导致 loss/梯度过度放大)。
- 当时,这个额外项通常不启用或不会改变结果(不同代码会用条件分支实现)。
4.2 参数怎么选
经验上很多实现会用 2 到 5 的量级(比如 3)。它不是越大越好:
- 太小:保护太强,学习可能变慢
- 太大:保护太弱,起不到稳定作用
5. Entropy:为什么要鼓励“更随机”
entropy bonus 常见形式(加入到最小化 loss):
5.1 从 logits 计算 token-level entropy(verl 常见写法)
很多实现会直接从 logits 计算每个 token 的熵(注意输出仍然是,后面要走 agg_loss 聚合):
1 | import torch |
直觉:
- 在早期训练,鼓励探索(别过早塌缩到某一种输出模式)
- 在 LLM 训练里,entropy 太低会导致输出变得呆板,甚至出现 mode collapse
怎么调参:
- 太大:模型“太随机”,reward 上不去
- 太小:容易塌缩或过拟合到奖励漏洞
6. KL:为什么用 KL 约束,而不是 JS
很多 LLM-RL(尤其 RLHF / RLAIF / 各种 agentic RL 变体)都会加 KL 正则,典型是约束当前策略别偏离参考策略(常见是 SFT 模型或某个 frozen baseline):
先说我的观点:在大多数 LLM-RL 工程里,真正决定训练行为的不是 “KL vs JS”,而是:
- 你在约束哪一个 KL(方向):还是?
- 你怎么算 KL(full distribution 还是 sampled 近似)?
- 你怎么聚合(token/seq/group)?
这三件事只要有一件变了,KL 的数值尺度与梯度性质就会明显变化,配方参数基本不可迁移。
6.1 KL 在工程上“很好算”
在 token-level 的实现里,你往往只需要:
(实际会有更精细的估计方式,但核心是:你只要能拿到 logprob 就行)
而 JS 散度需要混合分布:
这意味着你要显式构造/评估,工程上更麻烦、也更贵。
6.2 KL 更符合“单向约束”的需求
在 RLHF 里,你常见的真实需求是:
“在提高 reward 的同时,别偏离 reference 太远。”
这本质是一个单向的、带约束的优化问题,KL 非常自然。
JS 虽然对称、有界,但它的对称性并不一定是你想要的,而且在高维动作空间(比如大词表)里,JS 的数值/梯度性质也未必更稳定。
6.3 更重要的一点:PPO/TRPO 的理论也经常围绕 KL
TRPO 的 trust region 约束是直接写 KL 的;PPO 也是在用 clip 近似这个约束。
所以当你把 PPO-clip + KL penalty 放在一起看,会发现它们在做同一类事情:
- PPO-clip:约束“这一步更新别太大”
- KL penalty:约束“整体别偏离 reference 太远”
6.4 KL 放在 reward 里 vs 放在 loss 里(RLHF/LLM-RL 很常见)
在 LLM-RL 里,KL 有两种非常常见的“落点”:
- 加在 loss 里:
policy_loss += kl_loss * kl_coef(verl/HF 里常见)。 - 写进 token-level reward(reward shaping):把 KL 看成一个“密集惩罚”,例如常见形式
其中往往只在序列最后一个 token 非零(或以序列级 reward 形式给出),而 KL 惩罚是 token 级的“每步都扣分”。两者目标一致:限制偏离,但优化动态、日志解读、以及和 advantage/GAE 的耦合会有差异。
6.5 我更建议你关注 KL 的“行为偏好”:它天然会削尖分布
只要你用的是(很多 RLHF/RLVR 常见写法),它在优化上更像一种 mode-seeking 的约束:跑到 ref 低概率区域会被强烈惩罚,因此更容易出现:
- 多样性下降(entropy 下降)
- 输出更模板化(distribution sharpening)
- 某些“低概率但正确”的路径被压没(你在 RLVR 那篇里已经见过这种现象)
这不是说 KL 不好,而是提醒你:当你看到“模型更稳但更保守”时,首先怀疑的不是“模型退化”,而是 KL/clip/聚合把探索掐掉了。这时更有效的动作往往是:
- 把 KL 当作控制量:设目标区间,按日志闭环调(而不是背一个常数系数)
- 先减数据复用强度(
ppo_epochs),再谈增大 KL(否则你会把 off-policy 问题误归因到 KL) - 明确你要的是“单次命中率提升”还是“能力边界拓展”(这两者的系统策略完全不同)
7. 聚合(Aggregate):token / sequence / group 的差别
LLM 的 logprob、advantage 很多时候都是 token-level 的张量(形状)。
你最终需要把它聚合成一个标量 loss 才能 backward()。常见聚合方式:
- token mean:对所有有效 token 取平均
- sequence mean:先对每个序列求平均,再对 batch 平均
- token sum:对 token 求和(注意会放大梯度尺度)
- group mean(GRPO 常见):先在 group 内聚合,再在 group 间聚合
核心结论:聚合方式会改变梯度的等效尺度,从而影响你对学习率、clip、KL 系数等超参的感受。
如果你把 mean 换成 sum,很多时候你会发现“同样的超参突然不稳定了”,原因往往就是梯度整体变大了。
7.1 常见 loss_agg_mode 的数学定义(带 mask)
设 loss 矩阵,mask(为 1 的位置计入损失):
token-mean- $$
seq-mean-token-sum- $$
seq-mean-token-mean(很多论文把它当成“sample-level loss”)- $$
seq-mean-token-sum-norm(一种“按长度做归一化”的 token-sum)- $$
7.2 和 GRPO / DAPO / DrGRPO 的对应(为什么会影响长 CoT 稳定性)
以 verl 文档/实现里的口径总结(不同实现会有细微差异,但核心直觉一致):
- GRPO 原始论文常用
seq-mean-token-mean(sample-level),在长 CoT 场景可能更不稳定。 - DrGRPO 倾向使用
seq-mean-token-sum-norm(降低长度偏置/数值不稳)。 - DAPO 倾向使用
token-mean(直接在 token 维度平均,梯度尺度更直观)。
如果你的任务输出长度差异很大(例如 deep research 报告长短不一),聚合方式几乎一定会影响训练是否稳定,甚至会直接改变“模型更偏好长输出还是短输出”(长度偏置)。
7.3 GSPO/GRPO:序列级 ratio、长度偏置与 stop-gradient trick
很多 LLM-RL 的不稳定来自两个因素叠加:
- token-wise ratio 在长序列上更容易数值爆炸/塌缩
- 长序列天然贡献更多 token,导致“长输出占更多梯度份额”(长度偏置)
以 GSPO 的一种常见写法为例,会先定义序列级的归一化 ratio:
再把它“分摊回 token 级”,并用 stop_gradient(记作 sg[·])避免破坏梯度结构:
直觉:让每个样本(序列)在 ratio 上先被长度归一化,再决定 token 级梯度怎么分配,从而缓解长度偏置和 token-wise 数值问题。
8. 从 PG 到 TRPO 到 PPO-clip(视频 02 推导补全)
这一节对应视频 [Agentic RL] 02 策略梯度基础,从 PG 到 TRPO 到 PPO-Clip 核心公式简单推导 的主线(配套 notebook 在 modern_genai_bilibili/agentic_rl/deep_RL/pg/from_pg_to_ppo-clip.ipynb)。
它主要回答 3 个“看公式经常卡住”的问题:
- PG loss 里为什么有
log π? r_t = π/π_old这个 ratio 是怎么来的?- 为什么 PPO-clip 公式里看起来“没有 log”?
8.1 REINFORCE:为什么会出现 log π
最朴素的 RL 目标(最大化期望回报)是:
你想对求梯度,但麻烦在于:期望是对“由采样出来的轨迹分布”取的,属于对分布求导。
核心技巧就是 log-trick(score function estimator):
应用到轨迹上,并利用环境转移与奖励不依赖(依赖的是策略),得到经典的 REINFORCE / Policy Gradient 形式:
其中是 return-to-go(从往后累计的折扣回报)。
工程里我们通常把“最大化”改写成“最小化 loss”,构造一个等价梯度方向的 surrogate loss:
这就是你在代码里看到的 PG loss / policy loss 的最原始版本(再加上后续的 clip、entropy、KL 等项,就变成 PPO 系列)。
8.2 Advantage:为什么可以从变成
PG 的方差很大,所以会引入 baseline来降方差而不引入偏差。关键性质是:
因此:
通常把叫做优势(advantage):
于是常用的 PG loss 形式就是:
8.3 Importance Sampling:ratio怎么来的,为什么 PPO 公式里“没 log”
现实训练里,你经常会:
- 先用旧策略rollout 一批轨迹(采样数据很贵)
- 再在同一批数据上做多次更新(多 epoch / 多 step)
此时你的期望在数学上应该写成“在旧分布上做重要性采样”:
对应得到 CPI/TRPO 常写的 surrogate objective:
一个很关键的观察(视频里强调的点)是:在附近,
也就是说,ratio 版本的目标在旧策略附近的一阶梯度方向与 vanilla PG 是一致的。
这也解释了“为什么 PPO 公式里看起来没有 log”:PPO 的目标写成了的形式,但在代码里你仍然会先算 logp_new/logp_old,然后做:
log 并没有消失,只是被你通过 exp(logp_new - logp_old) 隐藏到了 ratio 里。
8.4 TRPO:把“更新别太猛”写成 KL 约束(trust region)
仅用还是可能出现“策略一步跨太大”导致性能崩溃的问题。TRPO 的做法是加一个 trust region 约束:
直觉:在“以旧策略为中心”的 KL 球里,找一个能让 surrogate 最大的更新。
缺点:这个约束优化在实现上通常要用二阶近似/共轭梯度等技巧,不太适合直接塞进深度学习常见的 mini-batch SGD 训练循环。
8.5 PPO-clip:用 clip 做一个“好用的 TRPO 近似”
PPO-clip 用一个非常工程友好的方式近似 TRPO 的 KL trust region:
最值得记住的 case-by-case 结论(你在实现/排查时会天天用):
- (好动作)
- :涨太猛,clip 生效,梯度被截平
- (坏动作)
- :降太猛,clip 生效,梯度被截平
换句话说:PPO 的 clip 主要限制“朝着对优势有利的方向”更新过头,从而把“稳定性”换成“训练效率/实现简单”。
这也回扣到本文主标题:在实际工程里,所谓 “PG loss components” 里最核心的一块,就是这个 PPO surrogate(通常写成 clip 版本),再叠加 entropy/KL/dual-clip/聚合等工程项。
9. PyTorch 伪代码:把这些项拼起来(可直接对照你用的框架)
下面给一个“最常见”的结构示例,假设你已经有:
logp_new: 当前策略对采样动作的 logprob,形状[B, T]logp_old: rollout 时旧策略 logprob(需要detach),形状[B, T]advantages: 优势(需要detach),形状[B, T]mask: 有效 token mask(padding 位置为 0),形状[B, T]entropy: 可选,形状[B, T]logp_ref: 参考策略 logprob(可选),形状[B, T]
1 | import torch |
9.1 读代码时最容易踩坑的点
- 最大化 vs 最小化:论文写 maximize,代码写 minimize;
min/max会翻转。 - advantages / logp_old 要 detach:它们是“常数”,不应对它们反传。
- mask 一定要做:padding token 不能算进 loss。
- 聚合方式会改变梯度尺度:mean/sum 会影响你对 lr/clip/kl 的直觉。
9.2 如果你用的是 verl:如何“真的改到代码里”
modern_genai_bilibili 的笔记里给了一个很实用的路线图(这里总结成可执行的 checklist):
- 全局搜
.backward(),先找到训练主循环真正反传的 loss(通常是loss.backward())。 - 在
core_algos.py(或同名文件)里找compute_policy_loss,它通常是 “PG loss 的注册中心”。 - 通过类似
@register_policy_loss("xxx")的注册机制添加新的pg_loss变体(例如把 entropy/KL/特殊 ratio 写法组合进去)。 - 如果你要改的是 training logic(比如动态采样、rollout 管理、异步 agent loop),通常需要自定义 Trainer(笔记里提到的
RayDAPOTrainer就属于这类)。
10. 这和 Agentic RL / Deep Research 有什么关系
如果你做的是“deep research agent”(检索 + 阅读 + 归纳 + 写作),你不一定要微调 LLM 本体。
更现实的路线是:
- LLM 用 API(当成 black-box policy 或 planner)
- 你训练的是 agent 的决策层:何时检索、检索什么、读哪些文档、如何分解任务、如何分配预算
- reward 来自任务指标:答案质量、引用覆盖、事实一致性、时间/成本、用户满意度等
这时 PPO/GRPO 这些 loss 仍然是核心工具,只是动作空间从“token”扩展到了“工具与策略”。
如果你具体做的是“deep research 报告型任务”,建议尽早把评测闭环定下来:
- RACE:评估报告质量(覆盖度/洞察/指令遵循/可读性),并用相对评分避免“打分膨胀”。
- FACT:逐条核查“每一个引用是否支撑对应陈述”,把 citation trustworthiness 从纯生成质量里拆出来单独评。
11. 小结
- PPO-clip 的本质:用 ratio + clip 做稳定的 surrogate objective
- dual-clip 的本质:对极端 case 再加一道保护,减少震荡
- entropy/KL 的本质:一个防塌缩,一个防漂移
- aggregate 的本质:改变梯度尺度,影响所有超参的手感

