☰
OpenClaw-RL 源码阅读笔记(4):架构拆解与 Slime/PPO 配置骨架
2026/9/28 4:18:05 网站建设 项目流程

1. 从一次训练卡死说起:OpenClaw-RL 架构到底怎么读

如果你正在复现 OpenClaw-RL 的训练流程,大概率会遇到一个很迷惑的现象:脚本跑起来了,SGLang 在服务,Megatron 在等数据,PRM 在打分,但训练循环就是不动。日志里没有报错,GPU 占用也正常,可rollout_batch_size迟迟凑不满。这个问题我第一次读源码时也卡了很久,最后发现根因不在算法,而在架构理解——OpenClaw-RL 把 Slime 原本"主动生成 rollout"的假设,改成了"被动等待真实用户对话产生样本"。

OpenClaw-RL 是一个面向在线强化学习(Online RL)的框架,专门针对智能体工具使用场景。它从环境反馈中提取过程奖励信号来训练语言模型,支持三种主要模式:openclaw-rl(基于二元奖励的 GRPO)、openclaw-opd(基于反思之明提示的在线策略蒸馏)、openclaw-combine(在同一 PPO 更新中同时利用 RL reward 和 OPD teacher signal)。适合谁?适合想把真实用户交互变成训练数据、又不想改 Slime/Megatron 核心代码的开发者。

这篇笔记聚焦架构层源码阅读,围绕 Slime 与 PPO 的模块划分、调用链与配置入口展开。我会给出可复制的config.toml骨架、TaoToken 统一 Key/API 通道接入 AI 工具的settings.json片段,以及逐步验证动作,帮你确认架构理解与配置生效。读完之后,你应该能自己画出数据从用户请求到梯度更新的完整路径。

2. 前置准备:TaoToken 统一 Key 与 API 通道

在动手读源码之前,先把 AI 工具的接入通道理顺。OpenClaw-RL 的调试过程需要频繁调用模型做对比验证,如果每个工具都单独配 Key,切换成本很高。TaoToken 提供统一的 Key/API 通道,官网入口是 https://taotoken.net/?utm_source=taotoken_aicg_blog_end&utm_medium=csdn&utm_campaign=rewrite&utm_content= ,API 端点是 https://taotoken.net/api (不加 UTM)。

你需要先拿到 API Key。登录后进入控制台,在 API Keys 页面创建一个新 Key,复制保存。这个 Key 会同时用于模型对话验证、Coding Plan 以及后续的接入文档对照。

对于长期编码和 Agent 场景,建议直接开通 Coding Plan,这样在调试 OpenClaw-RL 的 rollout 逻辑时不会因为额度问题中断。模型对话入口可以用来快速验证 Key 是否生效,接入文档则提供了不同工具链的配置模板。

拿到 Key 之后,在项目根目录创建或修改settings.json,把统一通道写进去。下面是我实测可用的片段:

{ "ai_provider": { "base_url": "https://taotoken.net/api", "api_key": "sk-your-taotoken-key", "default_model": "claude-sonnet-4-20250514", "timeout_seconds": 120, "max_retries": 3 }, "tools": { "model_chat": { "endpoint": "https://taotoken.net/api/v1/chat/completions", "stream": true }, "coding_plan": { "enabled": true, "workspace": "./openclaw-rl-workspace" } } }

注意base_url不要带末尾斜杠,否则部分 HTTP 客户端会拼出双斜杠导致 404。api_key用你刚创建的那串,不要提交到 git,建议放进.env再用环境变量注入。

3. 架构拆解:Slime 与 PPO 的模块划分

3.1 统一 PPO 框架 + 三种 advantage 注入

OpenClaw-RL 的 RL 训练本质是"一套统一的 PPO 框架 + 三种不同的 advantage 注入方式"。这个设计原则很关键,理解了它,后面读代码就不会迷路。

方法Advantage 来源适用场景
Binary RLA = R(raw broadcast)简单场景,只有 ±1 reward
OPDA_t = teacher_lp_t - old_lp_t有 teacher model 提供 per-token 信号
CombineA_t = w_rl·R + w_opd·(teacher_lp_t - old_lp_t)同时需要 reward 和 teacher 信号

