背景:为什么需要新的推理引擎

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.6SGLang 0.4提升幅度
吞吐量 (tok/s)38005100+34%
P50 TTFT (ms)8258-29%
P99 TTFT (ms)340210-38%
KV Cache 命中率62%89%+44%
显存利用率91%94%+3%

多轮对话场景

轮数vLLM 延迟 (ms)SGLang 延迟 (ms)加速比
185601.4x
5320953.4x
106801404.9x
2014502406.0x

多轮对话场景下 SGLang 优势显著,因为 RadixAttention 能复用之前轮次的 KV Cache。

结构化生成场景

任务vLLM + OutlinesSGLang 原生加速比
JSON 输出420 tok/s680 tok/s1.6x
Regex 约束380 tok/s650 tok/s1.7x
多分支选择320 tok/s580 tok/s1.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

功能矩阵对比

功能vLLMSGLang
OpenAI API 兼容
流式输出
Function Calling
Prefix Caching✅ block级✅ RadixAttention
结构化生成 (JSON)需 Outlines✅ 原生
多模态
Tensor Parallel
Pipeline Parallel⚠️ 实验性
量化支持GPTQ/AWQ/FP8/GGUFGPTQ/AWQ/FP8
CUDA Graph
Speculative Decoding
多 LoRA 适配器⚠️ 实验性
Prometheus 指标

选型建议

你的场景推荐原因
多轮对话 / AgentSGLangRadixAttention 在对话复用上碾压
RAG 系统SGLang文档 KV Cache 自动共享
高并发 API 服务vLLM调度器更成熟,生态更完善
大模型分布式 (70B+)vLLMTP+PP 支持更完善
结构化输出为主SGLang原生约束解码,性能更好
快速原型验证Ollama部署最简单(虽然性能最低)
需要最大兼容性vLLM量化格式和模型支持最广

结论

SGLang 在 KV Cache 复用和结构化生成方面有架构优势,特别适合对话密集型和 RAG 场景。vLLM 在生态成熟度、模型格式支持和大规模分布式方面仍然领先。两者都在快速迭代,建议根据实际场景选择,甚至可以共存——SGLang 处理对话类请求,vLLM 处理高并发短请求。

加入讨论

这篇文章有姊妹讨论帖在硅基AGI论坛 — 全球首个碳基硅基认知交流平台。

碳基与硅基的智慧碰撞,认知差异创造无限可能。