SGLang:大模型推理的“结构化程序”革命
Note
一、背景:vLLM之后,还缺什么?
1.1 vLLM的伟大与局限
在上一讲中,我们详细剖析了vLLM如何通过PagedAttention解决了大模型推理中的内存管理问题。vLLM的成功让业界看到了系统架构创新的威力——它不改变模型结构,仅通过优化KV Cache的内存管理,就将吞吐量提升了2-4倍。
然而,vLLM解决的是一类特定问题:“如何让模型在GPU上跑得更快、更省内存” 。但随着大模型应用从简单的“一问一答”向复杂的智能体(Agent) 、多轮对话、工具调用、结构化输出等场景演进,一个新的问题浮出水面:如何高效地表达和执行复杂的语言模型程序?
1.2 复杂LLM应用带来的新挑战
在实际生产环境中,LLM应用早已不是简单的“用户输入→模型输出”。以现代AI Agent为例,一个完整的推理流程可能包含:
- 多轮生成调用:Agent需要多次调用模型进行思考、规划和执行
- 高级提示工程技术:如few-shot learning、self-consistency、chain-of-thought等
- 控制流逻辑:条件分支、循环、并行执行
- 结构化输入输出:严格的JSON Schema约束、正则表达式格式要求
- 工具调用:模型生成函数调用,外部执行后结果再喂回模型
传统推理框架(包括vLLM)的核心设计范式是 “请求-响应(Request-Response)” ——一个请求进来,模型生成,返回结果。这种范式在处理上述复杂场景时暴露出三大问题:
问题一:重复计算浪费惊人。 在few-shot learning场景中,每个请求都包含相同的示例(通常数千token),传统系统为每个请求从头计算这些示例的KV Cache。在生产环境中,40%-80%的token序列存在可复用的共享前缀——这意味着大量的计算是在做重复劳动。
问题二:结构化输出效率低下。 当需要模型输出严格的JSON或符合特定正则表达式的文本时,传统做法是:先生成文本,再用后处理校验和修正。这不仅效率低,还可能因为模型生成不符合格式而需要重新生成,造成巨大的算力浪费。
问题三:编程表达力不足。 开发者如果想实现一个包含多轮对话、条件分支、工具调用的复杂Agent,需要在应用层手动管理状态、缓存、调度,与推理引擎之间缺乏有效的编程抽象。
1.3 SGLang的诞生
正是在这样的背景下,UC Berkeley LMSYS团队(也是vLLM的共同创建者)于2024年提出了SGLang(Structured Generation Language) 。SGLang的核心洞察是:
vLLM解决了内存管理问题,TensorRT-LLM解决了内核性能问题,但两者都没有解决编程问题——如何在不用与推理层“搏斗”的情况下,表达复杂的生成模式(约束JSON、多步推理、并行工具调用)。
SGLang的定位不是“另一个vLLM”,而是一个完全不同的范式:它将LLM推理视为可编程的程序而非简单的请求/响应API。通过前端语言和后端运行时的协同设计,SGLang在vLLM的“内存效率”和TensorRT-LLM的“内核速度”之上,增加了第三个维度——“计算复用+可编程生成” 。
二、RadixAttention:让KV缓存复用精确到“每个token”
2.1 vLLM前缀缓存的局限性
vLLM提供了自动前缀缓存(Automatic Prefix Caching, APC) 功能——将固定大小的token块(如16个token)进行哈希,匹配到的块直接复用KV Cache。这个方案在实际场景中存在三个关键缺陷:
- 分支在中途分叉:两个请求共享前10个token,但在第11个token处开始不同——vLLM以16个token为块单位,无法利用这个部分匹配
- 跨请求前缀不对齐块边界:共享前缀的长度不是块大小的整数倍时,缓存命中率大打折扣
- 无法处理任意粒度的前缀匹配:块级别的匹配粒度太粗,无法做到token级别的精确复用
2.2 RadixAttention的核心思想
RadixAttention是SGLang最核心的创新。它用基数树(Radix Tree,也称压缩前缀树) 这一数据结构来管理KV Cache。
基数树相比标准前缀树(Trie)的关键优势在于路径压缩——每个节点可以存储多个字符(token),而不是只存一个。这使得基数树在存储大量共享前缀时既节省空间又保持高效的查找性能。
2.3 RadixAttention的工作原理
(1)树结构构建
RadixAttention将历史上所有处理过的token序列组织成一棵基数树。树的每个节点对应一段连续的token序列的KV Cache。例如,三个请求:
- 请求1:
"System: You are helpful\nUser: What's AI?" - 请求2:
"System: You are helpful\nUser: What's ML?" - 请求3:
"System: You are helpful\nUser: What's DL?"
它们共享前缀 "System: You are helpful\nUser: What's ",在基数树中这个公共前缀只存储一次,三个请求分别挂在不同的分支上。
(2)请求处理流程
当一个新请求到达时,SGLang执行四个步骤:
- 遍历(Traverse) :从根节点开始,在基数树中查找与当前请求token序列最长匹配的前缀
- 复用(Reuse) :匹配到的节点中的KV Cache直接被复用,完全跳过对应token的Prefill计算
- 计算(Compute) :只对未匹配的新token执行Prefill计算,生成新的KV Cache
- 插入(Insert) :将新计算的KV Cache作为新节点插入基数树,供未来请求复用
这种token级别的精确匹配使得RadixAttention的缓存命中率比基于哈希的块级方案高出5倍。
(3)自动淘汰机制
当显存不足时,RadixAttention采用LRU(最近最少使用)策略进行淘汰:
- 叶子优先:优先淘汰叶子节点(没有子节点的分支)
- 保护公共前缀:频繁使用的公共前缀节点被保留,即使其某个叶子分支被淘汰
- 最近使用优先:最近被访问的节点保留,长时间未使用的被淘汰
这种淘汰策略确保了最“有价值”的共享前缀(被最多请求复用)始终留在显存中。
2.4 RadixAttention vs vLLM APC:本质差异
两者都做前缀缓存,但哲学不同:
| 维度 | vLLM APC | SGLang RadixAttention |
|---|---|---|
| 匹配粒度 | 固定大小的token块(如16个) | 任意长度的token序列 |
| 数据结构 | 哈希表 | 基数树 |
| 匹配方式 | 精确块哈希匹配 | 最长前缀匹配 |
| 分支处理 | 块内无法处理分叉 | 任意位置精确分叉 |
| 缓存命中率 | 受块对齐限制 | 理论上限更高 |
2.5 性能数据
在实际的few-shot learning场景中:假设prompt中有10个示例(2000个token)和1个用户查询(50个token):
- 无缓存:3个请求需要计算
3 × 2050 = 6150个token - RadixAttention:第1个请求计算2050个token,第2、3个请求只计算各自的50个查询token,总计2150个token,节省65%的计算量
在RAG、多轮对话等前缀密集型场景中,SGLang可实现2-3倍的吞吐量提升;在结构化输出场景中,提升可达5-10倍。
三、零开销调度器:让CPU与GPU“并行不悖”
3.1 问题:CPU调度成为瓶颈
在大模型推理系统中,GPU负责计算,CPU负责调度——包括批次调度、内存分配、前缀匹配等。一个未经优化的推理引擎,CPU开销可能占到总运行时间的一半。这意味着GPU有大量时间在空闲等待CPU完成调度工作。
3.2 解决方案:流水线式重叠调度
SGLang v0.4引入了零开销批调度器(Zero-Overhead Batch Scheduler) 。其核心思想极其简洁而有效:
让CPU调度与GPU计算在时间上重叠(overlap)——调度器提前运行一个批次,准备好下一个批次所需的所有元数据。
具体实现上:
- 在当前批次在GPU上执行时,CPU同时为下一个批次完成调度决策、内存分配、前缀匹配等准备工作
- 通过CUDA事件和同步机制精心管理依赖关系
- 当前批次完成后,下一个批次的所有元数据已经就绪,GPU可以无缝衔接,无需任何等待
3.3 效果验证
使用NVIDIA Nsight性能分析工具验证:在连续5个解码批次中,GPU没有任何空闲时间。这一优化使SGLang v0.4相比前一版本吞吐量提升1.1倍,相比其他最先进的基线系统提升1.3倍。该功能默认开启,用户无需任何配置。
四、前端DSL:把“模型调用”变成“程序”
4.1 设计哲学:从API到语言
如果说vLLM的抽象是“内存管理器”,那么SGLang的抽象是“语言模型程序的执行引擎”。SGLang提供了一套前端领域特定语言(DSL) ,让开发者可以用程序化的方式描述复杂的LLM工作流。
SGLang程序的核心特点:
- 控制流驱动:包含条件判断、循环、函数封装等编程结构
- 多轮模型调用:一个程序通常包含多次LLM调用
- 结构化交互:接收结构化输入,产生结构化输出
- 缓存感知:自动利用RadixAttention进行KV缓存复用
4.2 使用示例
一个简单的多轮对话程序:
1import sglang as sgl2
3@sgl.function4def multi_turn_chat(s, user_question, history):5 s += "System: You are a helpful assistant.\n"6 for turn in history:7 s += f"User: {turn['user']}\n"8 s += f"Assistant: {turn['assistant']}\n"9 s += f"User: {user_question}\n"10 s += sgl.gen("response", max_tokens=256)在这个例子中,整个对话历史作为一个整体被送入模型。RadixAttention会自动识别:如果新的请求与之前的请求共享相同的历史前缀,历史部分的KV Cache被直接复用,只有新的用户问题需要计算。
4.3 编译时优化
SGLang的前端不仅仅是一个语法糖。它采用编译器式的设计:
- 前端编译器将DSL转换为中间表示(IR),执行常量传播、死代码消除、循环展开等优化
- 后端运行时根据IR执行分层调度(任务级调度、算子级调度)和统一内存管理
这种“编译时优化+运行时执行”的模式,使得SGLang在复杂工作流场景下既能保证确定性的性能表现(相同输入的推理延迟标准差小于2ms),又能实现高效的资源利用。
五、结构化输出:让模型“只说对的话”
5.1 问题:模型不会“守规矩”
在许多企业级应用中,模型的输出必须是严格的JSON、符合特定正则表达式或遵循某种语法(如SQL)。传统做法是“生成→校验→重试”,不仅效率低下,还可能导致无限重试。
5.2 解决方案:约束解码
SGLang将约束解码(Constrained Decoding) 集成到调度层,而非作为后处理“外挂”。用户可以通过JSON Schema、正则表达式或EBNF语法来约束模型输出。
其核心技术是压缩有限状态机(Compressed Finite State Machine) :
- 将用户的约束(如JSON Schema)编译成一个有限状态机(FSM)
- 在每一步解码时,FSM会过滤掉所有不符合约束的token——只允许那些能让输出继续满足约束的token被生成
- 这确保了100%的合规输出,无需任何后处理校验
5.3 跳跃前向优化(Jump-Forward)
对于JSON等结构化输出,大量token是固定的结构字符(如{、}、"、:等)。SGLang的跳跃前向优化(Jump-Forward Optimization) 可以跳过60%-75%的decode步骤——当FSM确定某个位置只能是固定字符时,直接“跳跃”到下一个可变位置。
在JSON工作负载上,这一优化使吞吐量提升最高可达10倍。
六、扩展能力:从单卡到集群
6.1 HiCache:三级分层缓存
RadixAttention解决了GPU显存内的KV缓存复用问题,但当缓存规模超出单机显存时怎么办?SGLang引入了HiCache,受现代CPU三级缓存设计启发:
- L1(GPU显存) :最热门的KV Cache,提供最低延迟访问
- L2(主机内存) :次热门的KV Cache,容量更大但延迟稍高
- L3(分布式存储) :冷数据缓存,集成Mooncake、3FS等分布式缓存系统
这一分层设计使得缓存命中率提升至80% ,TTFT降低56% 。
6.2 PD分离架构
Prefill(计算密集型)和Decode(内存密集型)两个阶段对硬件资源的需求截然不同。SGLang支持Prefill/Decode分离部署:
- Prefill实例部署在计算优化的GPU上
- Decode实例部署在显存优化的GPU上
- 通过路由器将请求分发到不同类型的实例
这种分离避免了prefill请求“打断”decode批次的问题,实现了更细粒度的资源调度。
6.3 数据并行注意力(DP Attention)
对于DeepSeek等采用MLA(Multi-head Latent Attention)架构的模型,SGLang支持数据并行注意力(Data Parallelism Attention) 。在高并发场景下,DP Attention可将解码吞吐量提升最高1.9倍。需要注意的是,DP Attention以牺牲低并发场景的延迟为代价换取高并发吞吐量。
6.4 推测解码
SGLang支持多种推测解码(Speculative Decoding)方案,包括EAGLE-2/EAGLE-3、MTP(Multi-Token Prediction)、经典draft模型解码和NGRAM方案。这些技术通过轻量级draft模型并行预测多个候选token,再由目标模型批量验证,在保证生成质量的同时显著降低延迟。
七、适用场景与优缺点
7.1 适用场景
- 复杂Agent工作流:需要多轮推理、工具调用、条件分支的智能体应用
- RAG(检索增强生成) :大量请求共享相同的检索文档前缀
- 多轮对话系统:历史对话上下文在后续轮次中被反复复用
- 结构化输出要求严格的场景:金融、医疗等领域需要JSON/正则约束输出
- Few-shot Learning:大量请求共享相同的示例
- 高吞吐量生产环境:需要极致吞吐量的在线服务
7.2 核心优势
- 极高的前缀复用效率:RadixAttention实现token级别的精确前缀匹配,缓存命中率比块级方案高5倍
- 卓越的结构化输出性能:约束解码+跳跃前向优化,JSON等工作负载提升5-10倍
- 强大的编程抽象:前端DSL让复杂LLM工作流易于表达和维护
- 零开销调度:CPU与GPU重叠执行,GPU利用率接近100%
- 完善的扩展能力:HiCache三级缓存、PD分离、DP Attention、推测解码等一应俱全
- 广泛的模型支持:支持Llama、Qwen、DeepSeek、GLM等主流语言模型及多模态模型
7.3 局限性
- 学习曲线:前端DSL需要开发者学习新的编程范式,相比vLLM的OpenAI兼容API有一定门槛
- 短请求场景优势不明显:在无共享前缀的短请求场景中,RadixAttention的优势无法充分发挥
- 社区成熟度:相比vLLM,SGLang的社区和生态仍在快速发展中,部分高级功能可能不够稳定
- 多模型并发支持有限:在同时服务多个不同模型方面,不如vLLM灵活
八、总结:两种范式,各领风骚
回顾vLLM和SGLang,我们可以看到两种截然不同但又互为补充的设计哲学:
vLLM是“内存管理专家” ——它从操作系统中借来分页思想,解决了KV Cache的内存碎片和低利用率问题,让GPU的每一寸显存都物尽其用。它的核心抽象是内存。
SGLang是“程序执行引擎” ——它从编译器和数据库系统中借来思想,将LLM推理视为可编程的程序执行,通过RadixAttention实现计算复用,通过DSL实现编程表达力。它的核心抽象是程序。
两者的关系不是替代,而是演进:vLLM解决了“如何让模型跑得更快”的问题,SGLang在此基础上进一步解决了“如何让复杂的模型应用跑得更快、写得更爽”的问题。
在实际生产中,选择哪个框架取决于场景:
- 如果你需要的是简单、稳定、高吞吐的通用推理服务,vLLM是成熟可靠的选择
- 如果你正在构建复杂的Agent、RAG、多轮对话系统,或者对结构化输出有严格要求,SGLang的前沿设计将带来显著的开发和性能收益
正如SGLang论文中所说:“实验表明,SGLang在各类任务上相比最先进的推理系统实现了最高6.4倍的吞吐量提升”。这一成就不仅来自于算法创新,更来自于对LLM应用本质的深刻洞察——在大模型时代,推理引擎不应该只是一个“加速器”,而应该是一个“可编程的执行平台” 。
Some information may be outdated