Agentic RL/强化学习:OpenClaw-RL异步处理源码解析

2026-06-03阅读 0热度 0
OpenClaw

【Agentic RL / 强化学习 / OPD】OpenClaw-RL 源码阅读笔记 --- (5)--- 异步处理

  • 0x00 概要

  • 0x01 异步架构

  • 0x02 训推分离

    • 2.1 为什么训练和推理通常分离?
    • 2.2 Agentic RL的三个分布
    • 2.3 OpenClaw-RL 如何处理三层分布分歧
  • 0x03 调度策略

    • 3.1 异步需求
    • 3.2 "仍然有学习价值"的边界在哪里
    • 3.3 调度策略是算法的一部分
    • 3.4 OpenClaw的调度策略
    • 3.5 改进建议
  • 0xFF 参考

0x00 概要

这个系列开宗明义:借着对OpenClaw-RL源码的梳理,系统性地回顾一下强化学习的核心概念和设计思想。所以读起来会有些基础知识的穿插和发散,OpenClaw-RL只是一个切入点。而且整篇系列是一个整体,有些概念的解释会分散在不同文章里,各位读者多包涵。

OpenClaw-RL 是一个专门针对智能体工具使用场景的在线强化学习框架。它从环境反馈中提取过程奖励信号来训练语言模型,支持三种主要模式:

  • openclaw-rl:基于二元奖励的强化学习(Binary RL / GRPO)
  • openclaw-opd:基于后见之明提示的在线策略蒸馏(On-Policy Distillation, OPD)
  • openclaw-combine:联合方法,在同一 PPO 更新中同时利用 RL reward 和 OPD teacher signal

framework

0x01 异步架构

OpenClaw-RL 的系统设计是四个异步解耦的循环——policy serving、environment hosting、reward judging、policy training 同时运行、互不阻塞。也就是说,模型可以一边持续服务,一边从刚刚发生的真实交互中在线学习。整个系统不存在任何显式的协调等待,一切都在异步消息驱动下自动流转。

组件

这四个组件以零协调开销异步运行:模型服务用户请求的同时,PRM正在评判上一轮交互,训练器同步更新策略——三者各干各的,谁也不等谁。这一设计使得从实时、异构的交互流中进行连续训练成为可行,无需任何流被暂停或批处理来配合其他组件。

在这种模块化设计中,各组件既保持功能独立性又实现数据互通。其总体是异步进行的,具体如下:

时间轴(完全异步,各组件不相互阻塞):
-----------------------------PolicyServing---------------------------------
SGLang:服务用户───────────────────暂停(503)─加载新权重─服务用户──►
Proxy:采集数据───────────────────暂停───────恢复─────采集数据──►
-----------------------------RewardJudging---------------------------------
PRM:评分─────评分─────评分───────────────────────评分─────评分──►
-----------------------------PolicyTraining---------------------------------
Megatron:─等待数据─────────────训练─同步─等待数据───训练─────────►

系统通过完全异步的设计实现四大核心优势:

  1. 服务连续性保障:策略服务与训练过程解耦,确保7×24小时无中断服务。通过双缓冲机制实现模型热切换,权重更新期间仍可维持原有策略响应。
  2. 实时学习能力:环境反馈与评估结果通过消息队列实时传输,训练模块可立即消化最新交互数据。系统支持每秒百次级的模型参数更新,实现真正意义上的在线学习。
  3. 长周期任务处理:针对软件工程等复杂任务,采用异步环境管理策略。不同任务轨迹可独立推进,通过工作流引擎协调依赖关系,有效缓解长尾延迟问题。
  4. 个性化适应机制:通过会话感知技术区分训练轮次与转发轮次,在保证用户体验的同时积累个性化数据。系统动态调整探索-利用平衡参数,实现用户偏好与模型能力的协同进化。

0x02 训推分离

因为异步架构和训推分离是一体两面,所以我们先介绍训推分离。

同步RL的理想情形(无漂移)是on-policy,即:

时刻t:
1. rollout: 使用π_t生成N条样本
2. update: 用这N条样本更新→得到π_{t+1}
3. rollout: 使用π_{t+1}生成下一批...
即,Policy π_θ → 生成轨迹 → 立刻更新 T_θ → 重复

