
Rollout 之后,问题回到更新本身:大模型如何在分布式训练引擎里完成一次可信的参数移动。
第三组把推理嵌入训练:response 不是训练脚本里顺手调用的一次生成,而是由 rollout service、backend adapter、KV cache、sleep/resume 和 agent loop 共同维护的训练时推理层。到这里,读者已经知道样本如何被生产出来。第四组要继续回答下一件事:这些 response、reward、logprob 和 advantage 回到训练系统以后,actor/critic 到底怎样完成一次大模型更新?
这一组的核心判断是:PPO/GRPO 的 update 不是 controller 里的一行算法调用,而是算法 batch、训练 worker、engine registry、分布式后端、micro-batch 调度和权重同步共同形成的工程合同。只有理解这层合同,才知道为什么同一套 RL 目标会因为 FSDP、Megatron、sequence parallel、dynamic batch size 和 checkpoint engine 的选择,呈现完全不同的吞吐、显存和同步约束。
先看第四组在系列里的位置。读这张图时注意三条线:第一,第三组的 rollout 产物如何进入 actor/critic update;第二,上层 trainer 为什么通过 BaseEngine和 EngineRegistry选择后端;第三,训练完的新权重为什么必须再回到 rollout replicas。

训练引擎与分布式核心总览
这张图不是把所有并行技术摊开,而是固定第四组的阅读路线:RayPPOTrainer._update_actor()和 _update_critic()先把 PPO mini-batch、epoch、shuffle 等算法参数塞进 TensorDict,然后调用 worker 的 update_actor()或 train_mini_batch();TrainingWorker再通过 EngineRegistry.new()实例化具体后端;后端内部才决定如何拆 micro-batch、如何做 forward/backward、如何处理 sequence parallel,最后由 checkpoint engine 把权重同步回 rollout。
第三组解决的是“response 如何生成”。但 RL step 的另一半压力来自 update:同一批 response 要重新算 logprob、根据 reward/advantage 计算 loss、做 backward、更新 optimizer state,并把新 actor 权重送回推理侧。对小模型来说,这很容易被理解成普通 PyTorch 训练循环;对后训练大模型来说,真正的约束变成了参数、梯度、优化器状态、激活、长序列 token 和跨 worker 通信如何被切开。
verl 的源码把这个边界拆得很清楚。BaseEngine.train_batch()定义了统一训练步:修正 position ids、清梯度、调用 forward_backward_batch()、再执行 optimizer_step()。但这个统一接口下面,FSDP 会围绕 shard、offload、Ulysses sequence parallel 和 per-tensor 参数导出工作;Megatron/MCore 会围绕 tensor/pipeline/expert/context parallel、pipeline schedule 和 micro-batch generator 工作。第四组要读的正是这个“接口统一,但成本不统一”的层次。
第 19 篇《FSDP/FSDP2:把大模型切开训练》先回答最基础的问题:为什么训练大模型时不能只关心模型参数,还必须同时考虑梯度、优化器状态、reshard、offload 和导出全量权重给 rollout 的成本。它会从 FSDPEngine的 device mesh、FSDP wrapping、micro-batch forward/backward 和 get_per_tensor_param()读起。
第 20 篇《Megatron/MCore:TP、PP、EP 如何支撑 MoE》进入另一类后端。它解决的问题不是“Megatron 有哪些并行术语”,而是 verl 如何把 Megatron-Bridge/MCore 的 tensor parallel、pipeline parallel、expert parallel、context parallel 和 sequence parallel 接到同一个训练 engine 合同里。
第 21 篇《EngineRegistry:如何让上层 Trainer 不关心底层后端》回到抽象层。它会解释为什么 TrainingWorker只需要拿 model_type和 engine_config.strategy调 EngineRegistry.new(),但后端仍然要实现 data parallel rank、train/eval mode、checkpoint、参数导出和 forward/backward 等完整职责。
第 22 篇《mini-batch、micro-batch、dynamic batch size 的区别》专门拆 batch。PPO mini-batch 是算法更新的单位;micro-batch 是 engine 为显存和流水线切出来的执行单位;dynamic batch size 则按 token 长度重新装箱。把这三者混在一起,就很难解释为什么同一份训练配置会影响 loss 归一化、梯度累积、pipeline bubble 和 GPU 利用率。
第 23 篇《长上下文训练为什么需要 Sequence Parallel》把问题从 batch size 推到 token 维度。FSDP 路径里有 Ulysses sequence parallel 的 device mesh 和 group 切换,Megatron 路径里也会把 sequence_parallel写入 provider。它要解决的问题是:当 prompt/response 变长以后,系统为什么不能只靠减小 micro-batch,而需要把序列维度本身变成并行对象。
第 24 篇《Checkpoint Engine:训练权重如何同步给推理引擎》把第四组重新接回第三组。训练后端负责产生新权重,rollout 后端负责继续生成样本,中间的 checkpoint engine 决定是 colocated naive 更新,还是通过 NCCL/NIXL/Mooncake/Kimi 等后端把权重传给 rollout replicas。这里会再次看到 sleep、release KV cache、abort/resume generation 和权重新鲜度之间的工程取舍。
第一个边界是 engine 抽象和后端现实。BaseEngine让上层看到统一的 train_batch()、infer_batch()、get_per_tensor_param()和 data parallel 接口;但 FSDP 与 Megatron 的真实执行路径完全不同。读第四组时,重点不是背并行名词,而是判断“这个后端把哪类状态切开,又把哪类复杂度留给了谁”。
第二个边界是算法 batch 和性能 batch。actor.ppo_mini_batch_size出现在算法更新语义里,ppo_micro_batch_size_per_gpu和 use_dynamic_bsz则进入 engine 执行语义里。前者决定一次 PPO epoch 如何迭代样本,后者决定每张 GPU 一次能承受多少 token,以及是否需要按长度重新排布 micro-batch。
第三个边界是训练更新和推理权重。第四组不是单纯讲训练系统,因为 RL 的 actor 更新完以后,下一轮 rollout 必须使用新权重。CheckpointEngineManager.update_weights()里先处理 naive 路径,再处理 abort requests、release KV cache、build process group、trainer/rollout 双侧 update 和 resume generation。这就是训练引擎为什么天然会影响推理服务层。
到第三组结束,我们已经能从 controller 追到 rollout service,知道 response 如何被训练系统生产。第四组把视角推进到 worker 内部:actor/critic update 不是一个黑盒,而是一组关于后端选择、状态切分、batch 执行、长上下文和权重同步的工程合同。
放回系列地图,第四组补的是 workers/resources内部的训练引擎层,并把它接到 weight sync:
training objective
-> dataflow
-> controller
-> workers/resources
-> training engine/distributed core
-> rollout/serving engine
-> weight sync
-> production train/serve system
读完这一组,读者应该能从 RayPPOTrainer._update_actor()继续追到 TrainingWorker.train_mini_batch(),再进入 FSDP 或 Megatron engine,最后理解新权重为什么要通过 checkpoint engine 回到 rollout。
verl/trainer/ppo/ray_trainer.py:1222-1265:actor/critic update 如何设置 PPO mini-batch、epoch、shuffle,并调用 worker 更新。verl/workers/engine_workers.py:132-139:TrainingWorker如何通过 EngineRegistry.new()根据 model_type和 engine_config.strategy创建训练后端。verl/workers/engine_workers.py:250-306:train_mini_batch()如何把 mini-batch 切到每个 DP rank,并逐个调用 train_batch()。verl/workers/engine/base.py:29-131:BaseEngine的统一训练接口,包括 forward_backward_batch()和 train_batch()。verl/workers/engine/base.py:267-337:EngineRegistry的注册、查找和实例化逻辑。verl/workers/engine/fsdp/transformer_impl.py:85-90、608-640、908-909:FSDP engine 的职责、micro-batch forward/backward 和 registry 注册。verl/workers/engine/megatron/transformer_impl.py:75-90、207-214、616-674、789-790、1004-1005:Megatron engine、并行配置注入、pipeline micro-batch 执行和 language/value model 注册。verl/workers/engine/utils.py:58-96:prepare_micro_batches()如何在 dynamic batch 和固定 micro-batch 两条路径之间切换。verl/trainer/config/actor/actor.yaml:13-33:actor 配置中 strategy、PPO mini-batch、micro-batch 和 dynamic batch 的入口。verl/checkpoint_engine/base.py:49-108、323-492:checkpoint engine registry、抽象接口和权重同步 manager 的主流程。