2.3 vLLM 与 TensorRT-LLM 对比实战 本节摘要:vLLM 和 TensorRT-LLM 是当前流式 LLM 推理领域两大主流引擎,设计哲学截然不同。vLLM 由学术界产出,重通用性和易用性,一套代码跑多种模型多种硬件,PagedAttention 是它的招牌;TensorRT-LLM 出自工业界,把模型编译到底层 kernel 做极致优化,在特定硬件上吞吐和延迟领先,但部署门槛高、灵活性低。本节对比两者的架构、性能、易用性和生态,给出不同场景的选型建议——多数团队从 vLLM 起步,遇到性能瓶颈或特定硬件时再考虑 TensorRT-LLM。
本节摘要:vLLM 和 TensorRT-LLM 是当前流式 LLM 推理领域两大主流引擎,设计哲学截然不同。vLLM 由学术界产出,重通用性和易用性,一套代码跑多种模型多种硬件,PagedAttention 是它的招牌;TensorRT-LLM 出自工业界,把模型编译到底层 kernel 做极致优化,在特定硬件上吞吐和延迟领先,但部署门槛高、灵活性低。本节对比两者的架构、性能、易用性和生态,给出不同场景的选型建议——多数团队从 vLLM 起步,遇到性能瓶颈或特定硬件时再考虑 TensorRT-LLM。
阅读完本节,你应当能够:
当你把 LLM 推理优化到要选引擎的阶段,大概率已经在 vLLM 上跑了一阵,开始纠结"要不要换 TensorRT-LLM"。这个纠结很真实,因为两者的取舍明显。
vLLM 像一把瑞士军刀——开箱即用,支持几十种主流模型,CPU 装个包就能起服务,调参直观,社区活跃。它的招牌 PagedAttention 把显存利用率拉满,连续批处理开箱自带,对中小团队几乎是默认选择。但它为了通用性,没有对每种硬件做极致的 kernel 优化,在追求极限吞吐的场景下不是最快。
TensorRT-LLM 像一台赛车——同样的硬件上能跑出更高的吞吐和更低的延迟,尤其在它深度优化过的模型和 GPU 上。代价是它要先把模型"编译"成优化的引擎(engine),这个过程慢且挑剔,对模型结构的改动不友好,部署和调参的门槛高。它更适合大流量、固定模型、愿意投入工程团队做优化的场景。
所以选型本质上是在问:你的流量大到值得为 20–30% 的吞吐提升投入额外的工程成本吗?如果是,TensorRT-LLM 值得;如果还在验证阶段或流量一般,vLLM 的易用性和灵活性更划算。
vLLM 的核心理念是"用通用的、优雅的机制解决普遍问题"。它的两个招牌技术我们在前两节讲过:PagedAttention 用分页管理 KV Cache 解决碎片化,连续批处理用 token 级调度提升利用率。这两个机制对模型结构没有特殊要求,只要模型用标准的 decoder attention,就能受益——这就是它能一套代码支持几十种模型的原因。
vLLM 还有一个被低估的优势:它的 Python 实现相对透明,遇到问题能看懂、能改、能贡献回社区。这对工程团队的长期维护很重要——黑盒引擎出 bug 时你只能等厂商修。
TensorRT-LLM 的核心理念是"为特定硬件和模型做深度优化"。它的工作流是:把模型的结构和权重,通过一个编译过程,转换成针对目标 GPU 高度优化的执行计划(engine)。这个编译会做一堆底层优化——kernel 融合(把多个小算子合成一个大 kernel 减少访存)、精度校准(在保证质量的前提下用更低精度)、显存布局优化(针对特定 GPU 的内存层级)。
这个"编译"是它又快又难用的根源。快,是因为针对你这块 GPU 的具体特性做了定制优化;难用,是因为每次模型权重更新或结构改动都要重新编译,编译可能要几十分钟到几小时,还可能因为某些不支持的算子失败。
它还有自己的一套 KV Cache 管理和批处理实现(如 in-flight batching,本质上就是连续批处理的工程实现),思路和 vLLM 类似,但实现细节针对特定硬件调得更狠。
在两者都优化到位的公平对比下,性能格局大致是:
| 指标 | vLLM | TensorRT-LLM | 差距 |
|---|---|---|---|
| 吞吐(tokens/s) | 基准 | 高 15–30% | TensorRT-LLM 领先 |
| TTFT | 基准 | 略低 | TensorRT-LLM 略优 |
| ITL | 基准 | 略低 | TensorRT-LLM 略优 |
| 显存效率 | 高(PagedAttention) | 高 | 接近 |
| 首次启动 | 快(直接加载) | 慢(要编译引擎) | vLLM 大幅领先 |
| 模型覆盖 | 广(几十种) | 窄(主流几种深度优化) | vLLM 领先 |
注意"公平对比"这四个字。很多时候看到的对比数据是不公平的——比如 vLLM 用默认配置、TensorRT-LLM 用专家调优过的配置,差距会被夸大到 2–3 倍。真实场景下,vLLM 把参数调好(连续批处理、prefix caching、合适的 batch)后,和调好的 TensorRT-LLM 差距通常在 20–30%。
我的建议是默认从 vLLM 起步。理由:部署快、模型覆盖广、出问题能自查、社区支持好。等你遇到明确的吞吐瓶颈(GPU 利用率已经很高但还嫌慢),且团队有能力承担引擎编译和维护的工程成本,再考虑迁移 TensorRT-LLM。很多团队从头到尾用 vLLM 也跑得挺好,没必要为了"可能的更快"过早增加复杂度。
| 维度 | vLLM | TensorRT-LLM |
|---|---|---|
| 安装 | pip 装包即可 | 要装 TensorRT、插件、编译工具链 |
| 模型上线 | 直接传模型路径 | 要先 build engine(耗时分钟到小时级) |
| 换模型/改权重 | 改路径重启 | 重新 build engine |
| 调参 | 配置文件直观 | 要懂引擎内部,部分参数在 build 时定死 |
| 故障排查 | Python 代码透明可读 | C++ 为主,黑盒成分多 |
| 社区支持 | 活跃,issue 响应快 | 厂商驱动,响应慢 |
⚠️ 常见坑:别被 benchmark 里 TensorRT-LLM 的极致数字忽悠。那些往往是厂商在最优硬件、最优模型、专家调优下的峰值。你自己部署时,光是 build engine 踩坑(不支持某个算子、精度校准出问题、版本不兼容)就可能耗掉一周。决策前先在你的真实模型和硬件上跑个最小验证,别信别人的数字。
除了这两大主流,还有几个引擎在特定场景有竞争力:
TGI(Text Generation Inference):HuggingFace 出品,主打和模型生态的深度集成,部署开箱即用。性能介于 vLLM 默认和调优之间,适合已经在用 HuggingFace 生态的团队。
DeepSpeed-FastGen:微软出品,动态 split-kv 和自动 batch 调度是特色,在某些长上下文场景表现好。
LMDeploy:上海人工智能实验室出品,对国产模型(InternLM 系列)支持好,量化推理是强项。
TensorRT-LLM 之外的厂商方案:苹果的 MLX、AMD 的方案,各自在特定硬件上有优势,但生态比两大主流小。
选型决策必须基于你自己的压测数据,别人的 benchmark 只能参考。可信的压测要注意:
用你真实的模型和真实的 prompt 分布。合成数据(固定长度的随机 prompt)测出来的吞吐,和真实业务(长短不一、有系统提示前缀)差很远。
测多个并发档位。从低并发(1–4)到高并发(64–256)都测,画吞吐-延迟曲线。有些引擎低并发快但高并发崩,反之亦然。
区分 TTFT 和 ITL 分别测。别只看总吞吐,要看你业务关心的指标。对话业务重点看 TTFT P95,批量业务重点看吞吐。
预热后再测。冷启动(首次加载模型、编译)的数据不代表稳态性能。先跑几百个请求预热,再开始统计。
# 概念性压测脚本骨架 import asyncio import time import statistics class LoadTester: def __init__(self, endpoint, prompts): self.endpoint = endpoint self.prompts = prompts async def run(self, concurrency, total): sem = asyncio.Semaphore(concurrency) latencies_ttft = [] latencies_total = [] async def one_request(prompt): async with sem: t0 = time.perf_counter() ttft = None async for token in self._stream(prompt): if ttft is None: ttft = time.perf_counter() - t0 latencies_ttft.append(ttft * 1000) latencies_total.append((time.perf_counter() - t0) * 1000) await asyncio.gather(*[one_request(p) for p in self.prompts[:total]]) self._report(latencies_ttft, latencies_total) def _report(self, ttft, total): for name, data in [("TTFT", ttft), ("Total", total)]: data.sort() print(f"{name}: P50={statistics.median(data):.0f}ms " f"P95={data[int(len(data)*0.95)]:.0f}ms " f"P99={data[int(len(data)*0.99)]:.0f}ms")
💡 关键直觉:压测不是跑一次出个数就完事。要画"并发数-吞吐-延迟"的完整曲线,看趋势和拐点,而不是孤立的峰值数字。一个在低并发慢但高并发稳的引擎,往往比峰值高但高并发崩的更适合生产。
下一章我们换赛道,从文本 LLM 转到语音——看流式 ASR、流式 TTS 怎么和 LLM 串成端到端的实时语音交互系统。
把两个引擎放回时间线里看,选型逻辑会更清晰。vLLM 诞生于 2023 年的 UC Berkeley,带着浓厚的学术开源气质:核心贡献是算法和系统论文,代码架构追求可读可改,社区用 PR 投票决定方向。这种气质决定了它的演化路径——新模型架构(MoE、多模态)通常几周内就有社区支持,代价是主干代码变化快,生产环境要锁版本、 regression 测试不能省。TensorRT-LLM 则是 NVIDIA 2023 年底的产品化答案:它继承 TensorRT 十年打磨的编译器栈,把权重布局、kernel 融合、多卡通信全部编译期固化,性能天花板高,但每次新模型要等官方或资深工程师做适配,版本节奏跟着 NVIDIA 硬件走。
两年来一个值得注意的趋势是差距在收敛。vLLM 吸收了 torch.compile 和自定义 CUDA kernel(FlashInfer 集成),补齐了 kernel 层的短板;TensorRT-LLM 则开源并简化了 build 流程(Model Optimizer),降低了使用门槛。2025 年之后业界还冒出了第三条路线:以 SGLang 为代表的"结构化输出 + 前缀缓存优先"引擎,在 agent 工作流负载(大量共享前缀、受限解码)上表现突出。所以更准确的说法是:引擎选择已经从"二选一"变成"按负载特征选主力"——通用对话 vLLM,NVIDIA 集群极致吞吐 TensorRT-LLM,agent 密集型负载可以评估 SGLang。
选型之外,迁移成本常被低估。从 vLLM 换到 TensorRT-LLM 不是改个 SDK 调用:API 语义有差异(流式事件结构、中断处理)、可观测性体系要重建(两者的 metrics 维度不同)、CI 里要加 engine 构建流水线(一个 70B 模型的编译要数十分钟到小时级)。实际操作中,值得迁移的信号是:你已经把 vLLM 调到接近最优(批处理策略、prefix caching、量化都做了),P99 延迟或单卡吞吐仍有 20% 以上的硬缺口,且团队有专人能维护编译栈。三个条件缺一个,迁移的投入产出比都算不过来。最后一个决策技巧:让两套引擎并行跑一个月的影子流量,用真实分布的对比数据做决策,比任何厂商白皮书都可靠——引擎差异对负载的敏感度极高,你的流量只有你自己测了才算数。补充一个小技巧:影子流量期间同时记录两套引擎的告警与运维事件次数,稳定性差异(崩溃率、内存泄漏、版本升级踩坑)在长期运行里才会显形,而这些恰恰是选型报告里最常缺席的一栏,却往往比百分之十几的吞吐差距更影响总拥有成本。