三条路径共享同一套 ratio-based clipped loss,区别只在 advantage 怎么算出来。Binary RL 走 Slime 内置 GRPO,reward 广播到全序列;OPD 靠字段劫持,API Server 把teacher_log_probs塞进 sample,Slime 的loss.py读到后自动算 per-token advantage;Combine 是唯一需要自定义 loss 的,用combine_loss.py::combine_loss_function读batch["advantages"]和batch["teacher_log_probs"],加权合成后再进 PPO clip。

3.2 文件结构与模块职责

OpenClaw-RL 的目录划分很清晰,核心 RL 框架在slime/,个性化 Agent 优化在openclaw-rl/、openclaw-opd/、openclaw-combine/,通用 Agent RL 在gui-rl/、swe-rl/、terminal-rl/、toolcall-rl/。

模块职责划分如下:

OpenClaw-RL/ ├── openclaw-rl/ │ ├── openclaw_api_server.py ← FastAPI 代理 + PRM 评分 + 样本提交 │ └── openclaw_rollout.py ← AsyncRolloutWorker: 桥接 API Server ↔ Slime ├── openclaw-opd/ ← OPD 变体(hint 提取 + teacher log-probs) ├── openclaw-combine/ ← Combined 变体(RL + OPD 并行) ├── slime/ │ └── train_async.py ← 基础 RL 框架(Megatron + SGLang) └── terminal-rl/ gui-rl/ swe-rl/ toolcall-rl/ ← Track 2 通用智能体 RL

openclaw_api_server.py是整个数据采集层的核心,它同时承担了 FastAPI 代理、PRM 评分、样本提交三件事。openclaw_rollout.py里的AsyncRolloutWorker是桥接层,负责管理 API Server 实例并收集样本。slime/train_async.py是训练主循环入口。

3.3 四大组件的异步解耦

OpenClaw-RL 的系统设计是四个异步解耦的循环——policy serving、environment hosting、reward judging、policy training 同时运行、互不阻塞。模型可以一边持续服务,一边从刚刚发生的真实交互中在线学习。

GPU 分配(8 卡节点,run_qwen3_4b_openclaw_rl.sh):

GPU 0-3: Megatron Actor (ACTOR_GPUS=4, TP=4) <- Policy Training GPU 4-5: SGLang Rollout (ROLLOUT_GPUS=2, TP=2) <- Policy Serving GPU 6-7: SGLang PRM/Judge (PRM_GPUS=2, TP=2) <- Reward Judging Environment: 无 GPU,OpenClaw App + 用户

三个角色(Actor/Rollout/Judge)用的都是同一个 Qwen3-4B,但只有 Actor 被训练更新。Rollout 是 Actor 的权重副本,定期同步;PRM Judge 是固定不变的 judge/teacher。

3.4 Slime 的插件化扩展点

Slime 设计了一套插件化的钩子系统,OpenClaw-RL 通过 shell 脚本中的参数注入,不修改 Slime 核心即可接管整个训练流程。四个扩展点:

# run_qwen3_4b_openclaw_rl.sh 中的关键参数: --rollout-function-path openclaw_rollout.generate_rollout_openclaw # 扩展点1 --custom-generate-function-path openclaw_api_server.generate # 扩展点2 --custom-rm-path openclaw_api_server.reward_func # 扩展点3 # 无需 --custom-loss-function-path(RL 用标准 GRPO) # run_qwen3_4b_openclaw_combine.sh --custom-loss-function-path combine_loss.combine_loss_function # 扩展点4

扩展点 1 是最核心的接管。Slime 框架原本假设 rollout 是主动的(给模型一个 prompt,模型生成 response),OpenClaw-RL 把它改成被动等待(等真实用户对话产生样本)。generate_rollout_openclaw()被 Slime 的RolloutManager调用,负责回调 OpenClawAPIServer 收集训练数据。

