发表时间: 2025-09 · Blog post by The SGLang Team (lmsys.org)
原文: https://lmsys.org/blog/2025-09-22-sglang-deterministic
The SGLang Team
一句话结论
SGLang 联合 slime 框架,通过引入批次无关算子并改造分块预填充策略,实现了完全确定性的 LLM 推理与 100% 可复现的强化学习训练,且在开启 CUDA graphs 时将性能开销压缩至仅 34.35%。
要解决什么问题
大语言模型推理中的不确定性会隐式地将同策略(on-policy)强化学习转变为异策略(off-policy)强化学习,严重破坏了严谨科学实验所需的可靠性。过去,即便用户在 SGLang 中将采样温度硬性设定为 0,由于动态批处理(dynamic batching)和基数缓存(radix cache)机制的存在,推理结果依然会发生随机波动。这个问题的核心卡点在于底层算子(如 RMSNorm、矩阵乘法、注意力机制)的归约(reduction)过程对批次大小高度敏感:当同一个请求被随机组合进不同大小的批次时,内核中归约拆分的过程会随之改变,导致每次归约块的计算顺序和大小出现差异。由于计算机底层的浮点数加法不具备严格的数学结合律,这种微小的计算顺序改变会引发浮点误差的随机累积与放大。只要批次大小在动态变化,这种底层机制就会导致非确定性的输出,成为阻碍强化学习训练完全复现的最大障碍。
怎么做的
核心思路是替换底层对批次敏感的算子,并在系统调度层面对齐计算块的边界,从而在数学层面保证浮点数计算顺序的绝对一致。该方案由四个关键部件构成,各自承担不同的职责:
第一,引入批次无关(batch-invariant)内核。系统直接集成了 Thinking Machines Lab 的均值、对数 softmax 和矩阵乘法算子,并针对多种后端实现了固定切分大小(split-KV size)的注意力内核。具体而言,在 FlashInfer 后端中利用 fixed_split_size 和 disable_kv_split 参数在内核规划阶段固定切分大小;在 FlashAttention 3 后端中将切分数量强制设为 1;在 Triton 后端中固定解码的切分大小,借此甚至将确定性推理扩展到了 AMD 硬件上。
第二,改造分块预填充(chunked prefill)策略。原有的尽力而为分块策略会为了凑齐最大块大小(如 8192),将一个序列的 KV 块随机截断,这破坏了注意力内核所需的固定切分大小。改造后的逻辑强制将截断点对齐到 split_kv_size 的整数倍:
这保证了被推迟到下一个分块计算的序列片段依然能作为一个完整的单元被注意力内核处理,维持归约行为的确定性。
第三,实现可复现的非贪婪采样。为了在温度大于 0 时依然保持确定性,废弃了原生的 torch.multinomial,引入全新的 multinomial_with_seed 算子。它通过一个带种子的哈希函数生成 Gumbel 噪声来扰动 logits:
NCCL_ALGO=Ring、NVTE_ALLOW_NONDETERMINISTIC_ALGO=0 等环境变量以及 PyTorch 的确定性算法开关,最终实现端到端的严格复现。
效果如何
实验在 Qwen3-8B 模型上进行,硬件使用 H100 80GB(用于吞吐量测试)和 H200 140GB(用于离线推理延迟测试)。对比基线为 SGLang 原有的非确定性常规模式(Normal Mode),分别在 FlashInfer、FlashAttention 3 和 Triton 三种注意力后端下进行了严格对比。
在确定性验证测试(包含单提示词、长短混合、同源不同前缀三种场景,共 50 次采样)中,常规模式会产生 2 到 18 种不同的输出,而确定性模式在所有后端和场景下均严格输出 1 种唯一结果。在 slime 框架的 GRPO 强化学习训练中,两次独立的训练运行产生了完全一致的 rollout 响应和首批迭代损失曲线,实现了 100% 的复现。
在性能方面,开启 CUDA graphs 后,确定性推理的吞吐量实现了约 2.8 倍的加速(例如 FlashInfer 后端从 441.73 tokens/s 提升至 1245.51 tokens/s)。在模拟 256 个请求、覆盖 1024 到 8192 不同输入输出长度的离线推理负载中,FlashInfer 和 FlashAttention 3 后端的平均性能损耗仅为 34.35%(显著优于早期方案的 61.5%)。
作者也坦承了该方法的局限性与代价:确定性模式的运行速度依然明显慢于常规模式,主要瓶颈在于批次无关的矩阵乘法和注意力内核尚未充分优化;目前仅支持稠密模型,暂不支持 DeepSeek-V3 等 MoE 模型;且在基准测试中,由于 FlashInfer 和 Triton 的基数缓存支持仍在开发中,该功能被暂时禁用;此外,大于 TP2 的张量并行设置仍需进一步改造归约内核才能保证确定性。
大语言模型推理结果的不确定性会隐式地将同策略(on-policy)强化学习转变为异策略(off-policy)强化学习,这为严谨的科学实验带来了挑战。为了解决这一问题,本文致力于在开源推理引擎中实现稳定且可用的确定性推理,并进一步实现完全可复现的强化学习(RL)训练。
本文的核心创新点与贡献如下:
大语言模型推理一致性的重要性:大语言模型(LLMs)推理输出一致性的能力正变得越来越重要。例如,正如研究人员所指出的,推理结果的不确定性会隐式地将同策略(on-policy)强化学习(RL)转变为异策略(off-policy)强化学习。然而,在SGLang中,即使将温度(temperature)参数调至0,由于动态批处理(dynamic batching)和基数缓存(radix cache)的使用,采样过程仍然不是确定性的。
批处理大小变化导致的不确定性:正如Thinking Machines Lab博客中所提到的,不确定性的最大来源是不断变化的批处理大小(batch sizes):即使用户反复提交相同的提示词(prompt),由于该请求可能与其他用户的请求被打包在不同的批次中,批处理大小的差异会导致非确定性的推理结果。
归约拆分过程与浮点数非结合性:为了进一步解释,不同的批处理大小会影响内核(kernels)的归约拆分(reduction splitting)过程。这导致每个归约块的顺序和大小发生变化,由于浮点算术的非结合性,从而引发非确定性的输出。为了解决这个问题,他们将归约内核(如RMSNorm、矩阵乘法、注意力机制等)替换为批处理不变(batch-invariant)的实现。这些内核也被作为一个配套库发布,供外部集成使用。
SGLang的确定性推理解决方案:基于Thinking Machines Lab的工作,SGLang提供了一个强大且高吞吐量的确定性LLM推理解决方案,该方案结合了批处理不变内核、CUDA图、基数缓存以及分块预填充(chunked prefill)技术,并具备高效的性能。其确定性已经通过全面的测试和RL训练实验得到了广泛验证。
SGLang的核心增强功能:
分块预填充(Chunked Prefill)的挑战:SGLang的分块预填充技术旨在管理具有长上下文的请求。然而,其默认的分块策略违反了注意力内核对确定性的要求。
输入序列与拆分单元的示例说明:如图所示,考虑两个输入序列seq_a和seq_b,每个序列的上下文长度为6,000。分块预填充的最大块大小(chunk size)为8192,而确定性注意力所需的拆分键值大小(split-KV size)为2,048。每个序列可以被划分为三个较小的单元(a1至a3,以及b1至b3),其长度分别为2,048、2,048和1,904。如果这些较小的单元在分块预填充期间保持完整,那么它们就可以被同一个注意力内核处理,并产生确定性的归约行为。
对齐截断点以保证确定性:标准的分块策略遵循"尽力而为"(best-effort)的原则。在这个例子中,该策略试图通过将seq_b的b2单元拆分为两个较小的部分,来生成一个包含8,192个标记(tokens)的chunk_1。这会导致截断点不一致,因为拆分后b2的长度取决于seq_a的长度。为了解决这个问题,我们调整了分块逻辑,将截断点与split_kv_size的整数倍对齐。这种调整确保了对b2的处理被推迟到后续的块中,从而允许它作为一个完整的单元被注意力内核计算。
注意力后端(Attention Backends)的定制化修改:注意力内核是实现确定性的重要组成部分。针对不同的注意力后端,我们以不同的方式对其进行了修改,以满足其使用要求。
fixed_split_size和disable_kv_split参数,在内核规划(kernel planning)期间固定拆分大小。分块预填充的截断与预填充拆分大小对齐。可复现的非贪婪采样(Reproducible Non-Greedy Sampling):为了将确定性扩展到贪婪解码(greedy decoding)之外,我们引入了一个新的采样函数:multinomial_with_seed。
基于种子哈希函数的Gumbel噪声扰动:我们不再依赖在批处理下固有非确定性的torch.multinomial,而是使用由基于种子的哈希函数(seeded hash function)生成的Gumbel噪声来对逻辑值(logits)进行扰动。因此,即使在温度大于0的情况下,相同的(inputs, seed)对也始终会产生相同的采样结果。
保留强化学习所需的随机性:这一修改在实现了确定性的多项式采样(deterministic multinomial sampling)的同时,保留了强化学习部署(rollouts)所必需的随机性。
强化学习框架集成(RL Framework Integration - slime):我们将温度大于0的确定性推理集成到了slime的GRPO训练流程中。在初步实验中,重复的RL训练运行在前几次迭代中产生了完全相同的rollout响应和损失值,证实了rollout过程本身是确定性的。
实现完整训练可复现性的关键配置:在后续的更新中,我们通过实现以下关键配置,进一步启用了完整的训练可复现性:
--deterministic-mode标志以进行确定性训练。环境变量(Environment Variables):配置关键设置:
NCCL_ALGO=RingNVTE_ALLOW_NONDETERMINISTIC_ALGO=0CUBLAS_WORKSPACE_CONFIG=:4096:8PyTorch:启用torch.use_deterministic_algorithms(True, warn_only=False)。
实现真正的端到端RL训练管道:通过这些全面的更改,我们成功在slime中实现了GRPO的完全训练可复现性,从而启用了真正确定性的端到端RL训练管道。
实验内容:引入了一个确定性测试套件,以验证在不同批处理条件下推理结果是否保持一致。测试包含三个子测试:
实验环境:模型使用QWen3-8B。启用了CUDA graph和分块预填充。对于Flashinfer和Triton禁用了基数缓存(因其支持仍在开发中)。
环境设置:为了设置环境,需要安装版本大于等于0.5.3的SGLang:
pip install "sglang[all]>=0.5.3"
启动服务器:SGLang支持跨多个模型的确定性推理。例如,对于Qwen3-8B,用户只需在启动服务器时添加--enable-deterministic-inference标志即可:
python3 -m sglang.launch_server \
--model-path Qwen/Qwen3-8B \
--attention-backend <flashinfer|fa3|triton> \
--enable-deterministic-inference
本文成功在SGLang中实现了稳定且可用的确定性推理,并通过与slime框架的深度集成,解锁了端到端100%可复现的强化学习训练流程。尽管目前的确定性推理在速度上相较于常规模式存在34.35%的性能损耗,但它为严谨的RL科学实验提供了必不可少的可靠性基石。
未来的工作将集中在以下关键领域以增强确定性推理: