自回归生成与 KV Cache

LLM 与 Prompt 基础入门8讲解 1

模型一次只生成一个 token,再把它拼回输入继续算;一次请求分成 prefill 与 decode 两个阶段,瓶颈完全不同。KV Cache 缓存的是已算过的注意力键值,省的是重复计算而不是首次计算 —— 它的显存占用随序列长度与并发线性增长,是长上下文成本的真正来源。

也叫:自回归 · autoregressive · KV Cache · KV 缓存 · prefill · decode · TTFT · 首 token 延迟

原理拆解出自 T0-1

首字慢和吐字慢,卡的不是同一处
Prefill 算力密集,决定 TTFT;Decode 显存带宽密集,决定 TPS —— 一次请求两个瓶颈

prompt 1200 token
Prefill(预填充)
一次性并行算完产出每层每个位置的 K/V
决定首 token 延迟 TTFT算力密集 compute-bound
Decode(解码)
复用 prefill 存下的 K/V每次只算 1 个新 token打字机效果就是这么来的
决定吐字速度 TPS显存带宽密集 memory-bound
遇到停止条件接到序列末尾,再算下一个
有没有 KV Cache,差在哪一步
对照项没有 KV Cache有 KV Cache
每生成一个 token整段前文重算一遍只算新 token 这一列
注意力代价O(n²),n 每轮增长每步 O(n)
prefill 那一次要算同样省不掉

窗口是「第一约束」,因为三层成本叠在同一维度上:显存 —— KV Cache 大小大致正比于序列长度,还要乘以并发数;计费 —— 多轮每轮重发全部历史,成本是累加;有效性 —— 窗口大 ≠ 用得上,token 数上升,准确召回的能力会下降(context rot,T1-3)。

幻觉的根源在这里就能讲清一半:模型每一步只是在词表上给出下一个 token 的概率分布再采样,训练目标从来不是「说真话」,是「像语料那样接下去」。上下文缺答案时,「我不知道」并不是天然高概率的续写。应用层能改分布的条件,改不了目标函数。

prefill 那一次省不掉 —— KV Cache 省的是重复计算,不是首次计算,这是追问最爱落的一点。顺手记住另一句:打字机效果不是前端做的动画,是生成机制本身长这样。

一次请求分成两个阶段,它们的瓶颈完全不同——这是本篇最有区分度的一段:

原文示意
   Prefill(预填充)                       Decode(解码)
   输入 1200 token 一次性并行算完    →     每次只算 1 个新 token
   产出:每层每个位置的 K/V           ↖     复用缓存里的 K/V
          │                                      │
          ▼                                      ▼
   决定首 token 延迟 TTFT                 决定吐字速度 TPS
   算力密集(compute-bound)              显存带宽密集(memory-bound)

对照一下有无 KV Cache 的差别:

# 没有 KV Cache:每生成一个 token,整段前文重算一遍
tokens = prompt_tokens
for _ in range(max_new):
    logits = model(tokens)                     # n 每轮增长,注意力代价 O(n²)
    tokens.append(sample(logits[-1]))

# 有 KV Cache:前文的 K/V 存着,只算新 token 这一列
logits, cache = model(prompt_tokens, cache=None)   # prefill,这一次省不掉
for _ in range(max_new):
    nxt = sample(logits[-1])
    logits, cache = model([nxt], cache=cache)      # decode,每步 O(n)

注意 prefill 那一次是省不掉的——KV Cache 省的是重复计算,不是首次计算。这一点是后面追问的高频落点。

为什么说上下文窗口是「第一约束」——因为三层成本叠在同一个维度上:

  1. 显存。KV Cache 的大小大致正比于 2(K 和 V)× 层数 × KV 头数 × 头维度 × 序列长度 × 精度字节,再乘以并发数。序列长度是线性项,并发是乘数,所以长上下文服务的真正天花板往往不是算力,是显存装不下多少并发。
  2. 计费。多轮对话每一轮都要把全部历史重新发一遍(下一篇会讲清为什么),成本随轮次是累加,不是常数。
  3. 有效性。窗口大 ≠ 用得上。官方口径是把上下文当成一份注意力预算:token 数上升时,模型从中准确召回信息的能力会下降,各家模型只是衰减快慢不同。这就是 context rot,T1-3 专门展开。

幻觉的根源,在这里就能讲清一半。 模型每一步在做的事,是在词表上给出下一个 token 的概率分布,然后从中采样。它的训练目标从来不是「说真话」,而是「像语料那样接下去」。当上下文里缺少答案时,「我不知道」并不是一个天然高概率的续写——除非后训练教过它、或者你的提示词与工具给了它这个出口。所以幻觉不是 bug,是这套目标函数在信息缺失时的默认行为。应用层能改的是分布的条件(给证据、给出口、给校验),改不了的是目标函数本身。

以上节选自T0-1 Token、上下文窗口与自回归生成:三个约束的同一个源头,读全文能看到前后语境。

考这个知识点的题1

会连带问到7