每批训练数据100%来自当前policy → 完全on-policy,即生成数据时的 policy = 更新时的 policy = on-policy → 理论保证:importance weight = 1,无需修正。

ratio = π_{t+1}(a|s) / π_t(a|s) = 1(刚更新一步,变化很小)

然而,实际情况远没有这么理想。

2.1 为什么训练和推理通常分离?

2.1.1 内存布局根本冲突

训练和推理同时在同一块 GPU 上高效运行,物理上就冲突——KV cache 和优化器状态争同一显存。

训练引擎(FSDP/Megatron)推理引擎(vLLM/SGLang)
显存用途:参数 + 梯度 + 优化器状态(约 4x 参数大小)KV Cache(约 2x 参数大小)
分片方式:ZeRO 参数分片(跨 GPU 不连续)每卡完整参数(连续 + 量化)
Attention:PyTorch Flash AttentionPagedAttention
批处理:固定 batch(padding 对齐)Continuous batching(动态)

由于前向传播占用的显存小于反向传播,所以一般一个 step 会首先 rollout 大量的轨迹,然后分批次进行梯度优化。

2.1.2 计算特性完全相反
  • 训练:计算密集(矩阵乘法,GPU利用率高),延迟不敏感
  • 推理:内存带宽密集(每token读权重),延迟极敏感

混合运行会让两者都变慢。

2.1.3 RL特有的权重同步问题
推理(rollout)→ 收集数据 → 训练(更新权重)→ 推理用新权重 → ...

如果训练和推理在同一进程,参数更新期间无法同时做推理。虽然可以用 xccl 广播把新权重从 Megatron 传到 SGLang,但是,这本身就是跨引擎同步,不是同框架内的操作。

比如:

GPU0-3 (Megatron)更新后 → 同步到 GPU4-5 (SGLang)
同步期间(几十秒到几分钟):
→ 在途的 rollout 用的是旧 weights
→ 同步完成前所有新对话都是 off-policy
2.1.4 工程复杂度爆炸

维护一个同时优化 FlashAttention、PagedAttention、ZeRO-3、梯度 checkpoint 的框架,代码复杂度是各自独立的 5-10 倍。因此,主要框架选择了各自专精:

框架策略
OpenRLHF彻底分离:Actor(vLLM) + Trainer(DeepSpeed)
VeRL"混合引擎"(同卡串行切换,不是真并行)
AReaL异步解耦:SGLang 推理 + FSDP 训练,用 xccl 同步权重
TRL简单 PPO,训练和推理共用 HF 权重(效率最低)
2.1.5 小结

因此,在第 2 个批次及以后,所优化的轨迹都不是那个 model 自己生成的,而是上一个 step 的 model 生成的,这就引入了 off-policy。另外,在 partial rollout 中,一条轨迹可能来自不同的 model,就更加加剧了这个问题。

2.2 Agentic RL的三个分布

在Agentic RL中,有三个分布:

  • π_rollout:采样时的策略分布(策略模型产生训练数据的 policy)
  • π_learner:更新时见到的样本分布(learner实际梯度计算用的数据)
  • π_deploy:最终部署时系统实际执行的策略分布(真实环境下 policy 的行为)

一致的理想情形:完全on-policy + 训练分布 = 部署分布。然而,这三个分布几乎不可能天然一致。

三层分歧的汇总如下:

生成数据        处理数据        真实服务
π_rollout ────► π_learner ────► π_deploy
     ↑               ↑               ↑
     异步更新 Gap    Filter+Buffer Gap  探索/利用+分布漂移 Gap
     k步policy差异   训练分布被人为塑造  用户分布随时间变化
     PPO clip约束?   (通常无显式约束)    通常完全不处理

以下,我们会结合OpenClaw-RL 逐层分析为何这几乎不可能。

2.2.1 第一层分歧

第一层分歧:π_rollout ≠ π_learner(Off-Policy Gap)

原因A:异步更新(权重同步延迟)
时刻t:
rollout生成样本 (s_0, a_0, ..., s_T) 使用 π_θ_t
时刻t+k:
learner处理这批样本,更新 π_θ_{t+k}
π_θ_{t+k} ≠ π_θ_t(中间已经k步更新了)
importance ratio = π_{t+k}(a|s) / π_t(a|s) ≠ 1

