← 返回题目列表

大模型推理的 Prefill 和 Decode 阶段有什么区别?为什么优化方法不同?

高频 中等 第 2 / 25 题 更新于 2026/07/25
PrefillDecode计算瓶颈KV Cache

简化版

大模型推理分两阶段:Prefill(预填充) 一次性并行处理全部输入 token、建好每层 KV Cache,矩阵大、并行度高,通常算力受限(compute-bound),决定首 token 延迟(TTFT)Decode(解码) 逐个自回归生成 token,每轮只算一个新位置但要读全部权重和历史 KV,通常访存受限(memory-bound),决定每 token 延迟(TPOT)。因为一个卡在算力、一个卡在带宽,所以优化手段完全不同:Prefill 优化大矩阵计算和长上下文注意力,Decode 优化 KV Cache 和批处理。

详细版

Prefill:输入长度 S 时,各层并行计算 S 个位置的 Q/K/V,把 K、V 写入缓存,输出最后位置的 logits 产生第一个 token。因果注意力只允许看前文,但整段 prompt 的多个位置能并行算。

Decode:第 t 轮只算新位置的隐藏状态,用新 Query 读取此前所有 K/V,采样出下一个 token 再进入下一轮。轮次间有数据依赖,不能把未来 token 一次算完

关键差异在算术强度(arithmetic intensity,每读一字节权重能做多少次计算)

  • Prefill 一次前向服务 S 个位置,权重读一次被 S 个位置复用 → 算术强度高 → 吃满算力。
  • 单序列 Decode 一次前向只产出 1 个 token,权重读一次只服务 1 个位置 → 算术强度低 → 卡在带宽。

所以 Prefill 常计算密集、Decode 常访存密集,但具体瓶颈随 batch、上下文、硬件变化(超长上下文注意力、大 Decode batch 都会改变结论)。

完整版教学

一、Prefill 做了什么

Tokenizer 先把 prompt 变成长度 S 的序列。Transformer 在每层并行计算所有 S 个输入位置,输出最后位置的 logits,并保存每个位置的 K、V 到缓存。第一个输出 token 产生前必须完成整段 prefill——所以prompt 越长,TTFT(首 token 延迟)越高

举例:一个 4K token 的长 prompt,prefill 要一次算 4096 个位置的全部注意力和 FFN,计算量大但高度并行,能把 GPU 的算力单元喂满。

二、Decode 做了什么

采样出一个 token 后,模型只为这一个新位置做前向。KV Cache 让历史 token 的 K、V 不必重算,但注意力仍要读取全部历史缓存。上下文越长,每轮要访问的缓存越多。

生成 M 个 token 至少要 M 次「依赖前一步结果」的串行迭代——这是 Decode 慢的根本:时间步串行,无法像 prefill 那样并行。批内不同序列还可能在不同时刻结束,增加调度复杂度。

三、为什么瓶颈不同:算术强度这把尺子

理解两阶段差异的核心概念是算术强度 = 计算量 ÷ 访存量。

Prefill(S个位置一起算):
   读一次权重 W → 服务 S 个位置 → 算术强度 ∝ S(高)→ 吃满算力单元

单序列 Decode(一次1个token):
   读一次全部权重 W → 只产出 1 个 token → 算术强度 ≈ 1(低)→ GPU 算力闲着等数据

在现代 GPU 上,算力远快于显存带宽。Decode 每轮要把整个模型的权重从显存搬进计算单元,却只算出一个 token,大量时间在「等权重搬运」——这就是 Decode 访存受限的本质。

批处理是 Decode 的救星:把 B 个序列的 Decode 放一起,一次权重读取被 B 个 token 复用,算术强度从 ~1 升到 ~B,GPU 利用率大增。这也是为什么 Decode 优化的核心是「把 batch 做大」(连续批处理、PagedAttention 都为此服务)。

记忆钩子:Prefill 是”一次读题、并行建缓存”(算力受限,决定首字快慢);Decode 是”带着缓存逐字作答”(访存受限,决定后续流畅度)。 前者靠算得快,后者靠攒大 batch、省带宽。

四、两阶段的优化方向完全不同

PrefillDecode
瓶颈算力(compute-bound)访存带宽(memory-bound)
决定指标TTFT(首 token 延迟)TPOT(每 token 延迟)
优化手段FlashAttention、算子融合、Prompt/Prefix 缓存、Chunked Prefill、高效长上下文注意力连续批处理、PagedAttention、KV 量化、投机解码、GQA/MQA
核心思路减少大矩阵计算、复用重复前缀攒大 batch、省 KV 带宽

两阶段共享同一份模型权重,却需要不同的 batch 策略,甚至可以拆开部署到不同实例(Prefill/Decode 分离),各自用最优配置。

五、如何定位到底卡在哪

不能拍脑袋,要分阶段 profiling,分别记录:

  • Prefill 的 token 数与耗时、Decode 的 token 数与耗时;
  • 每轮活跃序列数、KV Cache 用量、通信时间;
  • GPU 算力利用率 vs 显存带宽利用率(判断 compute-bound 还是 memory-bound)。

只有把两阶段的指标拆开看,才能判断该优化「模型计算、内存管理还是调度」。比如 TTFT 高就查 prefill(长 prompt?排队?),TPOT 高就查 decode(batch 太小?上下文太长 KV 读太多?)。

六、易错点与边界

  • 别把「Prefill 计算密集、Decode 访存密集」当铁律:超长上下文时 prefill 的注意力也会被 KV 访存拖累;Decode batch 很大时也可能变回 compute-bound。
  • 流式输出不改变实际 Decode 速度:它只是把已生成的 token 尽早推给用户、改善体感,模型该算多久还是多久。
  • TTFT 和 TPOT 要分开优化:交互式聊天对 TTFT 敏感,离线批量更看总吞吐——优化目标不能混。

七、加强记忆

Prefill vs Decode 记「算力 vs 带宽、TTFT vs TPOT」:Prefill 一次并行读完整段输入、建 KV 缓存,算术强度高、算力受限、决定首 token 延迟;Decode 逐 token 串行生成、每轮读全部权重只出一个 token,算术强度低、访存受限、决定每 token 延迟。因为瓶颈不同,优化手段也不同——Prefill 靠 FlashAttention/前缀缓存/算子融合,Decode 靠攒大 batch(连续批处理、PagedAttention)省带宽。定位问题就分阶段 profiling:TTFT 高查 prefill,TPOT 高查 decode。