OpenClaw对话场景下GRPO优化策略与稳定性

项目概述与框架定位
本系列内容以OpenClaw-RL源码为切入点,系统梳理强化学习的核心概念与实践方法。由于系列文章整体关联性较强,部分概念会在不同章节中交叉出现,敬请读者理解。OpenClaw-RL是一款面向在线强化学习场景的专用框架,主要用于智能体工具使用场景下的语言模型训练,通过从环境反馈中提取过程奖励信号实现模型优化,支持三种核心训练模式:
- openclaw-rl:基于二元奖励的强化学习(Binary RL / GRPO)
- openclaw-opd:基于后见之明提示的在线策略蒸馏(On-Policy Distillation, OPD)
- openclaw-combine:联合训练模式,在同一次PPO更新中同时利用强化学习奖励与OPD教师信号
GRPO核心原理与设计思路
GRPO,即Group Relative Policy Optimization,其核心创新点在于无需额外训练价值模型,通过同一提示词生成多条回复并进行组内比较,来估算策略优势。与标准PPO相比,GRPO省去了价值网络的训练成本,转而利用同组回复的相对得分来计算优势值:
# 标准PPO:需要训练价值函数V(s),优势=奖励 - V(s)
# GRPO:同一提示生成N条回复,优势=单条奖励 - 组内平均奖励
# 类比:个人得分减去班级平均分
我们可以用考试场景类比:假设老师要求针对同一作文题提交8篇习作,PPO的做法是聘请一位固定的“评分专家”来预估每篇作文的大致得分,再通过实际得分与预估得分的差值来计算优势;而GRPO则不需要专家,直接通过8篇习作的相对得分来判断优劣。
PPO与GRPO的核心差异
标准PPO的完整流程包括:收集按当前策略生成的样本、通过价值网络估算基线优势、使用带裁剪的目标函数更新策略以避免更新幅度过大,其核心优势在于训练稳定、易于落地,但需要额外训练价值网络,带来了计算成本与训练不稳定的问题。
而GRPO的核心思路是“自我对比”:无需绝对评分标准,仅通过同组回复的相对表现来指导更新。例如在8篇作文的例子中,GRPO会计算每篇得分与平均分的差值,得分高于平均分的回复会被鼓励,低于平均分的则被抑制。这种方式不仅省去了价值网络的训练,还能适配不同难度的任务,即使所有回复的整体得分都偏低,依然能通过相对表现找到优化方向。
“Group Relative”的命名也体现了这一逻辑:Group指同一提示下的多条回复组成的样本组,Relative则强调仅依赖组内的相对排名,而非绝对得分。
DeepSeek R1的GRPO落地实践
DeepSeek R1的GRPO实现包含三个关键要素:可验证的二元奖励(答案对错有明确标准)、组内归一化(通过同组回复消除绝对分差)、无需Critic网络(用组内比较替代价值函数)。其标准流程如下:
# 标准GRPO实现流程
for prompt in 数据集:
# 同一提示采样N条回复
responses = sample_N(policy, prompt, N=8)
# 用验证器为每条回复打分(0或1)
rewards = [verify(r) for r in responses]
# 组内均值作为基线
baseline = mean(rewards)
# 归一化得到优势值
advantages = (rewards - baseline) / std(rewards)
# 执行PPO裁剪更新
PPO_clip_update(policy, advantages)
完整的执行步骤包括:采样提示词、批量生成回复、奖励打分、组内归一化、PPO更新,整个流程无需额外的价值网络训练,大幅降低了计算成本。
GRPO与传统基线方法的对比
传统的REINFORCE带基线方法需要训练一个价值网络V(s)来估算基线,但价值网络的训练往往不稳定,导致基线估算有偏,进而影响优势值的准确性。而GRPO的基线直接来自组内回复的平均奖励,是无偏的精确估计,同时省去了价值网络的训练成本,节省GPU资源。此外,组内归一化还能让不同难度提示的梯度量级保持一致,提升训练稳定性。
当然GRPO也有其代价:需要为每个提示生成N条回复,带来了N倍的生成成本;如果N过小,基线的估计方差会变大;当N=1时,GRPO会完全退化,无法计算优势值,这也是OpenClaw-RL面临的核心困境之一。
OpenClaw-RL中的GRPO定制实现
OpenClaw的Binary RL模式并非纯粹的GRPO或PPO,而是两者的混合体:使用了PPO的裁剪损失,但采用了REINFORCE风格的优势估计。
三种模式的总体对比
我们可以通过表格对比标准PPO、标准GRPO与OpenClaw Binary RL的核心差异:
| 对比项 | 标准PPO | 标准GRPO | OpenClaw Binary RL |
|---|---|---|---|
| 优势来源 | GAE(r,V),需要Critic网络 | 组内相对归一化,需要同提示多条回复 | 直接使用标量奖励,单轮turn的±1/0值 |
| 基线 | V(s),Critic网络输出 | 组内均值/标准差 | 无基线,或近似批次均值 |
| 策略损失 | PPO clip ε=0.2 | PPO clip ε=0.2 | PPO clip ε=0.2, ε_high=0.28 |
| KL约束 | 隐式通过clip实现 | 隐式通过clip实现 | 无,通过--kl-coef 0.0关闭 |
| Critic网络 | 需要 | 不需要 | 不需要 |
为何未采用完整PPO框架
完整的PPO框架包含三个核心部分:独立的Critic网络估计V(s)、GAE广义优势估计、价值损失训练Critic。而OpenClaw的Binary RL仅使用了PPO的裁剪损失技巧,并未采用完整的PPO流程:
- 未使用Critic网络与GAE优势估计,直接将标量奖励广播到所有token
- 关闭了KL惩罚,通过--kl-coef 0.0参数禁用
- 未使用奖励归一化,通过--disable-rewards-normalization参数关闭
其核心更新逻辑为:REINFORCE风格的优势估计 + PPO裁剪更新,即通过原始奖励直接作为优势值,并通过PPO clip限制更新幅度,避免策略变化过大。
完整的PPO模块调用链如下:
# Binary RL流程
Slime主循环
→ compute_advantages_and_returns(advantage_estimator="grpo")
→ get_grpo_returns(),将标量奖励广播到所有token
→ policy_loss_function(),默认Slime损失
→ compute_policy_loss(ppo_kl, grpo_adv, e=0.2, e_high=0.28),使用PPO clip
OPD流程
Slime主循环
→ compute_advantages_and_returns(advantage_estimator=“on_policy_distillation”)
→ advantages = teacher_lp - student_lp,逐token计算教师与学生的概率差
→ policy_loss_function()
→ compute_policy_loss(ppo_kl, opd_adv, e=0.2, e_high=0.2),对称PPO clip
Combine流程
Slime主循环
→ compute_advantages_and_returns(),计算grpo_adv存入batch
→ combine_loss_function(),自定义联合损失
→ teacher_adv = teacher_lp - rollout_lp
→ combined_adv = w_opd * teacher_adv + w_rl * grpo_adv
→ compute_policy_loss(ppo_kl, combined_adv, e=0.2, e_high=0.28)
为何未采用纯粹GRPO框架
纯粹的GRPO需要满足两个核心条件:同一提示生成多条回复用于组内比较,以及通过(reward_i - mean(group))/std(group)计算优势值。但OpenClaw的对话场景无法满足这一条件:实时对话只能返回单条回复,无法为了训练而生成多条“fake responses”给用户。
与DeepSeek R1的数学题场景不同,OpenClaw的对话场景没有明确的标准答案,无法通过可验证的奖励来判断回复优劣,因此OpenClaw将DeepSeek R1的组内比较替换为了LLM judge的隐式信号与多数投票降噪,实现了从闭卷考试到开卷对话的适配:
- DeepSeek R1:8条同提示回复,组内相对排名
- OpenClaw:3次独立judge评分,投票取多数
- DeepSeek R1的方差来自生成随机性,可控性强
- OpenClaw的方差来自judge不确定性与用户行为多样性,噪声更大
因此OpenClaw的GRPO在N=1的场景下退化为了带PPO clip的REINFORCE算法。
GRPO优势的具体代码实现
OpenClaw对标准GRPO进行了大幅简化,将优势值直接设置为标量奖励并广播到整个回复序列。通过--disable-rewards-normalization参数关闭了批次内的归一化,保留了原始的±1奖励值,不进行(r - mean)/std的处理。
# ppo_utils.py中的get_grpo_returns实现
def get_grpo_returns(rewards: torch.Tensor, kl: list[torch.Tensor]):
returns = []
for i in range(len(rewards)):
# 将标量奖励广播到所有token,无基线
returns.append(torch.ones_like(kl[i]) * rewards[i])
return returns
PPO裁剪损失实现
def compute_policy_loss(kl, advantages, eps_clip, eps_clip_high):
# 计算新策略与旧策略的概率比
ratio = torch.exp(-kl)
# 无裁剪的策略梯度
pg_loss1 = -advantages * ratio
# 带裁剪的策略梯度,限制概率比在[1-eps_clip, 1+eps_clip_high]
pg_loss2 = -advantages * torch.clamp(ratio, 1.0 - eps_clip, 1.0 + eps_clip_high)
# 取更保守的损失值
pg_loss = torch.max(pg_loss1, pg_loss2)
return pg_loss
当N=1时,标准GRPO的优势值计算会出现(R - R)/0的未定义情况,因此OpenClaw直接使用原始奖励作为优势值,此时的GRPO退化为REINFORCE + PPO clip:梯度近似为R · ∇log π(o | q),并通过PPO clip限制更新幅度。
损失掩码与优势信号的协同作用
loss_mask用于筛选有效的训练样本,其设置逻辑为:当prm_score != 0时,loss_mask设为True,纳入训练;当prm_score ==0时,loss_mask设为False,排除训练;同时通过“至少一个保证”机制确保每个会话至少有一个有效样本。
loss_mask与GRPO Advantage的本质区别在于:
- loss_mask:二元门控,决定该token/turn是否参与梯度计算:
- 得分+1(好回复):loss_mask=1,参与训练
- 得分0(中性回复):loss_mask=0,排除训练,除非触发至少一个机制
- 得分-1(差回复):loss_mask=1,作为负样本参与训练
- GRPO Advantage:方向信号,决定纳入训练的token的更新方向:
- 正值:增大该token的生成概率
- 负值:减小该token的生成概率
- 近零值:基本不改变token的生成概率
最终的梯度贡献为:gradient(token t) = loss_mask(t) × policy_gradient(advantage(t)),其逻辑真值表如下:
- loss_mask=0 → 梯度为0,无论优势值如何
- loss_mask=1且优势>0 → 正向梯度,提升token生成概率
- loss_mask=1且优势<0 → 负向梯度,降低token生成概率
- loss_mask=1且优势≈0 → 近零梯度,无明显更新
评分与两者的完整映射关系为:
- Judge score=+1:loss_mask=1,奖励+1.0,推高该轮所有token的生成概率
- Judge score=0:loss_mask=0,奖励0.0,无梯度更新
- Judge score=-1:loss_mask=1,奖励-1.0,拉低该轮所有token的生成概率
无KL约束下的训练稳定性分析
在传统RLHF中,KL惩罚并非“通用安全带”,其主要作用包括防止奖励模型被hack、防止策略远离自然语言流形、防止训练数值不稳定、防止遗忘参考模型的能力。而OpenClaw在kl_loss_coef=0的情况下依然保持稳定,源于五个核心因素:
- PPO clip(0.2/0.28):提供逐步骤的信任域限制
- GRPO零和特性:组内优势之和为0,不会出现一边倒的强化
- 用户多样性:外部提示词不重复,天然提供熵增
- 短训练周期:36/24次交互的量级,策略漂移有限
- 模式崩溃自停:当组内奖励方差趋近于0时,优势值趋近于0,梯度自然消失
GRPO与OPD的核心对比
我们可以通过表格对比GRPO(Binary RL)与OPD的核心差异:
| 对比项 | GRPO(Binary RL) | OPD |
|---|---|---|
| 输入来源 | sample.reward["score"],标量值如+1.0/-1.0 | sample.teacher_log_probs,向量如[-0.1, -0.3, -0.1, -0.2] |
| 优势形状 | [T] 所有token的优势值相同,如[+1, +1, +1, +1] | [T] 逐token的优势值不同,如[+0.2, +0.9, 0.0, +0.6] |
| 奖励归一化 | 可选,OpenClaw中默认关闭 | 不涉及,直接使用教师与学生的概率差 |
| KL的作用 | 仅用于匹配张量形状,不影响优势计算 | 完全不使用KL,仅用于形状对齐 |
| 适用条件 | 奖励不为None且loss_mask=1 | 教师对数概率不为None且loss_mask=1 |
| 奖励为0时 | 优势值全为0,梯度为0,样本无效 | 不适用,OPD会直接丢弃奖励为0的样本 |
两者的优势函数在Slime框架中的具体位置如下:
# slime/backends/megatron_utils/loss.py: compute_advantages_and_returns()
├── if advantage_estimator == "grpo": # Binary RL使用
│ advantages = get_grpo_returns(rewards, kl)
└── elif advantage_estimator == "on_policy_distillation": # OPD使用
teacher_log_probs = [t_lp.to(device=device) for t_lp in teacher_log_probs]
advantages = teacher_log_probs - student_log_probs
对话场景下的GRPO落地实践
尽管OpenClaw并未采用纯粹的GRPO,但对话场景下的GRPO落地依然是一个值得探讨的问题,其核心矛盾在于:GRPO需要同一提示的多条回复进行组内比较,但实时对话只能返回单条回复。以下是四种可行的落地方案:
方案一:会话历史作为“软组”基线
当前OpenClaw的优势计算为每条turn的优势=奖励,无基线。我们可以改进为使用会话内的历史奖励均值作为基线:
# 改进后的优势计算
session_baseline = running_mean(session_rewards[session_id])
advantages[i] = reward_i - session_baseline
该方案的意义在于:比会话历史平均得分高的回复会获得正优势,反之则获得负优势。其适用场景为同一个用户的持续对话,会话内的分布相对稳定;优点是改造成本极低,仅需添加少量代码;局限是会话内的turn数量较少,样本量小,基线不稳定。
方案二:Best-of-N + 单条回复返回用户
该方案的流程为:用户发送查询后,并行生成N条候选回复,通过轻量级Judge快速打分,选择得分最高的一条回复给用户,再使用所有N条回复及其得分进行GRPO组内更新。例如:
用户发送query
↓
并行生成N=4条候选回复
↓
Judge快速打分
↓
选择得分最高的回复返回用户
↓
使用所有N条回复与得分执行GRPO更新
R = [+1, -1, 0, +1]
baseline = mean(R) = 0.25
advantages = [+0.75, -1.25, -0.25, +0.75]
该方案的优点是完全符合标准GRPO的语义,同时还能通过Best-of-N提升用户体验;缺点是推理成本增加了N倍。
方案三:OPD作为隐式N=2 GRPO
OPD本质上已经是一种N=2的GRPO:将学生的原始回复与教师提示的“更好路径”进行比较,优势值=教师对数概率 - 学生对数概率。与标准GRPO的组内比较不同,OPD的“另一条回复”是教师的log-prob,而非实际生成的文本回复:
Response A:学生的原始回复,得分由PRM评估
Response B:教师提示的“更好回复路径”
→ 优势值 = teacher_lp - student_lp,即OPD优势
GRPO(N=8):advantages = [r_i - mean®] for 8个候选
OPD(N=2):advantage[t] = log π_teacher(t) - log π_student(t)
分别对应“更好回复”与“实际给用户的回复”
因此OPD可以看作是一种无需额外多采样的隐式GRPO,无需改动现有代码即可实现。
方案四:Speculative Sampling + GRPO
该方案在生成回复时,使用draft模型生成N条token级别的候选回复,通过策略模型对每条候选打分并执行GRPO组内比较,最终只将被接受的token序列返回给用户,类比于Speculative Decoding与强化学习的结合。该方案属于前沿方向,目前尚未有成熟的工程化实现。
各方案的实用程度对比
实用程度 方案
-------------------------------------
最低改动 会话历史均值作为基线(仅需少量代码修改)
已经存在 OPD作为隐式N=2 GRPO(无需改动现有代码)
最接近标准GRPO Best-of-N + 选最优回复(推理成本增加N倍)
前沿方向 Speculative Sampling + GRPO(尚未工程化)
强化学习训练的深层本质
在进行强化学习优化时,我们常常陷入“选择PPO还是GRPO”的表层争论,但真正的核心在于是否能够有效控制模型生成行为的分布。我们更应该关注的是:策略应当朝什么方向变化、变化幅度多大,以及如何在提升模型能力的同时保持训练稳定。
PPO与GRPO本质上都在解决同一个核心问题:给定一批采样样本与对应的奖励,如何更新策略权重?PPO通过价值网络+clip+KL惩罚实现更新,而GRPO通过组内统计作为基线+clip实现更新,但无论选择哪种算法,真正决定训练效果的是三个更深层的核心问题:
- ①策略更新方向:优势估计问题,即梯度的指向是否正确
- ②策略更新幅度:步长控制问题,即梯度的尺度是否合适
- ③训练稳定性:稳定性-进步的权衡问题,即如何在提升能力的同时避免训练崩溃
核心问题的深度解析
问题①:梯度方向由什么决定? 本质上,优势值是什么,策略就会朝什么方向更新。因此准确的优势估计是训练有效的核心前提。
问题②:更新幅度由什么控制? 常见的步长控制手段包括:
- PPO clip:限制策略概率比,避免更新幅度过大
- KL惩罚:直接约束新策略与参考策略的距离,需要调整惩罚系数
- 熵正则化:防止策略收缩为确定性分布,保护探索空间
- 学习率:最直接的步长控制手段,但粒度较粗
- 每批次更新步数:增加同一批数据的重复使用次数,放大有效步长
训练稳定性的核心来源
训练稳定性并非由单一算法决定,而是三个条件的组合:
- 优势方差控制:方差过大的优势值会导致梯度方向不稳定,出现震荡更新。方差的来源包括奖励噪声、基线质量、轨迹长度等。
- 步长约束匹配任务结构:单轮任务(如数学题)使用ε=0.2的clip即可满足需求,而长轨迹的智能体任务则需要更保守的步长控制,例如K1.5使用镜像梯度风格的相对熵正则化。
- 分布偏移可控:当离线策略数据进入训练时,梯度方向可能不再准确,需要进行重要性采样修正或陈旧性过滤,否则更新方向可能完全错误。
不同技术路线的核心要素对比
我们可以通过表格对比不同强化学习技术路线的三个核心要素:
① 方向(优势估计) ② 幅度控制 ③ 稳定性保障
──────────────────────────────────────────────────────────────────
标准PPO GAE(低方差) clip + KL惩罚 critic降噪
GRPO 组均值(无critic) clip only 简单但方差大
K1.5 LongRL GRPO 镜像梯度+KL正则 相对熵约束
K2.5 步骤级GRPO token-level clip IS修正
SAMPO REINFORCE++ 无KL+熵监控 off-policy修正
OpenClaw RL Turn级标量奖励 clip ε=0.2/0.28 仅靠clip保障
OpenClaw OPD 教师-学生差值 clip+蒸馏 教师锚定
Combine GRPO+OPD混合 clip+联合损失 两路互补
参考资料
【论文学习】Stabilizing Reinforcement Learning with LLMs: Formulation and Practices


