系列:vLLM 与 SGLang 框架解码手记

(三)SGLang 原理与结构:RadixAttention 与"程序视角"的推理

1. 出发点不同:SGLang 看的是”程序”

vLLM 问的问题是”显存怎么管才不浪费”。SGLang 问的是另一个问题:

真实的 LLM 应用,请求之间到底长什么样?

答案是:高度重复。

如果每条请求都从头算 prefill,这些完全相同的前缀会被重复计算几千遍。

SGLang 的名字本身就说明了立场:Structured Generation Language —— 它把 LLM 调用看成一个有结构的程序,而不是一串互不相干的独立请求。

2. RadixAttention:用基数树复用前缀 KV

2.1 机制

vLLM 也有前缀缓存,但早期主要是精确前缀哈希匹配(同一段完全相同的 block 才复用)。SGLang 做得更彻底:把所有活跃请求的 KV 组织成一棵基数树(Radix Tree)。

system prompt + 工具定义 1800 token · KV 只存一份 对话 A · 历史 620 tok 对话 B · 历史 340 tok 批量评测 · 题干 900 tok 第 5 轮提问 重试分支 第 3 轮提问 选项 A 选项 B 选项 C 无前缀复用(每条独立 prefill) 6 条请求 × (1800 + 历史 + 提问) ≈ 16,000 token 的重复计算 RadixAttention(树上共享) 共享段只算一次,只 prefill 叶子增量 ≈ 2,000 token · TTFT 与显存双降

图 1:基数树把重复前缀折叠成共享路径。共享前缀越长、分支越多,收益越大——这正是 Agent 与批量评测的典型形态。

2.2 收益边界

RadixAttention 的收益完全取决于工作负载的前缀共享率。多轮 Agent、批量评测、思维树这类场景可以省掉 70%+ 的 prefill;但如果你的请求两两之间毫无共同前缀(比如纯文档摘要,每篇文章都不一样),它带来的只是一点点树维护开销。选型时先看你的流量长什么样。

2026 年 7 月 25 日发布的 SGLang v0.5.16 把这套机制推到了新版本:UnifiedRadixTree 成为默认前缀缓存——统一了此前分散的多种缓存路径(普通前缀缓存、分层缓存、PD 场景下的缓存),维护和命中逻辑收敛到一棵树上。

3. 结构化输出:压缩状态机

第二个差异化能力是约束解码。

当你要求模型输出严格的 JSON、或匹配某个正则、或遵循 EBNF 语法时,朴素做法是每生成一个 token 就检查一次约束、把非法 token 的 logits 置为 -inf。这个检查在 CPU 上做,又是一个每步同步点。

SGLang 的做法是压缩有限状态机(compressed FSM):

对于返回固定 schema 的 Agent 工具调用,这个优化的实际效果非常明显——很多”结构性字符”是白送的。

这块也是 bug 高发区。SGLang PR #30747 修的就是 PP(流水线并行)+ 结构化输出同时开启时的崩溃(Issue #28424)。根因是调度逻辑和约束校验逻辑并发抢状态;修复方式是把约束校验与 micro-batch 边界对齐。
vLLM 侧同期也在补:0.26 让 grammar 失败不再让整个引擎崩溃,改为单请求报错。

4. 零开销 Spec V2:投机解码的调度革命

这是 SGLang 在 2026 年中最重要的性能工作,v0.5.15(7/10)起成为默认,端到端吞吐 +约 11% TPS。

4.1 传统投机解码的隐藏成本

投机解码本身的原理(草稿模型起草 → 大模型一次并行验证)可以看推测解码手记。这里说的是工程实现上的浪费。

传统实现每一步都要:

GPU: 草稿模型生成 4 个候选
GPU: 目标模型并行验证
GPU → CPU (D2H): 把"接受了几个 token"拷回来      ← 同步点!
CPU: 根据接受数决定下一步的序列长度、KV 布局
CPU → GPU (H2D): 把新的元数据拷回去               ← 同步点!

那两次拷贝之间,GPU 完全空闲。而且因为接受数是运行时才知道的动态值,整个流程无法被 CUDA Graph 捕获——每步都得重新启动一堆小 kernel。

4.2 SGLang 的解法

传统投机解码:每步两次同步,无法整图捕获 draft ×4 verify D2H CPU 定长度/KV H2D draft ×4 … GPU 空转气泡(每一步都有)

