同一个模型 checkpoint,放进不同推理引擎后,输出速度、可承载并发和部署复杂度可能完全不同。原因是模型权重只定义了“算什么”,没有定义请求如何排队、KV Cache 如何分配、多个请求怎样组成 batch、选哪个 GPU kernel,以及结果如何流式返回。

vLLM、SGLang 和 TensorRT-LLM 都覆盖了这条路径的大部分环节,功能也在持续交叉。把它们简单概括成“通用、Agent、极致性能”很方便,却不足以做工程决策。真正的选型问题是:在同一模型、同一硬件和同一流量下,哪套系统更稳定地满足延迟目标,并且团队能够长期维护。

本文按 2026-08-09 的官方文档校订。推理引擎变化很快,具体模型、量化和后端支持应在采用时重新查阅支持矩阵。文中不保留脱离测试条件的固定吞吐排名。

从一次请求看推理引擎的职责

用户发送一条 Chat Completions 请求后,至少经过下面几层:

HTTP / RPC request
        │
        ▼
API validation + chat template + tokenizer
        │
        ▼
request queue + admission control
        │
        ▼
scheduler + KV cache manager
        │
        ▼
model runner + attention/GEMM/communication kernels
        │
        ▼
logits processing + sampling + detokenization
        │
        ▼
streaming response + metrics + cancellation

推理引擎的核心工作,可以归结为持续重复两个动作:

  1. 从所有等待和运行中的请求里,决定这一轮计算哪些 token;
  2. 把这些 token 组织成 GPU 能高效执行的输入,并正确维护每个请求的状态。

这比离线执行一次 model.generate() 复杂得多。请求长度不同、到达时间不同,用户还可能中途取消;系统既要填满 GPU,又不能让排队时间无限增长。

五个指标描述的是不同体验

假设一个请求输入 1000 token,输出 200 token:

  • TTFT(Time to First Token):从请求到达,到收到第一个输出 token;包含排队、tokenization 和 prefill。
  • TPOT(Time per Output Token):开始生成后,相邻输出 token 的平均间隔;主要反映 decode 体验。
  • ITL(Inter-token Latency):逐 token 间隔的分布,可发现偶发卡顿,不能总被平均 TPOT 代表。
  • E2E latency:请求到完整响应结束的时间。
  • Throughput:单位时间处理的 request 或 token 数。

在线服务还常使用 goodput:在给定 SLO 内完成的有效吞吐。例如要求 TTFT P99 小于 2 秒、TPOT P99 小于 80 ms,那么超时请求产生的 tokens/s 再高,也不算满足目标的容量。

这些指标会互相牵制。调度器等待更多请求组成大 batch,可以提高吞吐,却增加排队时间;长 prefill 与 decode 混跑能提高 GPU 利用率,却可能让正在流式输出的用户突然卡顿。

因此,“某引擎有 10 万 tokens/s”至少还缺少:输入/输出长度、请求率、并发、GPU、模型、精度、并行度和延迟分位数。没有这些条件,数字无法用于选型。

先定义工作负载,再讨论引擎

三个常见场景的最优目标就不相同。

在线聊天

请求持续到达,输入中等、输出较长,用户直接感知流式速度。重点是 P95/P99 TTFT、TPOT、取消响应和高负载下的稳定性,而不是无限队列下的峰值吞吐。

RAG 与 Agent

system prompt、工具 schema 或文档前缀可能在请求间重复;输入很长,单次输出未必长。前缀缓存命中、structured output、tool calling、长 prefill 的调度公平性和多轮状态会明显影响结果。

离线批处理

请求已提前准备,通常没有严格 TTFT。引擎可以使用更大的 batch,目标偏向总完成时间、tokens/s 和单位 token 成本。在线服务中的队列公平性在这里不一定重要。

此外还要明确:

  • 模型是 dense、MoE 还是多模态;
  • 权重、激活与 KV Cache 使用何种精度;
  • 单机还是多机,互联是 PCIe、NVLink 还是网络;
  • 是否需要 LoRA、推测解码、grammar、embeddings 或 rerank;
  • 流量是稳定、突发,还是明显共享前缀。

只有这些条件固定后,引擎之间的比较才有意义。

三个引擎的设计重心

下表描述的是评估入口,不是功能边界。三者都在快速吸收其他系统的能力。