在单轮RL里:

  • k很小(一次更新周期)。

在Agentic RL里:

  • 一个episode跑T=20步,在此期间其他worker可能更新了policy
  • step 1的数据用的是π_t,step 20的数据已经是π_{t+20}的环境下生成的

比如(Weight Sync 窗口):

  • 权重同步期间(503 阻断了新的 rollout):→ 但已在队列里的样本是同步之前生成的
  • 同步完成后(SGLang 有了新的权重):→ learner 还在处理同步前的旧样本 → 旧样本的 rollout_log_probs 来自"旧权重的 SGLang" → 当前 policy 是"新权重的 Megatron" → ratio 在 weight sync 边界处跳跃

ratio 时间线(示意):

-------------------------[weight sync]-------------------
ratio: 1.0, 1.1, 0.9, 1.2, ... | 1.8, 1.5, 2.1, ...
                                 ↑ sync后ratio突然变大
原因B:队列/Buffer的时间延迟

OpenClaw具体情况:

  • 轮次N的response进入queue → 等待PRM打分(异步)
  • 在此期间,其他样本继续训练 → policy继续更新
  • PRM打完分,样本进入训练 → 这时policy已经是π_{N+k}
  • policy用π_{N+k}π_N生成的数据上更新 → off-policy

即,系统架构决定了异步性:

rollout worker ────► buffer/queue ────► learner
(连续产生数据)    (样本等待处理)    (继续更新policy)

样本在buffer里等待期间:

  • learner继续更新policy
  • policy从π_t变成了π_{t+k}

当样本被learner取出时:

  • 样本的log_prob是π_t计算的
  • gradient更新的是π_{t+k}
  • ratio = π_{t+k}(a|s) / π_t(a|s) ← 不再 ≈ 1

即使在“同步“系统里:

  • rollout进入queue → 等待learner → 处理时policy已更新
  • queue depth × 更新频率 = staleness
原因C: Filtering改变分布

OPD只保留hint-accepted的样本:

  • → learner看到的分布 = “模型回复较差、有改进空间的那些turn"
  • ⇆ rollout原始分布(所有turn)

Binary RL的at-least-one:

  • → 强制把某些score = 0的样本变成mask = 1
  • → learner见到的有效样本分布被人为调整
原因D:PRM打分的异步延迟
Turn产生 → _fire_prm_scoring(异步发出3个judge请求)
↓ 等待5-30秒(judge LLM推理时间)
↓ 期间:其他turn继续进入learner
PRM返回 → 样本进入队列 → 被learner处理

样本的 rollout_log_probs 是 5-30 秒前的 policy 计算的,policy 在这 5-30 秒内可能已经更新了若干步

原因E:多步 Episode 的时间跨度

假设每步 2 秒,T=20 步的 episode:

step 1 生成于 t=0, rollout_lp 来自 π_{t=0}
step 20 生成于 t=40s

这 40 秒内如果 learner 更新了 k 步:step 1 的样本被 π_{t=0+40s+training_time} 处理,π 已经变了很多

漂移量 ≈ f(episode_length × step_time × learner_speed)

原因F: 轨迹时长不均

还有一种情况是 轨迹时长不均,比如:Task A: 2秒 Task B:30分钟 Task C:10秒。

如果等所有任务完成再更新: → Task A在 policy v1 时生成,等待时变成 stale → 等 Task B完成,TaskA已经是30分钟前的数据 → 如果不等 Task B,则TaskB贡献的梯度在下一轮更新才进来

2.2.2 第二层分歧

第二层分歧:π_rollout ⇆ π_deploy(协变量偏移)

原因A:探索 vs 利用的采样差异

rollout(训练时):

  • temperature = T_high,随机采样 → 生成多样化的响应,探索更广的路径 → 分布更宽、更均匀

deploy(部署时):

  • temperature = T_low(或top-p),更确定性 → 给用户最好的那条路径 → 分布更尖锐、集中在高概率区域
  • D_KL(π_deploy || π_rollout) > 0 :用高temperature的数据训练,要使用 low temperature的推理 → 分布不一致
原因B:用户行为随时间变化

训练数据收集时:用户问A类问题。

三个月后部署:用户问B类问题(新需求、新话题、模型能力提升导致用户问更难的)

  • π_rollout在旧的状态分布D_old上采样
  • π_deploy 面对新的状态分布D_new
  • D_new ⇆ D_old → 分布偏移
