大模型推理引擎 2026 终极对决:vLLM vs SGLang,从 PagedAttention 到 RadixAttention,一次把 LLM 部署讲透(深度实战)
训练模型是把模型"教出来",部署模型才是把它"用起来"。2026 年,几乎所有后端团队都在面对同一个问题:同一张 GPU,凭什么别人的服务能扛 10 倍 QPS,你的却一上线就 OOM?答案不在模型,而在推理引擎。本文把 vLLM 和 SGLang 这两大主流引擎掰开揉碎,从 KV Cache 的显存账本,一直讲到 P/D 分离与量化部署,配可直接抄的生产级代码。
0. 为什么 2026 年每个工程师都该懂 LLM 部署
过去两年,"大模型"三个字几乎等于"训练"。但真正到生产环境跑业务时你会发现:训练是一次性的资本开支,推理是每天 24 小时持续的运营成本。一个 70B 的模型,训练可能烧了几百万,但上线后每个月光 GPU 租金和 latency 损失,才是长期流血点。
更残酷的现实是:GPU 显存是 LLM 服务里最稀缺的资源,没有之一。你花大价钱买回来的 H 卡,很多时候 GPU 利用率(MFU)还不到 40%——不是算力不够,而是引擎不会"调度"。
这就是为什么推理引擎(Inference Engine)成了 2026 年最值得投入学习的系统软件方向。它们干的事情,本质上是把操作系统、编译器和分布式系统的老把式,重新用在了 Transformer 上:
- 用分页的思路管理显存(vLLM 的 PagedAttention)
- 用前缀树的思路复用计算(SGLang 的 RadixAttention)
- 用批处理/调度的思路压榨吞吐(Continuous Batching)
- 用请求拆分的思路平衡延迟(Chunked Prefill、P/D 分离)
本文的主角是目前社区最活跃的两个开源引擎:vLLM(伯克利 LMSYS 系,生态最广)和 SGLang(前后端协同设计,性能与结构化生成见长)。我们不止讲概念,更要给出能跑的代码。
1. 核心概念:推理引擎到底在优化什么
1.1 KV Cache 与那本算不清的显存账
自回归生成是 LLM 推理的本质:每生成一个新 token,都要"回头看"之前所有 token 的注意力。为了避免重复计算,引擎会把每一层注意力算出来的 Key 和 Value 缓存下来,这就是 KV Cache。
KV Cache 显存占用公式:
KV Cache 大小 = 2 × 层数 L × 注意力头数 H × 每头维度 D × 序列长度 S × 每个元素字节数
以一个 70B 级别、上下文 32K 的模型为例:单层 KV 可能就占几百 MB,整段 32K 上下文的 KV Cache 可以轻松超过模型权重本身。换句话说,显存里大部分空间不是给模型参数用的,是给缓存用的。
传统做法的灾难在于:给每个请求预分配一整块连续显存,按"最大可能长度"来划。结果绝大多数请求用不到那么长,造成严重的内部碎片;而且哪怕两个请求的系统提示词完全相同,也各自复制一份 KV Cache——双重浪费。这就像给每个顾客都预租一整桌酒席,哪怕他只吃一口。
1.2 连续批处理(Continuous Batching)
早期方案是"静态批处理":凑够 N 个请求一起算,全部生成完才释放。问题是请求长短不一,短的早结束了还得陪跑,吞吐极低。
连续批处理(源自 Orca 论文的 iterative-level scheduling)的做法是:以"单步迭代"为粒度调度。每生成一个 token,调度器就重新决定下一步跑哪些请求——谁先生成完谁先走,新请求随时插入。这把 GPU 的利用率从"看运气"变成了"稳定拉满"。
1.3 分页注意力:vLLM 的 PagedAttention
vLLM 的核心创新,是借用了操作系统虚拟内存分页的思想。它把每个序列的 KV Cache 切成固定大小的 block(页),像页表一样用 block table 做映射:
- KV Cache 不再需要连续存储,物理显存可以分散存放,按需分配;
- 显存浪费被控制在 ~4% 以内;
- 更妙的是支持内存共享:多个请求若共享同一段前缀(比如同一段系统提示词),对应的 block 可以直接引用,不用复制。
# vLLM 离线推理的最小例子(V1 引擎)
from vllm import LLM, SamplingParams
prompts = [
"你好,请用一句话解释什么是 KV Cache:",
"用 Rust 写一个快速排序:",
]
# temperature=0.8, top_p=0.95, 最多生成 256 个 token
sampling_params = SamplingParams(temperature=0.8, top_p=0.95, max_tokens=256)
llm = LLM(model="Qwen/Qwen2.5-7B-Instruct", gpu_memory_utilization=0.90)
outputs = llm.generate(prompts, sampling_params)
for output in outputs:
print(f"Prompt: {output.prompt!r}")
for ot in output.outputs:
print(f" -> {ot.text}")
注意 gpu_memory_utilization=0.90 这一行——它告诉 vLLM 最多可以用掉 90% 的显存来装 KV Cache 池。PagedAttention 把这块池子切成一个个 block 统一管理,这就是高吞吐的来源。
1.4 基数注意力:SGLang 的 RadixAttention
SGLang 走了一条更"激进"的路。它不只在单个请求内部分页,而是把所有活跃请求的 KV Cache 用一棵**基数树(Radix Tree)**组织起来,全局共享。
机制如下:
- 每个请求的 token 序列被当成一条路径,逐层插入全局基数树;
- 新请求到来时,从根节点匹配最长公共前缀;
- 匹配到的部分直接复用已有 KV Cache,只重新计算差异部分;
- 节点带引用计数和最近访问时间,用于淘汰。
这意味着:同一系统提示词下的 100 个并发对话、同一份 RAG 文档的多次追问、多轮对话的历史上下文——它们的公共前缀只算一次。实测在多轮对话和共享前缀场景下,KV 缓存命中率可提升 3~5 倍,首 token 延迟显著下降。
PagedAttention 与 RadixAttention 的本质区别:前者解决"单请求内显存碎片",后者解决"跨请求计算复用"。vLLM 后来也通过 enable_prefix_caching 支持了前缀缓存,但 SGLang 把"前缀复用"做成了运行时的第一公民,配合基数树实现自动、细粒度的全局共享。
1.5 分块预填充(Chunked Prefill)
Transformer 推理有两个截然不同的阶段:
- Prefill(预填充):一次性处理整段输入提示词,算力密集、延迟高;
- Decode(解码):逐 token 生成,访存密集、latency 敏感。
如果不加控制,一个 8K token 的 prefill 会长时间霸占 GPU,把后面正在 decode 的请求"饿死",导致尾延迟(tail latency)飙升。
分块预填充把长 prefill 切成多个 chunk,和 decode 请求穿插执行,保证 GPU 时刻有活干,同时不让任何长请求独占资源。vLLM 通过 enable_chunked_prefill,SGLang 在运行时默认开启。
1.6 推测解码(Speculative Decoding)
Decode 阶段一次只产出一个 token,GPU 大量算力浪费在"等数据"上。推测解码的思路:用一个小而快的草稿模型(或 ngram/EAGLE/MTP 等机制)先"猜"出接下来 N 个 token,再用大模型并行验证——猜对了就一次性采纳多个,猜错就回退到正确的那个。
验证用的是"拒绝采样"(rejection sampling),数学上保证结果与原始大模型完全一致(不损失质量)。在草稿模型匹配度高的场景下,吞吐可提升 2~3 倍。
# vLLM 用 ngram 草稿做推测解码(无需额外模型)
vllm serve Qwen/Qwen2.5-7B-Instruct \
--speculative-model "[ngram]" \
--num-speculative-tokens 5 \
--ngram-prompt-lookup-max 4
1.7 P/D 分离(Disaggregated Prefill/Decode)
当流量大到一定程度,把 prefill 和 decode 放在同一批 GPU 上会互相干扰。P/D 分离的做法:用一组 GPU 专门做 prefill,另一组专门做 decode,中间通过高速网络传输 KV Cache(vLLM 用 Mooncake / NIXL connector,SGLang 也有对应方案)。
这能让 prefill 集群专注算力、decode 集群专注低延迟,整体资源利用率再上一个台阶。代价是引入 KV 传输的网络开销和系统复杂度。
1.8 量化(Quantization)
显存不够时,量化是性价比最高的手段:
- 权重量化:FP8 / INT4 / AWQ / GPTQ,把 16 位权重压到 8 位甚至 4 位;
- KV Cache 量化:把 KV 也降精度存储;
- 新兴的 FP4 在 2026 年的新硬件上开始落地。
量化能显著降显存、提吞吐,代价是极少量精度损失,对大多数业务可接受。
2. 架构分析:V1 引擎 vs SGLang 运行时
2.1 vLLM V1:集中式调度 + 分层执行
vLLM 在 2025–2026 年完成了向 V1 引擎的迁移。核心是一个叫 EngineCore 的集中式调度器,它在独立进程里持有全局视图,统一决定每一步跑哪些请求、分配哪些 KV block。
分层结构(从外到内):
API Server (OpenAI 兼容)
└─ Engine (接收请求, 输出生成结果)
└─ EngineCore / Scheduler (集中式调度, 全局唯一)
└─ Executor (MultiProcExecutor 负责多卡)
└─ Worker (每张 GPU 一个, 真正跑模型前向)
V1 的关键改进:调度与执行解耦、异步化、zero-copy 的数据通路,以及对 Speculative Decoding、Chunked Prefill、Prefix Caching、Guided Decoding、Disaggregated P/D 的一等支持。代码量约 77 万行(Python + CUDA 内核),是工程复杂度最高的开源推理引擎之一。
2.2 SGLang:前后端协同 + 零开销调度
SGLang 的设计哲学是"前后端协同(co-design)":
- 前端:一门领域特定语言(DSL),让你用近似 Python 的语法编排复杂 LLM 程序——多轮对话、任务规划、工具调用、JSON 结构化输出;
- 后端:一个极致优化的运行时,专注调度、内存管理与多卡并行。
其后端亮点:
- 零开销 CPU 调度器:调度决策几乎不占 CPU,把算力全留给 GPU;
- RadixAttention:全局前缀缓存,自动复用;
- 大规模专家并行(EP):对 DeepSeek 这类 MoE 模型做大规模专家并行 + 数据并行注意力,吞吐显著优于通用框架;
- 结构化输出:基于正则/有限状态机(FSM)的约束解码,强制模型输出合法 JSON / 特定格式;
- 量化支持 FP4/FP8/INT4/AWQ/GPTQ,以及 Torch 编译(torch.compile)加速。
2.3 设计哲学对比(一句话总结)
| 维度 | vLLM | SGLang |
|---|---|---|
| 定位 | 通用、生态最广的推理库 | 性能与结构化生成优先的运行时 |
| 缓存复用 | PagedAttention + prefix caching | RadixAttention 全局前缀树 |
| 强项场景 | 通用在线服务、社区插件多 | 多轮对话、共享前缀、MoE 大模型 |
| 编程模型 | OpenAI 兼容 API 为主 | 前端 DSL + 后端运行时协同 |
| 典型用户 | 想"开箱即用"接现有业务 | 追求极致吞吐 / 复杂 LLM 程序 |
两者的边界在 2026 年越来越模糊——vLLM 加了 prefix caching 和 disaggregated P/D,SGLang 也支持 OpenAI 兼容 API。选型更多是"场景 + 团队熟悉度"的权衡,而非能力有无。
3. 代码实战
3.1 安装
# 方式一:pip 安装 vLLM(需要 CUDA 环境)
pip install vllm
# 方式二:pip 安装 SGLang
pip install "sglang[all]"
# 方式三(推荐生产):Docker,避免环境踩坑
docker pull vllm/vllm-openai:latest
docker pull lmsysorg/sglang:latest
3.2 vLLM:从离线推理到在线服务
离线推理已见 1.3。生产环境通常用 OpenAI 兼容的服务:
# 启动一个 OpenAI 兼容的推理服务
vllm serve Qwen/Qwen2.5-7B-Instruct \
--host 0.0.0.0 --port 8000 \
--gpu-memory-utilization 0.90 \
--max-model-len 32768 \
--enable-prefix-caching \
--enable-chunked-prefill \
--tensor-parallel-size 1
客户端直接用 OpenAI SDK 调,零改造:
from openai import OpenAI
client = OpenAI(base_url="http://localhost:8000/v1", api_key="EMPTY")
resp = client.chat.completions.create(
model="Qwen/Qwen2.5-7B-Instruct",
messages=[
{"role": "system", "content": "你是一个严谨的中文技术助手。"},
{"role": "user", "content": "用三句话解释连续批处理。"},
],
temperature=0.7,
max_tokens=512,
)
print(resp.choices[0].message.content)
3.3 SGLang:启动服务 + 前端 DSL
# 启动 SGLang 服务(默认也是 OpenAI 兼容)
python -m sglang.launch_server \
--model-path Qwen/Qwen2.5-7B-Instruct \
--host 0.0.0.0 --port 30000 \
--tp 1 \
--mem-fraction-static 0.85 \
--context-length 32768
用 SGLang 前端 DSL 编排一个"带工具调用 + 结构化输出"的复杂程序:
import sglang as sgl
@sgl.function
def extract_user(s, text: str):
# 强制输出 JSON 结构(约束解码)
s += sgl.system("你只输出 JSON,不要解释。")
s += sgl.user(f"从下面文本抽取姓名和年龄:\n{text}")
s += sgl.gen("json",
regex=r'\{\s*"name"\s*:\s*"[^"]*",\s*"age"\s*:\s*\d+\s*\}')
state = extract_user.run(text="张三今年28岁,是一名后端工程师。")
print(state["json"])
# 输出类似:{"name": "张三", "age": 28}
注意 regex= 参数——SGLang 用正则驱动的约束解码,保证模型吐出来的一定是合法 JSON,省去你事后 json.loads 一直 try/except 的痛苦。
3.4 结构化输出实战
结构化输出是工程落地的刚需(喂给下游 API、存数据库)。两个引擎都支持:
vLLM(guided decoding):
from vllm import LLM, SamplingParams
schema = {
"type": "object",
"properties": {
"name": {"type": "string"},
"age": {"type": "integer"},
},
"required": ["name", "age"],
}
llm = LLM(model="Qwen/Qwen2.5-7B-Instruct", guided_decoding_backend="xgrammar")
out = llm.generate(
[{"prompt": "从'李四 35 岁'抽取信息:", "guided_json": schema}],
SamplingParams(temperature=0, max_tokens=128),
)
print(out[0].outputs[0].text) # 保证合法 JSON
SGLang(见 3.3 的 regex 用法),两者底层都用类似的 FSM/CFG 约束解码,区别在接口风格。
3.5 量化部署实战
# vLLM 加载 AWQ 量化模型(提前用 AutoAWQ 量化好)
vllm serve TheBloke/Qwen2.5-7B-Instruct-AWQ \
--quantization awq
# SGLang 加载 FP8 模型
python -m sglang.launch_server \
--model-path neuralmagic/Qwen2.5-7B-Instruct-FP8 \
--quantization fp8
量化能让你在单张消费级显卡上跑原本需要高端卡的大模型,是私有化部署的救命稻草。
3.6 P/D 分离部署(vLLM 示例)
# disaggregated_prefill.py 思路(精简版)
# 启动两个 vLLM 实例:prefill 用 GPU0,decode 用 GPU1,KV 通过连接器传输
from vllm import LLM, SamplingParams
from vllm.config import KVTransferConfig
# Prefill 节点
kv_config_p = KVTransferConfig(
kv_connector="MooncakeConnector",
kv_role="kv_producer",
)
llm_p = LLM(model="Qwen/Qwen2.5-7B-Instruct",
kv_transfer_config=kv_config_p,
gpu_memory_utilization=0.9)
# Decode 节点
kv_config_d = KVTransferConfig(
kv_connector="MooncakeConnector",
kv_role="kv_consumer",
)
llm_d = LLM(model="Qwen/Qwen2.5-7B-Instruct",
kv_transfer_config=kv_config_d,
gpu_memory_utilization=0.9)
生产环境通常用 NIXL / Mooncake 这类高性能 KV 传输连接器,配合负载均衡代理把请求路由到 prefill 再转 decode。
3.7 生产级 Docker Compose
# docker-compose.yml —— 单卡 vLLM 服务
services:
vllm:
image: vllm/vllm-openai:latest
runtime: nvidia
ipc: host
ports:
- "8000:8000"
volumes:
- ./models:/models
command: >
--model /models/Qwen2.5-7B-Instruct
--tensor-parallel-size 1
--gpu-memory-utilization 0.90
--max-model-len 32768
--enable-prefix-caching
--enable-chunked-prefill
deploy:
resources:
reservations:
devices:
- driver: nvidia
count: 1
capabilities: [gpu]
3.8 基准测试:别拍脑袋,看数字
# vLLM 自带压测工具,测量 TTFT / TPOT / 吞吐
python -m vllm.entrypoints.openai.cli.benchmark.serve \
--backend vllm \
--model Qwen/Qwen2.5-7B-Instruct \
--dataset-name sharegpt \
--num-prompts 1000 \
--request-rate 16
# SGLang 自带压测
python -m sglang.bench_serving \
--backend sglang \
--model-path Qwen/Qwen2.5-7B-Instruct \
--dataset-name sharegpt \
--num-prompts 1000 \
--request-rate 16
关注三个核心指标:TTFT(首 token 延迟,受 prefill 影响)、TPOT(每 token 延迟,受 decode 影响)、吞吐(请求/秒或 token/秒)。延迟和吞吐天然冲突,调优就是在这条曲线上找业务平衡点。
4. 性能优化:怎么选、怎么调
4.1 选型决策树
- 通用在线服务、要接一堆现成业务、社区插件多 → 选 vLLM,OpenAI 兼容 + 生态最稳。
- 多轮对话 / 大量共享前缀 / RAG 反复追问同一文档 → 优先考虑 SGLang,RadixAttention 的复用收益明显。
- DeepSeek 等 MoE 大模型、追求极致吞吐 → SGLang 的大规模专家并行更占优。
- 需要复杂 LLM 程序编排(工具调用、结构化输出、控制流) → SGLang 前端 DSL 更顺手;vLLM 也能做,但偏底层。
- 不确定 → 两个都跑一遍 bench_serving,用真实流量分布比数字,别凭感觉。
4.2 双方通用调优清单
| 参数 | 作用 | 建议 |
|---|---|---|
gpu_memory_utilization / mem-fraction-static | KV 池占显存比例 | 0.85~0.92,留点余量防 OOM |
max_model_len | 最大上下文 | 别盲目设 128K,按真实分布设,省显存 |
enable_prefix_caching / RadixAttention | 前缀复用 | 多轮/共享前缀场景务必开 |
enable_chunked_prefill | 长 prefill 切片 | 高并发必开,降尾延迟 |
--speculative-model | 推测解码 | 草稿匹配度高时 +2~3x 吞吐 |
tensor_parallel_size / --tp | 多卡张量并行 | 模型放不下时加 |
4.3 量化取舍
- 显存吃紧 → 上 AWQ / GPTQ(INT4),精度损失小;
- 新硬件(支持 FP8)→ FP8 几乎无损且最快;
- 极致压缩 → 试 FP4(2026 新兴,需硬件支持);
- KV Cache 也建议量化,长上下文场景省得最多。
4.4 多卡与分布式
- TP(张量并行):单节点多卡切模型,最常用;
- PP(流水线并行):模型特别深时切层;
- EP(专家并行):MoE 专用,SGLang 对 DeepSeek 类做得最好;
- DP(数据并行):多副本扛并发,配合前缀共享。
4.5 监控
把 TTFT、TPOT、GPU 利用率、KV Cache 命中率做成 dashboard。KV Cache 命中率低?说明前缀没复用上,检查 system prompt 是否一致、是否开了 prefix caching。GPU 利用率忽高忽低?多半是 prefill/decode 互相干扰,考虑 chunked prefill 或 P/D 分离。
5. 总结与展望
2026 年的 LLM 推理引擎,早已不是"能把模型跑起来"那么简单,而是一场围绕显存、调度、复用的系统工程较量:
- vLLM 用 PagedAttention + V1 集中式调度,把"通用高吞吐推理"做到了极致,生态与兼容性无出其右;
- SGLang 用 RadixAttention + 前后端协同,把"前缀复用"和"结构化生成"做到了极致,尤其在多轮对话、MoE 大模型上锋利。
几个明确的趋势:
- P/D 分离 会从"大厂专属"下沉到中小团队,KV 传输连接器(NIXL/Mooncake)越来越标准化;
- 长上下文 推动 KV Cache 量化、分层缓存(如 HiCache)成为标配;
- 多模态统一:SGLang 已支持扩散模型、VLM,推理引擎正变成"生成式 AI 的统一运行时";
- 异构硬件:FP4、NPU、国产加速卡会被引擎快速吸收。
一句话选型建议:求稳、求生态、求通用 → vLLM;求快、求复用、求复杂编排 → SGLang;真要上生产,两个都 bench 一遍,让真实流量分布替你拍板。
本文代码均可在对应引擎最新版本运行;版本迭代快,具体参数以官方文档为准。动手前先
bench_serving,别让直觉替你做性能决策。
参考资源
- vLLM 官方文档与 GitHub(PagedAttention、V1 Engine 架构解析)
- SGLang 官方文档与 GitHub(RadixAttention、大规模专家并行博客)
- Orca: 《Efficient Memory Management for LLM Serving with PagedAttention》
- 各引擎自带
bench_serving压测工具与示例