Skip to content
alarik.me
Go back

GLM-5.3 系统优化深度解读:slime 框架如何支撑长周期 RL 扩展

GLM-5.3 与 GLM-5.2 使用相同底座,所有提升来自后训练扩展。Z.ai 开源的 slime 框架支撑了这轮 RL 训练,并宣布系统级优化带来 2.3× 端到端吞吐提升。本文拆解其背后的核心工程决策。

Table of contents

Open Table of contents

一、slime 框架整体架构:单条 dataflow 上的训练-Rollout 统一

slime 的核心设计理念是:把训练、rollout 和数据缓冲区统一在单条 dataflow 上。这不是一句口号,而是一个具体的工程约束,它决定了所有环境交互、reward 计算、verifier 调用都通过”数据生成”的方式插入,而不是侵入训练循环。

三大核心模块

slime 由三个核心模块构成,通过 Ray 编排协同:

模块引擎职责产出
TrainingMegatron从 Data Buffer 读取数据,执行梯度更新,训练后同步参数到 rollout更新后的模型权重
RolloutSGLang + sgl-router生成新数据(含 rewards / verifier outputs),自定义 generate 函数可包装多轮循环、工具调用、沙箱交互写入 Data Buffer 的轨迹
Data Buffer桥接层管理 prompt 初始化、自定义数据、rollout 生成方法(含 agentic workflows)供 training 消费

关键点在于:数学题、代码沙箱、verifier、长周期 agentic 环境全部以”数据生成”方式插入。环境通过 OpenAI-compatible API 与 slime 交互,sgl-router 提供单一 HTTP 端点。这意味着添加一个新环境不需要改训练循环,只需要写一个 generate 函数。

设计哲学:Native 而非封装

slime 在两个关键维度上选择了”native 透传”而非”封装抽象”:

SGLang-native:所有 SGLang 参数通过 --sglang- 前缀透传,不做封装。用户可以直接用 --sglang-enable-ep-moe--sglang-enable-dp-attention 等参数,不需要等框架适配。这保证了 SGLang 的最新特性可以立即被 slime 使用。

Megatron-native:Megatron 参数同样直接透传,支持 TP(Tensor Parallelism)、PP(Pipeline Parallelism)、EP(Expert Parallelism)、CP(Context Parallelism)全部并行策略。

这种设计有一个更深层的原因:选择单一 rollout backend(SGLang)而非多 backend 抽象。多 backend 抽象的陷阱在于 lowest-common-denominator 问题:为了兼容多个推理引擎,只能使用所有引擎都支持的功能子集,结果是无法利用任何引擎的独特优势。slime 选择深度绑定 SGLang,换取了对 SGLang 全部特性的直接访问。

--colocate 标志切换 colocated / decoupled 部署模式:colocated 模式下训练和 rollout 共享 GPU 资源(通过时分复用),decoupled 模式下两者使用独立 GPU 集群。Ray 负责管理 GPU 资源分配和异步执行。

slime 框架整体架构

上图展示了 slime 的核心数据流:Megatron(训练引擎)从 Data Buffer 读取训练数据,完成训练后将权重同步到 SGLang Server;Custom Rollout Generation 通过 SGLang Router 发起推理请求,生成的数据回流到 Data Buffer,形成闭环。

二、MOPD:多教师在线策略蒸馏的训练机制

MOPD(Multi-teacher Online Policy Distillation)是 slime 训练算法的核心创新之一。要理解它为什么重要,先看 OPD 解决的问题:RL 信号的稀疏性

为什么需要 OPD:从稀疏奖励到密集信号

传统 RL 中,student 自己采样轨迹,但只在 episode 结束时获得标量奖励,整个序列共享一个信号,信息量仅 O(1)O(1) bits:

RL:稀疏奖励信号

传统知识蒸馏(Off-Policy Distillation)解决了信号密度问题:teacher 生成轨迹,student 在这些轨迹上学习,每个 token 都有 teacher 的 log-prob 信号(O(N)O(N) bits)。但代价是 exposure bias:student 从未见过自己分布下的数据:

Off-Policy Distillation:teacher 轨迹上的密集信号

OPD 结合了两者优势:student 采样自己的轨迹(on-policy,无 exposure bias),teacher 对每个 token 评分(密集信号)

On-Policy Distillation:student 轨迹 + teacher 密集信号

数学原理:Reverse KL 与 Monte Carlo 估计

OPD(On-Policy Distillation)的核心思想来自 Thinking Machines Lab[9]:student 在自己采样的轨迹上训练,teacher 对每个 token 评分,提供密集的 token 级学习信号

