文章摘要
文章围绕OpenClaw对话场景下GRPO优化策略与稳定性展开。介绍OpenClaw - RL框架及GRPO原理,对比其与PPO差异,阐述DeepSeek R1的GRPO实践。分析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惩罚:直接约束新策略与参考策略的距离,需要调整惩罚系数
  • 熵正则化:防止策略收缩为确定性分布,保护探索空间
  • 学习率:最直接的步长控制手段,但粒度较粗
  • 每批次更新步数:增加同一批数据的重复使用次数,放大有效步长
OpenClaw的选择是仅依赖PPO clip(ε=0.2, ε_high=0.28)控制步长,关闭了KL惩罚,属于相对激进的更新方式,适配在线实时数据的训练场景。

训练稳定性的核心来源

训练稳定性并非由单一算法决定,而是三个条件的组合:

  • 优势方差控制:方差过大的优势值会导致梯度方向不稳定,出现震荡更新。方差的来源包括奖励噪声、基线质量、轨迹长度等。
  • 步长约束匹配任务结构:单轮任务(如数学题)使用ε=0.2的clip即可满足需求,而长轨迹的智能体任务则需要更保守的步长控制,例如K1.5使用镜像梯度风格的相对熵正则化。
  • 分布偏移可控:当离线策略数据进入训练时,梯度方向可能不再准确,需要进行重要性采样修正或陈旧性过滤,否则更新方向可能完全错误。
因此,训练稳定性的真正来源是:低方差的优势估计、匹配任务结构的步长约束、以及可控的分布偏移,而非仅仅依赖使用了PPO或GRPO算法。

不同技术路线的核心要素对比

我们可以通过表格对比不同强化学习技术路线的三个核心要素:

                ① 方向(优势估计)   ② 幅度控制       ③ 稳定性保障
──────────────────────────────────────────────────────────────────
标准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

以上内容不代表本平台立场,仅供读者参考