原因C:Agentic特有的状态分布循环依赖
π_t 决定采样哪些trajectories → trajectories决定遇到哪些states → states的分布影响下一步的 action distribution → action distribution又影响π_{t+1}的训练方向

这是一个循环:

state_distribution = f(policy)
policy = f(state_distribution)

当policy更新后,状态分布也会变化 → rollout时的状态分布和deploy时的状态分布持续偏移 → 单轮RL没有这个问题(状态=用户的prompt,不依赖policy)

2.2.3 第三层分歧

第三层分歧:π_learner ⇆ π_deploy(优化目标错位)

  • π_learner优化的是:reward信号所定义的"好“
  • π_deploy面对的是:真实用户的"有用“

当reward ≠ 真实用户价值时:模型学会了“让judge打高分的技巧“,而不是“真正帮助用户的能力“

具体来说,以下二者不同:

  • learner分布 = “被judge filter后的数据"(有偏)
  • deploy分布 = “所有真实用户请求"(无偏)
2.2.4 拓展
漂移的数学影响

PPO clip假设:ratio∈[1-ε, 1+ε]

  • 正常情况:

    ratio≈1 → 梯度完整保留
    
  • 漂移情况:

    ratio=2.5(新policy更倾向于这个action)
    → min(2.5*A, 1.28*A) = 1.28*A → 被clip,损失了49%的梯度信号
    ratio=0.3(新policy不太倾向于这个action)
    → min(0.3*A, 0.8*A) = 0.3*A → 低梯度,但方向可能是错的
    

漂移越大 → 被clip的样本越多 → 有效梯度越弱 → 需要更多样本才能达到同样的学习效果。

为什么在AgenticRL中比单轮RL更严重

单轮RL:每条样本 = 1个动作 → 更新 → 立即部署。三个分布分歧最小

AgenticRL:每个 episode=T个动作,T步期间policy可能更新多次(gap ∝ T),环境响应policy 的状态分布循环依赖 → 三个分布分歧随episode长度放大

漂移的不均匀性是最大问题

同一个训练batch里:

  • 样本A:5分钟前生成,ratio=1.1 (新鲜,漂移小)
  • 样本B:30分钟前生成,ratio=3.2 (陈旧,漂移大,被clip)
  • 样本C:2分钟前生成,ratio=0.95 (非常新鲜)

问题:不同样本的漂移程度不同 → 每个样本对梯度的贡献比例不同 → 批次内的有效学习率实际上是不均匀的 → 训练方差增大,不稳定

2.2.5 小结

三个分布不一致是 Agentic RL 的结构性问题,而非工程缺陷:

  • 异步训练把 rollout 和 learner 分开,filter 和 buffer 进一步改变 learner 分布,探索/利用差异和用户行为漂移让 deploy 分布独立演化。
  • 单轮 RL 中这些分歧很小;但是,Agentic RL 中,它们随 episode 长度放大,成为训练不稳定的核心来源。PPO clip 只约束了 rollout-learner 的第一层分歧,后两层几乎没有系统性防护。

2.3 OpenClaw-RL 如何处理三层分布分歧

2.3.1 第一层

π_rollout ≠ π_learner(Off-Policy Gap)

处理机制 1: Weight Sync 期间的 503 Pause

在 503 pause 期间,权重同步时暂停 rollout,防止产生更多 off-policy 数据。

# openclaw_api_server.py
# 权重同步时暂停rollout,防止产生更多off-policy数据
if not self.submission_enabled.is_set():
    raise HTTPException(status_code=503, detail="submission paused for weight update")

虽然做了处理,但是并不能完全消除问题,比如,在 Megatron更新完权重 → 同步到SGLang(几十秒到几分钟)这期间:

  • √ rollout被503阻断 → 不产生新的off-policy数据 → 减少了weight sync边界的大规模漂移
  • ✗ 同步完成前已在队列里的样本 → 仍然off-policy(无法消除)
  • ✗ 样本没有staleness字段(不知道等待了多久)
  • ✗ 没有importance weighting(所有样本等权,不管新旧)
  • ✗ 没有自动丢弃“太旧“的样本(ARLArena的OPSM思路)
  • ✗ weight sync边界的ratio跳跃没有特殊处理
