TT Lab
开始
学习 学习路径 课程

LLM 服务

prefill 和 decode 是两件事

在 TT Lab 中继续学习

一句话总结

LLM 推理分为两个阶段:一次处理整个提示词的 prefill 受计算能力限制,而逐个生成令牌的 decode 受内存带宽限制。

为什么需要了解这些

训练时只看一个指标也足够——每秒处理的令牌数。服务推理时,这个指标还不够。用户真正感受到的是两个方面,而它们来自不同原因。

TTFT(Time To First Token,首令牌时间)是从发送请求到收到第一个令牌的端到端时间。交互式服务可以把 200ms 作为示例 SLO,但实际目标应根据产品体验、模型大小、提示词长度和部署环境确定。TTFT 包含网络、请求队列、调度、分词和 prefill。对于长提示词,计算完整注意力的 prefill 往往是主要组成部分,但它并不总是单独决定整个 TTFT。

ITL 或 TPOT(Inter-Token Latency、Time Per Output Token)是此后逐个令牌输出的时间间隔,只需快于人的阅读速度即可。该数值由 decode 阶段决定。

关键在于两个阶段的瓶颈不同。prefill 会执行大规模矩阵乘法,因此受计算能力制约;decode 每生成一个令牌,都必须完整读取一次模型权重,因此受内存带宽制约。所以,即使扩大 decode 的批量,耗时也不会明显增加——无论如何,读取权重的时间占据主导。这一性质正是批处理效果格外显著的原因。

工作原理

KV 缓存是这里出现的新资源。Transformer 在处理每个令牌时,都要引用此前所有令牌的键和值。若每次重新计算,复杂度将达到 O(n²),因此系统会把已经计算的键和值累积在内存中,这就是 KV 缓存。

问题在于其大小。计算公式如下。

KV 바이트 = 2 x 레이어 수 x 은닉 차원 x 시퀀스 길이 x 배치 x dtype 바이트

以 fp16 运行一个 7B 模型(32 层、隐藏维度 4096),上下文为 4K、批量为 1 时,结果为 2 × 32 × 4096 × 4096 × 1 × 2 = 2GiB。把上下文扩大到 128K 后,结果变成 64GiB。模型权重只有 14GB,KV 缓存却占用 64GB;批量为 8 时更会达到 512GiB,绝不可能装入单张 GPU。

因此,推理服务系统的大部分设计都围绕 KV 缓存管理展开。PagedAttention 把 KV 缓存拆成固定大小的块,像操作系统虚拟内存一样允许非连续分配,从而减少内部碎片。GQA 会根据模型的 KV 头数量,以分组方式共享键和值头,降低缓存大小。KV 缓存量化(INT8、INT4)能减少 dtype 占用的字节数,但是否支持以及对精度有何影响,必须按服务器和模型分别确认。

生产现场会看到什么

测量时的常见错误,是把 TTFT 与 ITL 混在一起计算平均值。用总延迟除以总令牌数,会把两个指标混合,最终什么都观察不到。必须分别测量,并各自查看 p50、p95、p99。

GPU 内存使用率配置(例如 vLLM 的 gpu_memory_utilization)也非常重要。在部分专用 GPU 环境中,可以把 0.90 左右作为起点,但安全值会因模型服务器版本、量化方式、CUDA Graph 和共存进程而异。设得过高会触发 CUDA OOM,过低则会减少 KV 缓存可用空间,降低并发吞吐量,因此必须用实际峰值负载验证。

提示词长度会改变一切

前述公式把序列长度作为乘数,这一点会在实际工作中反复出现。决定使用更长的提示词,既是在购买准确率,也是在出售吞吐量。 如果不了解这项交换比例,容量规划每次都会偏离实际。

三个方面会同时变差。

TTFT 会变长。 prefill 必须对整个提示词计算注意力,成本会随长度急剧增长。如果系统提示词有几千个令牌,那么无论用户问什么,每次都要承担这笔成本。

并发处理数量会减少。 缓存与长度成正比,因此提示词长度翻倍时,同样的内存只能容纳一半请求。上一模块提到的抢占正是从这里开始。

成本会上升。 无论是按令牌计费的服务,还是自行运营,读取和计算的数据量都会直接转化为费用或硬件需求。

因此,实际工作的应对方式非常明确。固定公共前缀——不要在每个请求中轻微改动系统提示词和示例,而应保持完全一致,让前缀缓存发挥作用。只要一个字符不同,后续内容就必须全部重新计算;如果把时间或请求 ID 等内容放在提示词前部,整个缓存都会失效。把会变化的内容放到后面,是维持该缓存命中的基本原则。

筛选要放入的文档。 不要把检索到的所有文档都塞进提示词,只选择排名靠前的少数文档,并从每份文档中截取必要部分。文档数量翻倍并不会让答案质量翻倍;混入无关内容反而经常会降低准确率。

限制输出长度上限。 如前所述,缓存会随着生成过程不断增长。没有上限时,单个请求会持续占用内存并挤掉其他请求的位置。真正需要长输出的任务应发送到不同于交互式服务的实例,这里的答案依然如此。

下一次检查要看什么

首先通过测验区分 TTFT 与 ITL 的瓶颈,以及 KV 缓存的容量条件。从下一模块开始,将亲手构建令牌流式服务器、模拟批处理调度器,并编写 KV 缓存计算器。