用户感受到的"模型速度",其实由两个阶段拼成。Prefill(预填充)并行读入整个prompt,逐层计算并写入KV缓存,最后产出第一个token;Decode(解码)则是自回归循环,一次只算一个token,读权重、读全部历史KV、算出下一个token、再追加新KV。
两个阶段的瓶颈完全不同。理解这一点,是所有推理优化——量化、批处理、投机解码——的基础。
![]()
算术强度决定瓶颈在哪
关键差异在于算术强度,也就是每个字节能做多少次浮点运算。
Prefill阶段整个序列并行,矩阵乘法饱满,瓶颈在算力(FLOPS),优化方向是更强的GPU、更好的kernel。Decode阶段单token、逐次访存,瓶颈是内存带宽,优化方向是更快的显存、更小的权重和KV。
直观理解:prefill是"一次搬完全部货物,路不是问题,装卸能力是问题";decode是"每次只搬一件,但每次都要跑全程,路的通行速度决定一切"。
批处理如何改变瓶颈
单条请求解码时,读一遍权重只为产出1个token,算力大量闲置,纯带宽受限。把多条请求拼成batch后,权重只需读一次,同时为N个请求各算一个token;访存量几乎不变,计算量翻了N倍,瓶颈从带宽滑向算力。
这正是吞吐与时延的取舍所在:批处理提升了总吞吐,但单请求的TPOT通常会变差。服务侧追求吞吐就会加大batch;单机本地推理没有并发,自然回到带宽受限状态。
这也是llama bench中pp128(prefill)和tg64(decode)分开测的原因:两个数字受不同因素支配,必须分别看。
KV缓存:用空间换时间
注意力要求每个新token回看全部历史。若不缓存,每个token的K/V都要重算,代价是平方级。缓存后只算增量,代价是显存占用随上下文线性增长:
KV内存 ≈ 层数 × 上下文长度 × KV头数 × 头维度 × 精度
长对话因此有双重成本:
- 静态成本:KV缓存占用或预留更多内存;
- 动态成本:每个新token要attend的历史位置变多,解码变慢、访存变大。
所以"上下文越长回答越慢、越占显存"不是错觉,是结构性的。对应手段包括:开新会话、摘要压缩旧轮次、调小上下文上限、KV量化。
三个指标对应三个维度
TTFT(首token时间)对应prefill性能,决定"点了发送要等多久才有反应";TPOT(每token时间)对应decode性能,决定"流式输出看起来流不流畅"。
端到端时延 ≈ TTFT + 输出token数 × TPOT。这个分解式是全篇最有实用价值的公式,任何"总时长"问题都能拆到这两个可独立优化的项上。
聚合吞吐则是所有在途请求的总tokens/s,是服务端的核心指标,靠批处理提升。
一份排查清单
觉得"响应慢",先测TTFT,问题在prefill:缩短prompt、换算力更强或优化更好的后端。
觉得"输出慢",问题在decode:用更小或更低精度的模型(量化)、更高端宽的硬件、避免慢速互联上的CPU/GPU卸载、控制活跃上下文长度。
显存不够,优先算KV公式,压缩上下文或量化KV。服务要扛量,加批处理,接受单请求时延的少量上升。
一句话总结:prefill拼算力,decode拼带宽,KV缓存决定显存与长上下文代价;TTFT、TPOT、吞吐三个指标分别对应这三个维度,所有优化技巧都是在移动这三条边界。
特别声明:以上内容(如有图片或视频亦包括在内)为自媒体平台“网易号”用户上传并发布,本平台仅提供信息存储服务。
Notice: The content above (including the pictures and videos if any) is uploaded and posted by a user of NetEase Hao, which is a social media platform and only provides information storage services.