Spec V2:draft-extend 可被 CUDA Graph 捕获,分支逻辑上 GPU 整步图:draft + verify + 元数据更新 整步图(下一步) 整步图(再下一步) CPU 提前一整步装配下一步 → GPU 无气泡,端到端 +约 11% TPS

同脉络的后续 PR:#31468 DFlash 去掉每步 host 同步(CPU 领先一整步)· #31487 减少 prefill CUDA graph 填充 #31986 DSpark 稠密草稿逐层 ctx KV 投影堆叠成单个大 GEMM · #31985 经 forward_embed 把草稿 embedding 折进草稿图

三个关键动作:

  1. 把 draft-extend 做成 CUDA-graph 可捕获:用固定上界的张量形状 + GPU 上的掩码,替代运行时可变长度;
  2. 砍掉 D2H / H2D:接受数留在 GPU 上,分支逻辑改写成 GPU 可执行的形式;
  3. 融合元数据计算:page table、序列长度这些元数据的更新也进图。

节省的不是算力,而是加速器空转的时间——所以低并发、时延敏感的 Agent 场景收益最大。

4.3 IndexShare MTP:长上下文的草稿降本

配合 GLM-5.2 的优化里还有一个亮点:IndexShare MTP。

MTP(Multi-Token Prediction)是模型自带草稿头的投机解码。在 DSA(稀疏注意力)模型上,草稿步骤本来也要自己算一遍 top-k 稀疏索引。IndexShare 让草稿步直接复用目标模型已经算好的 top-k 索引,长上下文场景下草稿成本降低约 1.9×。

再加上 TopK-V2(Lightning-TopK)——用”选择”算法替代”完整排序”,专门优化 80k 级超长输入序列。

三者叠加的实测结果:GLM-5.2 NVFP4 在 Blackwell 上跑到 500+ tok/s/user(lmsys 官方博客,7/13)。

5. 其他值得知道的能力

特性说明版本
Breakable CUDA Graph图可被中断,兼顾图收益与调度灵活性;DP attention 下默认开 breakable prefill graph(#31682)v0.5.15 起
MLA context parallel decodingMLA 架构(DeepSeek 系)的上下文并行解码v0.5.15
FlashInfer all-to-all MoE routingMoE 路由走 FlashInfer 的 all-to-allv0.5.15
HPC-Ops attention 后端扩充可选注意力算子矩阵(#30540)07-22 main
原生 web search内置检索工具调用v0.5.15
VLM 跨请求 ViT 编码批处理多模态并发时把视觉编码批起来(#24013)07-18 main
大规模 EP(专家并行)MoE 模型的专家并行部署持续演进
安全提醒:SGLang 0.5.5–0.5.12 存在多模态路径穿越漏洞(GHSA-qwrp-wghp-94q2),0.5.15 及以后已修复。仍在跑旧版本的务必升级。

6. 两家的性格差异

跟踪了这么多次发版,能看出很清楚的性格:

vLLMSGLang
起点显存管理程序结构 / 前缀复用
优势模型 + 硬件 + 量化的广度共享前缀、结构化输出、前沿吞吐的深度
发版风格稳,大版本换代后密集修 bug激进,主分支前沿优化落地极快
典型场景通用生产底座、多硬件、多模型Agent / 多轮 / 批量评测 / 大规模 EP
量化激进度全格式覆盖NVFP4 / MXFP4 方向扩张更猛

一个很典型的观察:在 07-22 那个窗口,SGLang 主分支全在做投机解码性能打磨(#31986/#31985),而 vLLM 全在修稳定性(#48524/#49302/#48843/#49306)——同一个主题的不同相位。

7. 小结

下一篇讲两家共同的前沿战场:为什么”消灭同步停顿”会成为 2026 年中的主线,以及 PD 分离这个正在成型的新范式。

觉得有用?欢迎点赞、收藏,或请作者喝咖啡 ☕️

支付宝收款码

支付宝

微信收款码

微信

💬 留言

评论由 Giscus 驱动(基于 GitHub Discussions)。 当前仓库 NaphJohn/LLM-blog 尚未启用 Discussions:请在 GitHub 仓库 Settings → General → Features 勾选 Discussions 后刷新本页,评论区即自动显示。