[VeRL] AgentLoop源码走读

最近 RL sys 圈子的吴锡斌老师在 verl 上设计了将 rollout 与 tool 调用解耦的 AgentLoop,实现了自由灵活的 mutli-turn RL。在每个 AgentLoop 内部,rollout engine 只对外提供一个 token-in-token-out 的接口,而 tool 调用则通过 ToolAgentLoop 来实现。我个人比较喜欢这样解耦的设计,同时,AgentLoop 的代码结构也比较清晰。我个人学习了一次整个代码后,觉着 AgentLoop 的设计甚是不错,但是 ActorRolloutRefWorker 的历史包袱还是很重。 本文简单分析了 agent loop 的源码,并给出了一些自己的看法。 如果我们把整个 ActorRolloutRefWorker 当做一个 sgl.Engine 的话,AgentLoop 里面包装的两层 AsyncSGLangServer 和 AsyncLLMServerManager。AsyncSGLangServer 相当于在 sgl.Engine 上包装了 fastapi 成了 server,而 AsyncLLMServerManager 是在 server 上包了一层 router 做 load balance,相当于 sglang 的 router。这两层设计都是合理的,主要麻烦的是 ActorRolloutRefWorker,层层调用,最后一共经过 7 个 class 才调到 sgl.Engine,最近 verl 团队也在致力于对这块 worker class 的重构,敬请期待。最后,AgentLoopManager,AgentLoopWorker 和 AgentLoop 这三层,我觉得 AgentLoopWorker 可能未必有必要,其他两层挺合理的。 ...

August 14, 2025 · 15 min · 3051 words · Me

[VeRL] 参数速览

VeRL框架的参数众多,基于当前(2025.8.5)主线分支整理,附带了相关的理解,一些描述不一定完全正确,供学习参考。 Batch Size 参数名称 详细解释 data.train_batch_size 作用:定义了单次训练发送给 Rollout Engine 的样本数量,也即这是在每个 PPO 迭代开始时,从训练数据集中采样的提示 (Prompt)数量。 详细解释:这个值是 RL 训练中的基本样本数量。例如,设置为 1024 意味着在一次迭代中会: 1. 从数据集中随机抽取 1024 个 prompt。 2. 将这 1024 个 prompt 发送给当前的 Rollout Engine 中,从而得到 1024 组完整的 trajectories(prompt, response)。 3. 接下来,这 1024 个 trajectories 进行经验计算(make experience),后续用于 Actor 和 Critic 模型的更新。 影响与权衡:影响总共训练的样本量。 data.val_batch_size (Deprecated) 作用:在 Validation 阶段使用的批次大小。 详细解释:这与 train_batch_size 类似,但仅用于评估模型性能,不参与训练。如果设置为 null,会使用验证集的大小作为默认值。Note: 已经deprecated,推荐设置为 null。此时,整个 validation dataset 一次性发给 SGLang engines,自行进行内存管理。 actor_rollout_ref.actor.ppo_mini_batch_size critic.ppo_mini_batch_size 作用:定义了 PPO 训练更新中的 mini-batch 大小。 详细解释:data.train_batch_size 收集到的全部经验数据将被分割成多个 mini-batch,每块的大小就是 ppo_mini_batch_size。模型每处理完一个 mini-batch,才会进行一次参数更新。 例如,如果 train_batch_size = 1024,ppo_mini_batch_size = 256,那么在一个 PPO Epoch 中,模型会进行 1024 / 256 = 4 次参数更新。 影响与权衡:增大 mini-batch,单次更新的梯度更稳定,但更新频率更低,更新次数减少。 actor_rollout_ref.actor.ppo_micro_batch_size_per_gpu critic.ppo_micro_batch_size_per_gpu 作用:定义了在单个 GPU 上进行一次 forward/backward 的数据大小。 详细解释:这是实现梯度累积的核心参数。mini-batch 会被再次切分为若干个 micro-batch。例如,在单卡上,ppo_mini_batch_size = 256,ppo_micro_batch_size_per_gpu = 32,那么梯度累积的步数就是 256 / 32 = 8。这意味着模型会运行 8 次 forward 得到 loss,然后 backward 的到 gradient。每次处理 32 个样本,直到累积完整个 mini-batch 计算出的梯度。此时,使用累积的总梯度,对模型参数进行一次更新(optimizer.step())。这个值必须根据显存大小来严格调整,是防止 OOM 的关键。 影响与权衡:增大此值,减少了梯度累积的次数,可以提高训练的吞吐量,增大显存消耗。 actor_rollout_ref.actor.ppo_micro_batch_size critic.ppo_micro_batch_size(Deprecated) 作用:已弃用,被 per_gpu 版本取代,因为它能更好地适应分布式训练环境。 Dynamic Batch Size 当样本长度差异很大时,按样本数量划分批次可能导致不同批次的计算量极不均衡,而基于 token 总数来控制 batch size 是一种平衡每个 batch 训练时间的方案。 ...

August 14, 2025 · 6 min · 1133 words · Me

[RL4LLM] 异步RL框架: Slime