处理机制2:PPO Clip(隐式IS修正)
# ppo_utils.py (slime/utils/ppo_utils.py:125-148)
ratio = (-ppo_kl).exp()  # ppo_kl是负的log-ratio,取负再exp得到π_θ/π_old
pg_loss = -torch.maximum(  # 注意是torch.maximum(非torch.min),因为前有负号
    ratio * advantages,
    torch.clamp(ratio, 1 - eps_clip, 1 + eps_clip_high) * advantages
)
  • eps_clip / eps_clip_high: 分别控制下/上裁剪阈值,允许非对称 clip(典型值 0.2 / 0.28)
  • 超出 [1-eps_clip, 1+eps_clip_high] 范围的 ratio 被截断 → 防止极端 off-policy 样本主导梯度
处理机制3:监控指标

train_rollout_logprob_abs_diff 会监控漂移量

# Slime内置
train_rollout_logprob_abs_diff  # 实时监控rollout-learner gap
# 如果这个值快速上升,说明off-policy问题加重
2.3.2 第二层

第二层:π_rollout ≠ π_deploy(协变量偏移)

OpenClaw的根本优势:在线学习使这层分歧几乎消失

离线RLHF(InstructGPT)
数据收集 → RM训练 → PPO训练 → 部署
   ↑                            ↑
这是几周前用户的行为分布       这是现在用户的行为分布

二者已经不同

OpenClaw
用户 → 直接与SGLang交互 → 数据同时用于训练
   ↑                          ↑
rollout分布 = 部署分布(同一个系统!)

具体细节如下:

# openclaw_api_server.py:rollout就是服务,服务就是rollout
# 没有单独的rollout服务器vs部署服务器的区别
async def _handle_request(self, body: dict[str, Any]):
    # 同时做两件事:
    # 1.服务用户:SGLang调用是内联的(非_forward_to_sglang方法)
    # 2.产生训练数据
    self._fire_prm_scoring(session_id, ...)

残余风险(无显式处理):用户看到模型改进后会提更难的问题 → 逐渐的分布漂移 → OpenClaw 无特殊机制,依赖持续在线学习自然适应。

2.3.3 第三层

第三层:π_learner ≠ π_deploy(优化目标错位)

处理机制:Reward信号直接来自真实用户行为

# _build_prm_judge_prompt:binary reward judge评估的是"用户实际怎么反应"
# 注意:OPD流程中使用的是_build_hint_judge_messages(非此函数)
# 参考openclaw-opd/openclaw_opd_api_server.py:71
def _build_prm_judge_prompt(response_text, next_state_text, next_state_role):
    # judge看的是:
    # response_text = 模型回复
    # next_state_text = 用户下一句话(真实行为)
    # judge评估的本质问题:
    # "根据用户的下一句话,这条回复有没有真正帮到他?"

这是 OpenClaw 最重要的设计决策之一:奖励信号不是人工构造的 proxy,而是从真实用户行为推断的。

对比:

  • RLHF: reward = "这条回复比那条回复更好" (偏好对,离真实使用有距离)
  • OpenClaw: reward ≈ "这条回复之后,用户继续了有意义的对话" (直接连接真实价值)

残余风险: judge 仍然是 LLM, 不是真实用户满意度的完美袋里 → 模型可能学会"让 judge 觉得有帮助"而非真正帮到用户

2.3.4 三层分歧的处理总结
分歧来源OpenClaw 处理方式剩余风险
层1: 异步更新 gap + Filter 改变分布503 pause + PPO clip + 训练时知道哪些被 filter 了同步窗口内积压样本 + filter 偏差不可消除
层2: 训练/部署环境不同 + 探索/利用差异在线学习: rollout = deploy, real-time 数据天然 on-distribution用户行为渐进漂移
层3: reward ≠ 真实价值next_state 作为真实用户信号judge 仍是近似

结论: OpenClaw 通过:

  • 在线架构几乎完全解决了第二层
  • 通过 503 pause + PPO clip 部分控制了第一层。异步off-policy漂移 = 样本生成时刻和参数更新时刻之间的policy差异,是分布式RL系统的结构性问题。它在Agentic RL里因episode长度而放大,PPO clip 只能约束但不能消除它。
  • 第三层通过 next_state设计大幅缩小,但未完全消除。

