OpenClaw-RL系统架构深度解析:强化学习源码阅读笔记
【Agentic RL / 强化学习 / OPD】OpenClaw-RL 源码阅读笔记 --- (4)--- 架构
本系列的核心目标一直没有变:借着对OpenClaw-RL源码的学习,把强化学习里那些关键概念和思想好好梳理一遍。所以,文章里免不了会穿插一些基础知识的扩展和发散,而OpenClaw-RL本身,更多是充当一个具体的切入点。另外,整个系列是一个整体,有些概念在不同文章里会出现,这也是为了方便大家对照着理解——提前打个招呼。
OpenClaw-RL是一个专门为智能体工具使用场景设计的在线强化学习框架。它的工作方式很直接:从环境反馈中提取过程奖励信号,用这些信号来训练语言模型。框架支持三种主要模式:
- openclaw-rl:基于二元奖励的强化学习,也叫Binary RL或GRPO。
- openclaw-opd:基于后见之明提示的在线策略蒸馏,简称OPD。
- openclaw-combine:联合方法,在同一PPO更新中同时利用RL reward和OPD teacher的信号。
这三种模式,其实可以看作是同一套框架下的三种不同“调优”策略。
0x01 架构
OpenClaw的RL训练,本质上是一套统一的PPO框架,加上三种不同的advantage注入方式。说得更直白一点,核心区别就在于“如何告诉模型它做得好还是不好”。
三种方法的对比总结如下:
- Binary RL:Advantage来源是R(raw broadcast),也就是把奖励标量广播到整个序列。适用场景很简单,只有±1的reward。
- OPD:Advantage来源是A_t = teacher_lp_t - old_lp_t,即teacher模型提供的per-token信号。适用于需要精细引导的场景,比如hint机制。
- Combine:Advantage来源是A_t = w_rl·R + w_opd·(teacher_lp_t - old_lp_t),同时需要reward和teacher信号。这是最灵活的方式,可以调节权重。
框架的设计有几个关键原则: 1. 统一PPO clip框架:三种方法共享同一套ratio-based clipped loss。 2. 数据驱动分流:Combine方法通过设置teacher_lp=rollout_lp或reward=0,自动区分OPD和RL的样本。 3. 无额外模型:用GRPO替代了Critic,teacher模型只做forward pass,不参与训练。 4. 异步架构:Proxy实时拦截用户对话,Trainer在后台持续更新。
1.1 架构图
(此处为架构图)
1.2 File Structure
代码的文件结构是这样的。核心的RL框架部分主要包括slime和Megatron-LM。slime负责实现Ray+Megatron-LM的分布式训练,Megatron-LM则是NVIDIA的模型并行后端。
在此基础上,分为几个主要模块: - 个性化Agent优化(Track1):包括openclaw-rl(Binary RL/GRPO)、openclaw-opd(On-Policy Distillation)、openclaw-combine(RL+OPD联合方法)和openclaw-tinker(Tinker云端零GPU方案)。 - 通用Agent RL(Track2):包括gui-rl(GUI Agent,基于OSWorld)、swe-rl(SWE Agent,基于mini-swe-agent)、terminal-rl(Terminal Agent,基于SETA)和toolcall-rl(Tool-Call Agent,基于ReTool)。 - 评估模块:openclaw-test,用于GSM8K多轮对话评估。 - 前端:openclaw,一个用TypeScript/Node构建的聊天应用。 - 配置文件:requirements.txt(301个Python依赖)和instructions/(环境搭建指南)。
各模块的具体职责,从源码目录结构就能看得更清楚。OpenClaw-RL核心的代码都放在对应的子目录下,比如openclaw-rl目录里就有API服务器和rollout脚本。
1.3 四大组件
OpenClaw-RL的系统设计,可以拆解成四个异步解耦的循环——policy serving、environment hosting、reward judging、policy training,它们同时运行、互不阻塞。这意味着模型可以一边持续为用户提供服务,一边从刚刚发生的真实交互中在线学习。
(此处为组件图)
这四个组件跟标准RL的区别,可以从一个对比中看出端倪。OpenClaw-RL并不是简单地把标准RL的组件搬过来,而是在异步化的基础上做了大量定制。
Policy Serving
这个组件的定义很清晰:运行策略模型、生成response、提供推理能力。它的功能定位包括几个方面: - 用户交互入口:接收外部环境的请求并返回响应。 - 模型推理服务:将请求转发至SGLang推理引擎获取模型响应。 - 会话状态管理:维护多轮对话的上下文状态。
技术实现上,Web框架基于FastAPI,实现了OpenAI兼容的/v1/chat/completions接口。核心文件是openclaw_api_server.py和openclaw_opd_api_server.py。
具体来看这个组件的内部构成:SGLang Rollout Engine是真正的Policy,负责LLM推理,跑在GPU 4-5上,由Slime启动,Ray Placement Group管理。OpenClawAPIServer._handle_request()充当HTTP转发袋里,通过httpx.post()向SGLang发送推理请求。_extract_logprobs_from_chat_response()负责采集rollout的log-probs。对外暴露的推理接口是FastAPI的/v1/chat/completions,端口为30000。而Megatron Actor(GPU 0-3)则保存着最新的策略权重,定期同步给SGLang。
Environment
环境托管模块,负责产生观测(next_state)和定义任务边界。它构建了智能体操作的真实或模拟环境: - 个人智能体场景:集成用户终端设备(手机/电脑)的会话系统。 - 通用智能体场景:支持云端并行终端、图形界面交互、软件工程开发环境及工具调用沙盒。
环境模块通过事件驱动机制实时反馈状态变化,包括用户追问、代码执行结果(stdout/stderr)或界面元素变更等信号。
具体实现上,Environment在OpenClaw中没有代码实体——它其实就是“真实用户+HTTP协议”本身。真实用户负责发消息(动作)和看response(观测),用户发来的HTTP请求中的messages就是观测序列,而新消息(messages[-1])则是上一轮的环境反馈。X-Session-Id header用于标识同一个环境episode(会话),X-Turn-Type(main/side)用于区分训练轨迹与非训练交互,X-Session-Done header则作为episode终止信号。
Reward Judging
奖励判断组件,负责评估当前response的质量,产生reward信号。它的评估机制采用“双轨制”: - 量化评估层(PRM Judge):基于预设指标体系生成即时评分(+1/-1等)。 - 质性指导层(OPD Hint Extractor):通过自然语言理解技术提取改进建议。
该模块将评估结果与指导信号整合为结构化反馈,构建出“教师上下文”用于模型微调。评估过程采用异步批处理模式,支持每秒千级交互的评估吞吐量。
功能定位很明确: - 质量评估:对袋里响应进行质量评分,评估逻辑基于下一状态判断质量,评分规则为+1(好)、-1(差)、0(中性),并通过多次独立评估取多数结果。 - 奖励信号生成:生成用于策略优化的奖励信号。 - 过程监督:提供细粒度的过程反馈,而不是仅关注结果。
技术实现上,过程奖励模型通过下一状态评估当前响应质量,多数投票机制执行多次独立评估提高可靠性,异步评估在后台线程中执行耗时的LLM评估。核心文件是集成在openclaw_api_server.py中的PRM相关逻辑。
具体来看,_fire_prm_scoring()触发PRM评分任务(异步),_prm_evaluate()是PRM评估的主逻辑(m=3并行),_query_prm_once()单次调用Judge LLM(GPU 6-7),_majority_vote()通过多数投票得出最终分数,_build_prm_judge_prompt()构造judge prompt。SGLang PRM Engine(GPU 6-7)负责运行Judge LLM推理。
对于OPD和Combine模式,还有一些额外的模块:_fire_opd_task()触发OPD评估任务,_opd_evaluate()执行Hint Judge + Teacher LP + Eval,_query_judge_once()单次调用Hint Judge,_select_best_hint()选取最优hint,_compute_teacher_log_probs()进行教师前向传播(max_new_tokens=0),_query_prm_eval_once()和_prm_eval_majority_vote()则是Combine特有的Eval Judge逻辑。
Policy Training
策略训练模块,利用reward信号更新策略参数。它基于Megatron等分布式训练框架构建,采用PPO等强化学习算法实现模型优化。创新点在于: - 独立数据队列机制:隔离在线服务与训练数据流。 - 增量学习架构:支持动态权重更新而不中断服务。
功能定位很清晰:基于收集的样本和奖励信号更新策略模型,并支持多GPU和多节点分布式训练。技术实现上,训练框架基于Slime和Megatron-LM,算法支持GRPO、PPO、KL正则化等多种RL算法。核心文件是slime/train_async.py及相关训练脚本。
具体模块的职责,从各个API服务器中的流程就能看出来。_maybe_submit_ready_samples()等待PRM完成后触发样本提交,_submit_turn_sample()构造Sample对象(包含loss_mask、reward等),_submit_rl_turn_sample()是Combine方法中RL-only样本的特殊处理。output_queue.put()则负责跨线程传递Sample。
Slime训练主循环的架构也很关键。generate_rollout_openclaw()是Slime rollout的入口(被动收集模式),_drain_output_queue()等待N个样本积累,AsyncRolloutWorker.pause/resume_submission()控制API开关(在权重同步期间暂停)。compute_advantages_and_returns()计算GRPO/OPD advantage,get_grpo_returns()处理GRPO advantage(reward标量广播),compute_policy_loss()计算PPO clip损失,combine_loss_function()则是Combine的自定义损失函数(w_opd + w_rl)。Megatron Actor(GPU 0-3)执行梯度更新和权重同步,而RolloutFnTrainOutput定义了rollout的输出格式。
GPU分配
四个组件各自运行在不同的GPU上,分配情况如下: - Policy Training:GPU 0-3,运行Megatron Actor,TP=4。 - Policy Serving:GPU 4-5,运行SGLang Rollout + FastAPI Proxy。 - Reward Judging:GPU 6-7,运行SGLang PRM/Judge。 - Environment:无需GPU,运行OpenClaw App + 用户。
整个GPU分配的配置可以用一行代码来表示(假设是8卡节点):GPU0-3用于Megatron Actor(Policy Training),GPU4-5用于SGLang Rollout(Policy Serving),GPU6-7用于SGLang PRM/Judge(Reward Judging)。
1.4 模型
OpenClaw-RL优化的是Qwen3-4B(Actor),它同时也是serving用户的模型(通过SGLang推理引擎的权重副本)。有意思的是,三个角色(Actor/Rollout/Judge)用的都是同一个模型,但只有Actor会真正被训练更新。
模型的具体配置如下: - Actor Model(GPU 0-3,Megatron TP=4):被优化的Student模型,做forward/backward/optimizer step,这就是OpenClaw-RL正在训练的模型。 - Rollout Model(GPU 4-5,SGLang TP=2):为用户服务的推理引擎,是Actor的权重副本(定期同步),不直接训练,只是Actor的“镜像”。 - PRM Judge/Teacher(GPU 6-7,SGLang):负责评分、生成hint、计算teacher_log_probs,可以是同一模型的另一个实例(用于OpenClaw OPD),不被训练,只是工具。
所以,真正被优化的只有Actor Model。Rollout和Actor是同一个模型的不同副本(权重周期性同步),而Judge/Teacher则是固定不变的。
在具体配置上,run_qwen3_4b_openclaw_rl.sh中统一指定MODEL_PATH=Qwen/Qwen3-4B。Actor(训练)用的是Megatron格式,做梯度更新;Rollout(推理)用的是SGLang格式,serve用户;PRM/Teacher(评估)也是SGLang格式,负责评分、hint和teacher scoring。
完整的训练循环是这样的:用户请求进入Rollout(Qwen3-4B)生成response,然后PRM Judge(Qwen3-4B)进行评分并生成hint,接着Teacher(Qwen3-4B + hint)计算teacher_log_probs,最后Actor(Qwen3-4B)做梯度更新——这一步是整个流程的核心,模型经过优化后,权重同步回Rollout,下次用户就能得到更好的response。
0x02 Slime 的作用
Slime在OpenClaw-RL中扮演着核心的RL后训练框架角色。它的职责是高效地组织rollout、trainer和data buffer等模块,实现异步、解耦的RL训练流程。Slime连接了模型推理(如SGLang)、训练(如Megatron)和数据流转,支撑了OpenClaw-RL的所有RL训练范式(OPD、Binary RL、Combine)。
2.1 集成机制
Slime通过以下机制与OpenClaw组件集成: - 插件化架构:通过命令行参数注入自定义函数。 - 异步数据流:OpenClaw APIServer异步生产数据,Slime异步消费。 - 训练资源隔离:不同组件使用独立的GPU资源,避免相互干扰。 - 统一接口:所有OpenClaw变体(RL/OPD/Combine)都遵循相同的集成模式。
Slime的启动流程大致如下:首先启动SGLang引擎,然后启动Slime Router(分配动态端口),接着将ip/port写入args,OpenClaw APIServer读取args后,对外暴露PORT=30000给OpenClaw App(用户流量入口)。整个过程中SGLang的启动、GPU分配、端口分配、Router注册全部由Slime控制。
这种设计使得OpenClaw-RL能够充分利用Slime强大的分布式训练能力,同时保持OpenClaw组件的灵活性和可扩展性。
2.2 Slime 扩展
Slime设计了插件化的钩子系统,OpenClaw-RL通过shell脚本中的参数注入,不需要修改Slime核心代码就能完整接管整个训练流程。
RolloutManager是Slime中负责管理rollout数据收集的核心类,它通过几个扩展点来集成OpenClaw组件: - 自定义生成函数:通过--custom-generate-function-path指定。 - 自定义奖励函数:通过--custom-rm-path指定。 - 自定义损失函数:通过--custom-loss-function-path指定。 - 自定义rollout函数:通过--rollout-function-path指定。
在具体的Shell脚本中,这些参数会被明确配置。例如,run_qwen3_4b_openclaw_rl.sh中会指定rollout-function-path、custom-generate-function-path和custom-rm-path,而combine版本则需要额外的custom-loss-function-path。
每个扩展点的职责都很清晰。从架构图可以看出,Slime通过这些扩展点构建了一个灵活的集成层。
2.3 OpenClaw-RL 做了哪些工作
OpenClaw-RL的核心工作量集中在了数据采集层(openclaw_api_server.py),通过4个扩展点精准插入到Slime框架中,完全不需要修改Slime或Megatron的核心代码。
分工非常明确:OpenClaw-RL负责openclaw_api_server.py(FastAPI袋里、会话管理、PRM评分、next_state检测、样本提交等)、openclaw_rollout.py(被动等待模式、drain_output_queue、pause/resume submission)、openclaw_opd_api_server.py(hint提取、teacher log-probs计算、top-K蒸馏)、combine_loss.py(combined_adv计算、自定义PPO loss)以及各种run脚本。而Slime框架则提供train_async.py(异步训练主循环)、Megatron-LM(TP/PP/CP训练)、SGLang(高效推理)、Ray(分布式任务调度)、GRPO优势计算、PPO损失函数、权重同步、checkpoint管理和WanDB日志等基础设施。
扩展点①:rollout_function_path——这是最核心的接管。
关键创新在于:Slime框架原本假设rollout是主动的(给模型一个prompt,模型生成response),而OpenClaw-RL把它改成了被动等待(等真实用户对话产生样本)。这个函数叫generate_rollout_openclaw(),由Slime的RolloutManager调用,负责协调OpenClaw APIServer收集训练数据。关键操作包括:获取全局AsyncRolloutWorker实例、启用样本提交(resume_submission())、从输出队列收集样本(_drain_output_queue())、然后禁用样本提交(pause_submission())。
代码逻辑也很清晰:当Slime期望“调用这个函数→返回rollout_batch_size个Sample”时,OpenClaw的实现是不主动生成,而是等待真实用户对话产生样本。如果是评估模式,则使用标准eval rollout。在正常训练时,先resume_submission()开放API接受新会话的样本提交,然后阻塞等待直到收集到足够的样本,再pause_submission()关闭提交(权重更新期间,所有请求返回503)。
标准Slime模式是“训练器→给我生成rollout_batch_size个样本→rollout引擎主动采样”,而OpenClaw-RL模式则变成了“训练器→给我生成rollout_batch_size个样本→generate_rollout_openclaw()打开阀门,等待→用户正常使用OpenClaw(同时APIServer收集并评分)→output_queue积满rollout_batch_size个样本→关闭阀门(暂停提交),返回给训练器”。
扩展点②③:custom_generate 和 custom_rm——这两个是直通接口。
真正的评分逻辑已经在_prm_evaluate()中异步完成并存入sample.reward。生成函数generate()是模块级的async函数,被Slime在评估模式下调用,用于生成单个样本的响应,实现上直接调用SGLang的/generate端点。奖励函数reward_func()也是模块级函数,对于OpenClaw-RL,直接返回样本中已有的PRM评分。
扩展点④:custom_loss_function_path——仅Combine使用。
这个扩展点的核心在于combine_loss_function(),它从Slime框架注入的batch中读取预计算的GRPO优势、OPD teacher信号和Megatron当前forward pass的输出,然后计算combined_advantages = w_opd * teacher_adv + w_rl * grpo_adv,最后计算PPO clip损失加上KL损失。
自定义Advantage接入Trainer的设计思路是:API Server负责“算好所有原材料”(reward、teacher_lp、rollout_lp),Slime只负责“组装advantage + 算loss”。三种方法的advantage注入路径各不相同: - Binary RL走Slime内置GRPO路径,不需要custom-loss-function-path,Advantage由Slime内部的get_grpo_returns()计算,OpenClaw只负责提供reward值。 - OPD通过劫持Slime的advantage字段来实现。API Server把teacher_log_probs塞进sample字段,Slime的loss.py读到teacher_log_probs后,计算advantages[i] = teacher_log_probs[i] - rollout_log_probs[i]。同样不需要custom-loss-function-path,Slime的loss.py内部已有OPD分支,由CLI参数触发。 - Combine是唯一需要custom loss的。combine_loss_function()会同时读取batch["advantages"](GRPO已算好的)、batch["teacher_log_probs"]和batch["rollout_log_probs"],然后计算combined_adv = w_rl * grpo_adv + w_opd * (teacher_lp - rollout_lp),用combined_adv替换原advantage后计算PPO clip loss。
从数据流全景图来看,整个流程一目了然。
2.4 集成
入口
主训练入口是slime/train_async.py,这是Slime异步训练的核心文件。主要功能包括:初始化Ray集群(创建placement groups分配GPU资源)、创建Rollout Manager(初始化包含SGLang引擎的rollout管理器)、创建训练模型(初始化actor和critic模型)、以及进入异步训练循环。
关键调用点在于:调用rollout_manager.generate.remote()获取训练数据,然后调用actor_model.async_train()执行训练,并定期保存模型和更新权重。
启动
Slime的启动是通过shell脚本完成的,比如OpenClaw-RL对应openclaw-rl/run_qwen3_4b_openclaw_rl.sh,OpenClaw-OPD对应openclaw-opd/run_qwen3_4b_openclaw_opd.sh,OpenClaw-Combine对应openclaw-combine/run_qwen3_4b_openclaw_combine.sh。
这些脚本的最后部分,通过Ray Job Submit调用Slime的主训练文件,同时传入各种自定义函数路径和其他参数。
循环
Slime框架的循环非常清晰。Slime训练器调用rollout_manager.generate(),RolloutManager调用自定义的generate_rollout_openclaw()函数,OpenClaw RolloutWorker管理OpenClaw APIServer实例并收集样本,OpenClaw APIServer处理用户请求并生成训练样本。
完整的循环流程是:Slime框架先初始化Ray集群+Megatron Actor+SGLang Rollout Engine,然后进入训练循环。循环中,先调用rollout_function_path(即generate_rollout_openclaw),启动OpenClaw APIServer(FastAPI on :30000),resume_submission()开始接受对话,等待output_queue积满rollout_batch_size个Sample,然后pause_submission()停止接受对话。接着调用reward_func()返回已有的score(直通),进行GRPO advantage计算(Slime内置),执行Megatron forward pass(TP=4),调用custom_loss_function(combine_loss或Slime内置),最后进行backward + optimizer step(带CPU offload)。循环结束后,进行权重同步:Megatron → SGLang(通过mbridge),并在每sa ve_interval步保存checkpoint。
2.5 核心模块
几大组件的角色定位很明确: - Slime:核心训练框架,提供分布式训练基础设施。 - OpenClaw APIServer:API袋里服务器,处理用户请求并生成训练样本。 - AsyncRolloutWorker:异步轨迹收集工作者,协调数据收集流程。 - Trainer:Slime训练器,负责模型训练和权重更新。
整体架构采用了生产者-消费者-协调者模式:OpenClaw APIServer作为生产者(生成训练样本),AsyncRolloutWorker作为协调者(管理收集流程),Slime Trainer作为消费者(消费样本进行训练)。
依赖关系也很清晰:Slime(核心框架)通过函数调用接口依赖AsyncRolloutWorker(协调层),AsyncRolloutWorker通过队列和状态控制依赖OpenClaw APIServer(数据生产层),OpenClaw APIServer通过HTTP API调用依赖SGLang(推理引擎),而Slime则直接集成SGLang引擎用于评估。
调用逻辑详细分析
Slime Trainer调用AsyncRolloutWorker的入口点在slime/train_async.py中,通过create_rollout_manager()创建rolloutmanager(包含AsyncRolloutWorker),然后通过rollout_manager.generate.remote()异步生成rollout数据,最后通过ray.get(actor_model.async_train())训练actor模型。关键调用链是Slime Train Loop → rollout_manager.generate.remote() → RolloutManager → 调用自定义的generate_rollout_openclaw() → AsyncRolloutWorker → 管理OpenClaw APIServer实例。
AsyncRolloutWorker调用OpenClaw APIServer的初始化过程也很有讲究。在AsyncRolloutWorker.init()中,会创建OpenClaw APIServer实例,然后启动服务器线程。状态控制调用包括:worker.pause_submission()触发self._server.purge_record_files(),worker.resume_submission()启用_submission_enabled标志,以及self._server.purge_record_files()清空内部状态。
核心数据结构
最重要的数据结构是Sample对象,它由OpenClawAPIServer._build_sample_for_turn()构建。字段包括:prompt(用户输入文本)、response(助手响应文本)、tokens(完整token序列)、rollout_log_probs(SGLang生成的对数概率)、teacher_log_probs(教师模型对数概率,仅OPD/Combine使用)、reward(PRM评分结果)、loss_mask(训练有效性掩码)。Sample对象的流向是:output_queue → Slime Trainer。
其他内部状态字典还包括:_turn_counts(会话回合计数器)、_pending_records(待处理回合记录)、_pending_turn_data(待评估回合数据,包含tokens和logprobs)、eval_scores(PRM评估结果缓存)。
output_queue的类型是queue.Queue(),内容为(group_index, [sample_list])元组,生产者是OpenClaw APIServer,消费者是AsyncRolloutWorker → Slime Trainer。
此外还有异步任务队列_prm_tasks,用于存储PRM评估的asyncio.Task,作用是跟踪异步评估状态,避免重复评估。
0x03 交互
接下来,来看看真实对话是如何从用户流入训练系统的。这个系统的核心设计有几个特点: 1. 用户无感知:训练在后台异步进行,不影响响应速度。 2. Zero标注:next_state自动成为reward信号,无需人工标注。 3. 完全私有:对话数据不离开用户服务器。 4. 实时持续学习:每次对话都可能成为训练数据,模型持续进化。
总体流程包含三条主要路径: - 训练数据收集路径:用户请求 → OpenClaw APIServer(生产样本) → output_queue → AsyncRolloutWorker(收集样本) → generate_rollout_openclaw() → RolloutManager → Slime Train Loop → Model Training。 - 评估数据生成路径:Slime Evaluation → generate() function → OpenClawAPIServer._forward_to_sglang() → SGLang → Response。 - 奖励计算路径:Slime Training → reward_func() → Sample.reward.score(already computed by OpenClaw APIServer)。
各个阶段的核心组件和数据也很清晰:Policy Serving阶段使用SGLang和FastAPI Proxy处理token ids、logprobs和response text;Environment阶段通过OpenClaw App(真实用户)产生conversation turns和teacher hints;Reward Judging阶段使用LLM Judge(多数投票)生成score ∈ {-1, 0, +1}后映射到loss_mask;Policy Training阶段用Megatron(GRPO/OPD/Combine)将advantages转化为gradient updates。
从正常训练循环的时序来看,时间轴是这样的:T0用户请求到达 → OpenClaw APIServer处理 → 样本缓冲;T1下一状态到达 → 触发PRM评估 → 异步评分;T2 Slime请求数据 → AsyncRolloutWorker启用提交;T3样本提交到队列 → AsyncRolloutWorker收集样本;T4 Slime开始训练 → 消费样本 → 更新权重;T5权重更新完成 → AsyncRolloutWorker禁用提交 → 清理状态;T6新请求使用新策略 → 循环继续。
但关键是,整体是异步进行的,各组件不相互阻塞。SGLang持续服务用户,只在暂停期间(503)加载新权重;Proxy不断采集数据,暂停后恢复再继续;PRM持续评分;Megatron则在等待数据和训练之间交替。
3.2 模块交互
模块间的通信接口如下:OpenClaw App通过HTTP/JSON与FastAPI Proxy通信,使用X-Session-Id/Turn-Type/Done等header。FastAPI Proxy通过httpx与Slime Router通信,支持OpenAI兼容协议并设置logprobs=True。Slime Router通过httpx与SGLang Engine通信,使用/v1/chat/completions端点。FastAPI Proxy还通过httpx与PRM Slime Router通信,使用/generate端点(plaintext prompt)。OpenClaw APIServer通过Queue与AsyncRolloutWorker通信,传递(group_id, [Sample])。AsyncRolloutWorker通过generate_rollout_fn与Slime/Megatron通信,传递RolloutFnTrainOutput。submission_enabled Event则用于控制FastAPI Proxy的pause和resume状态。
整体模块交互流程和具体展开图如下所示。
3.3 详细流程
Policy Serving
Policy Serving的流程中,有一个关键点需要特别说明:next state。OpenClaw-RL关注的是一个贴近真实部署的问题:agent在线运行时,每一步交互后天然产生的next-state signal,能不能直接被回收成训练信号?这里的next state可以是很多东西——用户下一句回复、工具执行结果、终端stdout/stderr、GUI状态变化、SWE环境中的测试verdict或报错trace。
另外,main vs side的区分逻辑也很重要。main代表用户对话的主线,会产生训练数据;side则是辅助性调用,比如UI渲染前的pre-flight请求、工具调用前的参数生成、非核心交互(session管理)等。side请求会被完整转发,但不会截取训练样本。
Environment
Environment在OpenClaw中没有代码实体,它就是“真实用户+HTTP协议”本身。
Reward Judging
Reward Judging的流程如下图所示。
Policy Training
Policy Training的流程也有明确的分支。三种方法的路径选择如下: - Binary RL:Proxy → PRM评分 → Sample(reward) → GRPO adv → policy_loss → 更新。 - OPD:Proxy → PRM + hint + teacher_lp → Sample(teacher_lp) → OPD adv → policy_loss → 更新。 - Combine:Proxy → PRM + hint + teacher_lp → Sample(reward + teacher_lp) → GRPO adv → custom_loss(混合) → 更新。
3.4 完整时序
最后,用一个完整的例子来串联整个流程。
Phase 1:用户对话 → Rollout
用户手机发送HTTP POST请求到FastAPI Proxy(GPU 4-5 SGLang),请求内容为messages: [{"role":"user","content":"北京有什么好玩的?"}],并携带headers: X-Session-Id: sess_abc, X-Turn-Type: main。SGLang生成response,例如"北京有很多好玩的地方,比如故宫、长城...",同时输出response_logprobs。Proxy拦截并记录prompt_ids、response_ids和response_logprobs,作为π_old的logprobs。
Phase 2:PRM评分(GPU 6-7)
进行3次独立调用(majority vote,m=3)。第一次调用认为回答准确全面,输出1;第二次认为信息丰富,输出1;第三次认为还行但可以更好,输出0。最终majority_vote([1,1,0]) = 1,reward = +1。仅OPD/Combine模式会进行Phase 2b(Hint + Teacher log-probs),由Hint judge调用给出建议,然后将hint注入用户消息,Teacher进行前向传播(max_new_tokens=0,不生成)输出teacher_log_probs。
Phase 3:构建Sample对象
构造Sample()对象,填充tokens、response_length、rollout_log_probs、teacher_log_probs(如果有)、reward({"score": 1.0})、loss_mask等信息,然后放入output_queue,等待Slime的rollout函数取走。
Phase 4:Advantage计算(Slime Trainer)
Binary RL模式(--advantage-estimator grpo)直接将reward广播给所有token,advantages全为+1。OPD模式(--advantage-estimator on_policy_distillation)逐token计算teacher和student的log-probs差,由于teacher都比student更自信,所有advantage都为正。Combine模式则同时使用grpo_adv和teacher_adv,计算combined advantage。
Phase 5:PPO更新(以Combine为例)
进行当前forward pass(π_new),计算new_log_probs。然后逐token计算ratio = exp(new_lp - old_lp)和advantage。由于某个token的ratio超过了clip阈值(1.28),会被clip掉。最终计算pg_loss1和pg_loss2,取max后得到该样本的sample_mean_loss。
Phase 6:参数更新
将total_loss与其他样本的贡献相加,除以global_batch_size,然后进行backward和optimizer.step()。效果是:所有相关token(如“北京”、“好玩”、“故宫”)的概率都增大了,但“好玩”这个token因为想增大更多而被clip限速了。