# openclaw_rollout.py def generate_rollout_openclaw(args, rollout_id, data_buffer, evaluation=False): """ Slime 框架期望: 调用这个函数 -> 返回 rollout_batch_size 个 Sample OpenClaw 实现: 不主动生成! 而是等待真实用户对话产生样本 """ worker = get_global_worker(args, data_buffer) if evaluation: eval_output, _ = run(eval_rollout(args, rollout_id)) return eval_output worker.resume_submission() # 开放 API 接受新会话的样本提交 completed_samples = run( _drain_output_queue(args, worker) # 阻塞等待,直到收集到 rollout_batch_size 个样本 ) worker.pause_submission() # 关闭提交(权重更新期间,503 所有请求) return RolloutFnTrainOutput(samples=completed_samples, metrics=...)

标准 Slime 模式是"训练器 → 给我生成 rollout_batch_size 个样本 → rollout 引擎主动采样"。OpenClaw-RL 模式是"训练器 → 给我生成 rollout_batch_size 个样本 → 打开闸门等待 → 用户正常使用 OpenClaw(同时 API Server 收集并评分)→ output_queue 积满 → 关闭闸门,返回给训练器"。

4. 可复制配置:config.toml 骨架与 settings.json

4.1 config.toml 骨架

下面是我整理的可复制config.toml骨架,覆盖 Slime 与 PPO 的关键配置入口。你可以直接放到项目根目录,按需改路径和 GPU 数。

[model] path = "Qwen/Qwen3-4B" actor_gpus = 4 rollout_gpus = 2 prm_gpus = 2 tensor_parallel = 4 [slime] train_async_entry = "slime/train_async.py" rollout_function_path = "openclaw_rollout.generate_rollout_openclaw" custom_generate_function_path = "openclaw_api_server.generate" custom_rm_path = "openclaw_api_server.reward_func" # combine 模式才需要下面这行 # custom_loss_function_path = "combine_loss.combine_loss_function" [ppo] advantage_estimator = "grpo" # 可选: grpo / on_policy_distillation clip_range = 0.2 kl_coef = 0.01 rollout_batch_size = 32 max_new_tokens = 512 temperature = 0.7 [prm] judge_samples = 3 # 多数投票次数 m=3 score_range = [-1, 0, 1] async_eval = true [server] api_port = 30000 sglang_router_port = 0 # 0 表示由 Slime 动态分配 prm_router_port = 0 [taotoken] base_url = "https://taotoken.net/api" api_key_env = "TAOTOKEN_API_KEY"

几个容易踩坑的点:advantage_estimator选on_policy_distillation时,Slime 的loss.py内部已有 OPD 分支,不需要再配custom_loss_function_path;sglang_router_port和prm_router_port填 0 让 Slime 动态分配,避免端口冲突;rollout_batch_size要和实际并发用户量匹配,太小会频繁触发权重同步,太大则训练延迟高。

4.2 settings.json 接入片段

前面第 2 节已经给了settings.json的基础片段,这里补充一个针对 OpenClaw-RL 调试场景的增强版,把模型对话和 Coding Plan 都挂到统一通道:

{ "ai_provider": { "base_url": "https://taotoken.net/api", "api_key": "sk-your-taotoken-key", "default_model": "claude-sonnet-4-20250514" }, "openclaw_rl": { "debug_chat_endpoint": "https://taotoken.net/api/v1/chat/completions", "coding_plan_enabled": true, "log_level": "debug" } }

debug_chat_endpoint用于在训练卡住时,单独发一条请求验证模型通道是否正常,排除是网络问题还是架构问题。

5. 验证请求与成功结果

配置写完之后,不要直接跑完整训练,先做三步验证。

第一步,验证 TaoToken 通道。用 curl 发一条最小请求:

curl -X POST https://taotoken.net/api/v1/chat/completions \ -H "Authorization: Bearer $TAOTOKEN_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "model": "claude-sonnet-4-20250514", "messages": [{"role": "user", "content": "ping"}], "max_tokens": 16 }'

成功结果:返回 JSON 里choices[0].message.content有内容,usage.total_tokens大于 0。如果返回 401,检查 Key;返回 404,检查base_url是否多了斜杠。

第二步,验证 Slime 扩展点加载。启动训练脚本后,观察日志里是否出现rollout_function_path和custom_rm_path的加载记录。成功标志是看到generate_rollout_openclaw被调用,且OpenClawAPIServer在:30000端口监听。

# 另开终端验证 API Server 是否起来 curl -s http://127.0.0.1:30000/v1/models | head -c 200

成功结果:返回模型列表 JSON,说明 FastAPI 代理已就绪。

第三步,验证样本收集。发一条模拟用户对话,观察output_queue是否收到样本:

curl -X POST http://127.0.0.1:30000/v1/chat/completions \ -H "Content-Type: application/json" \ -H "X-Session-Id: test-session-001" \ -H "X-Turn-Type: main" \ -d '{ "model": "qwen3-4b", "messages": [{"role": "user", "content": "帮我写一个快速排序"}], "logprobs": true }'

成功结果:返回带logprobs的响应,同时训练日志里出现sample submitted to output_queue或类似记录。如果rollout_batch_size设为 1,此时训练循环应该开始消费样本并进入 forward/backward。

6. 本篇常见错排查

6.1 训练循环卡在_drain_output_queue

现象:日志停在waiting for rollout_batch_size samples,GPU 占用正常但无进展。

原因:rollout_batch_size设得比实际并发用户量大,或者resume_submission()没被调用。检查generate_rollout_openclaw里worker.resume_submission()是否执行,以及 API Server 的submission_enabled事件是否被 set。

排查动作:把rollout_batch_size临时改成 1,发一条对话看是否触发训练。如果触发,说明是批量大小问题;如果不触发,检查_drain_output_queue的阻塞条件。

6.2 PRM 评分一直返回 0

现象:sample.reward["score"]始终是 0,GRPO advantage 全为 0,梯度不更新。

原因:PRM Judge 的 prompt 构造有问题,或者judge_samples多数投票逻辑没生效。检查_build_prm_judge_prompt()的输出是否符合预期,以及_majority_vote()是否收到 m=3 个独立结果。

排查动作:单独调用_query_prm_once(),打印原始 judge 输出。如果 judge 返回格式不匹配解析逻辑,score 会 fallback 到 0。

6.3 Combine 模式 loss 报维度不匹配

现象:combine_loss_function里combined_adv和logits维度对不上。

原因:batch["teacher_log_probs"]和batch["rollout_log_probs"]的 token 长度不一致,或者w_opd/w_rl权重没配。检查 API Server 提交样本时teacher_log_probs是否按max_new_tokens=0的 forward 结果正确填充。

排查动作:在combine_loss_function入口打印batch["advantages"].shape和batch["teacher_log_probs"].shape,确认两者在 token 维度对齐。

6.4 权重同步期间请求 503

现象:用户对话在权重更新期间收到 503。

原因:这是设计行为,pause_submission()会关闭提交,purge_record_files()清理状态。如果 503 持续时间过长,说明权重同步(mbridge)卡住。

排查动作:检查 Megatron → SGLang 的 mbridge 同步日志,确认save_interval和同步耗时。如果同步超过预期,考虑减小模型或增加同步带宽。

7. 继续深入:从架构理解到实操验证

读到这里,你应该能画出 OpenClaw-RL 的完整数据流:用户请求 → OpenClawAPIServer(生产样本)→ output_queue → AsyncRolloutWorker(收集样本)→ generate_rollout_openclaw() → RolloutManager → Slime Train Loop → Model Training。评价数据走generate()函数,奖励计算走reward_func(),两者都是模块级函数,不是 OpenClawAPIServer 的方法。

下一步建议你按这个顺序动手:先用模型对话入口验证 TaoToken 通道,再对照接入文档把settings.json配好,然后跑rollout_batch_size=1的最小训练循环,确认样本能进能出。长期编码和 Agent 调试场景,直接开 Coding Plan,避免额度中断打断你的源码阅读节奏。

架构理解到位之后,Slime 的四个扩展点就是你的操作面板。改rollout_function_path换数据来源,改custom_rm_path换奖励逻辑,改custom_loss_function_path换 advantage 合成方式。OpenClaw-RL 的工作量集中在数据采集层,Slime/Megatron 核心代码一行不用动——这也是它最值得学的地方。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询