[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

[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

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

该part主要聚焦相关模块初始化部分 还是以 verl 出发,分析其 end to end mutli-turn RL 训练的全过程。整体上,我希望覆盖所有重要的 class 以及函数,更细粒度的代码不再展开。 为了前后内容的一致性,基于 76f63cffa5 的 commit 进行分析。 虽然本文以分析 verl 的代码为主,写完之后我才意识到,系统设计问题是非常通用的。诸如“log probs 重计算”,“Rollout Engine 显存管理”等等系统设计,是各大 RL 框架都需要考虑的核心问题。 此外因为最近在学习SGLang的实现,本文的推理后端选择的是SGLang展开分析。 整个训练的示意图如下,我们会具体展开每个部分。 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 数据预处理 以 GSM8K 为例,预处理脚本是 examples/data_preprocess/gsm8k_multiturn_w_tool.py。整个脚本只做了经典的 huggingface datasets mapping,核心逻辑如下: ...

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