Agent 训练实战 / 03
GRPO vs PPO:Agent 强化学习算法深度对比与选型
上一篇讲了 Agent RL 的整体框架和 Reward 设计。算法层面提到了 PPO 和 GRPO,但没有展开。这篇专门把这两个算法拆开讲清楚——不是推公式,而是回答一个工程问题:你的 Agent 训练场景该选哪个,为什么?
PPO 是 RLHF 时代的事实标准,InstructGPT、ChatGPT 都用它。GRPO 是 DeepSeek-R1 带火的新方案,去掉了 Critic 网络,用组内相对排序替代绝对打分。两者的设计哲学不同,适用场景也不同。
先搞清楚一个前置问题:为什么需要优势估计
不管是 PPO 还是 GRPO,核心目标都是一样的:让好的动作出现概率增大,让差的动作出现概率减小。 但怎么判断一个动作是“好”还是“差”?
直觉上用 Reward 就行了——Reward 高就是好动作。但 Reward 的绝对值没有意义,有意义的是相对于基线好了多少。这就是“优势(Advantage)”的概念:
Advantage = 这个动作实际获得的回报 - 在当前状态下"平均"能获得的回报
A(s, a) = Q(s, a) - V(s)
> 0 → 这个动作比平均水平好 → 应该增加概率
< 0 → 这个动作比平均水平差 → 应该降低概率
= 0 → 和平均水平一样 → 不用调
PPO 和 GRPO 的核心分歧就在于:怎么估计这个“平均水平”。
PPO:用 Critic 网络估计基线
核心机制
PPO 的做法是训练一个额外的 Value 网络(Critic),专门预测“在当前状态下,未来能拿到多少 Reward”。
(对话历史 + 工具返回)"] --> B["Policy 网络
(Agent 模型)"] A --> C["Value 网络
(Critic)"] B --> D["输出动作 a
(tool_call 或文本)"] C --> E["输出 V(s)
预估未来回报"] D --> F["环境返回 Reward r"] F --> G["Advantage = r + γV(s') - V(s)
(用 GAE 更精确)"] G --> H["用 clipped objective
更新 Policy"] G --> I["用 MSE loss
更新 Critic"] style B fill:#022c22,stroke:#10b981,color:#34d399 style C fill:#1e293b,stroke:#f59e0b,color:#fbbf24 style G fill:#1a2535,stroke:#334155,color:#94a3b8
关键公式(伪代码形式):
# 1. 用 GAE 计算优势
for each step t in trajectory (reversed):
delta_t = reward_t + gamma * V(s_{t+1}) - V(s_t)
advantage_t = delta_t + gamma * lambda * advantage_{t+1}
# 2. 计算策略更新的目标函数
ratio = pi_new(a|s) / pi_old(a|s) # 新旧策略的概率比
clipped_ratio = clip(ratio, 1-eps, 1+eps) # 限制更新幅度
policy_loss = -min(ratio * advantage, clipped_ratio * advantage)
# 3. 更新 Critic
value_loss = MSE(V(s), actual_return)
# 4. 总 loss
total_loss = policy_loss + c1 * value_loss + c2 * KL(pi_new || pi_sft)
PPO 在 Agent 场景的具体问题
问题 1:Critic 网络的显存开销
Agent 模型本身可能就是 7B–70B 参数。PPO 需要一个同等规模的 Critic 网络(通常和 Policy 共享底层,加一个 Value Head)。在 Agent 场景中:
显存占用估算(以 7B 模型为例):
├── Policy 模型 ~14 GB (FP16)
├── Policy 优化器状态 ~28 GB (Adam, FP32)
├── Critic 模型 ~14 GB (FP16)
├── Critic 优化器状态 ~28 GB (Adam, FP32)
├── KV Cache + 激活值 变长,Agent 轨迹越长越大
└── 总计 ~84 GB + 激活值
对比没有 Critic 的方案,PPO 的显存开销几乎翻倍。在 Agent 场景中轨迹本身就很长(几千到上万 tokens),KV Cache 已经占了不少显存,再加一个 Critic 压力很大。
问题 2:Critic 网络难训
Critic 要预测“从当前状态出发,未来能拿到多少 Reward”。这在 Agent 场景中特别难,因为:
- Agent 的状态空间是变长文本,不像游戏状态那样是固定维度的向量
- 一条轨迹里 Reward 可能只在最后一步才有(稀疏 Reward),中间步骤的 Value 全靠 Critic 自己估计
- Agent 执行路径的方差很大——同一个起点,不同的工具调用可能导致完全不同的结果
Critic 估计不准,Advantage 就不准,策略更新的方向就会偏。这是 PPO 在 Agent 场景中不稳定的主要来源。
问题 3:Clip 机制的两面性
PPO 的 clip 机制限制了每次更新的幅度(通常 ε = 0.1–0.2)。好处是稳定,坏处是在 Agent 场景中可能太保守——模型需要较大的策略调整才能从“错误的工具调用习惯”转变到“正确的调用方式”,clip 会拖慢这个过程。
GRPO:用组内相对排序替代 Critic
核心机制
GRPO 的设计哲学完全不同:不训练 Critic,不估计绝对 Value,而是让同一个 prompt 的多条轨迹互相比较。
生成 N 条轨迹"] B --> C1["轨迹 o₁ → Reward r₁"] B --> C2["轨迹 o₂ → Reward r₂"] B --> C3["轨迹 o₃ → Reward r₃"] B --> C4["... oₙ → Reward rₙ"] C1 --> D["组内归一化
Â_i = (r_i - mean) / std"] C2 --> D C3 --> D C4 --> D D --> E["用归一化后的 Â
更新 Policy"] style B fill:#022c22,stroke:#10b981,color:#34d399 style D fill:#1e293b,stroke:#f59e0b,color:#fbbf24
关键公式(伪代码形式):
# 1. 对同一个 prompt,生成 N 条轨迹
for i in range(N):
trajectory_i = policy.rollout(prompt)
reward_i = compute_reward(trajectory_i)
# 2. 组内归一化,得到相对优势
mean_r = mean(rewards)
std_r = std(rewards)
for i in range(N):
advantage_i = (reward_i - mean_r) / std_r
# 3. 用 clipped objective 更新策略(和 PPO 类似)
ratio = pi_new(o_i|q) / pi_old(o_i|q)
clipped_ratio = clip(ratio, 1-eps, 1+eps)
loss = -min(ratio * advantage_i, clipped_ratio * advantage_i)
# 4. 加 KL 约束
total_loss = loss + beta * KL(pi_new || pi_sft)
核心区别一目了然:没有 Critic,没有 Value 估计,优势完全来自同组轨迹的相对比较。
GRPO 的关键设计决策
决策 1:N 取多少?
N 是每个 prompt 生成的轨迹数量,直接影响训练质量和成本:
| N | 优势估计质量 | Rollout 成本 | 适用场景 |
|---|---|---|---|
| 4 | 较粗,噪声大 | 低 | 快速迭代、Reward 区分度高 |
| 8 | 中等,实用 | 中 | 大多数场景的默认选择 |
| 16 | 较好 | 高 | Reward 区分度低、需要精细排序 |
| 32+ | 很好但边际递减 | 很高 | 不推荐,性价比低 |
经验值:N=8 是大多数 Agent 场景的 sweet spot。 更大的 N 带来的优势估计改善不足以 justify 翻倍的 rollout 成本。
决策 2:Reward 归一化的粒度
GRPO 原始论文是在每个 prompt 的 N 条轨迹内做归一化。但也有变体:
选项 A:Per-prompt 归一化(原版)
优势_i = (r_i - mean(同 prompt 的 N 条)) / std(同 prompt 的 N 条)
✓ 消除了不同 prompt 难度差异的影响
✗ N 太小时 std 估计不稳定
选项 B:Per-batch 归一化
优势_i = (r_i - mean(整个 batch 所有轨迹)) / std(整个 batch)
✓ 统计量更稳定
✗ 简单 prompt 和难 prompt 的 Reward 混在一起,信号被稀释
选项 C:Per-prompt 归一化 + batch 级别 std 兜底
mean 用 per-prompt,std 用 max(per-prompt std, batch std * 0.1)
✓ 兼顾两者优点
实践中选项 A 最常用,但如果发现训练不稳定(loss 震荡大),可以切换到选项 C。
决策 3:如果一个 prompt 的 N 条轨迹全成功或全失败怎么办?
这是 GRPO 一个容易被忽略的 edge case:
情况 1:N 条轨迹全拿到 Reward=1
→ std=0,归一化除以 0
→ 所有 advantage 变成 0,这个 prompt 对训练没贡献
情况 2:N 条轨迹全拿到 Reward=0
→ 同上,对训练没贡献
这在 Agent 场景中很常见——简单任务全做对,极难任务全做错。
解决方法:
- 给 std 加一个小的下界(如 1e-4),防止除零
- 在任务采样时做难度均衡,确保每个 batch 里有一定比例的“中等难度”任务(模型做对 30%–70% 的那种)
- 监控“有效 prompt 比例”——如果超过 50% 的 prompt 的 N 条轨迹结果完全一致,说明任务难度分布需要调整
GRPO 的优势:为什么 DeepSeek 选它
省显存,省得不是一点点。
GRPO 显存占用(7B 模型):
├── Policy 模型 ~14 GB
├── Policy 优化器状态 ~28 GB
├── Reference 模型 ~14 GB (SFT checkpoint, 推理模式, 不需要优化器)
├── KV Cache + 激活值 变长
└── 总计 ~56 GB + 激活值
对比 PPO:~84 GB + 激活值
省了 ~28 GB(Critic 的优化器状态)+ Critic 的激活值
对于 Agent 场景,这个差距更大——Agent 轨迹长,KV Cache 本身就吃显存,省掉 Critic 的显存可以换成更长的轨迹长度或更大的 batch size。
不存在 Critic 估计不准的问题。
GRPO 的优势完全来自实际 Reward 的比较,不依赖任何网络的估计。只要 Reward 函数本身是可靠的,优势估计就是可靠的。在 Agent 场景中,Reward 通常比 Value 好估计得多——“这条轨迹任务完成了吗”比“从当前状态出发未来大概能得多少分”简单太多。
更适合结果导向的 Reward。
Agent 场景中最常见的 Reward 形式是“任务最终完成了给 +1,否则 0”——整条轨迹只有一个 Reward。PPO 在这种场景下需要 Critic 把这个终末 Reward 传播到每一步(通过 GAE),传播过程中误差会累积。GRPO 直接在轨迹级别比较,天然适合这种粗粒度 Reward。
GRPO 的劣势:什么场景不该选它
Rollout 成本翻了 N 倍。
PPO 每个 prompt 只需要 1 条轨迹,GRPO 需要 N 条。在 Agent 场景中,一条轨迹可能涉及多次工具调用,每次调用都有延迟。N=8 意味着 rollout 时间(和工具调用成本)翻 8 倍。
Rollout 成本对比(假设每条轨迹 5 次工具调用,每次 2 秒):
PPO: 1 条轨迹 × 10 秒 = 10 秒/prompt
GRPO: 8 条轨迹 × 10 秒 = 80 秒/prompt(可并行到 ~10 秒,但 GPU 成本 ×8)
如果工具调用涉及付费 API(比如外部搜索引擎、数据库查询),这个成本会更直接。
对 Reward 区分度的要求高。
GRPO 靠同组轨迹之间的 Reward 差异来学习。如果 Reward 区分度低(大部分轨迹得分差不多),GRPO 的学习信号就很弱。
好的 Reward 分布(GRPO 友好):
轨迹 1: 0.9 轨迹 2: 0.3 轨迹 3: 0.7 轨迹 4: 0.1
→ 有明显的排序,GRPO 能学到东西
差的 Reward 分布(GRPO 不友好):
轨迹 1: 0.82 轨迹 2: 0.79 轨迹 3: 0.81 轨迹 4: 0.78
→ 差异太小,归一化后的优势接近噪声
PPO 不存在这个问题,因为它的优势估计来自 Critic,不依赖同组比较。
不擅长 step-level 的信用分配。
GRPO 原版对整条轨迹给一个统一的优势分数。但 Agent 轨迹中,可能前 4 步都是对的,第 5 步选错了工具导致失败——GRPO 会给整条轨迹一个负优势,前 4 步被错误惩罚了。
PPO 通过 GAE 可以做 step-level 的信用分配——每一步有各自的优势估计,更精细。
缓解方法:GRPO 的变体可以引入 step-level 的 Reward(比如每一步工具调用成功 +0.1),但这就回到了“需要设计过程 Reward”的老问题。
全面对比
| 维度 | PPO | GRPO |
|---|---|---|
| Critic 网络 | 需要,额外显存和训练成本 | 不需要 |
| 显存占用 | 高(Policy + Critic + 两套优化器) | 中(Policy + Reference) |
| 每 prompt rollout 数 | 1 条 | N 条(通常 8) |
| 优势估计方式 | Value 网络 + GAE | 组内 Reward 归一化 |
| 信用分配粒度 | step-level(通过 GAE) | trajectory-level(整条轨迹) |
| 对 Reward 稀疏性的容忍 | 较差(Critic 难学稀疏信号) | 较好(直接比较最终结果) |
| 对 Reward 区分度的要求 | 低 | 高(同组轨迹需要有差异) |
| 训练稳定性 | Critic 估计不准会导致不稳定 | N 太小或 Reward 区分度低时不稳定 |
| 实现复杂度 | 高(GAE、Critic 训练、双网络同步) | 中(主要是 rollout 管理) |
| 代表性工作 | InstructGPT, ChatGPT | DeepSeek-R1, Kimi-K1.5 |
企业场景选型指南
不存在“哪个绝对更好”的结论,选型取决于你的具体约束。
选 GRPO 的场景
✓ Reward 可以自动计算且区分度高
→ 代码 Agent(测试通过/失败)、SQL Agent(结果正确/错误)
→ 二值 Reward 天然有区分度
✓ GPU 显存紧张
→ 模型大(13B+)、轨迹长(8K+ tokens)
→ 省掉 Critic 的显存可以换更大 batch 或更长轨迹
✓ 团队 RL 基础设施不成熟
→ GRPO 实现比 PPO 简单,不需要调 Critic 的超参
→ 出了问题更容易 debug(没有 Critic 这个变量)
✓ 训练任务的难度可控
→ 可以调整任务采样策略,保证 N 条轨迹有足够差异
选 PPO 的场景
✓ 需要 step-level 的精细优化
→ 长轨迹(15+ 步)场景,需要知道每一步的好坏
→ 有明确的过程 Reward 可以利用
✓ Rollout 成本极高
→ 工具调用涉及付费 API、长时间计算
→ 每个 prompt 多跑 8 条轨迹不可接受
✓ Reward 区分度低
→ 轨迹之间的 Reward 差异小(比如都在 0.7-0.9 之间)
→ GRPO 的组内比较信号太弱
✓ 已有成熟的 PPO 基础设施
→ 团队有 PPO 调参经验、Critic 训练经验
→ 不需要从零搭建
混合方案:先 GRPO 后 PPO
一种在企业实践中越来越常见的做法是两阶段训练:
阶段 1:GRPO(快速拉升基线)
├── 用自动 Reward(任务完成率)
├── 不需要 Critic,快速迭代
├── 目标:把 Agent 从"能跑"提升到"大部分场景跑得通"
│
阶段 2:PPO(精细优化)
├── 引入过程 Reward 和更细粒度的评估
├── 用 GRPO 阶段的 checkpoint 初始化 Critic
├── 目标:优化边界场景、减少冗余步骤、提升鲁棒性
这个方案的逻辑是:GRPO 在粗粒度优化上效率高(不需要 Critic),PPO 在精细优化上能力强(step-level 信用分配)。先粗调再精调。
实战踩坑经验
坑 1:GRPO 的 N 条轨迹要真正独立采样
如果你用了 temperature=0 或者 top_p 太小,N 条轨迹可能几乎一模一样——归一化之后 advantage 全是噪声。
错误配置:temperature=0.1, top_p=0.9
→ 8 条轨迹中有 6 条几乎相同
正确配置:temperature=0.7-1.0, top_p=0.95
→ 8 条轨迹有足够的多样性
但 temperature 也不能太高——太高轨迹质量太差,高 Reward 的轨迹比例太低,学不到什么。需要根据模型当前的能力调整。
坑 2:PPO 的 Critic 不能用太旧的 checkpoint
如果 Policy 更新了很多步但 Critic 还是用的旧参数,Value 估计会严重偏离真实值,导致 Advantage 估计错误。
好的做法:Policy 和 Critic 同步更新,每一步都更新 Critic
坏的做法:Policy 更新 10 步才更新一次 Critic(为了省计算)
坑 3:KL 约束在两种算法里都不能省
不管是 PPO 还是 GRPO,都需要 KL 散度约束策略不要偏离 SFT checkpoint 太远。在 Agent 场景中,没有 KL 约束最常见的崩溃模式是:
格式退化:模型不再输出合法的 JSON tool call,开始胡乱生成
重复循环:模型学到"多调几次工具"能偶尔碰上正确答案,陷入重复调用
能力崩塌:Agent 能力上去了,但通用对话能力崩了
坑 4:监控 Reward 分布,而不只是均值
训练过程中只看平均 Reward 是不够的。要同时监控:
必须监控的指标:
├── Reward 均值和方差 趋势是否正常
├── Reward 分布直方图 是否出现双峰(部分 hack,部分正常)
├── 高 Reward 轨迹的人工抽检 模型真的做对了还是在 hack
├── KL 散度 策略偏离是否在可控范围
├── 有效 prompt 比例 (GRPO) 多少 prompt 的 N 条轨迹有足够差异
└── Critic loss (PPO) Value 估计是否在收敛
小结
- PPO 和 GRPO 的核心分歧在优势估计:PPO 用 Critic 网络做绝对估计,GRPO 用组内相对比较
- GRPO 省显存、实现简单、天然适合结果导向的稀疏 Reward,但 rollout 成本翻 N 倍且需要 Reward 有区分度
- PPO 能做 step-level 信用分配、对 Reward 区分度要求低,但 Critic 难训且显存开销大
- 企业选型看三个约束:显存预算、rollout 成本、Reward 粒度。代码/SQL 类 Agent 优先试 GRPO,长轨迹精细优化场景考虑 PPO
- 混合方案(先 GRPO 粗调 + 后 PPO 精调)是越来越常见的工程实践
- 不管选哪个,KL 约束不能省、Reward 分布要监控、高 Reward 轨迹要人工抽检
下一篇建议继续看: