← 返回题目列表

Prefill 阶段如何优化?

高频 困难 第 15 / 25 题 更新于 2026/09/17
推理优化KV CachePagedAttention部署

简化版

Prefill 会并行处理完整 Prompt,计算所有输入 Token 的隐藏状态并建立 KV Cache。它通常是计算密集阶段,长 Prompt 的注意力计算与 KV 写入会显著拉高首 Token 延迟(TTFT)。

优化要从四层入手:业务层减少无效上下文,调度层做 Chunked Prefill 和长度感知批处理,算子层使用 FlashAttention、融合 Kernel 与合适精度,集群层考虑前缀缓存或 Prefill/Decode 分离。最终用真实输入长度分布验证 TTFT、吞吐、显存和回答质量。

详细版

Prefill 与 Decode 的瓶颈不同:Prefill 一次处理 S 个 Token,大矩阵乘法更容易充分利用 GPU,但标准注意力的计算量随 增长;Decode 每步只处理一个 Token,更常受权重和 KV Cache 带宽限制。

常用优化组合是:

  1. 清理重复检索片段、历史对话和模板,先减少输入 Token。
  2. 使用 FlashAttention,避免显式物化巨大的注意力矩阵。
  3. 按 Token 数而不是请求数组批,并对超长 Prompt 分块。
  4. 对稳定公共前缀复用 KV Cache,同时严格校验模型与模板版本。
  5. 长上下文场景评估张量并行、序列并行或阶段拆分。

不能只追求 Prefill Tokens/s。输入裁剪可能损失证据,Chunked Prefill 可能增加调度轮次,前缀缓存会占用显存并引入隔离风险;因此要一起看 TTFT P95/P99、有效输入吞吐、缓存命中率、显存水位和任务质量。

完整版教学

1. Prefill 到底做了什么

给定长度为 S 的 Prompt,模型一次前向计算全部位置,并把每层注意力的 Key、Value 写入缓存。最后一个位置的 Logits 用于产生首个输出 Token,之后才进入逐 Token Decode。

Prompt tokens ──> embedding ──> Transformer layers ──> first-token logits
                                      |
                                      └──> KV Cache for positions 1..S

因此 Prefill 同时决定首 Token 何时出现以及 Decode 从多大的 KV Cache 起步。

2. 为什么长 Prompt 成本高

标准自注意力中,每个位置都要与前面位置交互。忽略常数后,注意力计算约为 O(S² × d),投影与前馈网络约为 O(S × d²);长度上升时,注意力部分会越来越突出。

KV Cache 容量则近似线性增长:

KV bytes = 2 × L × H_kv × D_head × S × bytes_per_element

例如序列长度翻倍,KV 容量约翻倍,但全注意力相关计算可能接近四倍。回答时要区分计算复杂度与缓存容量。

3. 第一步为何是减少无效 Token

不参与答案的 Token 既消耗 Prefill 算力,也永久占用本次请求的 KV Cache。RAG 中重复召回、过长网页导航、未压缩历史和冗余 Few-shot 都是常见来源。

应先做文档去重、按权限过滤、历史摘要和动态 TopK,再设输入预算。裁剪不能简单保留头尾;对事实问答应优先保留与查询相关且可引用的证据,并在评测集上检查答案召回是否下降。

4. FlashAttention 优化的是什么

朴素实现会把 S × S 注意力分数写入显存,再读回做 Softmax 和加权求和。FlashAttention 通过分块与在线 Softmax,让中间块尽量留在片上存储,减少高带宽显存读写。

它保持精确注意力语义,但不意味着理论计算量从平方变成线性。收益受序列长度、Head 维度、数据类型与硬件 Kernel 支持影响,必须用目标卡型实测。

5. 批处理应按 Token 预算

两个请求数相同的 Batch,可能分别包含 8 × 5128 × 16000 个输入 Token,计算与显存完全不同。调度器应限制每轮 Prefill Token 总量,而不是只限制请求数。

组批方式优点风险
固定请求数实现简单长度波动会造成延迟尖峰
长度分桶Padding 少、执行稳定等待凑桶可能增加排队
Token 预算资源控制更准确调度与估算更复杂

在线请求还要设置最大输入长度,避免单个异常 Prompt 把整轮计算占满。

6. Chunked Prefill 如何降低干扰

超长 Prefill 若一次执行到底,会让已有 Decode 请求长时间得不到调度,TPOT 出现抖动。Chunked Prefill 把长输入切成若干 Token 块,与 Decode 迭代交错执行。

不分块: [---------- long prefill ----------][decode]
分块后: [chunk][decode][chunk][decode][chunk]

