作者:PySuper | 来源:zhengxingtao.com
当同样的模型、同样的硬件,不同推理框架带来的吞吐量差异可以高达 200% 以上——你选的框架,就是你的天花板。
目录
1. SGLang 是什么?从哪来的?
2. 核心创新:RadixAttention —— 让 KV 缓存真正"活"起来
3. 与 vLLM 全面对比:不只是快 29% 那么简单
4. 实战一:单机部署 Llama-4 Scout
5. 实战二:RAG 场景优化 —— 6 倍加速的真相
6. 多模态支持:不只是文本
7. SGLang vs Ollama / LM Studio / llama.cpp:定位完全不同
8. 生产部署:从 Docker 到 Kubernetes
9. SGLang vs vLLM 决策树
10. 踩坑记录
11. 写在最后
1. SGLang 是什么?从哪来的?
1.1 一句话版本
SGLang(Structured Generation Language)是一个专为 LLM 和多模态模型设计的高性能推理服务框架,核心创新 RadixAttention 能自动复用跨请求的 KV 缓存,在多轮对话和 RAG 场景下比 vLLM 快 6.4 倍。
1.2 身世背景
SGLang 由 UC Berkeley 的 LMSYS 团队开发——对,就是搞 Chatbot Arena 和 Vicuna 的那个团队。这不是什么野鸡项目,而是从第一天起就在大规模生产环境中打磨出来的:
据 SGLang GitHub 官方仓库(https://github.com/sgl-project/sglang)的数据:
25,000+ GitHub Stars
400,000+ GPU 在全球运行 SGLang
每日万亿级 Token 生成量
xAI(Grok 3) 的默认 LLM 引擎
Microsoft Azure 用于 DeepSeek R1 on AMD 的推理
AMD、NVIDIA、LinkedIn、Cursor 等均在使用
2026 年 1 月,SGLang 项目拆分为商业初创公司 RadixArk,由 Accel 领投,估值约 4 亿美元。联合创始人兼 CEO 盛颖此前是 xAI 的研究科学家。这意味着 SGLang 有商业公司长期背书,不会像某些学术项目那样"发完论文就不管了"。
1.3 为什么需要另一个推理框架?
你可能已经在用 vLLM 了,也许还觉得挺好的。那为什么要关心 SGLang?
核心问题在于:传统推理框架把每个请求都当成独立的。 你的应用发一个 prompt,服务器从头算每个 token,返回结果,然后忘掉一切。这对单轮对话没问题,但在以下场景就崩了:
多轮对话:每轮都要重新计算之前所有历史 token 的 KV 缓存
RAG 流水线:system prompt + 检索文档占了 60-80% 的 token,每次请求都重复计算
Agent 工作流:多个 LLM 调用共享相同前缀,但服务器不知道
Few-shot 学习:示例部分完全一样,却被反复计算
SGLang 的核心洞察是:LLM 工作负载是有结构的,这个结构可以被利用。
plaintext
传统框架:每个请求从头算一遍
┌─────────────────────────────────────────────────┐
│ Request A: [System Prompt] + [History] + [Q1] │ ← 全量计算
│ Request B: [System Prompt] + [History] + [Q2] │ ← 全量计算(重复!)
│ Request C: [System Prompt] + [History] + [Q3] │ ← 全量计算(重复!)
└─────────────────────────────────────────────────┘
SGLang:相同前缀只算一次
┌─────────────────────────────────────────────────┐
│ Request A: [System Prompt] + [History] + [Q1] │ ← 全量计算
│ Request B: [System Prompt] + [History] + [Q2] │ ← 缓存命中 + 增量计算
│ Request C: [System Prompt] + [History] + [Q3] │ ← 缓存命中 + 增量计算
└─────────────────────────────────────────────────┘
↑ 这部分被 RadixAttention 自动缓存复用
2. 核心创新:RadixAttention —— 让 KV 缓存真正"活"起来
2.1 传统 KV 缓存的浪费有多严重?
在 vLLM 等框架中,每个请求的 KV 缓存在请求完成后就被丢弃了。即使下一个请求共享 99% 的前缀,系统也会从头重新计算所有 token 的 Key-Value 激活值。
据 CSDN 博客《SGLang推理框架实测:KV缓存优化带来3倍性能提升》(https://blog.csdn.net/weixin_29069575/article/details/157380875)的实测数据:
在 ShareGPT 多轮对话数据集中,约 68% 的请求共享至少前 1.2K tokens 的上下文。这就是 RadixAttention 命中率飙升的基础。
一句话理解 RadixAttention 的价值:
它把"每个请求从头算一遍"变成"相同开头只算一次,后面全走高速缓存通道"。
2.2 RadixAttention 工作原理
RadixAttention 使用基数树(Radix Tree) 作为缓存索引结构。这不是一个复杂的概念,但它的效果非常惊人:
plaintext
Radix Tree 结构示意:
[Root]
│
[System Prompt KV Cache]
│
┌───────────┼───────────┐
│ │ │
[对话历史 A] [对话历史 B] [Few-shot 示例]
│ │ │
[Q1] [Q2] [查询1] [查询2]
↑
命中缓存!跳过重复计算
工作机制:
新请求到来:在 Radix Tree 中沿树向下匹配最长公共前缀(LCP)
命中缓存:直接复用该路径下所有已计算的 KV,零额外计算
未命中处:即为"分叉点",从此开始新计算
动态插入:新计算的结果作为新分支插入树中
LRU 淘汰:显存不足时按最近最少使用策略淘汰节点
据 SGLang 原始论文(https://github.com/sgl-project/sglang)的报告,RadixAttention 的管理开销极低:
在没有任何 KV 缓存复用机会的基准测试中,100 个请求运行 74.3 秒,RadixAttention 数据结构管理仅耗时 0.2 秒,开销不到 0.3% 。因此可以默认开启。
2.3 缓存命中率实测
据 CSDN 博客《SGLang:面向结构化LLM程序的高性能推理部署框架》(https://blog.csdn.net/m0_47999117/article/details/160533498)的数据:
plaintext
┌──────────────────────────────┬──────────────────┐
│ 场景 │ KV Cache 命中率 │
├──────────────────────────────┼──────────────────┤
│ 少样本学习(Few-shot) │ 50% ~ 70% │
│ 思维树推理(Tree-of-Thought) │ 70% ~ 90% │
│ 多轮对话历史 │ 60% ~ 85% │
│ 自洽采样(Self-consistency) │ 80% ~ 99% │
│ 多模态图像复用 │ 90%+ │
└──────────────────────────────┴──────────────────┘
相比之下,vLLM 的缓存命中率仅为 21.7% (同场景下),SGLang 达到 82.3% 。
2.4 缓存感知调度(Cache-Aware Scheduling)
有了 Radix Tree 缓存还不够。如果调度顺序不对,有用的前缀可能还没被复用就被淘汰了。SGLang 引入了缓存感知调度策略:
plaintext
传统 FCFS 调度: 缓存感知调度(SGLang):
[Req A: 无共享前缀] [Req B: 长共享前缀] ← 优先执行
[Req B: 长共享前缀] [Req C: 长共享前缀] ← 紧接执行
[Req C: 长共享前缀] [Req A: 无共享前缀]
↑ 缓存频繁失效 ↑ 最大化缓存命中
按共享前缀长度对请求优先排序,近似 Radix Tree 的深度优先遍历。论文形式化证明:该策略在离线场景下达到最优缓存命中率。
2.5 压缩有限状态机(Compressed FSM)
结构化输出(强制 JSON/Schema)是现代 LLM 应用的刚需。传统实现有严重低效:
plaintext
普通 FSM 解码 JSON:
{ → " → n → a → m → e → " → : → 每步单独解码!
^ ^ ^ ^ ^ ^ ^ ^
即使内容完全确定,也只能一次一个 token
压缩 FSM 解码:
{"name": → 一次性解码整个固定前缀!
实测效果:JSON 格式解码吞吐量提升最高 1.6 倍。
3. 与 vLLM 全面对比:不只是快 29% 那么简单
3.1 核心架构对比
plaintext
┌─────────────────────┬──────────────────────────┬──────────────────────────┐
│ 维度 │ vLLM (PagedAttention) │ SGLang (RadixAttention) │
├─────────────────────┼──────────────────────────┼──────────────────────────┤
│ 内存管理 │ 分页块,<4% 浪费 │ 分页块 + 基数树缓存 │
│ 缓存复用 │ 仅限单个请求内 │ 跨请求前缀匹配 │
│ 调度策略 │ 连续批处理(FIFO) │ 缓存感知(前缀优先) │
│ 内存开销 │ 基线更低 │ 较高(保留缓存树) │
│ 最佳场景 │ 独立 prompt,批量任务 │ 共享前缀,多轮对话 │
│ 结构化输出 │ 支持但较慢 │ XGrammar,3-10x 更快 │
│ 社区规模 │ 3x 贡献者基数 │ 增长更快 │
│ 硬件支持 │ 更广(TPU/Trainium/Gaudi)│ NVIDIA/AMD/TPU/Intel/NPU │
└─────────────────────┴──────────────────────────┴──────────────────────────┘
3.2 标准吞吐量基准(H100, Llama 3.1 8B)
据 Particula Tech《SGLang vs vLLM in 2026》(https://particula.tech/blog/sglang-vs-vllm-inference-engine-comparison)和 LocalAIMaster(https://localaimaster.com/blog/sglang-vs-vllm-comparison)的基准数据:
plaintext
┌────────────────────────┬──────────────┬──────────────┬─────────────────┐
│ 指标 │ SGLang │ vLLM │ 差异 │
├────────────────────────┼──────────────┼──────────────┼─────────────────┤
│ 总吞吐量 │ 16,215 tok/s │ 12,553 tok/s │ SGLang +29% │
│ 输出 Token 吞吐量 │ 894 tok/s │ 413 tok/s │ SGLang +117% │
│ 首 Token 延迟(TTFT) │ 79 ms │ 103 ms │ SGLang 快 23% │
│ Token 间延迟(ITL) │ 6.0 ms │ 7.1 ms │ SGLang 快 15% │
└────────────────────────┴──────────────┴──────────────┴─────────────────┘
关键洞察:29% 的总吞吐量差距是标题数字,但输出 Token 吞吐量才是用户真正感知的"速度"——SGLang 生成输出 Token 比对手快 2 倍以上。
3.3 并发行为对比
据 Particula Tech 的测试数据,在并发负载增加时,两者差距进一步拉大:
plaintext
┌──────────────┬───────────────┬───────────────┬───────────┐
│ 并发数 │ vLLM (tok/s) │ SGLang (tok/s)│ 差异 │
├──────────────┼───────────────┼───────────────┼───────────┤
│ 1 │ 120 │ 125 │ ~4% │
│ 10 │ 650 │ 680 │ ~5% │
│ 50 │ 1,850 │ 1,920 │ ~4% │
│ 100 │ 2,400 │ 2,460 │ ~2% │
└──────────────┴───────────────┴───────────────┴───────────┘
但在多轮对话的高并发场景下,SGLang 维持每请求 30-31 tok/s 稳定,vLLM 从 22 掉到 16 tok/s。SGLang 的缓存感知调度让单请求质量在高负载下依然稳定。
3.4 DeepSeek 系列专项优化
据 Fish Audio Blog《开源 LLM 推理引擎对比》(https://fish.audio/zh-CN/blog/open-source-llm-inference-engines-2026/)和 Particula Tech 的数据:
在 DeepSeek V3 上,SGLang 达到 3.1 倍于 vLLM 的推理速度,这得益于:
优化的 MLA(Multi-head Latent Attention)后端:FlashAttention3、FlashInfer、FlashMLA、CutlassMLA
EAGLE 投机解码支持:在 H200 上 batch_size=1 时 1.8 倍加速,batch_size=32 时 1.5 倍加速
DeepSeek V4 Day-0 支持:SGLang v0.5.12 已完整支持 DeepSeek V4 推理
如果你部署任何 DeepSeek 模型,SGLang 不只是更快,它是官方推荐引擎。
3.5 vLLM 在哪些场景更强?
公平地说,vLLM 也有自己的优势场景:
据 GitHub Issue mistral.rs#2011(https://github.com/EricLBuehler/mistral.rs/issues/2011)的基准测试:
在 150 并发下使用 Qwen2.5-0.5B 的测试中,vLLM 完成了 16,369 请求(363.76 req/s),而 SGLang 仅完成 6,750 请求(150 req/s)。原因是 SGLang 的 Python 路由管道受 GIL 瓶颈限制,而 vLLM 的 PagedAttention 实现在 C++ CUDA 扩展中绕过了 Python 限制。
但这只在小模型 + 超高并发 + 无共享前缀的场景下成立。 一旦出现缓存命中,SGLang 立刻反超。
据 Runpod 的测试:在单轮独立 prompt 下(DeepSeek-R1-Distill-Llama-70B),vLLM 确实比 SGLang 快(60 tok/s vs 52.7 tok/s)。但缓存命中后,SGLang 拉回差距(35 tok/s vs 32.8 tok/s)。
4. 实战一:单机部署 Llama-4 Scout
4.1 环境准备
据 SGLang 官方文档(https://sgl-project.github.io/basic_usage/llama4.html),SGLang 从 v0.4.5 起支持 Llama 4 Scout(109B)和 Llama 4 Maverick(400B)。
bash
# 硬件要求:8x H100/H200 80GB GPU
# 操作系统:Ubuntu 22.04+
# CUDA:12.1+
# Python:3.10+
# 方法一:pip 安装(推荐开发测试用)
pip install "sglang[all]"
# 验证版本(确保 >= 0.4.5,当前最新 v0.5.12)
python -c "import sglang; print(sglang.__version__)"
# 方法二:Docker 安装(推荐生产用)
docker pull lmsysorg/sglang:latest
# 方法三:从源码编译(获取最新特性)
git clone https://github.com/sgl-project/sglang.git
cd sglang
pip install -e "python[all]"
4.2 启动 Llama-4 Scout 推理服务
bash
# 基础启动命令
python3 -m sglang.launch_server \
--model-path meta-llama/Llama-4-Scout-17B-16E-Instruct \
--tp 8 \
--context-length 1000000 \
--host 0.0.0.0 \
--port 30000
关键参数说明:
plaintext
┌──────────────────────────┬─────────────────────────────────────────────┐
│ 参数 │ 说明 │
├──────────────────────────┼─────────────────────────────────────────────┤
│ --tp 8 │ 8 卡张量并行,充分利用 8x H100 │
│ --context-length 1000000 │ 最大上下文长度 1M tokens │
│ --chat-template llama-4 │ 使用 Llama-4 专用聊天模板 │
│ --enable-multimodal │ 启用多模态能力 │
│ --mem-fraction-static │ 静态显存分配比例,默认 0.88 │
└──────────────────────────┴─────────────────────────────────────────────┘
4.3 注意力后端自动选择
SGLang 会根据硬件自动选择最优注意力后端,你通常不需要手动指定:
plaintext
┌─────────────────────────────┬──────────────────────┐
│ 硬件平台 │ 自动选择的后端 │
├─────────────────────────────┼──────────────────────┤
│ Blackwell (B200/GB200) │ trtllm_mha │
│ Hopper (H100/H200) │ fa3 (FlashAttention3) │
│ AMD GPU │ aiter │
│ Intel XPU │ intel_xpu │
│ 其他平台 │ triton(降级方案) │
└─────────────────────────────┴──────────────────────┘
如果需要手动覆盖:
bash
python3 -m sglang.launch_server \
--model-path meta-llama/Llama-4-Scout-17B-16E-Instruct \
--tp 8 \
--attention-backend fa3 \
--context-length 1000000
4.4 OOM 处理
Llama-4 Scout 是 MoE 模型,显存需求大。以下是不同硬件的建议配置:
plaintext
┌────────────────────────┬──────────────────────────────────────────┐
│ 硬件配置 │ 建议 --context-length │
├────────────────────────┼──────────────────────────────────────────┤
│ 8x H100 80GB │ 最高 1M(标准模式) │
│ 8x H100 80GB (Hybrid) │ 最高 5M(启用 hybrid KV cache) │
│ 8x H200 141GB │ 最高 2.5M(标准模式) │
│ 8x H200 141GB (Hybrid) │ 最高 10M(启用 hybrid KV cache) │
└────────────────────────┴──────────────────────────────────────────┘
如果遇到 OOM:
bash
# 降低上下文长度
--context-length 65536
# 降低静态显存分配比例
--mem-fraction-static 0.80
# 启用 Hybrid KV Cache(将不活跃的 KV 缓存卸载到 CPU 内存)
# SGLang v0.5.12 已原生支持 HiSparse 用于 DeepSeek V4 的 CPU 卸载
4.5 精度验证
据 SGLang 官方文档,在 MMLU Pro 数据集上的精度验证结果:
plaintext
┌───────────────────────────────┬─────────────────┬─────────────────┐
│ 模型 │ 官方基准 │ SGLang │
├───────────────────────────────┼─────────────────┼─────────────────┤
│ Llama-4-Scout-17B-16E │ 74.3 │ 75.2 │
│ Llama-4-Maverick-17B-128E │ 80.5 │ 80.7 │
└───────────────────────────────┴─────────────────┴─────────────────┘
SGLang 的推理精度与官方基准一致甚至略高(可能是缓存命中带来的数值稳定性差异),不存在精度损失。
4.6 投机解码加速(EAGLE3)
对于 Llama-4 Maverick,SGLang 支持使用 NVIDIA 提供的 EAGLE3 草稿模型进行投机解码:
bash
python3 -m sglang.launch_server \
--model-path meta-llama/Llama-4-Maverick-17B-128E-Instruct \
--speculative-algorithm EAGLE3 \
--speculative-draft-model-path nvidia/Llama-4-Maverick-17B-128E-Eagle3 \
--speculative-num-steps 3 \
--speculative-eagle-topk 1 \
--speculative-num-draft-tokens 4 \
--trust-remote-code \
--tp 8 \
--context-length 1000000
注意:EAGLE3 草稿模型只能在聊天模式下工作,不支持纯补全模式。
4.7 使用 OpenAI SDK 调用
SGLang 提供完全兼容 OpenAI API 的接口,迁移成本为零:
python
from openai import OpenAI
# 只需改一行 base_url,其他代码完全不变
client = OpenAI(
base_url="http://localhost:30000/v1",
api_key="EMPTY" # SGLang 不需要 API key
)
# Chat Completions
response = client.chat.completions.create(
model="meta-llama/Llama-4-Scout-17B-16E-Instruct",
messages=[
{"role": "system", "content": "You are a helpful assistant."},
{"role": "user", "content": "Explain quantum computing in simple terms."}
],
max_tokens=512,
temperature=0.7
)
print(response.choices[0].message.content)
# Text Completions
response = client.completions.create(
model="meta-llama/Llama-4-Scout-17B-16E-Instruct",
prompt="The key insight behind RadixAttention is",
max_tokens=256
)
print(response.choices[0].text)
# Embeddings
response = client.embeddings.create(
model="meta-llama/Llama-4-Scout-17B-16E-Instruct",
input="Hello, world!"
)
print(response.data[0].embedding[:5])
4.8 结构化输出
SGLang 内置约束解码,强制模型输出符合 JSON Schema 的内容:
python
import json
from openai import OpenAI
client = OpenAI(
base_url="http://localhost:30000/v1",
api_key="EMPTY"
)
# 方法一:使用 response_format 强制 JSON 输出
response = client.chat.completions.create(
model="meta-llama/Llama-4-Scout-17B-16E-Instruct",
messages=[
{"role": "user", "content": "Extract the name, age, and city from: John is 30 years old and lives in NYC."}
],
response_format={
"type": "json_schema",
"json_schema": {
"name": "person_info",
"strict": True,
"schema": {
"type": "object",
"properties": {
"name": {"type": "string"},
"age": {"type": "integer"},
"city": {"type": "string"}
},
"required": ["name", "age", "city"],
"additionalProperties": False
}
}
},
max_tokens=256
)
result = json.loads(response.choices[0].message.content)
print(result)
# {"name": "John", "age": 30, "city": "NYC"} ← 保证格式正确,无需后处理!
python
# 方法二:使用正则约束解码(SGLang 特有)
# 通过 SGLang 的原生 Python API
import sglang as sgl
@sgl.function
def extract_info(s, text):
s += "Extract information from the following text:\n"
s += text + "\n"
s += "Result (JSON format): "
s += sgl.gen(
"result",
regex=r'\{[^{}]*"name"\s*:\s*"[^"]*"\s*,\s*"age"\s*:\s*\d+\s*,\s*"city"\s*:\s*"[^"]*"\s*\}'
)
runtime = sgl.Runtime(model_path="meta-llama/Llama-4-Scout-17B-16E-Instruct", tp_size=8)
result = extract_info.run(runtime, text="John is 30 years old and lives in NYC.")
print(result["result"])
5. 实战二:RAG 场景优化 —— 6 倍加速的真相
5.1 为什么 RAG 是 SGLang 的杀手场景?
在典型 RAG 应用中,请求结构通常是:
plaintext
[System Prompt] + [Retrieved Documents] + [User Query]
↑ 60-80% tokens 固定 ↑ 可能重复 ↑ 每次不同
这意味着:
System Prompt 在所有请求中完全相同 → 100% 缓存命中
检索文档 在多轮对话中经常重复 → 高缓存命中率
用户查询 每次不同 → 需要实际计算
据 WeavAI《SGLang 2026 Guide》(https://weavai.app/blog/en/2026/04/24/sglang-2026-guide-fast-llm-inference-deployment/)的数据:
在 RAG 应用中 system prompt 占请求 tokens 的 60-80%,RadixAttention 让这部分计算被完全跳过,带来最高 6 倍加速。
5.2 完整 RAG 流水线代码
以下是一个完整的 RAG 流水线,展示如何最大化利用 SGLang 的 RadixAttention:
python
"""
SGLang RAG Pipeline - 最大化 RadixAttention 缓存命中
关键设计原则:
1. System Prompt 放在最前面(固定前缀)
2. 工具定义放在动态内容之前
3. 检索文档按固定顺序排列
4. 用户查询放在最后
"""
import json
import time
from dataclasses import dataclass, field
from typing import List, Optional
from openai import OpenAI
# ========================
# 配置
# ========================
SGLANG_BASE_URL = "http://localhost:30000/v1"
MODEL_NAME = "Qwen/Qwen2.5-7B-Instruct"
# System Prompt - 固定不变,这是 RadixAttention 的核心缓存对象
SYSTEM_PROMPT = """You are a precise document analysis assistant. Your task is to answer questions based ONLY on the provided documents.
Rules:
1. Only use information from the provided documents
2. If the answer is not in the documents, say "I cannot find this information in the provided documents."
3. Always cite the source document when providing an answer
4. Be concise and factual
5. If multiple documents provide conflicting information, note the discrepancy
Output format: JSON with keys "answer", "confidence" (0-1), "source_docs"
"""
@dataclass
class Document:
"""检索文档的数据结构"""
doc_id: str
title: str
content: str
score: float = 0.0
@dataclass
class RAGRequest:
"""RAG 请求"""
query: str
documents: List[Document] = field(default_factory=list)
conversation_history: List[dict] = field(default_factory=list)
class SGLangRAGPipeline:
"""
SGLang RAG Pipeline - 针对 RadixAttention 优化的设计
Prompt 结构设计(从上到下,缓存命中率递减):
┌──────────────────────────────────────┐
│ System Prompt(固定,100% 命中) │ ← 所有请求共享
├──────────────────────────────────────┤
│ 工具/格式定义(固定,100% 命中) │ ← 所有请求共享
├──────────────────────────────────────┤
│ 对话历史(部分命中,60-85%) │ ← 同一对话共享
├──────────────────────────────────────┤
│ 检索文档(部分命中,50-70%) │ ← 相似查询共享
├──────────────────────────────────────┤
│ 用户查询(0% 命中) │ ← 每次不同
└──────────────────────────────────────┘
"""
def __init__(self, base_url: str = SGLANG_BASE_URL, model: str = MODEL_NAME):
self.client = OpenAI(base_url=base_url, api_key="EMPTY")
self.model = model
def _build_messages(
self,
query: str,
documents: List[Document],
conversation_history: Optional[List[dict]] = None
) -> List[dict]:
"""
构建消息列表 - 关键:保持前缀一致性
原则:
1. System Prompt 始终在最前面
2. 文档按 doc_id 排序(确保相同文档集的 token 序列一致)
3. 对话历史在文档之前(因为对话历史更可能跨查询共享)
4. 用户查询在最后
"""
# Step 1: 构建文档文本块(按 doc_id 排序保证顺序一致性)
sorted_docs = sorted(documents, key=lambda d: d.doc_id)
docs_text = "\n\n".join([
f"[Document {d.doc_id}] {d.title}\n{d.content}"
for d in sorted_docs
])
# Step 2: 将文档信息放入 system message(与 system prompt 一起,最大化缓存命中)
full_system = f"""{SYSTEM_PROMPT}
=== RETRIEVED DOCUMENTS ===
{docs_text}
=== END OF DOCUMENTS ==="""
messages = [{"role": "system", "content": full_system}]
# Step 3: 加入对话历史(如果有)
if conversation_history:
messages.extend(conversation_history)
# Step 4: 用户查询放最后
messages.append({"role": "user", "content": query})
return messages
def query(
self,
request: RAGRequest,
max_tokens: int = 512,
temperature: float = 0.1
) -> dict:
"""执行 RAG 查询"""
messages = self._build_messages(
query=request.query,
documents=request.documents,
conversation_history=request.conversation_history or None
)
start_time = time.time()
response = self.client.chat.completions.create(
model=self.model,
messages=messages,
max_tokens=max_tokens,
temperature=temperature,
response_format={"type": "json_object"} # 强制 JSON 输出
)
latency = time.time() - start_time
try:
result = json.loads(response.choices[0].message.content)
except json.JSONDecodeError:
result = {"raw_text": response.choices[0].message.content}
return {
"answer": result,
"latency_ms": latency * 1000,
"tokens_used": {
"prompt": response.usage.prompt_tokens,
"completion": response.usage.completion_tokens
}
}
def multi_turn_query(
self,
queries: List[str],
documents: List[Document]
) -> List[dict]:
"""
多轮对话查询 - 充分利用 RadixAttention
在多轮对话中,每轮的 system prompt + 文档 完全相同,
RadixAttention 自动缓存这部分,后续轮次只计算新增内容。
"""
conversation_history = []
results = []
for i, query in enumerate(queries):
request = RAGRequest(
query=query,
documents=documents,
conversation_history=conversation_history.copy()
)
result = self.query(request)
result["turn"] = i + 1
results.append(result)
# 将本轮对话加入历史
conversation_history.append({"role": "user", "content": query})
conversation_history.append({
"role": "assistant",
"content": json.dumps(result["answer"])
})
return results
# ========================
# 模拟向量检索(实际项目中替换为你的向量库)
# ========================
class SimpleRetriever:
"""简单的文档检索器(演示用,生产环境请用 FAISS/Milvus/Qdrant)"""
def __init__(self, documents: List[Document]):
self.documents = documents
self.doc_map = {d.doc_id: d for d in documents}
def retrieve(self, query: str, top_k: int = 3) -> List[Document]:
"""
简单的关键词匹配检索
生产环境应替换为向量相似度检索
"""
query_words = set(query.lower().split())
scored_docs = []
for doc in self.documents:
doc_words = set(doc.content.lower().split())
overlap = len(query_words & doc_words)
scored_docs.append((overlap, doc))
scored_docs.sort(key=lambda x: x[0], reverse=True)
return [doc for _, doc in scored_docs[:top_k]]
# ========================
# 使用示例
# ========================
def main():
# 准备文档库
documents = [
Document(
doc_id="doc_001",
title="SGLang Architecture Overview",
content="SGLang uses RadixAttention as its core innovation. RadixAttention manages KV cache using a radix tree data structure, enabling automatic cross-request prefix reuse. The system achieves up to 6.4x throughput improvement on prefix-heavy workloads."
),
Document(
doc_id="doc_002",
title="RadixAttention Deep Dive",
content="RadixAttention stores KV cache entries in a radix tree where each node represents a sequence of tokens. When a new request arrives, the runtime walks the tree matching prompt tokens against existing nodes. Every matched node means the KV activations already exist in GPU memory. Cache hit rate reaches 82.3% in multi-turn conversations."
),
Document(
doc_id="doc_003",
title="SGLang vs vLLM Benchmark",
content="On H100 GPUs running Llama 3.1 8B, SGLang achieves 16,215 tok/s vs vLLM's 12,553 tok/s, a 29% throughput advantage. For DeepSeek V3, SGLang is 3.1x faster than vLLM. The output token throughput difference is even more dramatic: 894 tok/s vs 413 tok/s."
),
Document(
doc_id="doc_004",
title="Production Deployment Guide",
content="SGLang supports Docker and Kubernetes deployment. The official Docker image is lmsysorg/sglang:latest. For production, use the runtime variant which is 40% smaller. SGLang also provides Helm Charts and SkyPilot integration for cloud deployment."
),
]
retriever = SimpleRetriever(documents)
pipeline = SGLangRAGPipeline()
# 单轮查询
print("=" * 60)
print("单轮 RAG 查询")
print("=" * 60)
query = "How fast is SGLang compared to vLLM?"
relevant_docs = retriever.retrieve(query, top_k=2)
request = RAGRequest(query=query, documents=relevant_docs)
result = pipeline.query(request)
print(f"Query: {query}")
print(f"Latency: {result['latency_ms']:.1f}ms")
print(f"Answer: {json.dumps(result['answer'], ensure_ascii=False, indent=2)}")
print()
# 多轮对话 - 充分利用 RadixAttention
print("=" * 60)
print("多轮 RAG 对话(RadixAttention 缓存复用)")
print("=" * 60)
multi_turn_queries = [
"What is RadixAttention?",
"How does the cache hit rate compare?",
"What about production deployment?",
]
# 使用相同的文档集 → system prompt + 文档部分被 RadixAttention 完全缓存
results = pipeline.multi_turn_query(multi_turn_queries, relevant_docs)
for r in results:
print(f"\n--- Turn {r['turn']} ---")
print(f"Latency: {r['latency_ms']:.1f}ms")
print(f"Tokens: prompt={r['tokens_used']['prompt']}, completion={r['tokens_used']['completion']}")
# 性能对比
print("\n" + "=" * 60)
print("性能对比提示")
print("=" * 60)
print("""
在多轮对话中,RadixAttention 的缓存效果逐轮增强:
- Turn 1: 全量计算(冷启动)
- Turn 2: System Prompt + Documents 缓存命中 → TTFT 降低 40-60%
- Turn 3: System Prompt + Documents + History 缓存命中 → TTFT 降低 50-70%
在 vLLM 中,每轮都是全量计算,没有跨请求缓存复用。
""")
if __name__ == "__main__":
main()
5.3 最大化 RadixAttention 缓存命中的 5 条规则
据 Runpod《SGLang in Production》(https://www.runpod.io/articles/guides/blog-sglang-production-llm-pipelines)的最佳实践:
plaintext
┌─────────────────────────────────────────────────────────────────────────┐
│ 规则 1:System Prompt 和 Few-shot 示例始终放在最前面 │
│ 规则 2:工具定义放在动态内容之前(而不是之后) │
│ 规则 3:检索文档按固定顺序排列(如按 doc_id 排序) │
│ 规则 4:变量内容放在 Prompt 末尾 │
│ 规则 5:保持前缀字节级一致(哪怕一个字符变化都会破坏缓存) │
└─────────────────────────────────────────────────────────────────────────┘
规则 5 的重要性:即使只改了 system prompt 中的一个字符,tokenizer 输出的 token ID 就会不同,导致 Radix Tree 的精确前缀匹配失败,所有下游节点的缓存全部失效。
python
# ❌ 错误做法:每次请求修改 system prompt
system_prompt = f"You are an assistant for user {user_id}." # 每次不同!
# ✅ 正确做法:固定前缀 + 变量后缀
system_prompt = "You are a helpful assistant." # 固定部分 → 缓存命中
user_context = f"Current user: {user_id}" # 变量部分 → 不命中但影响小
5.4 批量 RAG 优化
当需要批量处理多个查询时,确保它们共享相同的前缀结构:
python
import asyncio
from openai import AsyncOpenAI
async def batch_rag_queries(
queries: List[str],
documents: List[Document],
base_url: str = "http://localhost:30000/v1",
model: str = "Qwen/Qwen2.5-7B-Instruct"
) -> List[dict]:
"""
批量 RAG 查询 - 利用 RadixAttention 的跨请求缓存
关键:所有请求使用完全相同的 system prompt 和文档集,
只有最后的用户查询不同。这样 RadixAttention 会自动缓存
共享前缀部分,后续请求只计算查询部分。
"""
client = AsyncOpenAI(base_url=base_url, api_key="EMPTY")
# 构建固定的 system prompt(包含文档)
sorted_docs = sorted(documents, key=lambda d: d.doc_id)
docs_text = "\n\n".join([
f"[Document {d.doc_id}] {d.title}\n{d.content}"
for d in sorted_docs
])
full_system = f"{SYSTEM_PROMPT}\n\n=== DOCUMENTS ===\n{docs_text}\n=== END ==="
async def single_query(query: str) -> dict:
messages = [
{"role": "system", "content": full_system},
{"role": "user", "content": query}
]
start_time = time.time()
response = await client.chat.completions.create(
model=model,
messages=messages,
max_tokens=256,
temperature=0.1
)
latency = time.time() - start_time
return {
"query": query,
"answer": response.choices[0].message.content,
"latency_ms": latency * 1000
}
# 并发执行所有查询
results = await asyncio.gather(*[single_query(q) for q in queries])
# 按延迟排序可以看到 RadixAttention 的缓存效果
# 第一个请求通常是冷启动,后续请求越来越快
results.sort(key=lambda x: x["latency_ms"])
print("批量查询结果(按延迟排序,可以看到缓存预热效果):")
for i, r in enumerate(results):
print(f" [{i+1}] {r['latency_ms']:.1f}ms - {r['query'][:40]}...")
return results
# 运行批量查询
async def run_batch():
docs = [
Document(doc_id="d1", title="AI Safety", content="AI safety involves..."),
Document(doc_id="d2", title="ML Training", content="Model training requires..."),
]
queries = [
"What is AI safety?",
"How to train models efficiently?",
"What are the key challenges in AI?",
]
await batch_rag_queries(queries, docs)
# asyncio.run(run_batch())
6. 多模态支持:不只是文本
6.1 支持的多模态模型
据 SGLang 官方文档(https://docs.sglang.io/supported_models/text_generation/multimodal_language_models.html),SGLang 支持广泛的多模态模型:
plaintext
┌───────────────────────────────┬──────────────────────────────────────┐
│ 模型家族 │ 代表模型 │
├───────────────────────────────┼──────────────────────────────────────┤
│ Qwen-VL │ Qwen3-VL-235B-A22B-Instruct │
│ LLaVA │ LLaVA-NeXT-Video-7B │
│ InternVL │ InternVL2-26B │
│ Gemma3 │ gemma-3-27b-it │
│ Llama Vision │ Llama-3.2-11B-Vision-Instruct │
│ GLM-4V │ GLM-4.5V │
│ NVILA │ NVILA-8B │
│ Nemotron VL │ Nemotron-Nano-12B-v2-VL │
└──────────────────────────────┴──────────────────────────────────────┘
6.2 图像理解示例
python
import base64
import requests
# 启动多模态服务
# python3 -m sglang.launch_server \
# --model-path meta-llama/Llama-3.2-11B-Vision-Instruct \
# --host 0.0.0.0 --port 30000
# 方法一:使用 URL
response = requests.post(
"http://localhost:30000/v1/chat/completions",
json={
"model": "meta-llama/Llama-3.2-11B-Vision-Instruct",
"messages": [
{
"role": "user",
"content": [
{"type": "text", "text": "Describe this image in detail."},
{
"type": "image_url",
"image_url": {
"url": "https://example.com/photo.jpg"
}
}
]
}
],
"max_tokens": 512
}
)
print(response.json()["choices"][0]["message"]["content"])
# 方法二:使用 Base64 编码的本地图片
def encode_image(image_path: str) -> str:
with open(image_path, "rb") as f:
return base64.b64encode(f.read()).decode("utf-8")
base64_image = encode_image("local_photo.jpg")
response = requests.post(
"http://localhost:30000/v1/chat/completions",
json={
"model": "meta-llama/Llama-3.2-11B-Vision-Instruct",
"messages": [
{
"role": "user",
"content": [
{"type": "text", "text": "What objects can you identify?"},
{
"type": "image_url",
"image_url": {
"url": f"data:image/jpeg;base64,{base64_image}"
}
}
]
}
],
"max_tokens": 256
}
)
print(response.json()["choices"][0]["message"]["content"])
6.3 视频输入支持
python
import requests
# 视频问答(Qwen3-VL 示例)
response = requests.post(
"http://localhost:30000/v1/chat/completions",
json={
"model": "Qwen/Qwen3-VL-30B-A3B-Instruct",
"messages": [
{
"role": "user",
"content": [
{"type": "text", "text": "What's happening in this video?"},
{
"type": "video_url",
"video_url": {
"url": "https://example.com/video.mp4"
}
}
]
}
],
"max_tokens": 300
}
)
print(response.json()["choices"][0]["message"]["content"])
6.4 多模态性能优化
bash
# 关键优化参数
python3 -m sglang.launch_server \
--model-path Qwen/Qwen3-VL-30B-A3B-Instruct \
--host 0.0.0.0 --port 30000 \
--keep-mm-feature-on-device \ # 保持特征在 GPU 上,降低延迟但增加显存
--mm-process-config '{ # 控制多模态输入限制
"image": {"max_pixels": 1048576},
"video": {"fps": 3, "max_pixels": 602112, "max_frames": 60}
}'
RadixAttention 对多模态也有效! 视觉 Token 的 KV 缓存同样参与前缀匹配。在图像-文本混合 RAG 场景中,相同的图像 KV 缓存可以被多个查询复用,缓存命中率可达 90%+。
7. SGLang vs Ollama / LM Studio / llama.cpp:定位完全不同
很多人会问:"我已经在用 Ollama 了,为什么还要看 SGLang?"
答案是:它们解决的是完全不同的问题。
plaintext
┌──────────────┬──────────────────────────────────────────────────────────┐
│ 工具 │ 定位与适用场景 │
├──────────────┼──────────────────────────────────────────────────────────┤
│ llama.cpp │ 本地推理,CPU/GPU 混合,量化为王 │
│ │ 适合:个人电脑、边缘设备、离线场景 │
│ │ 不适合:高并发服务、大规模部署 │
├──────────────┼──────────────────────────────────────────────────────────┤
│ Ollama │ llama.cpp 的用户友好封装,一键下载运行 │
│ │ 适合:个人开发、快速实验、桌面使用 │
│ │ 不适合:生产 API 服务、高吞吐场景 │
├──────────────┼──────────────────────────────────────────────────────────┤
│ LM Studio │ GUI 驱动的本地推理,更偏向"个人 AI 工作站" │
│ │ 适合:非技术用户、可视化操作、模型探索 │
│ │ 不适合:API 服务、集群部署、自动化流水线 │
├──────────────┼──────────────────────────────────────────────────────────┤
│ vLLM │ 高吞吐推理服务,PagedAttention 内存管理 │
│ │ 适合:通用 API 服务、批量任务、广泛硬件兼容 │
│ │ 不适合:多轮对话优化、RAG 加速、结构化输出 │
├──────────────┼──────────────────────────────────────────────────────────┤
│ SGLang │ 高性能推理服务,RadixAttention 缓存复用 │
│ │ 适合:多轮对话、RAG、Agent 工作流、结构化输出 │
│ │ 不适合:个人桌面、边缘设备、纯 CPU 推理 │
└──────────────┴──────────────────────────────────────────────────────────┘
7.1 选型决策
plaintext
你需要本地/个人使用?
├── 是 → 只需要跑模型聊天?
│ ├── 是 → Ollama
│ └── 需要 GUI → LM Studio
└── 否 → 你需要 API 服务?
├── 是 → 你的场景有共享前缀吗?
│ ├── 是(多轮对话/RAG/Agent) → SGLang ✅
│ └── 否(批量内容生成) → vLLM
└── 你需要边缘部署/无 GPU?
└── llama.cpp
7.2 性能差距有多大?
据 CSDN 博客(https://blog.csdn.net/Z987421/article/details/160547453)的 RAG 延迟优化分析:
plaintext
同等硬件、同等模型下的 RAG 场景延迟对比(A100 8×, Qwen2-7B-Instruct):
┌──────────────────────────────┬──────────────┬──────────────┬──────────────┐
│ 框架 │ 吞吐量 tok/s │ TTFT (ms) │ 显存占用 (GB) │
├──────────────────────────────┼──────────────┼──────────────┼──────────────┤
│ Ollama (llama.cpp) │ ~800 │ ~950 │ ~45 │
│ vLLM v0.6.3 │ 3,218 │ 482 │ 42.1 │
│ SGLang v0.5.6(默认) │ 5,943 │ 313 │ 39.8 │
│ SGLang v0.5.6(RadixAttn+结构化)│ 9,232 │ 232 │ 38.2 │
└──────────────────────────────┴──────────────┴──────────────┴──────────────┘
SGLang 启用完整优化后是 Ollama 的 11.5 倍,是 vLLM 的 2.87 倍。
8. 生产部署:从 Docker 到 Kubernetes
8.1 Docker 部署(推荐起步方案)
bash
# 拉取官方镜像
docker pull lmsysorg/sglang:latest
# 生产环境推荐使用 runtime 变体(体积减少约 40%)
docker pull lmsysorg/sglang:latest-runtime
# 启动单 GPU 服务
docker run --gpus all \
--shm-size 32g \
-p 30000:30000 \
-v ~/.cache/huggingface:/root/.cache/huggingface \
--env "HF_TOKEN=your_token_here" \
--ipc=host \
lmsysorg/sglang:latest-runtime \
python3 -m sglang.launch_server \
--model-path Qwen/Qwen2.5-7B-Instruct \
--host 0.0.0.0 \
--port 30000
# 启动多 GPU 服务(4 卡张量并行)
docker run --gpus all \
--shm-size 32g \
-p 30000:30000 \
-v ~/.cache/huggingface:/root/.cache/huggingface \
--env "HF_TOKEN=your_token_here" \
--ipc=host \
lmsysorg/sglang:latest-runtime \
python3 -m sglang.launch_server \
--model-path meta-llama/Meta-Llama-3.3-70B-Instruct \
--tp 4 \
--host 0.0.0.0 \
--port 30000
重要:
--shm-size 32g不能省略,SGLang 使用共享内存进行 GPU 间通信,默认的 64MB 会导致启动失败。
8.2 Docker Compose 部署
yaml
# compose.yml
version: "3.8"
services:
sglang:
image: lmsysorg/sglang:latest-runtime
shm_size: "32g"
ipc: host
ports:
- "30000:30000"
volumes:
- ~/.cache/huggingface:/root/.cache/huggingface
environment:
- HF_TOKEN=${HF_TOKEN}
deploy:
resources:
reservations:
devices:
- driver: nvidia
count: all
capabilities: [gpu]
command: >
python3 -m sglang.launch_server
--model-path Qwen/Qwen2.5-7B-Instruct
--host 0.0.0.0
--port 30000
healthcheck:
test: ["CMD", "curl", "-f", "http://localhost:30000/health"]
interval: 30s
timeout: 10s
retries: 5
start_period: 300s
bash
# 启动
docker compose up -d
# 查看日志
docker compose logs -f sglang
# 健康检查
curl http://localhost:30000/health
8.3 Kubernetes 部署
据 SGLang 官方 K8s 文档(https://sgl-project.github.io/references/multi_node_deployment/deploy_on_k8s.html),支持 LeaderWorkerSet(LWS)进行分布式推理:
yaml
# sglang-deployment.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: sglang-server
labels:
app: sglang
spec:
replicas: 1
selector:
matchLabels:
app: sglang
template:
metadata:
labels:
app: sglang
spec:
containers:
- name: sglang
image: lmsysorg/sglang:latest-runtime
command:
- python3
- -m
- sglang.launch_server
- --model-path
- Qwen/Qwen2.5-7B-Instruct
- --host
- "0.0.0.0"
- --port
- "30000"
- --tp
- "4"
- --mem-fraction-static
- "0.85"
ports:
- containerPort: 30000
resources:
limits:
nvidia.com/gpu: "4"
requests:
nvidia.com/gpu: "4"
volumeMounts:
- name: dshm
mountPath: /dev/shm
- name: model-cache
mountPath: /root/.cache/huggingface
readinessProbe:
httpGet:
path: /health
port: 30000
initialDelaySeconds: 300 # 模型加载需要时间
periodSeconds: 10
timeoutSeconds: 5
livenessProbe:
httpGet:
path: /health
port: 30000
initialDelaySeconds: 600
periodSeconds: 30
volumes:
- name: dshm
emptyDir:
medium: Memory
- name: model-cache
persistentVolumeClaim:
claimName: sglang-model-cache
---
apiVersion: v1
kind: Service
metadata:
name: sglang-service
spec:
selector:
app: sglang
ports:
- protocol: TCP
port: 30000
targetPort: 30000
type: ClusterIP
bash
# 部署
kubectl apply -f sglang-deployment.yaml
# 检查状态
kubectl get pods -l app=sglang
kubectl logs -f deployment/sglang-server
# 测试服务
kubectl port-forward svc/sglang-service 30000:30000
curl http://localhost:30000/v1/models
8.4 多节点分布式推理(DeepSeek-R1 示例)
对于需要跨节点部署的大模型(如 DeepSeek-R1),SGLang 支持 LWS(LeaderWorkerSet):
yaml
# lws-distributed.yaml
apiVersion: leaderworkerset.x-k8s.io/v1
kind: LeaderWorkerSet
metadata:
name: sglang-deepseek
spec:
replicas: 1
leaderWorkerTemplate:
size: 2 # 2 个节点
restartPolicy: RecreateGroupOnPodRestart
leaderTemplate:
metadata:
labels:
role: leader
spec:
dnsPolicy: ClusterFirstWithHostNet
hostNetwork: true
hostIPC: true
containers:
- name: sglang-leader
image: lmsysorg/sglang:latest
securityContext:
privileged: true
command:
- python3
- -m
- sglang.launch_server
- --model-path
- deepseek-ai/DeepSeek-R1
- --mem-fraction-static
- "0.93"
- --tp
- "16"
- --dist-init-addr
- "$(LWS_LEADER_ADDRESS):20000"
- --nnodes
- "$(LWS_GROUP_SIZE)"
- --node-rank
- "$(LWS_WORKER_INDEX)"
- --trust-remote-code
- --host
- "0.0.0.0"
- --port
- "40000"
resources:
limits:
nvidia.com/gpu: "8"
ports:
- containerPort: 40000
readinessProbe:
tcpSocket:
port: 40000
initialDelaySeconds: 300
periodSeconds: 10
volumeMounts:
- mountPath: /dev/shm
name: dshm
- name: model
mountPath: /work/models
volumes:
- name: dshm
emptyDir:
medium: Memory
- name: model
hostPath:
path: /data/models/deepseek-r1
8.5 SkyPilot 一键云部署
据 SGLang 官方安装文档(https://projects.localizethedocs.org/sglang-docs-l10n/en-us/latest/get_started/install.html),支持 12+ 云平台一键部署:
yaml
# sglang.yaml
envs:
HF_TOKEN: null
resources:
image_id: docker:lmsysorg/sglang:latest
accelerators: A100
ports: 30000
run: |
conda deactivate
python3 -m sglang.launch_server \
--model-path meta-llama/Meta-Llama-3.1-8B-Instruct \
--host 0.0.0.0 \
--port 30000
bash
# 一键部署到任意云
HF_TOKEN=your_token sky launch -c sglang --env HF_TOKEN sglang.yaml
# 获取 API 端点
sky status --endpoint 30000 sglang
8.6 生产监控指标
SGLang 暴露了 Prometheus 格式的监控指标:
python
"""
SGLang 生产监控指标采集示例
"""
import requests
import time
from dataclasses import dataclass
@dataclass
class SGLangMetrics:
"""SGLang 关键监控指标"""
# 吞吐量
total_requests: int = 0
total_tokens: int = 0
total_prompt_tokens: int = 0
total_completion_tokens: int = 0
# 延迟
avg_ttft_ms: float = 0.0
avg_itl_ms: float = 0.0
avg_e2e_latency_ms: float = 0.0
# 缓存
cache_hit_rate: float = 0.0
cache_hit_tokens: int = 0
cache_total_tokens: int = 0
# 资源
gpu_memory_used_gb: float = 0.0
gpu_memory_total_gb: float = 0.0
gpu_utilization: float = 0.0
# 队列
running_requests: int = 0
queued_requests: int = 0
def collect_metrics(base_url: str = "http://localhost:30000") -> SGLangMetrics:
"""从 SGLang 服务采集监控指标"""
try:
# SGLang 暴露 /metrics 端点(Prometheus 格式)
response = requests.get(f"{base_url}/metrics", timeout=5)
metrics_text = response.text
m = SGLangMetrics()
# 解析关键指标
for line in metrics_text.split("\n"):
if line.startswith("#") or not line.strip():
continue
parts = line.split()
if len(parts) < 2:
continue
name, value = parts[0], parts[1]
if "sglang_total_request" in name:
m.total_requests = int(value)
elif "sglang_token_total" in name and "prompt" not in name:
m.total_tokens = int(value)
elif "sglang_prompt_token_total" in name:
m.total_prompt_tokens = int(value)
elif "sglang_completion_token_total" in name:
m.total_completion_tokens = int(value)
elif "sglang_cache_hit_rate" in name:
m.cache_hit_rate = float(value)
elif "sglang_running_requests" in name:
m.running_requests = int(value)
elif "sglang_queued_requests" in name:
m.queued_requests = int(value)
return m
except Exception as e:
print(f"Failed to collect metrics: {e}")
return SGLangMetrics()
def print_dashboard(metrics: SGLangMetrics):
"""打印简易监控面板"""
print("\n" + "=" * 60)
print(" SGLang 监控面板")
print("=" * 60)
print(f" 运行中请求: {metrics.running_requests}")
print(f" 排队中请求: {metrics.queued_requests}")
print(f" 总完成请求: {metrics.total_requests}")
print(f" 缓存命中率: {metrics.cache_hit_rate:.1%}")
print(f" GPU 显存: {metrics.gpu_memory_used_gb:.1f}/{metrics.gpu_memory_total_gb:.1f} GB")
print(f" GPU 利用率: {metrics.gpu_utilization:.1%}")
print("=" * 60)
# 持续监控
# while True:
# metrics = collect_metrics()
# print_dashboard(metrics)
# time.sleep(10)
9. SGLang vs vLLM 决策树
据 Particula Tech 和 Runpod 的综合分析,以下是 2026 年的选型决策树:
plaintext
你需要部署 LLM 推理服务?
│
├── 你的工作负载是什么?
│ │
│ ├── 多轮对话 / 聊天机器人
│ │ └── → SGLang ✅(RadixAttention 自动复用对话历史)
│ │
│ ├── RAG 流水线
│ │ └── → SGLang ✅(6.4x 吞吐优势,前缀缓存复用)
│ │
│ ├── Agent 工作流(多步调用共享上下文)
│ │ └── → SGLang ✅(跨请求 KV 缓存复用)
│ │
│ ├── 结构化输出(JSON/Schema 约束)
│ │ └── → SGLang ✅(XGrammar 快 3-10x)
│ │
│ ├── DeepSeek 模型
│ │ └── → SGLang ✅(3.1x 更快,官方推荐)
│ │
│ ├── 批量内容生成(每个 prompt 不同)
│ │ └── → vLLM(RadixAttention 无缓存收益)
│ │
│ ├── 需要最广硬件支持(TPU/Trainium/Gaudi)
│ │ └── → vLLM(更成熟的硬件生态)
│ │
│ └── 混合场景(部分有前缀共享,部分没有)
│ └── → SGLang(RadixAttention 开销仅 0.3%,无缓存时
│ 几乎零退化,有缓存时大幅加速)
│
└── 个人/实验用途
└── → Ollama / LM Studio
2026 年的简洁建议:
如果你做的是任何涉及共享前缀的工作负载(多轮对话、RAG、Agent、Few-shot),选 SGLang
如果你做的是纯批量生成、每个 prompt 都不一样,两者差异不大,vLLM 更成熟
如果你用 DeepSeek 模型,必须选 SGLang,没有第二个选项
10. 踩坑记录
10.1 RadixAttention 缓存命不中
现象:明明请求前缀相同,但缓存命中率极低,性能没有提升。
原因:前缀不是字节级一致的。哪怕一个空格、一个换行符的差异,都会导致 tokenizer 输出不同的 token ID,Radix Tree 匹配失败。
python
# ❌ 错误:System prompt 中有动态内容
system_msg = f"You are a helpful assistant. Current time: {time.now()}"
# ❌ 错误:Few-shot 示例的顺序不一致
few_shot = random.sample(examples, k=3) # 每次顺序不同
# ❌ 错误:文档列表没有排序
docs = retrieved_docs # 每次检索结果顺序可能不同
# ✅ 正确:固定前缀 + 排序文档
system_msg = "You are a helpful assistant." # 完全固定
few_shot = sorted(examples, key=lambda x: x["id"]) # 固定顺序
docs = sorted(retrieved_docs, key=lambda x: x.doc_id) # 按 ID 排序
10.2 共享内存不足
现象:Docker 启动后立刻 OOM 或进程崩溃,日志显示 "Unable to create shared memory"。
原因:Docker 默认的 /dev/shm 大小只有 64MB,SGLang 的多 GPU 通信需要大量共享内存。
bash
# ❌ 错误:使用默认共享内存
docker run --gpus all lmsysorg/sglang:latest ...
# ✅ 正确:设置足够大的共享内存
docker run --gpus all --shm-size 32g lmsysorg/sglang:latest ...
10.3 高并发下 Python GIL 瓶颈
现象:150+ 并发下,SGLang 的吞吐量反而不如 vLLM。
原因:据 mistral.rs#2011 的测试,SGLang 的 Python 路由管道受 GIL 限制,在极高并发 + 小模型场景下成为瓶颈。vLLM 的 PagedAttention 实现在 C++ CUDA 扩展中,绕过了 GIL。
解决方案:
对于大模型(70B+),这个瓶颈通常不存在(GPU 计算是瓶颈而非 CPU 调度)
减少单节点并发数,增加副本数(水平扩展)
关注 SGLang 后续版本的 C++/Rust 绑定优化路线
10.4 模型加载超时导致 K8s 健康检查失败
现象:Kubernetes 部署时,Pod 频繁重启,日志显示模型还没加载完就被杀掉。
原因:大模型加载到 GPU 需要数分钟,但 K8s 默认的 readinessProbe 超时太短。
yaml
# ❌ 错误:initialDelaySeconds 太短
readinessProbe:
httpGet:
path: /health
port: 30000
initialDelaySeconds: 30 # 70B 模型可能需要 5 分钟加载
periodSeconds: 5
# ✅ 正确:给足够的加载时间
readinessProbe:
httpGet:
path: /health
port: 30000
initialDelaySeconds: 300 # 至少 5 分钟
periodSeconds: 10
failureThreshold: 10 # 允许更多失败次数
10.5 Context Length 设置过大导致 OOM
现象:启动时直接 OOM,还没开始处理请求就挂了。
原因:--context-length 决定了预分配的 KV 缓存空间。设置过大,显存不够。
bash
# ❌ 错误:盲目设置最大上下文
--context-length 1000000 # 在显存不足时直接 OOM
# ✅ 正确:根据实际需求和显存调整
# 先用较小的值启动,确保能运行
--context-length 65536
# 然后根据监控数据逐步调整
--context-length 131072
# 最终确定最优值
--context-length 32768
# 同时降低静态显存分配比例
--mem-fraction-static 0.80 # 默认 0.88,留更多显存给 KV 缓存
10.6 量化模型精度问题
现象:AWQ/GPTQ 量化后的模型在某些场景下输出质量明显下降。
原因:SGLang 的 RadixAttention 在量化模式下可能引入微小的数值误差,这些误差在长链推理中会累积。
bash
# 如果精度敏感,降低量化等级
# AWQ int4 → GPTQ int8 或 BF16
--quantization awq_marlin # 使用 Marlin 内核加速 AWQ,精度更好
10.7 多模态请求显存爆炸
现象:发送高分辨率图片或长视频时,显存瞬间飙升然后 OOM。
原因:视觉 Token 的 KV 缓存比文本大得多,一张高分辨率图片可能生成数千个视觉 Token。
bash
# 限制多模态输入大小
--mm-process-config '{
"image": {"max_pixels": 1048576}, # 限制图片像素
"video": {"fps": 3, "max_pixels": 602112, "max_frames": 60}
}'
10.8 CUDA 版本不匹配
现象:启动报错 "CUDA version mismatch" 或找不到 CUDA kernel。
原因:SGLang 需要 CUDA 12.1+,但系统安装了旧版本。
bash
# 检查 CUDA 版本
nvidia-smi | head -3
# 确保 CUDA >= 12.1
# 如果系统 CUDA 太旧,使用 Docker 部署(内置正确版本)
docker run --gpus all lmsysorg/sglang:latest-runtime ...
# 对于 CUDA 13 环境(B300/GB300),使用专用镜像
docker pull lmsysorg/sglang:latest-cu130-runtime
10.9 Prefill-Decode 分离配置复杂
现象:启用 PD Disaggregation 后性能反而下降。
原因:PD 分离需要仔细配置 Prefill 和 Decode 节点的资源比例。如果比例不对,会导致某一侧成为瓶颈。
bash
# PD 分离适用于大规模集群(96+ GPU)
# 小规模部署(单节点/2-4节点)不建议使用
# 正确配置示例(96 GPU 集群)
# Prefill 节点:24 GPU(算力密集)
# Decode 节点:72 GPU(显存密集)
# 比例约 1:3
# 实测效果(96x H100, DeepSeek)
# Prefill 吞吐量: 3.8x 提升
# Decode 吞吐量: 4.8x 提升
11. 写在最后
11.1 SGLang 的 2026 年版图
据 PyPI 上 SGLang v0.5.12 的发布说明和 Fish Audio 的对比分析:
plaintext
SGLang 2026 年关键数据:
├── 25,000+ GitHub Stars
├── 400,000+ GPU 全球运行
├── 每日万亿级 Token 生成
├── 60+ LLM 家族支持
├── 30+ 多模态模型支持
├── 扩散模型支持(图像/视频生成,提速高达 5x)
├── TTS 支持(Fish Audio S2,前缀缓存命中率 86.4%)
├── DeepSeek V4 Day-0 支持
├── Llama 4 Scout/Maverick 支持
├── NVIDIA GB300 NVL72 25x 推理性能
├── 商业公司 RadixArk 背书(Accel 领投,估值 $400M)
└── a16z 开源 AI 基金第三批资助
11.2 什么时候该认真考虑 SGLang?
如果你满足以下任意一条,SGLang 值得你花时间:
你在做 RAG 应用 —— 6.4 倍加速不是理论数字,是可复现的
你在做多轮对话 —— RadixAttention 自动缓存历史,不用你操心
你在部署 DeepSeek —— SGLang 是官方推荐引擎,3.1x 更快
你需要结构化输出 —— XGrammar 比替代方案快 3-10 倍
你在做 Agent 工作流 —— 多步调用共享上下文,缓存复用是刚需
11.3 什么时候坚持 vLLM?
纯批量生成,每个 prompt 都不同 —— RadixAttention 无收益
需要最广硬件兼容 —— TPU、Trainium、Gaudi 只 vLLM 支持
团队已有 vLLM 运维经验 —— 迁移成本需要考虑
需要 encoder-decoder 模型 —— vLLM 支持更广
11.4 我的真实建议
据 CSDN 博客(https://blog.csdn.net/weixin_29069575/article/details/157380875)的实测结论:
仅开启 SGLang 默认配置,吞吐已比 vLLM 高出 84.6%;启用 RadixAttention 与结构化输出后,吞吐达 vLLM 基线的 2.87 倍。首 Token 延迟(TTFT)下降超 50%。
在 2026 年,如果你要部署 LLM 推理服务,默认选择 SGLang 是一个低风险高回报的决定。RadixAttention 的开销仅 0.3%,在最坏情况下(无缓存命中)几乎零退化,在最好情况下(多轮对话/RAG)带来数倍加速。
这不是赌注,这是数学。
作者:PySuper | 来源:zhengxingtao.com
本文所有基准数据均来自公开来源,具体引用已在正文中标注。建议读者根据自身硬件和工作负载进行独立验证。
参考来源:
Particula Tech: SGLang vs vLLM in 2026 (https://particula.tech/blog/sglang-vs-vllm-inference-engine-comparison)
LocalAIMaster: SGLang vs vLLM Comparison (https://localaimaster.com/blog/sglang-vs-vllm-comparison)
SGLang 官方文档: Llama4 Usage (https://sgl-project.github.io/basic_usage/llama4.html)
SGLang 官方文档: Multimodal Models (https://docs.sglang.io/supported_models/text_generation/multimodal_language_models.html)
SGLang 官方文档: Deploy on K8s (https://sgl-project.github.io/references/multi_node_deployment/deploy_on_k8s.html)
Runpod: SGLang in Production (https://www.runpod.io/articles/guides/blog-sglang-production-llm-pipelines)
WeavAI: SGLang 2026 Guide (https://weavai.app/blog/en/2026/04/24/sglang-2026-guide-fast-llm-inference-deployment/)
Fish Audio: 开源 LLM 推理引擎对比 2026 (https://fish.audio/zh-CN/blog/open-source-llm-inference-engines-2026/)
CSDN: SGLang推理框架实测 (https://blog.csdn.net/weixin_29069575/article/details/157380875)
CSDN: SGLang高性能推理部署框架 (https://blog.csdn.net/m0_47999117/article/details/160533498)
GitHub: mistral.rs#2011 Benchmark (https://github.com/EricLBuehler/mistral.rs/issues/2011)
SGLang PyPI: v0.5.12 (https://pypi.org/project/sglang/)
评论区