SGLang 结构生成语言
五层读懂一个词。这次拆的是:SGLang--vLLM 之外最值得关注的新锐推理引擎。两大杀手锏:RadixAttention(用 Radix Tree 做前缀缓存,自动复用任意共享前缀)和 Structured Generation(用正则/JSON Schema 约束输出,零幻觉的格式生成)。不是「另一个 vLLM」,而是用不同的方法解决了 vLLM 的一些盲区。
L1 · 一句话点破
SGLang = RadixAttention(树状前缀缓存)+ Structured Generation(约束生成)+ 高效推理引擎。RadixAttention 用 Radix Tree 自动管理所有请求的前缀缓存(不仅 system prompt,任意公共前缀都复用);Structured Generation 用 FSM(有限状态机)约束 LLM 输出严格符合 JSON/regex 格式。是 vLLM 之外最有差异化价值的推理引擎——更智能的前缀复用 + 零幻觉的格式输出。
L2 · 通俗类比
vLLM 的前缀缓存(Prefix Caching)像停车场 VIP 专用道:
- 只有 system prompt 这条路能共享
- 其他路(用户消息等)即使相同也不能复用
- 规则固定,不够灵活
SGLang 的 RadixAttention 像「自动拼车系统」:
- 用一棵 Radix Tree(基数树)管理所有请求的前缀
- 任何公共前缀自动识别和共享
- 新请求进来,系统自动匹配已有前缀,只算不同的部分
类比:
- vLLM:只允许「同一个人的 system prompt」拼车
- SGLang:任何路线重叠的部分都能自动拼车,不需要人工指定
Structured Generation 像「填空题」而非「作文」:
- 普通 LLM 输出:自由文本("天气是晴天,温度 25°C")→ 要解析
- SGLang 约束输出:
{"weather": "晴天", "temperature": 25}→ 直接可用 - 模型不会输出格式错误的内容(被 FSM 阻止)
SGLang 的独特组合:
| 技术 | vLLM | SGLang |
|---|---|---|
| 前缀缓存 | Hash-based(system prompt) | Radix Tree(任意前缀) |
| 结构化生成 | 不支持(后处理) | 原生 FSM 约束 |
| 编程模型 | Python API | SGLang DSL + Python |
| Overlap Scheduling | ❌ | ✅(通信-计算重叠) |
代价:
- 社区和生态比 vLLM 小
- Radix Tree 有一定内存开销
- 某些场景的绝对吞吐可能低于 vLLM
- 模型支持范围和插件生态小于 vLLM
适用:
- 需要严格格式输出的 API(JSON 响应)
- 大量请求有公共前缀的场景(共享文档/上下文)
- 批量处理同构问题(同 prompt 模板,不同 input)
- 函数调用/结构化数据提取
L3 · 正经定义
SGLang(Structured Generation Language):由斯坦福、UC Berkeley 等(Zheng et al., 2023)提出的 LLM 推理与服务框架。核心创新:
- RadixAttention:用 Radix Tree(基数树)自动管理多请求的前缀共享,任意公共序列的 KV-Cache 被自动复用,不仅限于 system prompt。
- Structured Generation:用 FSM(有限状态机)约束 LLM 输出,严格符合 JSON/regex/任意文法,消除格式错误。
- SGLang DSL:一种嵌入 Python 的领域特定语言,用于表达 LLM 调用的控制流(并行、分支、循环、工具调用)。
参考资料:
- 📄 Zheng et al., SGLang: Efficient Execution of Structured Language Model Programs, NeurIPS 2024
- 🔧 GitHub:https://github.com/sgl-project/sglang
- 📝 官方文档:https://sgl-project.github.io/
L4 · 原理深挖
4.1 RadixAttention: 树状前缀缓存
vLLM Prefix Caching 的局限:
请求 A: [system_prompt, "讲一个故事关于猫"]
请求 B: [system_prompt, "讲一个故事关于狗"]
vLLM: 只有 system_prompt 共享 KV-Cache
"讲一个故事关于" 这部分公共前缀不共享,重复计算RadixAttention 的解决:
用 Radix Tree(基数树/压缩前缀树)管理所有请求的前缀:
Radix Tree:
Root
├─ [system_prompt] ──> (共享 KV-Cache)
│ ├─ ["讲一个故事关于猫"] ──> (生成 "从前有只猫...")
│ └─ ["讲一个故事关于狗"] ──> (生成 "小狗叫旺财...")
└─ [other_prompt] ──> (独立分支)自动匹配流程:
新请求: [system_prompt, "讲一个故事关于", "龙"]
1. Radix Tree 查找最长公共前缀:
匹配: [system_prompt, "讲一个故事关于"] (现有 KV-Cache)
2. 只计算未匹配部分 ("龙") 的 prefill KV-Cache
3. 将 "龙" 节点的 KV-Cache 挂到 Radix Tree 上
后续有相同前缀的请求自动复用与 vLLM 前缀缓存的对比:
| 维度 | vLLM Prefix Caching | SGLang RadixAttention |
|---|---|---|
| 数据结构 | Hash 表 | Radix Tree |
| 共享粒度 | 完整 system prompt | 任意前缀 |
| 自动匹配 | 否(需显式标记) | 是(自动) |
| 内存开销 | 低 | 略高(树结构) |
| 适用场景 | system prompt | 所有公共前缀 |
效果(few-shot 提示场景):
20 个请求共享 100-token 的 few-shot 示例前缀:
- vLLM:不共享(非 system prompt),20× 计算前缀
- SGLang:自动共享,只算 1× 前缀
节省 95% 的前缀计算。
4.2 Structured Generation: FSM 约束
问题:LLM 输出 JSON 时,可能格式错误:
期望: {"name": "张三", "age": 30}
实际: {"name": "张三, "age": 30} # 漏引号
实际: The answer is {"name": "张三"}... # 多余文本
实际: {"name": "张三", "age": -5} # 逻辑错但不是格式错传统解决:
- Prompt 工程:在 prompt 里强调格式(不可靠)
- 重试:格式错就重试(浪费 token)
- 后处理:解析失败就 fallback(不优雅)
SGLang 的解决:用有限状态机(FSM)约束生成过程。
原理:
JSON Schema: {"name": str, "age": int}
FSM 状态:
Start -> "{" -> "name" -> ":" -> str_value -> "," -> "age" -> ":" -> int_value -> "}" -> End
每个状态只允许特定的 next token:
状态 "{" -> 只能输出 "name"
状态 str_value -> 只能输出字母/中文/转义符
状态 int_value -> 只能输出数字
LLM 在每步生成时:
logits -> 筛选允许的 tokens -> softmax -> sample
不允许的 token 概率置零效果:
- 100% 格式正确(格式层面,不是语义层面)
- 不需要重试
- 不需要后处理解析
支持的正则式约束:
import sglang as sgl
@sgl.function
def extract_city(s, text):
s += "从文本提取城市: " + text
s += sgl.gen("city", regex=r"(北京|上海|广州|深圳|杭州|成都)")
@sgl.function
def json_output(s, text):
s += "提取人物信息: " + text
s += sgl.gen("person",
json_schema={
"type": "object",
"properties": {
"name": {"type": "string"},
"age": {"type": "integer"},
"city": {"type": "string", "enum": ["北京", "上海"]}
},
"required": ["name", "age"]
}
)FSM 跳转:
- JSON Schema 自动转化为 FSM
- FSM 在每步 token 生成时筛选词汇表
- 支持嵌套对象、数组、union type、enum、regex
4.3 SGLang DSL: 嵌入 Python 的领域语言
核心理念:把 LLM 调用的控制流(并行、分支、循环)表达为 Python 代码。
示例 1: 并行生成多个候选
@sgl.function
def parallel_eval(s, question):
# 并行生成 3 个候选答案
s += "问题: " + question + "\n"
forks = s.fork(3)
for i, fork in enumerate(forks):
fork += f"候选 {i+1}: " + sgl.gen(f"answer_{i}", max_tokens=100)
forks.join()
# 评分选最佳
s += "最佳答案: " + sgl.gen("best", max_tokens=50, choices=[
f"候选1: {forks[0]['answer_0']}",
f"候选2: {forks[1]['answer_1']}",
f"候选3: {forks[2]['answer_2']}",
])示例 2: 分支
@sgl.function
def branch_on_type(s, text):
s += "分析文本: " + text
s += "类型: " + sgl.gen("type", choices=["新闻", "评论", "广告"])
if s["type"] == "新闻":
s += "摘要: " + sgl.gen("summary", max_tokens=100)
elif s["type"] == "评论":
s += "观点: " + sgl.gen("opinion", max_tokens=100)
else:
s += "跳过"示例 3: 工具调用循环
@sgl.function
def react_loop(s, question, tools):
s += "问题: " + question + "\n"
for i in range(5):
s += f"Step {i+1}:\n"
s += "Thought: " + sgl.gen("thought", max_tokens=100)
s += "Action: " + sgl.gen("action", choices=tools)
# 执行工具...
# 检查是否完成4.4 Overlap Scheduling
通信-计算重叠:
- vLLM:TP 通信和计算串行(先通信再算,或先算再通信)
- SGLang:通信和计算可重叠(一边传 KV块,一边算注意力)
效果:TP 场景下延时降低 10-30%。
4.5 SGLang vs vLLM
| 维度 | vLLM | SGLang |
|---|---|---|
| 前缀缓存 | Hash-based, 细粒度受限 | Radix Tree, 任意前缀 |
| 结构化生成 | ❌ | ✅ FSM 约束 |
| 编程模型 | Python API | DSL + Python |
| Overlap | 有限 | ✅ |
| 生态/社区 | 🔥🔥🔥🔥🔥 | 🔥🔥 |
| Star (2025) | 40k+ | 10k+ |
| 模型支持 | 广泛 | 广泛(追赶中) |
| 量化支持 | GPTQ/AWQ/FP8 | GPTQ/AWQ/FP8 |
| 文档质量 | 好 | 中 |
什么时候选 SGLang 而非 vLLM:
- ✅ 需要 100% 准确的 JSON/格式化输出
- ✅ 大量请求有公共前缀(如批量同构问题)
- ✅ 需要表达复杂调用逻辑(并行/分支/循环)
- ✅ 追求极致前缀缓存复用率
什么时候选 vLLM 而非 SGLang:
- ✅ 需要最广泛的社区支持和模型兼容
- ✅ 通用 API 服务(不需要结构化输出)
- ✅ 需要 Multi-LoRA Serving
- ✅ 小团队、需要完善文档
4.6 SGLang 的性能
Few-shot 场景(100 req × 100-token 共享前缀):
| 引擎 | 前缀计算 | 总延迟 | vs 基线 |
|---|---|---|---|
| vLLM | 100× | 1200ms | 1x |
| SGLang | 1× | 200ms | 6x |
结构化生成场景(JSON 输出):
| 方案 | 格式错误率 | 首答成功率 |
|---|---|---|
| Prompt only | 15% | 85% |
| Prompt + 重试(3次) | 3% | 97% |
| SGLang FSM | 0% | 100% |
4.7 SGLang 的局限
局限 1: 社区和生态较小。star 10k+ vs vLLM 40k+,插件/扩展/文档都不如 vLLM。
局限 2: 没有 Multi-LoRA Serving。目前不支持多 LoRA 适配器热切换。
局限 3: 对部分模型的兼容性。小众模型的适配不如 vLLM 完善。
局限 4: Radix Tree 内存开销。树结构管理有额外内存,极端场景下可能反而浪费。
局限 5: DSL 学习曲线。虽然不是强制的,但要发挥全部威力需要学 DSL。
局限 6: 版本迭代快,稳定性。活跃开发期,API 可能有 breaking change。
局限 7: 绝对吞吐在某些场景不如 vLLM。通用 API 服务场景吞吐可能略低。
L5 · 沿革与坑
5.1 沿革
- 2023-12:SGLang 论文初稿(Zheng et al.),提出 DSL + RadixAttention
- 2024-01:开源 release,v0.1
- 2024 中:RadixAttention 优化,结构化生成 FSM
- 2024-10:Overlap Scheduling、多节点支持
- 2024-11:NeurIPS 2024 录用
- 2025-01:SGLang v0.3,性能大幅提升,生态扩展
- 2025:增长迅速,成为 vLLM 的主要竞争者
5.2 常见坑
坑 1: 期望 SGLang 完全替代 vLLM。在通用 API 服务场景,vLLM 仍更成熟。SGLang 优势在特定场景。
坑 2: Structured Generation 期望语义正确。FSM 保证格式,不保证语义。{"age": -5} 格式对,内容错。
坑 3: FSM 状态爆炸。复杂 JSON Schema(深层嵌套、大 enum)FSM 状态多,token 筛选慢。要简化 schema。
坑 4: Radix Tree 不释放。长期运行 Radix Tree 膨胀。要配置淘汰策略。
坑 5: DSL 过度使用。简单任务不需要 DSL。Python API 已经够用。
坑 6: 忘记指定 backend。SGLang 支持多种 backend(vLLM, TGI, HF),默认可能不是你想要的。
坑 7: RadixAttention 与 vLLM Prefix Caching 的期望差异。RadixAttention 共享任意前缀,但性能保证的是「有公共前缀时更优」,无公共前缀时和 vLLM 无差。
坑 8: 版本兼容。SGLang 依赖的 CUDA/PyTorch 版本和 vLLM 不完全相同。混装可能冲突。
坑 9: 单请求/小 batch 优势不如高并发。和 vLLM 一样,SGLang 优势在批量场景。
坑 10: FSM + Sampling 的组合。temperature=0 + FSM 不错,temperature>0 + FSM 可能限制多样性(被允许的 token 子集不够大)。
5.3 面试怎么考
- SGLang 的两大创新? 答:RadixAttention(Radix Tree 自动管理任意前缀共享)和 Structured Generation(FSM 约束输出,零格式错误)。
- RadixAttention 和 vLLM Prefix Caching 的区别? 答:vLLM 用 Hash 表只缓存 system prompt;SGLang 用 Radix Tree 自动识别和复用任意公共前缀,few-shot 场景效果显著。
- Structured Generation 怎么做到的? 答:JSON Schema/regex 转 FSM(有限状态机),每步生成时用 FSM 筛选合法 token,不允许的 token 概率置零。格式 100% 正确。
- SGLang vs vLLM 怎么选? 答:需要结构化输出 / 大量同构请求 / 复杂调用逻辑 → SGLang;通用 API / 最广泛兼容 / Multi-LoRA → vLLM。
- SGLang DSL 解决了什么问题? 答:用 Python 代码表达 LLM 调用的控制流(fork/join 并行、if/else 分支、for 循环、工具调用),比手动管理 prompt 更高效。
速记卡
两大创新:
| 创新 | 方法 | 优势 |
|---|---|---|
| RadixAttention | Radix Tree 前缀管理 | 任意前缀自动共享 |
| Structured Generation | FSM 约束 | 零格式错误 |
Radix Tree vs Hash Table:
vLLM Hash: 只共享 system_prompt 块
SGLang Tree: 任意公共前缀自动共享FSM 约束流程:
JSON Schema → FSM → 每步筛选合法 token → 生成
结果: 100% 格式正确SGLang DSL 模式:
fork/join → 并行生成多个候选
if/else → 分支策略
for → 循环(工具调用)
choices → 选项约束
regex → 正则约束
json_schema → JSON 约束vLLM vs SGLang 选择:
| 场景 | 推荐 |
|---|---|
| 通用 API 服务 | vLLM |
| JSON 格式化输出 | SGLang |
| 同构批量请求 | SGLang |
| Multi-LoRA 服务 | vLLM |
| 复杂调用逻辑 | SGLang |
| 最大兼容性 | vLLM |
一句话记忆:SGLang = RadixAttention(Radix Tree 自动共享任意前缀,few-shot 场景倍数提升)+ Structured Generation(FSM 约束,JSON 格式 100% 正确)+ DSL 编程模型(fork/join 并行、分支、循环)。vLLM 是通用首选,SGLang 在结构化生成和前缀密集型场景有明显优势。10k+ star,是 vLLM 之外最值得关注的推理引擎。局限:社区较小、没有 Multi-LoRA、通用场景吞吐可能略低于 vLLM。
上一篇:vLLM 推理引擎 -- 通用推理首选,SGLang 在其盲区(结构化生成 + 智能前缀缓存)做出差异化。下一篇:Prompt Engineering 提示工程 -- 引擎负责跑得快,Prompt 负责跑得对。