这三层分歧在 OpenClaw 里远比传统 offline Agentic RL 框架要小。

0x03 调度策略

Agentic RL 里的on-policy是一个程度问题,而非二元问题,不是“on or off",而是"drift有多大“。

这种不可避免的异步性带来了一个范式转换:

  • 旧问题:“怎么保持on-policy?“

  • 新问题:“多大的偏移还有学习价值?偏移控制在什么范围内训练不会崩?

  • 这是一个完全不同的优化目标:

    • 不是 minimize(off-policy drift),而是 find(drift range where learning signal is still valid)
    • 不是保持on-policy,而是让漂移保持在可学习范围内 → 承认off-policy 是不可避免的 → 把“控制偏移程度“作为核心优化目标

也导致了调度策略必然是算法一部分。

  • 传统RL算法 = 损失函数 + 更新规则
  • Agentic RL算法 = 损失函数 + 更新规则 + 调度策略 (三者缺一不可)

没有调度策略的Agentic RL算法是不完整的规范。

3.1 异步需求

为什么需要 Async RL?同步 RL 的问题:等最长输出完成 → GPU 大量空闲。比如,AIME24 上,同步训练需 41 小时,异步只需 14.8小时 (2.77x 加速),性能完全持平。

举例两个核心挑战。

挑战 1: 数据陈旧性 (Staleness)

训练轮次: v1 → v2 → v3 → v4(当前)
收集轨迹:用v1生成的 → 用v2生成的 → on the fly ...
                                         ↑ training看到的是旧数据

挑战 2: 同一轨迹由多个策略版本生成

LLM生成token序列时被打断(weight update):
token 1-50:  由v2生成
token 51-100: 由v3生成(weight更新了)
token 101-150: 由v4生成

而PPO 假设同一策略生成整条轨迹。

3.2 "仍然有学习价值"的边界在哪里

学习信号失效的三种失效情况:

Importance Weight 极端化

P_new(t) / P_old(t) >> 1 或 << 1
→ IS修正不稳定,梯度方向噪声极大
→ PPO clip 阻止这种极端化(这就是ε=0.2/0.28的作用)

Advantage符号翻转

"那时候policy认为好的轨迹,现在的policy根本不会走这条路"
→ 用旧轨迹的reward更新新policy,方向反了
→ Stale Sample Filtering可以阻止这种情况(丢弃超过T步的样本)

分布漂移超出任何IS修正的能力

两个policy的KL太大 → 即使有重要性权重也无法有效校正
→ 这时候 off-policy 修正 = 病态问题
→ KL约束或policy约束作为上界

3.3 调度策略是算法的一部分

关键洞察:调度决策直接决定 learner 实际在优化什么分布。我们来看看几种调度算法。

3.3.1 示例 1:Windowed FIFO

严格 FIFO:learner 总是看最老的已完成任务

  • 效果:训练分布=轨迹提交时间的分布
  • 问题:长任务总是等太久才进入训练(慢任务=老数据=更陈旧)

贪心 Async:谁先完成谁先训练

  • 效果:训练分布=按任务完成速度加权
  • 问题:快任务(简单任务)在训练集中被over-represent,模型越来越擅长简单任务,越来越少见到困难任务的轨迹

Windowed FIFO(窗口W):窗口内的已完成任务可以先训练

  • 效果:在“时间局部公平“和“吞吐“之间折中

窗口大小W = 一个算法参数,不是工程参数:

  • W大 → 接近贪心Async → 简单任务over-represent
  • W小 → 接近严格FIFO → 慢任务惩罚大
  • W的选择 = 隐式地选择了训练分布的偏置方向
3.3.2 示例 2:TITO(Train In Train Out)
  • 传统做法:Rollout 产生文本 → 重新 Tokenize → 喂给 Trainer
  • TITO做法:Rollout产生tokens → 直接喂给Trainer(不重新分词)

区别在哪里?重新 Tokenize:可能因为 tokenizer 版本差异产生细微不同→ Trainer 优化的 action 和 Rollout 实际采样的 action 不完全对应 → 梯度的方向≠真正应该更新的方向

TITO是“系统设计”,但它改变的是“梯度到底在优化什么“ → 这是算法问题,只是伪装成了工程问题