维度 vLLM SGLang TensorRT-LLM
主要入口 Python/offline 与兼容多种 API 的 serving server/runtime 与结构化 LLM program 生态 LLM/serve/bench 等 NVIDIA 工具链
缓存重点 分页 KV、automatic prefix caching、多类 connector RadixAttention 与 cache-aware 调度 paged KV、reuse、offload/disaggregation 等
调度重点 通用 continuous batching 与广泛 workload prefix/structured/agent workload 的运行时协同 NVIDIA GPU 上的 executor、kernel 与通信协同
硬件范围 CUDA 之外也有多类后端,但支持度因模型而异 重点围绕主流加速硬件,需查支持矩阵 深度绑定 NVIDIA GPU 特性
评估风险 功能组合多,具体 backend 可能回退 版本迭代快,server 与 runtime 参数变化 硬件/量化支持矩阵细,旧教程容易过时

vLLM:广覆盖的 serving runtime

vLLM 从 PagedAttention 和 continuous batching 起步,当前覆盖模型 serving、离线推理、分布式执行、量化、structured output、prefix caching、LoRA、多模态与多种 API。

它的优势不是“每个场景绝对最快”,而是常能用较短路径把 Hugging Face checkpoint 变成可用服务,并保留足够多的调优空间。OpenAI-compatible server 也已不只包含基础 Chat/Completions;实际兼容范围仍需逐 endpoint 和参数核对,不能把“compatible”理解为所有语义完全相同。

评估 vLLM 时要确认:

  • 模型是否走原生实现,还是 remote/custom model path;
  • attention、MoE 和 quantization 实际选择了哪个 kernel;
  • V1 调度器与目标功能组合是否支持;
  • 多机时使用什么 distributed backend 和 KV connector;
  • 默认 generation_config 是否改变了 sampling 参数。

SGLang:让前缀结构进入运行时决策

SGLang 的代表性设计是 RadixAttention:将 token 前缀组织成 radix tree,使运行时可以复用共享前缀的 KV Cache,并让调度器考虑缓存命中。对共享 system prompt、few-shot 示例、树状搜索和 Agent 工具定义等 workload,这个视角非常自然。

SGLang 同时提供结构化生成、模型 serving 与面向 LLM program 的上层能力。它并不只适合 Agent,也可以作为普通兼容 API server;相反,使用 Agent 框架也不意味着 SGLang 必然更快,收益取决于前缀是否真的在 token 级重复,以及调度能否保留这些缓存。

评估时应重点记录:

  • prefix cache hit 的 token 比例,而不只是请求命中率;
  • 请求路由后,共享前缀是否落在同一实例;
  • grammar/tool calling 是否改变采样瓶颈;
  • 目标模型、量化和并行组合的成熟度;
  • cache-aware 调度是否牺牲了其他请求的公平性。

TensorRT-LLM:NVIDIA 软硬件协同路径

TensorRT-LLM 长期强调 NVIDIA GPU 上的定制 kernel、低精度、in-flight batching、多 GPU 通信和 executor。到本文校订时,官方最新迁移文档已说明 PyTorch 是唯一执行后端,旧式 TensorRT engine build、trtllm-build 与 checkpoint conversion 流程已从新路径移除。因此,不能再把它固定描述为“必须先离线编译 TensorRT engine”。

这个变化本身说明了为什么选型文档必须写明日期:同一个项目名的部署工作流可能经历架构级调整。TensorRT-LLM 的持续差异化仍来自 NVIDIA 平台的 kernel、量化和通信整合,而不是名称中的 TensorRT 三个字。

评估时要逐项核对:

  • GPU compute capability 是否支持目标 FP8/FP4/NVFP4 路径;
  • checkpoint 是否已经量化,还是需要 Model Optimizer 校准;
  • 模型、KV Cache 和通信各自使用什么 dtype;
  • 单机与多机的支持组合和已知限制;
  • 当前文档属于 latest 还是旧版 legacy 路径。

功能勾选表为什么不够

“支持 prefix cache”至少可能有四种含义:

  1. 单进程内能复用完整 token blocks;
  2. 多 worker 能通过相同路由提高命中;
  3. 跨实例有外部 KV 存储或 connector;
  4. 多租户下提供缓存隔离。

同理,“支持 FP8”可能只指权重,也可能是 W8A8、KV Cache FP8 或特定 GPU 的 block scaling;“支持 MoE”也不代表任意 expert parallel、量化和推测解码组合都成熟。

选型表应记录实际准备上线的组合:

