← 返回书架人工智能 · 交互式 Wiki
模型工程/生成执行与 KV Cache资料与边界
生成与检索服务进阶专题讲解

ARCHITECTURE / INFERENCE ENGINE

自回归推理的两个阶段:prefill 与 decode

标准全因果 Attention 的 prompt 可以并行计算并写入 KV Cache;常规 decode 每轮每请求输入一个新 token,并读取此前可见位置的 K/V。 prefill 与 decode 的计算形态不同,瓶颈还取决于 batch、序列长度、结构与硬件。

01

prefill 与 decode 怎样计算

同一组权重,处理 token 的方式不同:prefill 并行吃整段 prompt,decode 逐个追加。

PREFILL

一次并行处理整段 prompt

所有 prompt token 同时经过各层,计算 self-attention;输出最后位置的 logits,同时缓存每一层的 K/V。通常更偏 compute-bound,决定 TTFT 的主体。

tokens_compute = prompt_length
DECODE

输入上轮 token,预测下一个

首 token 由 prefill 的最后位置 logits 采样。decode 将它作为下一次输入,逐层计算新 Q/K/V、读取历史 KV 并追加本位置的 K/V,再预测后一个 token。小 batch 常受权重与 KV 读取带宽限制。

new_tokens = 1 per decode step
TTFT排队 + prefill + 首个 token
TPOT / ITL每个后续 token 的 decode 间隔
总生成时延TTFT + (N−1) × TPOT
02

走一遍 prefill → decode

下面按 forward 步骤展示输入位置数、已生成 token 数和缓存长度。

固定等长 batch、无 EOS 提前停止,最多展示 40 个输出。每次 forward 后立刻采样;因此已生成 G 个 token 时,缓存长度是 P+G−1。真实 serving 还需处理分块 prefill、动态批处理与分页。随机采样时还应核对随机流是否跟随请求身份。

EXECUTION STATE

等待 prefill

0 generated
最近一次 forward 输入 token0
每条序列缓存位置0
batch KV 位置0
点击“执行 prefill”:prompt 的所有 token 一次并行进入模型,并写入所有层的 KV。
03

KV Cache 占多少显存?

标准 MHA 每层保存 K 与 V。GQA/MQA 让多个 query heads 共享 KV heads,缓存按共享后的数量计算。下面假设各层配置相同、K/V 的 head dim 相同、每请求保留 S 个位置且不跨层共享;滑窗、MLA、层间共享及量化元数据需另算。

ATTENTION PRESET

每 token / 每请求128 KiB
单请求当前上下文512 MiB
batch 总 KV2.0 GiB
公式 KV bytes = B × S × L × 2 × Hkv × dhead × bytes
KV 随上下文增长(当前 batch)2.0 GiB @ 4K
当前 GQA:query heads 可以更多,但 KV 只有 8 组。上下文翻倍,缓存几乎按线性增长;长上下文服务中,KV 可能成为显存的主要占用。
04

Attention 的计算量与数据访问量

大 O 记号帮助看增长趋势,但真实延迟还受内存层次、kernel、batch 与序列调度影响。

PREFILL

更多是并行矩阵乘

投影与 MLP 是大的矩阵乘,GPU 利用率高;self-attention 的 token 交互项随 S² 增长。长 prompt 是吞吐与 TTFT 的主要压力。

attention interaction ≈ O(S² d)
DECODE

每步算得少,却要搬很多 KV

单 token 的 Q 很小,历史 K/V 读取量随 S 增长。GPU 可能更多在等内存带宽,而不是算术单元;批处理可提高总吞吐但增加缓存。

KV read ≈ O(S · L · Hkv · dhead)
WEIGHTS

每步都要过全部层

decode 每生成一个 token 都要遍历 L 层投影、MLP/MoE 与最终 head。权重读取通常占固定大块成本,MoE 可减少每 token 的专家计算但增加路由。

layers = L every token
05

真实 serving 系统在做什么

这些方法主要改进请求调度、缓存管理和执行效率。

CONTINUOUS BATCHING

