副标题: 2026 年的 LLM 推理引擎格局已经清晰------vLLM 是生产部署的事实标准,SGLang 在 Agent 和结构化输出场景独占鳌头,TensorRT-LLM 是 NVIDIA 硬件上的性能天花板。本文从架构哲学、调度策略、KV Cache 管理、编译优化到实测性能,做一次三强全面对比。
一、引子:三个引擎,三套哲学
先说结论、再讲细节。2026 年的推理引擎图谱,三者的定位早已分道扬镳:
| vLLM | SGLang | TensorRT-LLM | |
|---|---|---|---|
| 出身 | UC Berkeley (2023) | Stanford (2024) | NVIDIA (2023) |
| 核心理念 | 调度引擎 | 语言+调度引擎 | 编译引擎 |
| 优化重心 | KV Cache 管理 + 调度 | KV Cache 管理 + 结构化输出 | GPU Kernel 编译 + 融合 |
| 模型兼容 | 最广(HuggingFace 90%+) | 很广(vLLM 基础上扩展) | 有限(主流架构 + 手动适配) |
| 部署复杂度 | 低 | 中 | 高 |
| 性能上限 | 高 | 很高 | 最高 |
注意:如果你还没读过本系列的 第 17 篇,建议先回去看------那篇深入拆解了 PagedAttention、Continuous Batching 和 RadixAttention 的底层原理。本篇是它的续篇:在理解原理的基础上,看三个引擎如何把这些技术落地,以及在实战中怎么选。
二、架构哲学:三条完全不同的路线
三个引擎的差距,根源在它们对"推理引擎该做什么"的定义完全不同。
2.1 vLLM:调度优先的通用引擎
vLLM 的定位是 "GPU 上的操作系统调度器"------核心工作是管理好显存、排好批次、调度好请求。它不强求极致性能,但追求:
- 开箱即用:HuggingFace 上下载的模型,90% 以上加载就能跑
- 生态兼容:OpenAI API 格式、LoRA 热切换、多模型并行
- 硬件广泛:NVIDIA、AMD、Intel、AWS Trainium、Google TPU 都支持
vLLM 的架构决策是"把调度做到极致,计算交给别人的 kernel"------它用 PagedAttention + Continuous Batching 最大化 GPU 利用率,但 attention 计算本身用的是 FlashAttention 或别人的 kernel。这层"调度和计算分离"的设计让它适配性极强,但也意味着在特定硬件上跑不出 NVIDIA 原生的极致性能。
2.2 SGLang:语言是一等公民
SGLang 的出发点是:"推理引擎不应该只调度张量,它应该理解程序的意图。"
SGLang 引入了一套前端 DSL(领域特定语言),让你可以用声明式的方式描述 "我要先做 prompt A、然后调 tool B、再用结果约束生成格式 C"。引擎收到这个"程序"后,可以:
- 分析哪个前缀可以被缓存
- 自动插入结构化约束解码
- 跨请求优化调度顺序
这个设计决策的后果是:SGLang 在三个引擎中最"重"------它不仅管调度,还管语言解析、约束执行和推理优化。但也是这个"重"让它在 Agent、多轮对话、RAG 场景下能比 vLLM 快 3-5 倍。
SGLang 在调度层继承了 vLLM 的大部分设计(PagedAttention、Continuous Batching),但在 KV Cache 管理上改用 RadixAttention(第 17 篇详述),在多轮对话/Agent 场景有质的优势。
2.3 TensorRT-LLM:编译器路线,把 GPU 榨干
TensorRT-LLM(简称 TRT-LLM)的定位完全不同------它是一套编译器。你把模型定义和配置扔进去,它花 15-30 分钟编译出一个高度优化的 GPU 可执行程序,然后上线运行。
编译路线的好处:
- 算子融合:多个小 kernel 合并成一个大 kernel,减少 kernel launch 开销
- 内存规划:提前算好每层的显存分配,运行时零动态分配
- 量化原生:FP8/INT4 直接在 Tensor Core 上算,不需要反量化
- 自动调优:对当前硬件做 auto-tuning,选最快的 kernel 实现
代价是:
- 换模型、换 GPU、改精度------都要重新编译
- 调试困难(编译出来的不是人能看懂的代码)
- 只支持 NVIDIA GPU
三者路线对比
vLLM: 调度层(极致优化)← 计算层(借别人的 kernel)
SGLang: 语言层(前端 DSL)→ 调度层(RadixAttention)→ 计算层
TRT-LLM: 编译层(全链路融合)→ 运行时几乎无调度开销
三、调度与批处理:Continuous Batching 的三副面孔
第 17 篇讲过 Continuous Batching 的核心思想------每步 token 后重新组批,长 prompt 切碎混排。但三个引擎在"具体怎么排"上有不小差异。
3.1 vLLM:最成熟的调度器
vLLM 的调度器三层结构:
等待队列 ─→ 调度策略 ─→ 当前运行集 ─→ 模型前向
│
└→ 抢占策略(recompute / swap)
调度策略要点:
- Decode 优先:所有正在生成 token 的请求优先调度
- Chunked Prefill 填空:用剩余的 token 预算调度 prefill chunk
- 配额控制 :
max_num_seqs(最大并发请求数)和max_num_batched_tokens(每步最大 token 数)双重限制
抢占策略(显存不够时):
- 默认 recompute:丢弃 KV Cache,后续重新 prefill
- 可选 swap:KV Cache 换出到 CPU 内存
vLLM 的调度器经过两年生产验证,在各种极端场景下都有不错的鲁棒性。
3.2 SGLang:更激进的调度
SGLang 在调度层做了几个关键改进:
更小的调度粒度:
- vLLM 以请求为单位调度,SGLang 以 token 为单位调度
- 配合 RadixAttention 的 page_size=1,SGLang 可以精确到每个 token 的调度优先级
Prefill 和 Decode 分离(Disaggregated Prefill):
- 解耦后,prefill 节点专注 compute-heavy 的前向,decode 节点做 memory-bound 的自回归
- 不同节点可以有不同的 batch 策略和硬件配置
前瞻调度(Lookahead Scheduling):
- SGLang 在调度当前步时,预读下一步的请求队列
- 如果发现后续请求与当前请求共享前缀,可以提前合并调度
3.3 TensorRT-LLM:最底层的调度
TRT-LLM 的调度叫 In-Flight Batching(IFB)------和 Continuous Batching 本质相同,但实现更底层。
关键差异 1:调度在内核里
vLLM 和 SGLang 的调度器在 Python 层,TRT-LLM 的调度器在 C++ runtime 层,深度嵌入到 CUDA stream 管理中。这意味着调度决策可以和 kernel 执行 pipeline 在一起。
关键差异 2:两个关键参数
max_batch_size:最大并发请求数max_num_tokens:每步最大 token 数
这两个参数决定了 TRT-LLM 的资源预算。配大了浪费显存,配小了限制吞吐。生产调优的核心工作就是做这两者的 grid search。
关键差异 3:三种调度策略
| 策略 | 行为 | 适用场景 |
|---|---|---|
GUARANTEED_NO_EVICT(默认) |
请求一旦开始,绝不驱逐 | 延迟敏感,在线服务 |
MAX_UTILIZATION |
尽可能多的请求,可能驱赶 | 吞吐优先,批处理 |
STATIC_BATCH |
传统静态批处理 | 不推荐生产使用 |
双参数调优实测效果(Llama 3.3 70B,4×H100):
max_batch_size 64 → 1944 tok/s (baseline)
max_batch_size 512 → 2467 tok/s (+27%)
+ max_num_tokens 2048 → 2474 tok/s
+ 组合调优 → 3074 tok/s(+58% 总提升)
三引擎调度对比一览:
| 特性 | vLLM | SGLang | TensorRT-LLM |
|---|---|---|---|
| 调度实现层 | Python | Python | C++ Runtime |
| 调度粒度 | 请求级 | Token 级 | 请求级 + kernel 级 |
| Prefill/Decode 分离 | ❌(计划中) | ✅ 原生支持 | ✅(Disagg 模式) |
| 长 prompt 切分 | Chunked Prefill | Chunked Prefill | Chunked Context |
| 抢占策略 | Recompute / Swap | Recompute | Evict / Guarantee |
| 调优复杂度 | 低 | 中 | 高(需 grid search) |
四、KV Cache 管理:从原理到实践
第 17 篇深入解释了 PagedAttention 和 RadixAttention 的原理。这里只聚焦三引擎在工程实现上的关键差异。
4.1 前缀缓存机制的对比
| vLLM | SGLang | TensorRT-LLM | |
|---|---|---|---|
| 机制 | 哈希表 Block 级 | Radix Tree Token 级 | Block 级(block_reuse) |
| 匹配精度 | 16-token Block | 逐 token | Block 级 |
| 淘汰策略 | 平坦 LRU | 树感知 LRU(先删叶子) | 优先级驱动 |
| 多轮对话优势 | 1x(baseline) | 3-5x | ~1.2x(有限复用) |
一个典型 RAG 场景的数据(100 并发,60% 文档重叠):
无缓存: 225K token/批的 prefill
vLLM APC: 125K token/批(优化 -44%)
SGLang: 65K token/批(优化 -71%)
TRT-LLM: 120K token/批(block_reuse 开启后的近似值)
SGLang 的 RadixAttention 在高并发共享前缀场景下优势明显,而且差距随着前缀长度增加而扩大。
4.2 TensorRT-LLM 的 Paged KV Cache
TRT-LLM 也支持 Paged KV Cache,有两个重要参数:
json
{
"kv_cache_config": {
"free_gpu_memory_fraction": 0.85,
"enable_block_reuse": true
}
}
enable_block_reuse 开启后,TRT-LLM 会缓存共享前缀的 Block。但和 SGLang 的 Radix Tree 不同,TRT-LLM 的复用是 Block 级的,只能在 16-token 边界上匹配,精细度不如 SGLang。
五、编译优化:TensorRT-LLM 的杀手锏
这是三个引擎最大的性能差距来源。
5.1 TensorRT-LLM 的编译流程
TRT-LLM 部署一个模型需要经过:
模型权重 + 配置
↓
图构建(build graph):将 PyTorch/FasterTransformer 模型转成 TRT-LLM 内部 IR
↓
图优化(graph optimization):算子融合、死代码消除、常量折叠
↓
自动调优(auto-tuning):对每个 fused kernel 搜索最优配置(block size, grid size...)
↓
内存规划(memory planning):提前分配所有 tensor 的物理地址
↓
序列化(serialization):生成 .engine 文件,部署时加载
编译完成后,推理时的调度开销基本归零------所有资源分配在编译期就确定了。
典型编译时长:
| 模型 | GPU | 编译时间 |
|---|---|---|
| Llama 2 7B | H100 | 5-10 min |
| Llama 3 70B | H100 | 15-25 min |
| Mixtral 8x7B | H100 | 20-35 min |
5.2 vLLM 和 SGLang 的编译策略
vLLM 和 SGLang 不做 AOT(ahead-of-time)编译。它们采用折中方案:
CUDA Graph 捕获:
-
在推理启动前,对固定 batch size 的模型前向做一次 CUDA Graph capture
-
将多次 kernel launch 打包成一个 graph,减少 CPU→GPU 通信开销
-
问题:只在固定 batch size 下有效,batch 变化需要重新 capture
无 CUDA Graph: 每次迭代 N 次 kernel launch(每个算子一次)
有 CUDA Graph: 每次迭代 1 次 graph launch,graph 内部包含所有 kernel
FlashAttention / PagedAttention kernel:
- 这些 kernel 本身是高优化的手动实现
- 但每个 kernel 之间仍是独立的------缺少 TRT-LLM 的跨算子融合
vLLM/SGLang 的 CUDA Graph 策略:
- 预设一批 batch size(如 1, 2, 4, 8, 16, 32...)
- 每次推理前选最接近的已捕获 graph
- 多出的 token 做 padding
SGLang 0.6+ 引入了 FlashInfer 作为 unified kernel backend,让 attention 的 kernel 融合度更高。
5.3 这个差距实际有多大?
一个典型的 decode 迭代:
vLLM/SGLang:
Layer 0: launch RMSNorm → launch Attention → launch Add → launch FFN → ...
Layer 1: launch RMSNorm → launch Attention → launch Add → launch FFN → ...
... 32-80 层
→ 每次迭代约 100-200 次 kernel launch
TensorRT-LLM (编译后):
每次迭代 → 1-2 次 fused kernel launch(合并了相邻的小算子)
→ CPU 调度开销接近于零
在 batch size 较小时(1-16),kernel launch 开销占比显著,此时 TRT-LLM 的融合优势最明显。随着 batch 增大,计算本身成为瓶颈,融合收益相对降低。
六、量化:FP8/INT4 的原生计算 vs 后量化
这是一个经常被低估的差异点。
6.1 TensorRT-LLM:量化就是计算精度
TRT-LLM 在做编译时,会为量化精度专门生成计算 kernel:
FP16 engine: 用 FP16 Tensor Core 计算
FP8 engine: 用 FP8 Tensor Core 计算(H100 原生支持)
INT4 engine: 用 INT4 Tensor Core 计算(Blackwell 原生支持)
INT8 engine: 用 INT8 Tensor Core 计算(所有架构都支持)
这意味着 TRT-LLM 跑 FP8 时,计算和存储都在 FP8,不需要反量化。H100 的 FP8 Tensor Core 算力是 FP16 的 2 倍,这是实打实的吞吐翻倍。
6.2 vLLM 和 SGLang:量化主要是省显存
vLLM 和 SGLang 的量化实现主要来自 AWQ / GPTQ 等权重量化方案:
存储: FP16 权重 → INT4 权重(4x 压缩)
计算时: INT4 → 反量化 → FP16 → FP16 matmul
省了显存,但计算时先反量化再计算------INT4 的算力优势没有直接转化为速度优势(因为计算还是 FP16 的)。你省的是 HBM 带宽(少读了 4x 的权重),不是计算 FLOPs。
vLLM/SGLang 量化流程:
从 HBM 读 INT4 权重 → 反量化为 FP16 → 在 FP16 Tensor Core 上计算
TRT-LLM FP8 流程:
从 HBM 读 FP8 权重 → 直接在 FP8 Tensor Core 上计算
→ 省带宽 + 省计算(H100 FP8 TFLOPs = 2× FP16 TFLOPs)
6.3 实际影响
| 场景 | vLLM AWQ | TRT-LLM FP8 | 差距 |
|---|---|---|---|
| DeepSeek V4-Flash 284B (4×H100) | 1,850 tok/s | 2,312 tok/s | +25% |
| 显存占用 | 同 | 同(FP8 也是 1 byte/param) | --- |
| 精度损失 | 极小(AWQ 校准) | <1% | --- |
TRT-LLM 的 FP8 同时省带宽和省算力,而 AWQ 只省带宽。这就是为什么 TRT-LLM 在支持 FP8 的硬件上总是最快的。
七、性能基准对比:一张表看清差距
7.1 小模型单卡测试(H100,Qwen2.5-7B,FP8/BF16)
输入 512 tokens,输出 256 tokens:
| 并发 | vLLM | SGLang | TRT-LLM |
|---|---|---|---|
| 16 | 11,200 tok/s | 12,800 tok/s (+14%) | 14,500 tok/s (+29%) |
| 64 | 18,400 tok/s | 21,600 tok/s (+17%) | 23,800 tok/s (+29%) |
| 128 | 22,100 tok/s | 27,300 tok/s (+23%) | 26,500 tok/s (+20%) |
P99 延迟:
| 并发 | vLLM | SGLang | TRT-LLM |
|---|---|---|---|
| 16 | 680 ms | 620 ms | 540 ms |
| 64 | 1,240 ms | 980 ms | 860 ms |
| 128 | 2,800 ms | 1,900 ms | 2,100 ms |
分析:
- 中低并发(16-64):TRT-LLM 的编译优化和 FP8 原生计算带来稳定的吞吐优势
- 高并发(128):SGLang 的 RadixAttention 前缀复用效果显著,吞吐反超 TRT-LLM,P99 延迟最优
7.2 大模型多卡测试(DeepSeek V4-Flash 284B MoE,4×H100,FP8)
| 引擎 | 吞吐 (tok/s) | TTFT (ms) | TPOT (ms) | P99 延迟 |
|---|---|---|---|---|
| TRT-LLM FP8 | 2,312 | 89 | 18 | 210 ms |
| SGLang FP8 | 2,150 | 92 | 22 | 195 ms |
| vLLM AWQ | 1,850 | 105 | 25 | 240 ms |
TRT-LLM 的 FP8 优势在 MoE 模型上同样明显,而 SGLang 在尾延迟控制上更好(RadixAttention 减少调度抖动)。
7.3 RTX 4090 单卡测试(Qwen2.5-1.5B)
| 指标 | TRT-LLM | SGLang | vLLM |
|---|---|---|---|
| TTFT 均值 | 224.0 ms | 179.2 ms | 531.1 ms |
| TTFT 最小值 | 223.5 ms | 38.6 ms(缓存命中) | 506.3 ms |
| TTFT 最大值 | 227.7 ms | 480.6 ms(缓存未命中) | 555.1 ms |
| 抖动范围 | 4 ms | 441 ms | 49 ms |
这个测试揭示了三个引擎的极端差异:
- TRT-LLM:延迟最低且最稳定(抖动仅 4ms),适合延迟敏感场景
- SGLang:缓存命中时极快(38.6ms),缓存未命中时波动大
- vLLM:延迟最高,但胜在稳定性和兼容性
八、部署运维实战
8.1 部署复杂度
vLLM(最简单):
pip install vllm
vllm serve meta-llama/Llama-3.1-8B --port 8000
→ 5 分钟内启动
SGLang(也简单):
pip install sglang
python -m sglang.launch_server --model meta-llama/Llama-3.1-8B
→ 5 分钟内启动
TRT-LLM(最复杂):
# 1. 拉 Docker 镜像
docker pull nvidia/cuda:12.8-devel
# 2. 安装 TRT-LLM
pip install tensorrt_llm
# 3. 将 HuggingFace 模型转成 TRT-LLM 格式
python examples/llama/convert_checkpoint.py --model_dir ... --output_dir ...
# 4. 编译 engine
trtllm-build --checkpoint_dir ... --output_dir ... --model_config config.json
# 5. 启动服务
python examples/run.py --engine_dir ...
→ 首次部署 30-60 分钟
8.2 模型变更成本
| 场景 | vLLM | SGLang | TRT-LLM |
|---|---|---|---|
| 换模型权重 | 重启即换 | 重启即换 | 重新编译(15-30 min) |
| 换精度(FP16→FP8) | 换权重即可 | 换权重即可 | 重新编译 |
| 换 GPU 架构 | 不需要改 | 不需要改 | 重新编译 |
| 加 LoRA adapter | 运行时热切换 ✅ | 运行时热切换 ✅ | 需要重新编译 ❌ |
这是 TRT-LLM 最大的痛点:编译后一切都被固定了。如果你有三套模型要部署,就得编三次。如果每个模型还要跑 FP16 和 FP8 两种精度,编译次数×2。
8.3 硬件支持矩阵
| 硬件 | vLLM | SGLang | TRT-LLM |
|---|---|---|---|
| NVIDIA H100/B200/RTX | ✅ 最佳 | ✅ 最佳 | ✅独占(必须 NVIDIA) |
| AMD MI300X | ✅ 社区支持 | ❌ 有限 | ❌ |
| Intel Gaudi 3 | ✅ 社区支持 | ❌ | ❌ |
| Google TPU | ✅ 实验性 | ❌ | ❌ |
| 华为昇腾 910B | ⚠️ 第三方移植 | ❌ | ❌ |
| Apple Silicon(MPS) | ⚠️ 实验性 | ❌ | ❌ |
vLLM 在硬件兼容性上有明显优势------社区驱动的 ROCm、Intel XPU、TPU 后端持续在完善。
九、选型决策框架
9.1 一张速查表
| 你的需求 | 首选 | 备选 | 原因 |
|---|---|---|---|
| 快速上线、原型验证 | vLLM | SGLang | 部署最简单,兼容性最好 |
| Agent / 多轮对话 | SGLang | vLLM | RadixAttention 多轮 3-5× |
| 结构化输出(JSON) | SGLang | vLLM + Guidance | 原生约束解码 |
| 极致吞吐、8×H200 | TRT-LLM | SGLang | FP8 原生计算 10-30% 领先 |
| 低延迟(对话类) | TRT-LLM | SGLang | 编译融合,无调度抖动 |
| LoRA 多适配器切换 | vLLM | SGLang | 原生支持,运行时热切换 |
| 国产 GPU 部署 | vLLM | --- | 唯一有社区移植的引擎 |
| 模型频繁换 / A/B 测试 | vLLM | SGLang | 重启即换,不用等编译 |
| 混合模型服务 | vLLM | SGLang | 多模型并行最成熟 |
9.2 务实路径:从 vLLM 起步,用 SGLang 补齐 Agent
大多数团队的进化路线:
第一阶段:vLLM
- 快速上线第一版 API
- 用 AWQ/GPTQ 量化降低显存需求
- 确认推理成为瓶颈后进入下一阶段
第二阶段:vLLM + SGLang 混用
- 简单场景(单轮生成、批量推理)继续用 vLLM
- Agent 场景、高并发前缀共享场景切换到 SGLang
- 两个引擎可以跑在同一套 GPU 集群上
第三阶段(可选):引入 TRT-LLM
- 当性能需求超过 vLLM/SGLang 能提供的
- 且模型固定不再频繁迭代
- 重点场景只部署在 NVIDIA 最新硬件上
- vLLM/SGLang 仍作为灵活性兜底
9.3 一个决定性的问题
在你纠结选哪个引擎之前,先回答这个问题:
你的模型明年还长这样吗?
- 如果答案是否定的 → 选 vLLM。灵活性比那 20-30% 的性能提升值钱得多。
- 如果你在做一个 Agent 平台,对话流程非常复杂 → 选 SGLang。RadixAttention + 结构化输出是别家没有的硬核优势。
- 如果你在做一个长期稳定的 SaaS,模型固定不变,NVIDIA 硬件专享 → 可以考虑 TRT-LLM,但要算清楚编译维护成本。
十、总结
核心数据回顾
| 维度 | vLLM | SGLang | TensorRT-LLM |
|---|---|---|---|
| 通用吞吐(7B, H100, 64并发) | 18.4K tok/s | 21.6K tok/s (+17%) | 23.8K (+29%) |
| 大模型吞吐(284B MoE, 4×H100) | 1.85K tok/s | 2.15K tok/s | 2.31K tok/s |
| 高并发 P99 延迟(128并发) | 2,800 ms | 1,900 ms | 2,100 ms |
| 延迟抖动(4090, TTFT) | 49 ms | 441 ms | 4 ms |
| Agent/多轮/结构化 | 一般 | 最佳 | 不支持 |
| 部署到上线 | 5 min | 5 min | 30-60 min |
| 模型变更成本 | 重启 | 重启 | 重新编译 |
| 硬件兼容 | 最广 | NVIDIA 为主 | 仅 NVIDIA |
给读者的建议
不要为了 20% 的性能提升选一个你最不熟悉的框架。 vLLM 和 SGLang 之间的差距(大部分场景在 15-25% 之间)往往小于你调优提示词、优化 batch 策略、选择合适的量化方式带来的收益。
三引擎的格局和它们的定位非常吻合:
vLLM 是"够用+灵活"------适合大多数人和大多数场景。
SGLang 是"场景特化"------如果你正好在它擅长的领域(Agent/结构化/多轮),它能给你别处拿不到的收益。
TRT-LLM 是"性能天花板"------但它有价格:灵活性、兼容性、运维便利性。
先看清自己的需求,再选引擎。如果看不清楚,从 vLLM 开始总是对的。