model_revision: exact repository + commit/revision
engine: name + version + commit
hardware: GPU model/count + interconnect
weight_dtype: bf16/fp8/int4/...
activation_dtype: ...
kv_cache_dtype: ...
parallelism: TP/PP/DP/EP
attention_backend: observed backend
features:
  prefix_cache: on/off
  speculative_decoding: method/config
  structured_output: grammar/backend
  lora: adapters/concurrency

如果一个组合只能在 issue 中找到实验说明,而不在官方支持矩阵或测试中出现,应把它视为集成风险,而不是已完成的复选框。

一套公平的对比实验

第一步:建立正确性基线

使用同一 tokenizer、chat template、checkpoint revision 和 sampling 参数。在 greedy decoding 下比较输出 token;若低精度造成差异,再用任务集检查质量,而不是直接把输出不同判为引擎错误。

还要检查 stop strings、EOS、structured output、tool calling 和 logprobs 的语义。API 能返回 200 不等于行为一致。

第二步:固定资源和容量

三个引擎使用相同 GPU 数、并行度与显存安全余量。不能让一个引擎用 FP8、另一个用 BF16,或一边启用 prefix cache、另一边关闭,再把结果归因于 runtime。

若默认参数不同,应同时报告两组:

  • out-of-box:反映部署门槛;
  • tuned under same constraints:反映优化潜力。

第三步:先测单请求路径

分别测短/长 prefill 和短/长 decode,确认没有异常回退。单请求数据用于理解 kernel 与固定开销,不代表在线容量。

第四步:扫描请求率

采用 open-loop 方式按目标到达率发送请求,不让客户端等待上一个请求结束才发送下一个。逐步提高 requests/s,直到 P99 SLO 或错误率失守。

每个点记录:

  • TTFT、TPOT/ITL、E2E 的 P50/P95/P99;
  • input/output tokens/s 与 requests/s;
  • queue time、running/waiting requests;
  • KV Cache usage、prefix hit、preemption 与 OOM;
  • GPU 利用率、功耗和多机通信量。

第五步:回放真实分布

固定 1k 输入/128 输出的合成测试无法代表真实服务。应从脱敏日志得到输入长度、输出长度、到达间隔、共享前缀和取消行为的分布,再回放相同 token IDs 或等价数据。

不要只使用平均长度。90% 的短请求和 10% 的超长请求,与所有请求都取平均长度,对调度器和缓存的压力完全不同。

怎样从结果做决定

可以把结论拆成四层,而不是宣布一个总冠军。

可运行性

模型能否加载,目标量化、并行和 API 是否正确。这里不满足,性能再高也无意义。

SLO 容量

在给定 P99 TTFT/TPOT 下,每张 GPU 能接受的最大请求率。这是在线服务最接近业务价值的核心数据。

成本与弹性

包括单位有效 token 成本、冷启动、模型加载、扩缩容粒度、突发流量恢复和多模型资源碎片。

维护成本

团队能否调试 kernel 回退、构建镜像、升级版本、观察缓存/调度指标,以及在问题发生时回滚。少量 benchmark 优势可能不值得长期承担一条团队不熟悉的技术栈。

一个常见但并非绝对的起点是:

  • 需要快速覆盖多种模型和 API,先以 vLLM 建立基线;
  • 流量具有明显共享前缀、结构化生成或复杂 LLM program,重点比较 SGLang;
  • 部署固定在 NVIDIA 平台,准备使用其最新低精度和通信路径,将 TensorRT-LLM 纳入同条件测试。

最终也不必全公司只保留一个引擎。离线批处理、在线聊天和超大 MoE 可以属于不同模型池,只要网关、指标与回滚策略保持一致。

一份可落地的选型记录

decision_date: 2026-08-09
workload:
  input_tokens: p50/p95/p99
  output_tokens: p50/p95/p99
  request_arrival: steady/bursty + target rps
  shared_prefix_ratio: ...
  cancellation_ratio: ...
slo:
  ttft_p99_ms: ...
  tpot_p99_ms: ...
  error_rate_max: ...
results:
  vllm: {max_slo_rps: ..., cost: ..., notes: ...}
  sglang: {max_slo_rps: ..., cost: ..., notes: ...}
  tensorrt_llm: {max_slo_rps: ..., cost: ..., notes: ...}
decision:
  selected: ...
  reasons: [...]
  rejected_tradeoffs: [...]
  reevaluate_when: model/GPU/workload/major-version changes

这份记录比一张静态功能表更有价值:它保留了决策成立的条件。当模型、GPU 或流量发生变化时,可以重新跑同一实验,而不是依靠已经过期的印象。

参考资料