https://github.com/THUDM/slime 一个异步实现但是非完全异步的RL框架 总体架构 从源码模块划分,有三大核心模块: training(Megatron):主训练流程,负责模型参数更新。 rollout(SGLang + router):负责采样、奖励/验证生成,产生训练数据。 data buffer:桥接训练与采样,管理数据流、缓存与生成方式。 分布式调度:关于资源分配、actor启动、任务调度都由于Ray管理,支持异步训练和采样 插件机制:支持自定义buffer、模型、模型格式转换(mbridge) flowchart LR subgraph Ray[Ray 分布式调度] A1[Actor Group<br>训练 Actor] A2[Rollout Group<br>采样/生成 Actor] A3[Placement Group<br>资源分配] end subgraph Training[Training <Megatron>] T1[模型训练] T2[权重同步] T3[评估/保存] end subgraph Rollout[Rollout <SGLang+Router>] R1[采样/生成] R2[奖励模型] R3[过滤器] end subgraph Buffer[Data Buffer] B1[数据缓存] B2[数据流转] B3[Offload/Onload] end subgraph Plugins[插件机制] P1[Buffer 插件] P2[Model 插件] P3[mbridge 格式转换] end A1-->|训练数据|B1 A2-->|生成数据|B1 B1-->|数据流|A1 B1-->|数据流|A2 A1-->|权重同步|A2 A1-->|评估/保存|T3 A2-->|采样/奖励/过滤|R1 R1-->|奖励|R2 R1-->|过滤|R3 B1-->|插件扩展|P1 A1-->|模型扩展|P2 A1-->|格式转换|P3 A3-->|资源分配|A1 A3-->|资源分配|A2 各模块视角的关系图 slime/rollout 组件图 rollout 负责采样、奖励、过滤,支持多种采样/奖励/过滤策略。 ...

August 7, 2025 · 15 min · 3119 words · Me

[RL4LLM] 异步RL框架: Areal

https://github.com/inclusionAI/AReaL 纯异步RL方案 异步PPO训练调用流程 graph TD A[用户执行: examples/run_async_ppo.sh] --> B[training/main_async_ppo.py] B --> C[AsyncPPOMATHConfig配置解析] C --> D[training/utils.py: run_experiment] D --> E[Ray初始化] E --> F[exp_cfg.initial_setup] F --> G[AsyncRLExperimentConfig.initial_setup] G --> H[创建ExperimentConfig] H --> I[启动Workers] I --> J[MasterWorker] I --> K[ModelWorker] I --> L[GenerationServer] I --> M[GserverManager] I --> N[RolloutWorker] %% MasterWorker训练流程 J --> J1[MasterWorker._poll_async] J1 --> J2[FunctionExecutor.execute_step] J2 --> J3[执行数据流图遍历] J3 --> J4[发送训练请求到ModelWorker] %% ModelWorker处理流程 K --> K1[ModelWorker._poll] K1 --> K2[接收MasterWorker请求] K2 --> K3[处理训练/推理请求] K3 --> K4[执行模型前向/反向传播] %% Rollout流程 N --> N1[RolloutWorker._poll_async] N1 --> N2[load_next_data] N2 --> N3[allocate_new_rollout] N3 --> N4[agent.collect_trajectory] N4 --> N5[env.step计算奖励] N5 --> N6[推送数据到训练端] %% 生成服务器流程 L --> L1[GenerationServer._poll] L1 --> L2[启动SGLang子进程] L2 --> L3[处理生成请求] %% 生成服务器管理器 M --> M1[GserverManager._poll] M1 --> M2[HTTP服务线程] M2 --> M3[请求调度和权重更新] %% 数据流 N6 --> O[stream_dataset.py] O --> J4 %% 异步通信 J4 -.->|异步请求| K2 N3 -.->|HTTP请求| M2 M2 -.->|调度请求| L3 %% 权重更新 K4 --> P[参数更新] P --> Q[权重同步] Q --> M3 M3 --> R[更新生成服务器权重] style A fill:#e1f5fe style J fill:#f3e5f5 style K fill:#e8f5e8 style L fill:#fff3e0 style M fill:#fce4ec style N fill:#f1f8e9 用户入口到配置解析 examples/run_async_ppo.sh → training/main_async_ppo.py ...

August 7, 2025 · 23 min · 4872 words · Me

[VeRL] Multi-Turn RL训练源码走读(2)

在 Part 1 中,我们介绍了 verl 的初始化过程,我们进一步介绍 verl 的训练过程,包括rollout部分、make experience部分以及training部分。 在 GRPO 中,单个 step 包含四个阶段:load data -> rollout -> make experience -> update model。区别于前一节的详述,本节会使用伪代码结合源码的方式进行阐述。 flowchart LR subgraph W2["Initialize"] WP[Process Data] --> A direction TB D1[Data Prepare] --> A A[TaskRunner] --> B1[RayPPOTrainer] B1 --> Workers subgraph Workers["Workers"] direction TB WA[ActorRolloutWorker] --> WD[FSDP Engine] WB[CriticWorker] --> WD WC[RewardModelWorker] --> WD WD --> WE[SGLang Engine] end Workers --> C1[Hybrid Engine] end subgraph W3["Train Loop"] direction TB E[DataLoader] --> RolloutBox subgraph RolloutBox["Rollout"] F1[Prepare Data] --> F2[SGLang Async Rollout] F2 --> F3[Multi-turn Chat Process] end RolloutBox --> ExpBox subgraph ExpBox["Make Experience"] G1[Recompute Log Probs] --> G2[Compute Reward] G2 --> G3[Compute Advantage] end ExpBox --> UpdateBox subgraph UpdateBox["Train The Model"] H1[Load FSDP Model Weight] --> H2[Compute Gradient] H2 --> H3[Weights Update] H3 --> H4[Sync Weights] end UpdateBox --> E end W2 --> W3 数据加载与预处理 verl 通过 DataProto 和 RLHFDataset 来实现数据处理。具体来说,在 main_ppo.py 中,我们观察这个函数: ...

August 3, 2025 · 27 min · 5743 words · Me