Per-token reverse KL 定义为:

KL(πθπteacher)=Exπθ[logπθ(xt+1x1..t)logπteacher(xt+1x1..t)]\text{KL}(\pi_\theta \| \pi_\text{teacher}) = \mathbb{E}_{x \sim \pi_\theta} \left[ \log \pi_\theta(x_{t+1} | x_{1..t}) - \log \pi_\text{teacher}(x_{t+1} | x_{1..t}) \right]

这里有两个关键细节:

  1. student 是 KL 的第一个参数(即 reverse KL KL(πθπteacher)\text{KL}(\pi_\theta \| \pi_\text{teacher}),而非 forward KL KL(πteacherπθ)\text{KL}(\pi_\text{teacher} \| \pi_\theta))。期望是在 student 分布 πθ\pi_\theta 上取的。
  2. Teacher 不生成训练轨迹,它只评估 student 实际采样的 token。这就是 “on-policy” 的含义:轨迹来自 student 自己的采样。

在工程实现中,slime 不枚举全词表计算期望,而是用 Monte Carlo 贡献来估计每个 token 的 KL 贡献:

r^t=logπθ(xt+1x1..t)logπteacher(xt+1x1..t)\hat{r}_t = \log \pi_\theta(x_{t+1} | x_{1..t}) - \log \pi_\text{teacher}(x_{t+1} | x_{1..t})

这个 r^t\hat{r}_t 被集成到 advantage 估计中:

A^tOPD=A^tβr^t\hat{A}_t^{\text{OPD}} = \hat{A}_t - \beta \cdot \hat{r}_t

其中 A^t\hat{A}_t 是基础 advantage(可以来自 GRPO、PPO、REINFORCE++ 等任何 estimator),β\beta--opd-kl-coef 控制的蒸馏系数。

需要注意的是:单个 hatrt\\hat{r}_t 可能为负(student 在某个 token 上恰好比 teacher 更自信),但 KL 在期望意义上非负。这是 Monte Carlo 估计的自然结果。

OPD 项与 advantage estimator 的选择正交,你可以在 GRPO 之上叠加 OPD,也可以在 PPO 之上叠加,甚至纯蒸馏时设 hatAt=0\\hat{A}_t = 0,只用 OPD 信号。

信息论视角:为什么 OPD 比纯 RL 更高效

从信息论角度看,RL 和蒸馏的学习信号密度有本质差异:

OPD 的关键在于将蒸馏的密集信号与 RL 的 on-policy 相关性结合。传统蒸馏用 teacher 生成的轨迹(off-policy),存在 exposure bias:student 可能在训练中走到 teacher 从未到过的状态。OPD 让 student 在自己的轨迹上被 teacher 评分,消除了这个问题。

Reverse KL(KL(πθπteacher)\text{KL}(\pi_\theta \| \pi_\text{teacher}))相比 forward KL 有三个关键特性:

  1. “Unhackable”:低 KL 总是对应 teacher 认为高概率的行为。不存在一个 student 行为能让 KL 低但 teacher 不认可的,因为 KL 的期望在 student 分布上取,student 无法”逃避”到 teacher 低概率的区域。
  2. “Mode seeking”:reverse KL 倾向于学习 teacher 的某个特定高概率模式,而非覆盖所有模式。这对 RL 后训练通常是有利的,你想要 student 专注学一个好策略,而不是分散到多个平庸策略。
  3. 减少 exposure bias:因为轨迹来自 student 自己的采样,student 不会在训练时遇到部署时从未见过的情况。

为什么 reverse KL 是 mode-seeking,forward KL 是 mode-covering? 关键在于期望在哪个分布上取。

Forward KL KL(pq)=xp(x)logp(x)q(x)\text{KL}(p \| q) = \sum_x p(x) \log \frac{p(x)}{q(x)},期望在 teacher pp 上:

所以 student 必须覆盖 teacher 的所有支撑区域,否则无穷惩罚。结果就是被拉平:覆盖所有 mode 但每个都拟合不精确(mode-covering)。SFT 实际上就是 forward KL,这就是为什么 SFT 倾向于产生”平均化”的策略。

Reverse KL KL(qp)=xq(x)logq(x)p(x)\text{KL}(q \| p) = \sum_x q(x) \log \frac{q(x)}{p(x)},期望在 student qq 上:

所以 student 只能把概率放在 teacher 高概率区域,但不需要覆盖所有 mode,可以只锁定一个峰(mode-seeking)。