每轮动态补请求

一个请求结束后立刻释放槽位,不等整批结束。prefill 与 decode 请求可以交错调度,提高 GPU 利用率。

PAGED ATTENTION

KV 分页,避免预留巨大连续空间

把每条序列的 KV 切成块,按需分配与回收。减少内存碎片和过度预留,也方便连续批处理与共享 prefix。

PREFIX CACHE

相同系统提示或文档前缀复用 KV

还必须匹配实际前缀 token/模态输入及其顺序、模型与 adapter 权重、位置和 attention 配置等缓存键;只比较用户文本不够。命中缓存能省前缀计算,但存储、淘汰与权限隔离仍需设计。

CHUNKED PREFILL

把长 prompt 切片调度

避免一个超长 prefill 独占 GPU 很久,让正在 decode 的请求也能获得执行机会,但会增加调度与时间指标复杂度。

SPECULATIVE DECODE

小模型猜,大模型验

用 draft 模型提出多个 token,再由目标模型并行验证接受。收益取决于接受率、验证成本和草稿模型的额外计算。

KV QUANTIZATION

更少 bytes,更多误差

FP8/INT8 缓存可减少带宽与显存,但可能影响长上下文质量;还要注意 scale、分组与 kernel 支持。

06 / MULTIPLE REQUESTS

请求不断到来,计算和缓存怎样分配?

静态波次等待当前一组全部结束,再接纳下一组;连续批处理允许在迭代边界加入新请求。分块 prefill 让长输入分几轮处理,可与 decode 共享调度预算。预算单位与优先级由具体系统定义。

三请求与四 token 缓存块

逻辑 tick · 最多 2 个活动请求
轮次
已计算位置
已复用位置

峰值已占用块:;当前预留容量(含共享块):

请求到达 tick状态输入已处理输出已采样活动 KV 位置首 token 等待完成耗时

    A:(到达0,输入8,输出4),B:(1,8,3),C:(2,4,2);A/B 共享前4个 token。FIFO 接纳,decode 优先,每请求每轮至多一个 decode;输出长度预先固定。缓存达到 P+G−1,完成后释放私有块。

    为了避免小容量下出现无可分配块的僵持,面板在接纳时为请求的已知最大长度预留容量额度,但物理块仍随 token 按需分配;预留额度与已占用块分别显示。真实引擎可能采用抢占、交换或重算等策略,本例没有实现这些策略,也没有把 tick 换算为毫秒。

    开启前缀时,预热块占一个物理块,生成它的先前成本不计入本队列。它只在 A/B 活跃时有活动引用,两个请求结束后仍作为可复用缓存保留。这里不继续缓存新产生的私有块,不模拟 LRU 驱逐或多租户哈希。

    07 / CACHE OWNERSHIP

    共享前缀为什么需要引用、版本和回收规则?

    匹配的是完整计算条件

    同样文本未必同样 token。模型版本、adapter、位置、模态输入和缓存隔离信息都可能影响键;块内容还依赖此前前缀。命中前必须确认上下文计算条件兼容。

    释放引用与驱逐是两步

    请求结束可以减少引用计数。引用为零的块可被保留为缓存,也可被回收覆盖;仍被其他请求使用的块不能直接覆盖。

    共享块应保持不可变

    完整前缀块可供多个请求只读使用。分支继续生成需要私有尾块;如果系统允许共享未满尾块,写入前通常需要复制或其他隔离机制。

    缓存省去什么

    命中的前缀 K/V 可复用,后续 query 仍要读取相关历史状态。Prefix cache 节省的主要是相同前缀的重复 prefill;实际时延还取决于查找、搬运和剩余计算。

    BACK TO THE SYSTEM

    把权重、KV、batch 与训练并行放回同一张资源账本。

    适用范围与一手资料

    单请求缓存按已输入位置计算。队列模拟最多两请求、已知输出长度、接纳时预留容量、按需分配物理块;共享块预热,不模拟 LRU、抢占或真实毫秒。

    公式与机制的原始依据 · 4 项
    知识目录
    搜索知识库