3.3.3 示例 3:Stale Sample 过滤阈值

丢弃超过T步前生成的样本

  • T大:更多历史样本进入训练→off-policy drift 更大 →可能 IS 不稳定
  • T小:只用新鲜样本→drift小→但吞吐低,样本效率差

T 的选择 = 定义了"可接受的off-policy范围" = 定义了 policy更新的有效覆盖范围 = 定义了 rollout和learner允许的分布偏移上界。这不是“丢弃多少数据的工程问题”,而是“给这个算法设定正确运行的条件” 。

比如,解决方案: Staleness Control (max_head_off policyness = η)。

η=0: 退化为同步RL(最慢,最准确)
η=1: 允许1步 off-policy(one-step overlap,业界常用)
η=2-8: AReaL推荐值,速度/质量平衡

当积累轨迹数量 / 陈旧程度超过 η 时,gateway 返回 HTTP 429 — 这就是限流机制的根源。

3.3.4 示例4:Decoupled PPO Objective

解决方案: Decoupled PPO Objective (三策略解耦)

标准 PPO 只有两个策略 (old/new), Decoupled PPO 引入三个:

# π_beha ve ← 实际采样时的策略版本(可能很旧)
# π_proximal ← 比当前策略落后一步的策略(用于稳定化)
# π_θ ← 当前正在训练的策略
Loss = - min(
    (π_θ / π_proximal) * A,   # 内层clip,对π_θ
    clip(..., 1-ε, 1+ε) * A
) * min(
    (π_proximal / π_beha ve),   # 外层clip,处理off-policy程度
    clip(..., 1-ε, 1+ε)
)

这样即使轨迹由不同版本策略生成,也能正确处理 importance ratio。

统一理解

统一理解:调度策略定义了以下三件事(全是算法级决策):

  • What samples enter training? → Stale filter + priority rules → 决定训练分布
  • In what order? → Windowed vs Greedy → 决定时间局部性偏置
  • At what staleness? → 从rollout生成到update的时间差 → 决定off-policy程度

这三件事合起来 = "learner实际看到的是什么世界的数据“ ,而这直接决定了policy朝什么方向更新

3.4 OpenClaw的调度策略

OpenClaw当前的“调度策略“如下(大多是隐式的):

① 进入训练的样本:score ≠ 0 的turn(Judge过滤) + at-least-one guarantee(防止全零session 贡献零梯度)

② 顺序:output_queuequeue.Queue,标准线程安全队列,非 asyncio.Queue)中使用了 FIFO 顺序,先打分完成的先进入队列 → 近似"贪心Async"(快任务/短对话先完成)

③ Staleness:无显式stale filter,一个用户2小时前的对话和 2分钟前的对话在训练时同等对待

④ 最关键的隐式调度机制:503 pause(weight sync)

  • sync期间:SGLang 权重冻结→所有进行中的对话用同一批权重
  • sync后恢复:积压的对话集中完成 →形成一个"伪 on-policy batch"

④ 有趣的调度特性:

  • weight sync = 隐式的 “同步 on-policy batch 窗口“
  • sync间隔 = 控制这个窗口的时间跨度

3.5 改进建议

改进建议是把隐式调度变成显式算法组件:

加 staleness filter:

  • 丢弃超过 K步前生成的 session
  • K = learner更新多少次后认为样本"过期“
  • 这是明确的算法参数,而非工程值

按 session freshness 加权

  • 最新的 session 在 training loss 中有更高权重
  • 类似重要性采样但用时间窗口近似

sync 间隔优化

  • 当前 sync 间隔可能是固定的
  • 应该根据 queue depth 和 staleness 动态调整→让“伪on-policy窗口“的大小受控

0xFF 参考

【论文学习】Stabilizing Reinforcement Learning with LLMs: Formulation and Practices

免责声明

本网站新闻资讯均来自公开渠道,力求准确但不保证绝对无误,内容观点仅代表作者本人,与本站无关。若涉及侵权,请联系我们处理。本站保留对声明的修改权,最终解释权归本站所有。

相关阅读

更多
欢迎回来 登录或注册后,可保存提示词和历史记录
登录后可同步收藏、历史记录和常用模板
注册即表示同意服务条款与隐私政策