Forward KL vs Reverse KL:mode-covering vs mode-seeking

上图直观对比了两种 KL 方向:teacher 分布有两个模式(左),forward KL 让 student 覆盖所有模式但牺牲精度(中),reverse KL 让 student 锁定一个模式(右)。

两种 Teacher 模式

slime 实现了两种 teacher 部署模式,对应不同的架构约束:

SGLang Mode(--opd-type sglang

Teacher 运行在外部 SGLang 服务器上。在 rollout 阶段,reward_func 调用 teacher server 获取 token-level log-probs,post_process_rewards 将结果裁剪到 response span,存入 sample.teacher_log_probs

适用场景:teacher 架构不同于 student,或 teacher 太大无法与训练模型共存。硬性要求:teacher 和 student 必须使用兼容的 tokenization 和 vocabulary,否则 token-level log-prob 无法对齐。

Megatron Mode(--opd-type megatron

Teacher 模型直接加载到 Megatron 进程中。在训练 forward pass 中计算 teacher log-probs,不需要额外的推理服务器。

适用场景:teacher 与 student 架构相同且能放入 GPU 内存。硬性要求:teacher checkpoint 必须是 Megatron 格式(torch_disttorch)。

两种模式的权衡是推理灵活性 vs. 传输开销:SGLang 模式支持异构 teacher 架构但需要网络通信,Megatron 模式无网络开销但要求架构兼容且共享 GPU 内存。

GLM-5.3 中的 MOPD 扩展

Thinking Machines Lab 的原始 OPD 论文明确提到不做 top-k distillation 以节省计算,只对 student 实际采样的 token 计算 teacher log-prob。GLM-5.3 的 slime 框架在此基础上扩展了三种模式:

这些扩展让研究者可以更灵活地控制采样、训练信号和教师信号的组合方式。从 O(1)O(1) 的采样 token 蒸馏到 O(N)O(N) 的全词表蒸馏,计算开销递增但信号密度也递增——研究者可以根据预算选择合适的粒度。

三、TensorBackuper:GPU↔CPU 两级权重快照系统

问题:多模型版本的内存墙

大模型 RL 训练中需要同时维护多个模型版本:

模型版本用途生命周期
Student/Actor正在训练的策略全程
ReferenceKL penalty 参考策略全程
Teacher蒸馏教师蒸馏阶段
Old Actorimportance sampling 用每个 epoch
Rollout Actor生成用快照每次 rollout

如果一个 100B 参数的模型需要维护 5 个版本,每个版本占约 200GB(bf16),总共需要 1TB GPU 显存,这在任何当前硬件上都不可行。slime 的解决方案是 TensorBackuper 系统(源码: slime/utils/tensor_backper.py[3]):不加载多个模型实例,而是在 CPU pinned memory 中存储多个权重快照,按需恢复到 GPU。

两级缓存架构:GPU ↔ CPU Pinned Memory

源码事实 vs 博客描述

GLM-5.3 博客提到”Local storage now serves as an additional caching layer”,暗示三级缓存(GPU→CPU→SSD)。但 slime 开源代码中只实现了两级:GPU 显存 ↔ CPU pinned memory。没有 SSD 三级缓存的实现。 SSD 缓存层可能是 Z.ai 内部版本的功能,未包含在开源代码中。

slime 开源版本的实际架构:

┌─────────────────────────────────────────────┐
│ GPU 显存 │
│ 当前活跃模型权重(通过 _switch_model 切换) │
│ 延迟:~0 | 容量:~80-192GB │
├─────────────────────────────────────────────┤
│ CPU Pinned Memory │
│ TensorBackuper 管理的权重快照 │
│ (ref, teacher, old_actor, rollout_actor) │
│ 延迟:~ms(PCIe 4.0 ~32 GB/s)| 容量:~1-2TB │
└─────────────────────────────────────────────┘

关键设计:checkpoint 只从磁盘加载一次,后续切换全部在 CPU pinned memory ↔ GPU 之间进行。

TensorBackuper 的两种实现

源码定义了两种实现,通过 tag 数量自动选择:

_TensorBackuperNormal(多 tag 场景):

在 CPU pinned memory 中存储权重快照。核心机制:

三个核心操作:

操作实现数据路径
backup(tag)遍历所有参数,copy_ 到 CPU pinned memoryGPU → CPU
restore(tag)从 CPU pinned memory copy_ 回 GPU 参数CPU → GPU
copy(src, dst)在 CPU 内存中直接复制CPU → CPU(不经 GPU)

copy(src_tag, dst_tag) 是一个重要的优化:当需要从已有快照派生新版本(如 actorrollout_actor)时,直接在 CPU 内存中完成,完全不占用 GPU 带宽。

_TensorBackuperNoop(单 tag 场景):

当只有一个 tag 激活时使用。不做完整备份,而是做 hash-based sanity check:对参数张量做 sum(uint32) 快速 hash,验证权重在 backup/restore 前后是否被意外修改。这是性能优化:如果只有一个模型版本,完整的 pinned memory 备份和恢复都是冗余的。

权重标签系统

TensorBackuper 通过 tag 系统管理不同模型版本(源码: slime/backends/megatron_utils/actor.py[6]):

Tag用途创建方式源码位置
actor当前训练策略初始化后 backup("actor")line 129
refKL penalty 参考策略load_other_checkpoint("ref", args.ref_load)line 132
teacher蒸馏教师策略load_other_checkpoint("teacher", args.opd_teacher_load)line 136
old_actor旧策略 checkpointload_other_checkpoint("old_actor", args.load)line 140
rollout_actor生成用策略快照copy("actor", "rollout_actor")line 143
单 Teacher 限制

teacher tag 只有一个。load_other_checkpoint("teacher", args.opd_teacher_load) 只调用一次,加载一个 teacher checkpoint。源码中没有任何多教师(teacher_1, teacher_2…)的支持。详见第四章。

加载流程:load_other_checkpoint

加载一个非 actor 的 checkpoint(如 ref、teacher)时(源码: actor.py line 655-680),slime 执行以下步骤:

  1. 临时修改 args.load 指向目标 checkpoint 路径
  2. 设置 no_load_optim=True, no_load_rng=True, finetune=True:只加载模型权重,不加载 optimizer state 和 RNG 状态
  3. 调用 Megatron load_checkpoint 加载到 GPU
  4. weights_backuper.backup(model_tag):将 GPU 权重备份到 CPU pinned memory
  5. 恢复原始 args:防止影响后续训练

整个流程的关键在于:checkpoint 只从磁盘加载一次,后续切换全部在 CPU pinned memory ↔ GPU 之间进行,消除了重复磁盘 I/O。

切换流程:_switch_model

模型切换的实现很简洁(源码: actor.py line 301-304):

def _switch_model(self, target_tag):
self.weights_backuper.restore(target_tag)
self._active_model_tag = target_tag

训练循环中的模型切换序列

训练循环中(源码: actor.py line 430-499),模型按以下顺序切换:

_switch_model("ref") → compute_log_prob(store_prefix="ref_")
_switch_model("teacher") → compute_log_prob(store_prefix="teacher_")
_switch_model("old_actor"/"actor") → compute_log_prob(store_prefix="")
_switch_model("actor") → 训练(forward + backward + optimizer step)
训练结束后 backup("actor") → 更新 actor 快照

每个前向计算(compute_log_prob)前切换到对应模型,计算完后切换回来。训练结束后通过 backup("actor") 更新 actor 的 CPU 快照,供下一轮使用。

集成 torch_memory_saver

slime 集成了 torch_memory_saver(源码: actor.py line 208-220),在训练/rollout 转换时管理内存:

sleep() 方法执行三步清理:

  1. clear_memory(clear_host_memory=True):释放 PyTorch 缓存的 GPU 和 host 内存
  2. destroy_process_groups():销毁 NCCL 进程组,释放通信资源
  3. torch_memory_saver.pause():将 GPU 内存状态保存到 host,释放 GPU

train_memory_margin_bytes 参数确实存在于源码中,用于预留 host 内存防止 OOM。这在多模型版本场景下尤为重要,多个权重快照同时驻留在 pinned memory 中会快速消耗 host 内存。

两级缓存的能力边界

slime 开源版本的两级缓存可以维护 5 个模型版本(actor, ref, teacher, old_actor, rollout_actor),但受限于 host memory 容量。对于一个 100B 参数模型,每个版本占约 200GB(bf16),5 个版本需要约 1TB pinned memory——这在高端服务器上可行(如 2TB RAM),但扩展空间有限。

GLM-5.3 博客提到的 SSD 三级缓存可以突破 host memory 限制,使冷数据(不常用的权重快照)溢出到 SSD,从而支持更多模型版本(如多教师)。但这一功能在开源代码中未实现。

四、Teacher 切换:单教师实现与多教师扩展

开源版本的单 Teacher 实现

slime 开源代码只支持单个 teacher(源码: actor.py line 136):

self.load_other_checkpoint("teacher", args.opd_teacher_load)

args.opd_teacher_load 是一个单一的 checkpoint 路径,加载后通过 weights_backuper.backup("teacher") 存储为一个名为 teacher 的 CPU pinned memory 快照。训练循环中需要 teacher log-probs 时,_switch_model("teacher") 从 pinned memory 恢复到 GPU,计算完毕后切回 actor。

整个过程利用了第三章描述的 TensorBackuper 机制:

加载阶段: 磁盘 → GPU → CPU pinned memory (backup "teacher")
训练阶段: CPU pinned memory → GPU (restore "teacher") → 计算 log-probs
切换回来: CPU pinned memory → GPU (restore "actor")

teacher 权重始终驻留在 CPU pinned memory 中,切换开销仅为 PCIe 传输,不涉及磁盘 I/O。

与 SGLang 模式 Teacher 的对比

如第二章所述,slime 支持两种 teacher 部署模式:

维度Megatron 模式 (--opd-type megatron)SGLang 模式 (--opd-type sglang)
Teacher 位置Megatron 进程内,通过 TensorBackuper 管理外部 SGLang server
切换方式_switch_model("teacher") (CPU→GPU)无需切换,网络请求
传输开销PCIe 带宽(~32 GB/s)网络带宽(取决于部署)
架构要求Teacher 必须是 Megatron 格式Teacher 和 student 需兼容 tokenization
GPU 占用与 actor 共享 GPU独立 GPU 资源

Megatron 模式下的单 teacher 实现是 slime 开源版本的主要路径,它通过 TensorBackuper 的权重快照机制避免了为 teacher 分配独立 GPU 资源。

GLM-5.3 博客提到的多教师动态切换

博客提到但未开源

GLM-5.3 博客原文提到:“with dynamic teacher switching and prefetching on the training side, several teachers can be used without standing up a dedicated long-running inference service for each, at limited added overhead and substantially lower resource consumption.”

这描述了多教师动态切换 + 预取的能力,但在 slime 开源代码中没有实现

  • 源码中只有一个 teacher tag,没有多教师支持
  • 没有预取(prefetch)实现——没有后台异步加载下一个 teacher 权重的逻辑
  • 没有 SSD 溢出实现——TensorBackuper 只有 GPU↔CPU 两级

这可能是 Z.ai 内部版本的功能,未包含在开源代码中。

GLM-5.3 博客描述的多教师方案核心思路是:多个 teacher 共享同一套 GPU 资源,通过权重 tag 切换实现按需加载。理论上基于 TensorBackuper 扩展:

  1. 多教师权重注册:每个 teacher 加载后备份到不同 tag(teacher_1, teacher_2, …)
  2. 训练侧按需切换_switch_model("teacher_1") → 计算 → _switch_model("teacher_2") → 计算 → _switch_model("actor")
  3. 预取重叠:训练 forward/backward 期间,后台从 SSD 预取下一个 teacher 权重到 pinned memory

单 Teacher 的局限性与多教师扩展的技术挑战

从开源代码的单 teacher 扩展到多教师面临几个技术挑战:

1. 内存容量瓶颈

单 teacher 已经需要一个完整的权重快照(~200GB for 100B model)。多教师场景下,所有 teacher 快照需要同时驻留在 CPU pinned memory 中。5 个 teacher 需要 1TB pinned memory,超出大多数服务器配置。这需要引入 SSD 溢出层(即博客提到的三级缓存),但开源代码中没有实现。

2. 预取时序控制

预取需要在训练计算期间异步进行,不能阻塞 GPU。这需要:

开源代码中的 backup/restore 都是同步操作,没有异步预取的框架。

3. tag 系统扩展

当前 TensorBackuper 的 tag 是字符串标识,扩展到多教师技术上不难(teacher_0, teacher_1, …),但需要修改训练循环中 teacher 切换的硬编码逻辑(当前只有一个 _switch_model("teacher") 调用)。

4. teacher 权重更新

如果 teacher 在训练过程中需要更新(如 self-distillation 场景),多 teacher 的更新调度会显著增加复杂度。开源版本中 teacher 是静态的,加载后不更新。

为什么多教师蒸馏有价值

尽管开源代码只支持单教师,多教师 OPD 在算法层面有明确价值:

这些价值使得多教师扩展成为一个值得探索的方向,开源社区可以基于 TensorBackuper 框架进行扩展。

五、Router 集成与调度:推理路由与训练侧调度

slime 中的两层调度

slime 开源代码中涉及两个层面的调度,需要明确区分:

层面组件职责源码
推理路由SGLang Router将 rollout 请求路由到推理 workerslime/rollout/sglang_rollout.py
训练调度DP Schedule将训练 samples 分配到 DP ranksslime/utils/dp_schedule.py

这两层调度是独立的:推理路由服务于 rollout 阶段的请求分发,训练调度服务于训练阶段的 micro-batch 分配。

推理路由:SGLang Router 集成

slime 通过 args.sglang_router_ipargs.sglang_router_port 连接 SGLang router(源码: sglang_rollout.py[5])。

一致性哈希路由(consistent_hashing

slime 显式支持 router_policy = "consistent_hashing"(源码: sglang_rollout.py line 199):通过 HTTP header X-SMG-Routing-Key 传递 session_id,实现一致性哈希路由。

# 简化示意
headers = {"X-SMG-Routing-Key": session_id}
response = requests.post(router_url, headers=headers, json=payload)

这确保同一 session 的请求始终路由到同一 worker,在多轮 agentic rollout 中复用 KV cache:agent 的多轮对话共享前缀(system prompt + 历史),路由到同一 worker 可以直接命中 prefix cache,避免重复计算。

SGLang 原生策略透传

SGLang router 自身支持多种负载均衡策略:

策略机制适用场景
random均匀随机选择 worker基线,无状态
round_robin顺序轮转均匀负载
cache_aware维护 prompt 前缀树,路由重复流量到同一 worker高 prefix 复用
power_of_two从两个随机候选中选择负载较轻的与 LoadMonitor 集成
consistent_hashing基于 session_id 一致性哈希多轮 agentic rollout

slime 的设计哲学是 native 透传:这些策略是 SGLang 自身的配置,slime 只通过 --sglang- 前缀透传参数,不做封装。用户可以直接配置 SGLang router 的策略和参数。

训练侧调度:DP Schedule

训练侧的 DP(Data Parallelism)调度(源码: slime/utils/dp_schedule.py[7])采用 “pack first, distribute second” 策略:

Step 1: 分组与打包(pack first)

将 samples 按 rollout id 分组,分成 micro-batches。打包策略有两种:

Step 2: 分配(distribute second)

将打包好的 micro-batches 分配到各个 DP rank。使用 Karmarkar-Karp 算法(最大差值法)做 FLOPs 平衡分配:

这是训练侧的 micro-batch 调度,解决的是不同 DP rank 间计算负载不均导致的同步等待问题,与推理 router 的请求路由是不同层面的调度。

权重同步传输

训练完成后需要将更新后的权重同步到 rollout 引擎(源码: actor.py)。slime 支持多种传输方式:

传输方式机制适用场景
UpdateWeightFromTensor直接通过 tensor 引用传输colocated(训练和 rollout 共享进程)
UpdateWeightFromDistributed通过 NCCL 传输decoupled,同集群
UpdateWeightFromDisk通过磁盘文件传输跨集群或大模型
UpdateWeightFromDiskDelta增量磁盘传输(只传变化的权重)频繁更新,带宽受限
Delta 模式限制

Delta(增量)传输模式只支持 disk 传输(UpdateWeightFromDiskDelta),不支持 colocate 模式(UpdateWeightFromTensor)。这是因为 colocate 模式下 tensor 引用传输本身已经很快,增量优化的收益不大。

SGLang 的 PD 分离能力(背景)

SGLang 能力,非 slime 实现

以下 PD(Prefill-Decode)分离能力是 SGLang 自身的功能,slime 可以通过 --sglang- 参数透传配置使用,但联合调度逻辑不在 slime 开源代码中。

SGLang 支持 PD 分离部署,将推理过程分为两个阶段独立优化:

传统统一引擎的问题:新 prefill batch 频繁中断正在进行的 decode batch;DP attention 模式下 prefill 和 decode worker 利用率不均衡。

PD 分离的优势:KV cache 通过 RDMA(Mooncake)传输;GPU staging buffer 解决不同 TP size 间的内存布局差异;cache-aware DP routing 基于 prefix cache affinity 路由。

Cache-aware Routing 的实测效果

来自 SGLang PR 的实测数据展示了 cache-aware routing 的价值:

场景TTFT 中位数变化缓存命中率变化
高复用(10组×50提示)-47%+55%(88.5% vs 57.1%)
低复用(50组×10提示)-38%+116%(27.4% vs 12.7%)

一个反直觉的发现:Round-robin 在低复用场景实际上比无缓存还差 13% TTFT,因为随机分发破坏了 prefix locality。这说明在 agentic RL 中,即使 prefix 复用率不高,cache-aware routing 仍然显著优于随机路由。

GLM-5.3 博客提到的联合调度

博客提到但未开源

GLM-5.3 博客原文描述了联合调度:

“we improved joint scheduling and load balancing between the router and slime, so that rollout requests with widely varying lengths and completion times make better use of inference resources.”

“We added workload-aware heuristics that derive throughput-oriented configurations — prefill/decode resource ratio, concurrency settings, and other throughput-critical parameters — from the characteristics of each rollout environment.”

这描述了两个能力:

  1. Router 与 slime 的联合调度:根据 rollout 请求的长度和完成时间差异优化推理资源利用
  2. Workload-aware 自动配置推导:从 rollout 环境特征自动推导 prefill/decode 资源比例、并发设置等吞吐关键参数

在 slime 开源代码中,这两个能力都没有实现。开源版本只支持手动配置 SGLang router 策略和参数透传,没有自动推导逻辑。这可能是 Z.ai 内部版本的功能。

GLM-5.3 博客描述的联合调度包含三个层面:

1. Router 感知 rollout 环境特征:不同 agentic 环境的请求模式不同,有些产生大量短交互(如简单数学题验证),有些产生少量长轨迹(如多轮代码迭代)。Router 需要知道当前 rollout 的请求模式才能做出好的调度决策。

2. 自动推导配置:从 rollout 环境特征自动推导吞吐导向的配置,包括 prefill/decode 资源比例、并发设置等。

3. 避免长短任务互相阻塞:通过 PD 分离 + workload-aware 调度,长任务的 prefill 不会中断短任务的 decode,短任务的高并发不会挤占长任务的 decode 资源。

这些能力在 slime 开源代码中不存在,但 SGLang 本身提供了实现这些能力的基础设施(PD 分离、cache-aware routing、多种负载均衡策略),社区可以在此基础上构建 workload-aware 的自动配置逻辑。

六、训练-Rollout 数值对齐:RL 信号可信度的基石

问题:数值不一致如何扭曲 RL 信号

RL 训练中有一个容易被忽视但极其严重的问题:训练引擎(Megatron)重新计算的 logprobs 与 rollout 引擎(SGLang)采样的 logprobs 之间存在数值差异

这看似是浮点精度问题,实则影响巨大。在 PPO 的 importance ratio 中:

rt(θ)=πθ(atst)πold(atst)r_t(\theta) = \frac{\pi_\theta(a_t|s_t)}{\pi_{\text{old}}(a_t|s_t)}

如果 πold\pi_{\text{old}} 来自 rollout 引擎(SGLang),πθ\pi_\theta 来自训练引擎(Megatron),两者的数值不一致会导致 importance ratio rtr_t 偏离 1.0,即使策略根本没有更新。这等于在 RL 信号中注入了系统性噪声。

在长周期 RL 训练中,这种噪声会累积:每一步的微小偏差通过 advantage normalization 和 gradient 更新传播,最终导致训练不稳定甚至发散。

slime 的解决方案

slime 从三个层面解决数值对齐问题:

1. 保持 logprob 计算和训练使用相同的 micro-batch schedule

不同 micro-batch size 理论上不应改变数学结果,softmax 和 cross-entropy 是逐 token 计算的。但实践中,不同 micro-batch size 会导致:

slime 团队发现,保持 logprob 计算和训练使用相同的 micro-batch schedule 可以让 recomputed logprobs 尽可能接近原始 logprobs。这是一个工程经验发现,而非理论推导:理论上 micro-batch size 不应该影响结果,但浮点数的非结合性使得实践中确实有影响。

2. R3-style 配置

R3-style 配置是一种特定的数值精度配置方案,确保训练路径和 rollout 路径使用一致的数值表示。

3. 完整数值对齐

最终效果:训练路径和 rollout 路径之间的 logprob 平均差异控制在 10710^{-7} 级别。相比之前方案,差异降低了 99.99%+。

Δlogprob=logπMegatron(x)logπSGLang(x)107\Delta_{\text{logprob}} = |\log \pi_{\text{Megatron}}(x) - \log \pi_{\text{SGLang}}(x)| \approx 10^{-7}

这个精度意味着 importance ratio 在策略未更新时接近 1.0,RL 信号不再被数值噪声污染。

训练-Inference Mismatch 的监控

slime 不仅仅做对齐,它还持续监控残留的 mismatch,提供多维度指标:

指标含义用途
mismatch_kl前向 KL 散度估计整体分布偏差
mismatch_k3_klK3 KL 估计三阶矩偏差
train_rollout_logprob_abs_difftoken 级绝对 logprob 差异逐 token 偏差
mismatch_ppl_ratioperplexity 比率整体不确定性偏差

当 mismatch 超过阈值时,slime 支持多种修正算法:

这些算法形成了一个从”修正”到”丢弃”的递进策略:如果 mismatch 可以被 importance sampling 修正就用 TIS,如果修正不了就丢弃(RS),如果想要更精确的建模就用 Decoupled PPO。

七、整体效果:2.3× 吞吐提升的归因

GLM-5.3 博客原文[1]给出了最终结果:

“for long-horizon coding RL tasks, these system-level optimizations improved end-to-end RL training throughput by more than 2.3×”

2.3× 不是一个单一优化的结果,而是多个优化叠加的综合效应。下表对每个优化的瓶颈和机制做了总结:

优化解决的瓶颈实现机制影响范围
数值对齐(10710^{-7}RL 信号可信度micro-batch schedule 一致 + R3-style 配置训练稳定性
两级权重快照(GPU↔CPU)多模型版本内存不够TensorBackuper + pinned memory可训练模型规模
Teacher 切换蒸馏需要 teacher log-probs单 teacher tag 切换(多教师+预取未开源)蒸馏能力
路由 + DP 调度长短任务混合推理浪费consistent_hashing + Karmarkar-Karp pack(workload-aware 未开源)rollout 吞吐
2.3× 吞吐整体可扩展性以上优化 + 未开源的 SSD 缓存/多教师/联合调度端到端

这些优化之间有协同关系:

要说明的是:slime 开源版本提供了两级快照、单 teacher 切换、一致性哈希路由和 DP 调度的基础设施。GLM-5.3 博客提到的 SSD 三级缓存、多教师动态切换预取、workload-aware 自动配置推导,很可能是 Z.ai 内部版本的功能,未包含在开源代码中。2.3× 吞吐提升是开源基础设施 + 未开源特性的综合效果。

八、API 变更与权重发布

GLM-5.3 在 benchmark 上取得了显著提升(下图),所有提升完全来自后训练扩展:

GLM-5.3 Benchmark 对比

在编码任务上,GLM-5.3 的提升尤为突出:

GLM-5.3 编码能力对比

安全能力的涌现式提升是 GLM-5.3 最出乎预期的发现:

GLM-5.3 网络安全能力

GLM-5.3 在 API 层面也有重要变更:

Thinking 模式thinking.type 只支持 enabled,不再支持 disabled。这意味着 GLM-5.3 始终启用 thinking 模式,模型的推理过程不再可选关闭。

Reasoning Effort:新增 reasoning_effort 参数,可选值为 low / high / max,默认 max。编码任务推荐使用 max,这与 slime 的 long-horizon RL 训练目标一致,更长的 reasoning 链对应更复杂的 agentic 任务。

权重发布:权重将在两周后发布,待完成安全评估后公开。Z.ai 在开源策略上保持谨慎,先做安全审查再发布。

GLM Coding Plan:新积分制上线,非高峰时段 50% 折扣。这降低了开发者使用 GLM-5.3 进行编码任务的成本门槛。

结语

OPD 实验结果

GLM-5.3 的关键信息是后训练扩展就是全部:不换底座,所有提升来自 RL on long-horizon environments。但前提是:RL 训练栈能高效消化越来越多的环境。

slime 展示了一条清晰的工程路径:算法创新(OPD)通过系统优化(两级权重快照、teacher 切换、路由调度、数值对齐)转化为可扩展的实际训练。不做抽象,做 native 透传——每一个工程决策都值得研究,因为下一个 2.3× 提升可能就藏在这些细节里。

Sources

  1. GLM-5.3 Blog — Z.ai 官方博客,GLM-5.3 技术公告
  2. slime GitHub Repo — slime 框架开源代码
  3. TensorBackuper Source — 两级权重快照实现
  4. OPD Implementation — OPD 蒸馏实现
  5. SGLang Rollout Source — SGLang rollout 与路由集成
  6. Actor Source — 模型切换、teacher 加载、权重同步
  7. DP Schedule Source — 训练侧 DP 调度
  8. Loss Source — OPD loss 与数值对齐
  9. Thinking Machines Lab OPD Blog — OPD 原始理论与实验
  10. slime OPD Documentation — slime OPD 文档

Share this post:

Previous Post
从 PPO 到 GRPO:LLM 强化学习的原理与 PyTorch 实现
Next Post
eLLM:用算力换显存的自适应 KV Cache