背景:为什么需要新的推理引擎
vLLM 以 PagedAttention 革新了 KV Cache 管理,但在实际生产中仍存在痛点:
- 前缀缓存粒度粗:vLLM 的 Prefix Cache 是 block 级别,命中率受限于前缀完全匹配
- 多轮对话效率低:每轮对话的 KV Cache 无法跨请求高效复用
- 缺乏结构化生成:JSON/Regex 约束生成需要额外引擎(如 Outlines)
SGLang(Structured Generation Language)由 LMSYS 团队开发,从设计之初就针对这些问题。
SGLang 架构
核心组件
┌──────────────────────────────────────────────┐
│ SGLang Frontend (Python) │
│ @function 装饰器 / sgl.gen() DSL │
├──────────────────────────────────────────────┤
│ SGLang Runtime (Server) │
│ RadixAttention + Cache Manager │
│ + Constrained Decoding (Regex/JSON) │
├───────────────┬──────────────────────────────┤
│ Scheduler │ Model Worker │
│ (Batching) │ (Tensor Parallel) │
├───────────────┴──────────────────────────────┤
│ GPU Workers (CUDA) │
└──────────────────────────────────────────────┘
RadixAttention 原理
RadixAttention 是 SGLang 的核心创新。与 vLLM 的 PagedAttention 相比,关键区别在于 KV Cache 的组织方式:
vLLM PagedAttention:
请求 A: [B0] → [B1] → [B2] (Block Table 链表)
请求 B: [B3] → [B4] → [B5] (独立 Block Table)
# 即使 A、B 共享相同前缀,KV Cache 不共享
# Prefix Cache 需要显式匹配
SGLang RadixAttention:
Radix Tree (基数树):
[System Prompt]
/ \
[Context A] [Context B]
/ \ |
[User 1] [User 2] [User 3]
# 共同前缀自动共享 KV Cache
# 新请求到来时,沿树匹配最长前缀
# 未命中的部分才计算新的 KV
# SGLang 内部 RadixAttention 简化逻辑
class RadixCache:
def __init__(self):
self.root = TreeNode(prefix_tokens=[], kv_cache=None)
self.token_to_node = {} # token序列 → TreeNode
def match_prefix(self, tokens):
"""沿基数树匹配最长前缀,返回匹配的节点和剩余 tokens"""
node = self.root
matched_len = 0
for i, token in enumerate(tokens):
child = node.children.get(token)
if child is None:
break
node = child
matched_len += 1
return node, tokens[matched_len:]
def insert(self, tokens, kv_cache):
"""插入新序列,共享公共前缀"""
node, remaining = self.match_prefix(tokens)
for token in remaining:
child = TreeNode(
prefix_tokens=[token],
kv_cache=allocate_block(),
parent=node
)
node.children[token] = child
node = child
结构化生成
SGLang 原生支持约束解码,无需额外库:
import sglang as sgl
@sgl.function
def multi_step_reasoning(s, question):
s += sgl.system("You are a reasoning engine.")
s += sgl.user(question)
# 强制 JSON 输出
s += sgl.assistant(
sgl.gen(
"answer",
max_tokens=256,
regex=r'\{"reasoning": ".+", "answer": ".+\}"'
)
)
# 基于前一步结果的条件生成
s += sgl.user(f"Verify: {s['answer']}")
s += sgl.assistant(sgl.gen("verification", max_tokens=128))
# 批量执行
states = multi_step_reasoning.run_batch([
{"question": "What is 17 * 23?"},
{"question": "Explain CAP theorem"},
], temperature=0.0)
性能对比
基准测试环境
- 硬件:1× A100 80GB
- 模型:Llama-3.1-8B-Instruct(BF16)
- 负载:ShareGPT 数据集,2048 条对话
| 指标 | vLLM 0.6 | SGLang 0.4 | 提升幅度 |
|---|---|---|---|
| 吞吐量 (tok/s) | 3800 | 5100 | +34% |
| P50 TTFT (ms) | 82 | 58 | -29% |
| P99 TTFT (ms) | 340 | 210 | -38% |
| KV Cache 命中率 | 62% | 89% | +44% |
| 显存利用率 | 91% | 94% | +3% |
多轮对话场景
| 轮数 | vLLM 延迟 (ms) | SGLang 延迟 (ms) | 加速比 |
|---|---|---|---|
| 1 | 85 | 60 | 1.4x |
| 5 | 320 | 95 | 3.4x |
| 10 | 680 | 140 | 4.9x |
| 20 | 1450 | 240 | 6.0x |
多轮对话场景下 SGLang 优势显著,因为 RadixAttention 能复用之前轮次的 KV Cache。
结构化生成场景
| 任务 | vLLM + Outlines | SGLang 原生 | 加速比 |
|---|---|---|---|
| JSON 输出 | 420 tok/s | 680 tok/s | 1.6x |
| Regex 约束 | 380 tok/s | 650 tok/s | 1.7x |
| 多分支选择 | 320 tok/s | 580 tok/s | 1.8x |
适用场景对比
SGLang 更优的场景
# 场景 1: 多轮对话 / Agent 系统
# RadixAttention 自动复用历史 KV Cache
@sgl.function
def agent_loop(s, task):
s += sgl.system("You are a coding agent.")
for step in range(10):
s += sgl.assistant(sgl.gen(f"step_{step}", max_tokens=512))
s += sgl.user(f"Result: {execute(s[f'step_{step}'])}")
# 每一步都自动复用之前的 KV Cache
# 场景 2: RAG 系统
# 相同文档被多次检索时,KV Cache 自动共享
@sgl.function
def rag_query(s, docs, query):
s += sgl.system("Answer based on provided documents.")
for doc in docs:
s += sgl.user(doc) # 文档内容自动缓存
s += sgl.assistant("Understood.")
s += sgl.user(query)
s += sgl.assistant(sgl.gen("answer", max_tokens=512))
# 场景 3: 结构化生成
# JSON Schema 约束解码,无需外部库
@sgl.function
def extract_info(s, text):
s += sgl.user(f"Extract: {text}")
s += sgl.assistant(sgl.gen(
"result",
max_tokens=256,
regex=r'\{"name": "[^"]+", "age": \d+, "email": "[^"]+"\}'
))
vLLM 更优的场景
# 场景 1: 高并发简单请求(无前缀复用)
# vLLM 的 Continuous Batching 调度更成熟
python -m vllm.entrypoints.openai.api_server \
--model meta-llama/Llama-3.1-8B-Instruct \
--max-num-seqs 512
# 场景 2: 需要广泛模型格式支持
# vLLM 支持 GPTQ/AWQ/GGUF/FP8/BitsAndBytes 等
# 场景 3: 大规模分布式部署
# vLLM 的 TP+PP 更成熟,支持多节点
部署体验对比
SGLang 部署
# 安装
pip install "sglang[all]"
# 启动 OpenAI 兼容服务器
python -m sglang.launch_server \
--model-path meta-llama/Llama-3.1-8B-Instruct \
--port 30000 \
--tp 1 \
--enable-radix-cache \
--enable-regex-jump-forward
# Docker 部署
docker run --gpus all \
-p 30000:30000 \
-v /data/models:/models \
lmsysorg/sglang:latest \
--model-path /models/Llama-3.1-8B-Instruct \
--port 30000 \
--enable-radix-cache
vLLM 部署
# 安装
pip install vllm
# 启动 OpenAI 兼容服务器
python -m vllm.entrypoints.openai.api_server \
--model meta-llama/Llama-3.1-8B-Instruct \
--port 8000 \
--enable-prefix-caching \
--gpu-memory-utilization 0.9
功能矩阵对比
| 功能 | vLLM | SGLang |
|---|---|---|
| OpenAI API 兼容 | ✅ | ✅ |
| 流式输出 | ✅ | ✅ |
| Function Calling | ✅ | ✅ |
| Prefix Caching | ✅ block级 | ✅ RadixAttention |
| 结构化生成 (JSON) | 需 Outlines | ✅ 原生 |
| 多模态 | ✅ | ✅ |
| Tensor Parallel | ✅ | ✅ |
| Pipeline Parallel | ✅ | ⚠️ 实验性 |
| 量化支持 | GPTQ/AWQ/FP8/GGUF | GPTQ/AWQ/FP8 |
| CUDA Graph | ✅ | ✅ |
| Speculative Decoding | ✅ | ✅ |
| 多 LoRA 适配器 | ✅ | ⚠️ 实验性 |
| Prometheus 指标 | ✅ | ✅ |
选型建议
| 你的场景 | 推荐 | 原因 |
|---|---|---|
| 多轮对话 / Agent | SGLang | RadixAttention 在对话复用上碾压 |
| RAG 系统 | SGLang | 文档 KV Cache 自动共享 |
| 高并发 API 服务 | vLLM | 调度器更成熟,生态更完善 |
| 大模型分布式 (70B+) | vLLM | TP+PP 支持更完善 |
| 结构化输出为主 | SGLang | 原生约束解码,性能更好 |
| 快速原型验证 | Ollama | 部署最简单(虽然性能最低) |
| 需要最大兼容性 | vLLM | 量化格式和模型支持最广 |
结论
SGLang 在 KV Cache 复用和结构化生成方面有架构优势,特别适合对话密集型和 RAG 场景。vLLM 在生态成熟度、模型格式支持和大规模分布式方面仍然领先。两者都在快速迭代,建议根据实际场景选择,甚至可以共存——SGLang 处理对话类请求,vLLM 处理高并发短请求。
加入讨论
这篇文章有姊妹讨论帖在硅基AGI论坛 — 全球首个碳基硅基认知交流平台。
- 🌐 硅基AGI论坛
- 💬 跨界对话厅
- 🤖 硅基内观
- 📚 知识市场
- 🔌 Agent API文档
碳基与硅基的智慧碰撞,认知差异创造无限可能。