它改善调度公平性和尾部 TPOT,但会增加轮次、边界管理与可能的 Kernel 开销。块大小要结合 TTFT 与 Decode SLO 调整,而不是越小越好。

7. 前缀缓存何时有效

若大量请求共享完全相同的系统提示、Few-shot 或文档前缀,可缓存其 KV,命中后只计算新增后缀。收益近似取决于公共前缀长度、复用次数与命中率。

缓存键至少应包含模型权重版本、Tokenizer、模板内容和推理配置;不同租户的私有前缀不能越权复用。模板中放置动态时间戳或随机 ID 会破坏前缀相同,应把动态字段尽量后移。

8. 并行策略如何选择

张量并行把单层矩阵切到多卡,可降低单卡计算时间,但每层都有通信;流水线并行更适合模型装不下单机,却可能产生气泡;长序列还可采用序列或上下文并行分摊激活与注意力。

多卡并非天然降低 TTFT。如果输入不够长,通信和同步开销可能超过计算收益。应先确定目标模型是否能单卡部署,再根据 Profile 决定并行维度。

9. 精度与量化怎样影响 Prefill

FP16/BF16 到 FP8 或更低位宽可降低权重读取并提升 Tensor Core 吞吐,但 Prefill 通常计算更密集,收益取决于硬件的低精度算力和量化 Kernel。

量化必须回归长上下文能力、困惑度与目标任务指标。只验证短文本准确率不足以证明长 Prompt 的注意力数值稳定;同时要检查首 Token Logits 偏差是否影响生成结果。

10. Prefill/Decode 分离的取舍

混部时,Prefill 与 Decode 争用同一 GPU,却需要不同优化目标。分离部署可以让 Prefill 节点偏重算力、Decode 节点偏重带宽,并分别扩缩容。

代价是 Prefill 完成后必须把整份 KV Cache 传给 Decode 节点。网络带宽、拓扑与序列长度会决定传输是否抵消收益,还要解决节点比例失衡和失败重试问题。

11. 如何做性能诊断

先拆分排队时间和纯 Prefill 执行时间,再按输入长度分桶。TTFT 高但 GPU 执行短,问题多半在排队或组批;Kernel 时间随长度异常上升,则应检查注意力实现、Padding 与并行通信。

prefill_metrics = {
    "queue_ms": scheduled_at - admitted_at,
    "compute_ms": first_token_at - scheduled_at,
    "input_tokens": prompt_token_count,
    "effective_tokens_per_s": prompt_token_count / (compute_ms / 1000),
}

还应记录真实 Token 数而非字符数,因为中英文、代码和特殊模板的分词密度不同。

12. 怎样设计可相信的压测

从生产日志脱敏抽样输入长度、并发和到达间隔,覆盖短、中、长与极长四个桶。分别报告 TTFT P50/P95/P99、输入 Tokens/s、OOM、拒绝率、缓存命中率及回答质量。

对照实验每次只改变一个主要变量,例如 Chunk 大小或 FlashAttention 版本。灰度上线时设置 TTFT 和错误率回滚阈值,并保留旧引擎与旧调度配置。

Prefill 优化不是单纯把 Prompt 算得更快,而是在不丢关键信息的前提下,让首 Token 延迟可预测。

13. 常见误区与追问

  • 误区:Prefill 与 Decode 可以用同一个吞吐指标衡量。 两者计算形态和用户体验指标不同。
  • 误区:FlashAttention 把注意力复杂度变成线性。 它主要减少中间结果的显存读写。
  • 误区:把 Prompt 截短一定没有质量代价。 被删掉的证据可能正是答案依据。
  • 误区:前缀缓存命中只看文本相同。 模型、Tokenizer 和模板版本也必须一致。
  • 误区:多卡一定降低 TTFT。 小负载下通信可能成为主要开销。
  • 追问:Chunked Prefill 为什么改善 TPOT? 它避免长 Prefill 独占调度周期,让 Decode 能穿插执行。
  • 追问:优化应先做哪一层? 先删除无效 Token,再优化调度和 Kernel,最后考虑复杂的集群拆分。

14. 加强记忆

  1. 先记职责:Prefill 处理完整输入并建立 KV Cache。
  2. 再记瓶颈:长序列计算、KV 写入和批次波动。
  3. 再记减法:去重、摘要、动态检索减少无效 Token。
  4. 再记算子:FlashAttention 与融合 Kernel 降低数据搬运。
  5. 再记调度:Token 预算、长度分桶、Chunked Prefill。
  6. 再记复用:稳定公共前缀才适合缓存。
  7. 最后记验收:真实长度分布下同时看 TTFT、吞吐、显存和质量。