
很多团队在扩展 大语言模型(LLM) 工作负载时都会遇到同样的困境:虽然购置了更快的 GPU,部署了更大的推理集群,但依然无法达到预期的延迟或吞吐量目标。原因其实很简单:LLM 的推理性能并不取决于单一硬件,而是受限于整个服务栈。从分词和提示预处理,到 KV 缓存管理、GPU 调度以及令牌流式传输,每个环节都可能成为短板。实际上,推理速度慢往往是一个系统层面的问题。
现代服务栈(例如 vLLM、Hugging Face Text Generation Inference 以及 TensorRT-LLM)正是为此而设计的。它们专注于持续/批次内处理(in-flight batching)、提高 KV 缓存利用率、分页注意力、分块预填充以及在不影响用户可见延迟的前提下最大化加速器利用率等调度策略。这种关注至关重要,因为 LLM 推理 实际上包含两种截然不同的性能模式:预填充通常属于计算密集型,而解码阶段则往往受限于内存带宽和 KV 缓存的调动,而非单纯的计算吞吐。
本文将探讨那些在生产环境中容易忽视但会严重限制 LLM 推理速度的瓶颈,并提供相应的解决方案。
核心要点
- LLM 推理是系统问题,而非仅仅是 GPU 问题:性能取决于从分词、KV 缓存到调度的整个流水线,而非单一组件。
- 预填充与解码的行为逻辑根本不同:预填充侧重计算,而解码通常受限于内存带宽,需要采取不同的优化策略。
- GPU 占用率高不等于效率高:由于内存瓶颈或调度不当,系统可能看似忙碌,但实际吞吐量却很低。
- 批处理策略和大小直接影响用户体验:更大的批次能提高吞吐量,但可能增加延迟,尤其是对 TTFT(首字延迟)和令牌间延迟的影响。
- 现代服务架构优于传统设计:持续批处理、前缀缓存和优化的 KV 缓存管理能显著改善实际性能。
LLM 推理请求的内部流程
让我们深入看看 LLM 推理请求内部实际发生了什么。从外部看,每个请求的概念很简单:用户提交文本并接收返回的令牌。但在内部,服务流水线则复杂得多:
请求 → 分词 → 预填充 → KV 缓存的创建或复用 → 解码 → GPU 调度 → 流式输出

首先,请求必须经过分词,即将原始文本转换为对应的令牌 ID。接着,预填充阶段会一次性对整个提示进行并行批处理,并初始化 KV 缓存。随后,解码阶段开始迭代运行,每次生成一个令牌,并不断复用之前的 KV 状态。系统调度器随后决定这些操作如何共享 GPU、内存和令牌预算。
解码完成后,令牌会通过 API 层流式传输给用户。正因为此,预填充和解码的耗时往往会不一致。这也解释了为什么 TTFT(Time to First Token)和稳态生成速度通常不相关:前者主要取决于首个令牌发出前的所有步骤,而后者则取决于重复的解码循环。
预填充与解码的分离是 LLM 服务的基本原理之一。预填充通常可以实现高密度并行,而解码本质上是迭代且有状态的。如果系统将这两个阶段视为同质化的工作负载,就会错失性能提升的机会。这也是为什么 vLLM 的工作流鼓励你分别对它们进行调优。例如,在我们的仪表板中,TTFT 是独立于令牌间延迟进行优化的。其 disaggregated prefilling 功能的存在,正是因为这些目标往往需要不同的优化策略。
隐性瓶颈 #1 — GPU 利用率不足
在 LLM 运营中,最具误导性的指标之一是只看“GPU 是否存在”而忽略了实际的 GPU 效率。一个看似“忙碌”的集群,其请求吞吐量可能极低。这是为什么呢?
因为现实世界的流量是异构的。有的提示很短,有的很长。有的输出在二十个令牌后结束,有的则需要数百个。静态的请求级批处理在这种环境下会力不从心,因为整个批次的处理速度往往受限于最慢的那个序列。当某个请求提前完成时,其对应的槽位会一直空闲,直到整个批次处理完毕。

阶段之间也会出现空闲时间。CPU 端的预处理、分词、请求解析和响应流式传输都会引入间隙,导致加速器不得不等待。vLLM 的服务文档特意推出了异步调度机制,旨在最大限度地减少这些间隙,从而提高吞吐量并降低延迟。请记住:利用率不足并不总是内核的问题,有时是流水线协调的问题。
购买更大的 GPU 并不能解决调度糟糕的问题。如果你的请求长短不一,批次太僵化,或者主机流水线无法及时供给数据,那么性能更强大的加速器也只能在旁边闲置……等得更快而已。
隐性瓶颈 #2 — 内存带宽而非纯算力
人们常有一种思维定势,认为推理主要是一个 FLOPS(浮点运算次数)问题。但实际情况是,“解码”阶段往往在成为计算瓶颈之前,就已经撞上了内存墙。执行模型通常是受内存带宽限制的。解码工作线程之所以受内存带宽限制,是因为它们每次发出一个令牌,同时需要反复读取模型状态和 KV 数据。
这解释了为什么系统可能显示极高的内存分配,但算术利用率却很低。在解码过程中,GPU 花费在移动权重和 KV 缓存数据上的时间,可能比进行繁重的张量数学运算还要多。这也解释了为什么在服务大模型时,高带宽内存(HBM)如此重要。瓶颈往往在于供给下一步令牌的速度,而不是产品说明书上标注的峰值矩阵乘法速率。
其实际意义在于,“GPU 利用率”和“GPU 效率”不能画等号。一个部署实例可能看起来负载已满,但每秒生成的令牌数却很少,因为内存流量已成为主要的制约因素。
隐性瓶颈 #3 — 延迟与吞吐量的权衡
每个服务团队最终都会面临同样的诱惑:为了获得更高的 吞吐量,我们应该增大批处理大小。你确实可以这么做!但这可能会损害用户体验。更大的批次通常意味着更好的硬件利用率,但如果预填充操作挤占了活跃的解码任务,往往会导致 首字延迟(TTFT) 增加、尾延迟升高或令牌间延迟变大。反之,减少批次令牌预算通常能改善令牌间延迟,而增加预算则有助于降低 TTFT 并提升吞吐量。
这种权衡的存在意味着,绝不能仅使用单一指标来孤立地优化服务系统。如果你关注聊天的响应速度,TTFT 就很重要。如果你关心流式输出的流畅度,令牌间延迟则是关键。而对于并发和效率,吞吐量至关重要。vLLM 在其基准测试和监控文档中公开了 TTFT、TPOT(每个输出令牌的时间)、ITL(令牌间延迟)、端到端延迟、百分位数以及 有效吞吐量 等指标,因为没有任何单一数字能完全概括推理质量。
最佳平衡点取决于你的工作负载。交互式聊天、批量摘要、Agent 流水线和离线报告生成对延迟的要求各不相同。如果没有明确这些目标就进行调优,无异于盲人摸象。
隐性瓶颈 #4 — 批处理策略
不同的批处理策略效果天差地别。静态批处理将请求一次性分组,然后进行处理。动态批处理 在组成批次上更加灵活,但可能对生成时长的变化反应不够迅速。持续批处理则与众不同。

它不是预先将所有请求打包,而是在每个生成步骤中持续重新调度工作。一旦有请求完成,新的请求会立即进入,无需等待整个批次排空。系统在每个生成步骤都会动态重新调度批次,以保持高 GPU 利用率。
隐性瓶颈 #5 — KV 缓存的浪费与复用
KV 缓存是影响服务性能的最大因素之一。它包含了之前令牌的注意力键和值。