slime 外部 Rollout 引擎接入指南:跨集群权重同步与训练/推理解耦实践
【免费下载链接】slimeslime is an LLM post-training framework for RL Scaling.项目地址: https://gitcode.com/GitHub_Trending/slime12/slime
在 LLM 后训练(RL 训练)中,当推理服务由训练作业之外的系统负责部署与生命周期管理时,slime 需要一种"只接入、不接管"的模式:连接已启动的 SGLang 引擎、注册路由器,并在需要时同步更新后的 Actor 权重。本文以 external-rollout-engines.md 为骨架,结合 slime 源码中的发现机制、权重同步参数与校验逻辑,系统讲解外部 Rollout 引擎的使用场景、配置方式、磁盘全量/增量权重更新方案,以及部署时的注意事项。读完本文,你将能够独立判断何时使用--rollout-external-engine-addrs、何时继续使用--sglang-config,并为跨集群、跨数据中心的训练/推理拆分场景选择正确的权重同步路径。
什么是外部 Rollout 引擎
外部 Rollout 引擎(external rollout engine)是指不是由 slime 训练作业启动的 SGLang 引擎。在这种部署形态下:
- 另一个系统负责部署引擎并拥有其生命周期;
- slime 在训练期间只负责连接这些引擎;
- slime 为这些引擎注册路由器(router);
- 需要时,slime 将更新后的 Actor 权重同步到引擎侧。
这一路径天然适合推理服务归属于训练作业之外的部署形态,例如:独立的推理集群、独立的 Ray 集群、预先手动预热的 SGLang 引擎,或由其他编排系统托管的 rollout 服务。
何时使用外部引擎:决策表
原文档给出的选择矩阵是判断接入方式的首要依据,先明确你的目标与对应入口:
| 目标 | 推荐入口 |
|---|---|
| 引擎已由外部启动,slime 只需连接做 rollout | --rollout-external-engine-addrs |
| slime 仍需自己启动引擎,但需要 PD 分离、多模型服务、异构服务器组或按组覆盖配置 | SGLang Config |
| 训练器与外部引擎可以组成 NCCL 组 | 默认--update-weight-mode full --update-weight-transport nccl |
| 训练器与外部引擎无法组成 NCCL 组,但能看到同一文件系统路径 | --update-weight-mode full --update-weight-transport disk |
| 大模型跨集群或跨数据中心同步时全量 checkpoint 太重 | --update-weight-mode delta --update-weight-transport disk |
| rollout 服务使用独立的 SGLang 环境,甚至不同的 GPU 型号/厂商 | 外部引擎 + disk 传输 |
| 需要冻结的参考模型、奖励模型或工具侧模型 | 优先在 SGLang Config 中设置update_weights: false |
需要特别记住一条硬约束:Delta 模式只支持磁盘传输。需要在 NCCL 上同步权重时,请使用全量模式。
快速上手:连接已启动的外部引擎
首先独立启动 SGLang 服务器(这部分完全由外部系统负责,slime 不参与启动):
python -m sglang.launch_server --model-path /path/to/model --port 10090 ... python -m sglang.launch_server --model-path /path/to/model --port 10091 ...然后将这些地址传给训练作业:
python train.py \ --rollout-external-engine-addrs host1:10090 host2:10091 \ ...--rollout-external-engine-addrs参数在 slime/utils/arguments.py 中定义为可接受多个值的参数(nargs="+"),因此可以一次性传入多个host:port。
slime 会依次查询每个引擎的/server_info或/get_server_info端点,推断出 GPU 数量、TP/PP 信息以及 worker 类型(regular、prefill或decode)。如果未提供--sglang-router-ip/--sglang-router-port,slime 会自己启动一个路由器,并将这些外部引擎注册到其中。
地址归一化规则
在 slime/backends/sglang_utils/external.py 中,normalize_external_engine_addr会统一处理地址格式:
- 支持
host:port与http://host:port两种写法,统一归一化为 HTTP base URL; - 若地址缺少协议前缀,自动补上
http://; - 若地址不含端口或 scheme 不是
http,会抛出ValueError(IPv6 地址必须加方括号)。
引擎信息发现机制
discover_external_engines(external.py)遍历所有地址,逐个请求/server_info(失败时回退到/get_server_info,见get_server_info),并从返回的 JSON 中解析出:
pp_size/pipeline_parallel_size:流水线并行度;tp_size/tensor_parallel_size:张量并行度;num_gpus/num_gpus_per_engine:引擎占用的 GPU 数(缺省时按tp_size * pp_size推算);ep_size/expert_parallel_size:专家并行度;moe_dp_size/moe_data_parallel_size:MoE 数据并行度;disaggregation_mode:用于判断 worker 类型(prefill/decode/null);disaggregation_bootstrap_port:PD 分离场景下 prefill 引擎的引导端口;encoder_only:编码器专用引擎标记。
_infer_worker_type(external.py)根据这些字段决定 worker 类型:encoder_only为encoder,disaggregation_mode为prefill/decode时取对应值,其余为regular。这些信息随后被封装为ExternalEngineInfo(external.py),其is_pd_worker属性可判断是否为 PD 分离 worker,parallel_config属性则汇总出完整的 TP/PP/EP/MoE-DP 配置,用于后续训练侧拓扑推导。
参数填充与拓扑推导
apply_external_engine_info_to_args(external.py)将发现结果写回参数对象:
args.rollout_external_engine_infos:引擎信息字典列表;args.rollout_num_engines:外部引擎总数;args.rollout_num_gpus:所有引擎 GPU 数量之和。
test_external_sglang_engines.py 中test_apply_external_engine_info_handles_pd展示了 PD 分离场景的完整链路:传入prefill:10090与decode:10091两个地址后,rollout_num_gpus会被正确推导为2 + 4 = 6,且 worker 类型分别为prefill与decode,prefill 引擎的disaggregation_bootstrap_port也被保留。同文件中test_discover_external_engines_reads_server_info则验证了tp_size=4, pp_size=2的引擎会被推导为 8 块 GPU。
服务组与路由器接线
start_external_rollout_servers(external.py)完成最终接线:
- 调用
start_router启动(或复用)路由器,并传入has_pd_disaggregation标记; - 为每个外部引擎创建一个
SGLangEngineRay Actor(num_cpus=0.2、num_gpus=0,不占用训练作业的 GPU 配额); - 按引擎 GPU 数累积
engine_gpu_counts与engine_gpu_offsets,用于后续的全局 GPU 编号编排; - 将
(router_ip, router_port)写入args.sglang_router_ip/args.sglang_router_port,并以default为模型名注册sglang_model_routers; - 返回以
default为键的ExternalRolloutServer,其engine_parallel_configs保留了每个引擎的完整并行配置。
值得注意的是,ExternalRolloutServer.recover()只记录一条警告日志——外部引擎不参与 slime 的容错恢复,因为它们的生命周期属于外部部署系统(详见下文部署清单)。
与--sglang-config的关系:互斥的边界划分
--rollout-external-engine-addrs与--sglang-config是互斥的,因为它们拥有不同的所有权边界:
--sglang-config:slime 拥有引擎生命周期。YAML 描述拓扑,slime 负责启动服务器组、路由器、多模型服务,并做选择性权重更新。--rollout-external-engine-addrs:外部系统拥有引擎生命周期。slime 只发现已运行的引擎、将其挂接到路由器上,并把它们当作默认的 rollout 模型。
如果核心需求是多模型服务、冻结的参考/奖励模型、PD 分离或异构组配置,优先选择--sglang-config;只有当引擎已经部署在训练作业之外时,才使用外部引擎模式。
这一互斥关系在 slime/backends/sglang_utils/arguments.py 的参数校验中也有体现:当设置了rollout_external(外部引擎模式)时,若同时配置了prefill_num_servers或sglang_config,会触发冲突校验。
环境与硬件解耦:外部引擎的核心收益
外部引擎模式最重要的隐含能力是环境解耦:SGLang 服务侧不需要使用 slime 训练作业的 Python 环境、Megatron 环境或 Ray 运行时。它可以在独立的 SGLang 容器、独立集群或其他编排系统中运行。slime 只依赖三样东西:
- HTTP 端点本身;
/server_info发现接口;- 所选权重同步传输方式所需的通信路径。
磁盘传输:允许异构 GPU 硬件
使用磁盘传输时,权重通过共享文件系统上的 HF checkpoint 或 safetensors delta 流动,SGLang 通过update_weights_from_disk热加载。这条路径不要求训练 GPU 与 rollout GPU 是同一型号,甚至不要求同一厂商——只要 SGLang 支持目标硬件后端、模型格式与精度配置即可。例如:训练跑在一个 GPU 集群上,rollout 服务跑在另一个 GPU 型号或厂商的集群上。
NCCL 传输:保持传统约束
使用 NCCL 传输时,NCCL 通信与硬件兼容性的常规要求仍然适用。对于跨厂商、网络不互通或跨数据中心的部署,优先选择--update-weight-transport disk。
权重更新路径总览
权重同步的两种策略由 slime/utils/arguments.py 中的两个参数共同决定:
| 参数 | 取值 | 含义 |
|---|---|---|
--update-weight-mode | full(默认)/delta | full每次同步广播所有参数;delta对上一次同步的 CPU 快照做 diff,只传输变化字节(仅磁盘传输) |
--update-weight-transport | nccl(默认)/disk | 权重同步的载体;full模式下 NCCL 广播分块、磁盘写入完整 HF checkpoint 后由引擎重载;delta模式仅支持磁盘 |
参数校验逻辑(arguments.py)进一步约束了组合方式:
--update-weight-transport=disk必须配合--update-weight-disk-dir,指向训练器与 rollout 引擎共享的文件系统,否则报错;--update-weight-mode=delta必须搭配--update-weight-transport=disk;--update-weight-mode=delta与--colocate互斥——colocate 场景通过 CUDA IPC 句柄跨进程传输权重,delta 的记账(快照 + diff + 编码)是纯开销;--update-weight-mode=delta必须配置--update-weight-local-checkpoint-dir(详见下文)。
更新方式一:从磁盘全量更新(Update From Disk)
全量 checkpoint 磁盘更新是外部部署最简单、最稳妥的回退路径:
--update-weight-mode full --update-weight-transport disk --update-weight-disk-dir /shared/fs/full-updates工作流程:每次权重同步时,训练器在--update-weight-disk-dir下写入一个完整的 HF checkpoint 目录(例如weight_v000123/),然后通过 HTTP 调用每个 SGLang 引擎的update_weights_from_disk端点,让引擎在不重启进程的情况下重新加载 checkpoint。
该流程的实现位于 slime/backends/megatron_utils/update_weight/update_weight_from_disk.py 中的UpdateWeightFromDisk类——从源码看,它通过save_hf_model_to_path落盘 checkpoint,并为每次同步维护weight_version递增版本号。该实现还支持--custom-update-weight-post-write-path钩子(arguments.py):对对象存储等非 POSIX 文件系统而言,跨主机读后写一致性无法自动保证,训练器各 rank 写完文件后需要显式发布(例如上传到后端对象存储),引擎才能看到写入。
本地缓存:从"每 rank 一次读"到"每主机一次读"
增加--update-weight-local-checkpoint-dir后,每个引擎会先把已发布的 checkpoint 拉取到其覆盖的每一台主机的本地磁盘(例如 NVMe),再从本地加载:
- 拉取动作通过
/pull_weights端点完成(该端点由 slime 的 sglang patch 提供); - 收益是每个主机只做一次共享文件系统读取,而不是每个 rank 读一次;
- 当共享目录由对象存储支撑、或引擎横跨多个节点时,这一差异非常关键。
--update-weight-local-checkpoint-dir的完整语义在 arguments.py 中有详细说明:对 delta 模式必需,对全量磁盘同步可选(配置后引擎改为先拉取到本地再加载,而不是直接读共享目录)。
调试辅助
--update-weight-disk-keep-files该参数(arguments.py)会跳过全量 checkpoint 目录的清理,在引擎确认加载完成之后仍保留这些目录,便于排查加载异常或做离线校验。
该模式的定位:控制面简单——不需要训练器与引擎之间的 NCCL 组,双方只需看到同一个共享文件系统路径。代价是体积:每次同步都写入完整的 Actor 权重,对大型模型或高频更新而言开销较大。
更新方式二:Delta 增量更新(Update With Delta)
Delta 更新面向大型模型跨集群、跨数据中心的训练/推理拆分场景。与每次同步都写全量 checkpoint 不同,训练器维护上一轮同步的CPU 快照,对每个参数与快照做 diff,只发布变化字节;每个引擎的/pull_weights端点(slime 的 sglang patch 提供)在其覆盖的每台主机上把 delta 应用进主机本地 checkpoint,随后引擎通过原生的update_weights_from_disk端点重载。slime 只调用引擎的 HTTP 端点,因此多节点外部引擎与 slime 自启动引擎在权重同步上的行为完全一致。
--update-weight-mode delta --update-weight-transport disk --update-weight-disk-dir /shared/fs/delta-updates --update-weight-local-checkpoint-dir /local/nvme/rollout-ckptdelta 模式的实现位于 slime/backends/megatron_utils/update_weight/update_weight_from_disk_delta.py,其机制、编码、完整性校验与共享文件系统可见性钩子,详见 Delta Weight Sync。
两个可选的底层调优参数
在 arguments.py 中,delta 模式还暴露了两个底层参数,引擎会从每个版本的 index 元数据中读取选择:
--update-weight-delta-encoding(xor默认 /overwrite):xor:新值 ^ 旧值,线缆体积最小、速度最快,但它是自逆操作,必须基于正确基线恰好应用一次(应用两次会还原回去);overwrite:只写变化位置 + 新的绝对值,体积更大但幂等,可任意次数重放。- 两者都是字节级、与 dtype 无关。
--update-weight-delta-checksum(xxh3-128默认 /blake3/adler32):- 每个张量的完整性校验和;由于应用过程受解压 + XOR 主导,这不是速度选择而是摘要属性选择;
xxh3-128:最快的非加密摘要,意外损坏碰撞概率可忽略;blake3:加密摘要,适用于不可信存储;adler32:32 位,用于与期望该格式的系统互通。
部署检查清单
外部引擎部署是否就绪,逐项核对以下要点(源自原文档并补充源码验证):
- 网络可达:外部引擎的 HTTP 地址必须能从训练作业所在节点访问(
get_server_info默认超时 30 秒,见 external.py)。 - 环境独立:外部引擎可以使用独立的 SGLang 环境,不需要 slime 或 Megatron 训练环境。
- 硬件异构可行:磁盘传输支持训练与 rollout 使用不同 GPU 型号或厂商,前提是 SGLang 支持目标硬件与模型格式。
- 共享路径是硬前提:磁盘传输要求训练器与 SGLang 引擎看到同一个
--update-weight-disk-dir路径;只对训练器可见的路径是不够的,参数校验会直接报错(arguments.py)。 - 容错边界:外部引擎不会被 slime 的故障恢复机制接管(
ExternalRolloutServer.recover()仅记录警告并跳过,见 external.py);其生命周期属于外部部署系统。 - 参数互斥:
--sglang-config与--rollout-external-engine-addrs互斥,不可同时使用。 - delta 与 colocate 互斥:delta 模式不支持
--colocate,因为 colocate 同步走 CUDA IPC 句柄,delta 编码并不能减少实际传输量(校验逻辑见 arguments.py)。
相关背景:训练/推理拆分下的权重同步趋势
值得留意的是,外部引擎、磁盘全量更新与 delta 磁盘传输所解决的问题,也是业界在大规模 RL 推理基础设施中普遍面临的课题:一旦训练与推理解耦,权重同步就必须跨进程、跨集群乃至跨数据中心工作,同时不能让全量模型传输主导训练循环。slime 提供的这条"外部引擎 + disk 传输"路径,正是对这一基础设施问题的工程化回答:训练侧只依赖 HTTP 端点与共享文件系统,权重以全量 checkpoint 或增量 delta 两种粒度流动,配合/pull_weights本地缓存与自定义发布钩子,适配从单集群到对象存储支撑的跨数据中心场景。
总结
外部 Rollout 引擎模式是 slime 在训练/推理拆分架构下的关键连接能力:通过--rollout-external-engine-addrs只接入不接管,通过磁盘传输实现环境与硬件解耦,通过全量/增量两种权重更新模式在"简单可靠"与"跨集群高效"之间取得平衡。选择路径时可遵循三条主线:引擎生命周期归属决定用--sglang-config还是外部引擎;NCCL 组是否可建立决定传输方式;模型规模与同步频率决定用全量还是 delta。结合本文的源码分析与部署清单,你可以为独立推理集群、跨厂商 GPU 或跨数据中心等真实部署场景快速落地一套可运行的权重同步方案。
【免费下载链接】slimeslime is an LLM post-training framework for RL Scaling.项目地址: https://gitcode.com/GitHub_Trending/slime12/slime
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考