大模型推理部署总览
训练是「一次性的、批量的」,推理是「高频的、在线的、成本敏感的」。面试官常问:为什么大模型推理慢?显存花在哪?怎么把吞吐做上去?本文用图解把推理链路拆开。
01部署要解决什么
训练追求「在有限时间内把模型训好」;部署/推理追求「在成本与延迟约束下,尽可能多地处理并发请求」。三类核心指标互相牵制:
💰 成本
单 token 显存占用、每美元能出的 token 数。量化、共享、批处理都为了降本。
⚡ 延迟 (Latency)
单个请求从发起到拿到首个/完整回复的时间。对话产品最敏感。
🚀 吞吐 (Throughput)
单位时间内处理的 token 数 / 请求数。决定一台机器能服务多少人。
02自回归解码的瓶颈
Decoder-only 模型逐 token 生成:第 t 个 token 依赖前 t-1 个。这意味着生成阶段本质上是串行的,每生成一个 token 都要跑一次完整前向。瓶颈有两处:
03KV Cache:避免重复计算
生成第 t 个 token 时,注意力需要对前面所有 token 的 K、V 做加权。若不缓存,每步都要重新算历史 K/V,复杂度从 O(n) 退化为 O(n²)。
❌ 不用 KV Cache
每步重算全部历史 K/V,计算随序列长度平方增长,无法接受。
✅ 用 KV Cache
历史 K/V 缓存起来,新 token 只算自己的 Q 并与缓存做注意力,复杂度降到 O(n)。
batch × 序列长度 × 层数 × 隐藏维 线性增长。长上下文、高并发下,KV Cache 占用常常超过模型权重本身。这正是后续 PagedAttention、KV 量化、滑动窗口的优化对象。# 伪代码:KV Cache 把历史 Key/Value 沿序列维追加
for step in range(max_len):
q, k, v = proj(x_new) # 只算新 token
k_cache = cat([k_cache, k], dim=-2) # 追加
v_cache = cat([v_cache, v], dim=-2)
out = attn(q, k_cache, v_cache) # 只做 1×seqlen 的小矩阵乘
04批处理:Static vs Continuous
连续批处理(Continuous Batching)是 vLLM、TGI、TensorRT-LLM 的标配:不按「请求」而按「每一步的 token」组批,某请求结束立刻腾出位置给新请求。相比静态批处理,吞吐可提升数倍、延迟更稳。
05PagedAttention 与 vLLM
传统实现按「最大长度」为每个请求预留连续显存,导致大量碎片与预留浪费。PagedAttention(vLLM 提出)借鉴操作系统「分页」:把 KV Cache 切成固定大小的 block,像内存页一样零散存放、按需分配、不同请求可共享前缀块。
🧩 分页管理
KV 块像虚拟内存页,逻辑连续、物理离散,显存利用率大幅上升。
🔁 前缀共享
相同 system prompt / 多轮对话前缀可共享同一批 KV 块,省显存。
06吞吐 vs 延迟:别混淆
TTFT(首 token 延迟)
发请求到收到第一个 token 的时间,主要花在 Prefill。受提示长度影响大。
TPOT(每 token 延迟)
相邻 token 的间隔,主要花在 Decode 的带宽。决定「打字机」是否流畅。
- 吞吐由批大小、GPU 利用率决定,越大越好但会拖长 TPOT。
- 延迟由模型大小、量化、批内竞争决定,对话场景希望 TPOT < 50ms。
07多卡并行部署
单个模型放不进一张卡时,需要切分。推理常用的切法:
🔀 张量并行 (TP)
把单层权重矩阵按列/行切到多卡,单层内并行。通信频繁,适合机内 NVLink。
🪜 流水线并行 (PP)
把不同层放到不同卡,微批流水。通信少但有「气泡」。
📊 数据并行 (DP)
多份同模型服务不同请求,最简单,适合高并发。
线上常组合使用:TP×PP 把模型放进去,再用 DP 复制多份扛并发。切分粒度越细,单卡显存越小,但通信开销越大。
08面试速记卡
为什么慢?
Decode 串行 + 每步读全量权重(带宽瓶颈);KV Cache 随长度线性涨显存。
怎么快?
KV Cache、Continuous Batching、PagedAttention、量化、投机解码、更大 batch。
显存去哪了?
权重(参数×精度)+ KV Cache(长上下文常占大头)+ 激活/临时缓冲。
TTFT / TPOT
TTFT 看 Prefill,TPOT 看 Decode 带宽,二者优化方向不同。