localaiforum
登录
指南 › 硬件

上下文窗口与 KV 缓存

上下文窗口有价签,以显存支付。上下文里的每个词元都迫使模型在每层记住两个小向量,而那块内存——KV 缓存——随每个词元增长,悄悄吃掉你以为拥有的余量。它解释了本地 LLM 最奇怪的一批失败:第四十轮的 OOM、随着聊天变长似乎变慢的模型、以及只在宣传册里能跑 “128k 上下文” 的 8 GB 卡。

缓存存储什么

注意力需要每个过去词元的键和值投影才能关注它。它们在预填充期间计算一次,并在请求的生命周期内保留:每层、每词元、各一个 K 向量和一个 V 向量,每个含 kv_heads × head_dim 个数。那块存储就是 KV 缓存,也是上下文对每个被服务的请求永远线性花费内存的原因。

公式

bytes per token = 2 (K and V) × layers × kv_heads × head_dim × 2 bytes (fp16)

算例,llama-3-8B 级 GQA(32 层、8 个 KV 头、head_dim 128):

2 × 32 × 8 × 128 × 2 = 131,072 字节 = 每词元 128 KB。

32k 上下文时是 32,768 × 128 KB ≈ 4 GB 的 KV 缓存——与旁边 Q4 权重相当。4 个 KV 头的更精简配置落在每 32k 约 2 GB。8B 级模型 fp16 KV 的数量级:按架构每 32k 预算 0.5–4 GB。检查点的精确数字直接来自其 config.json——num_key_value_heads、num_hidden_layers 和头尺寸。

GQA 是长上下文变便宜的原因

分组查询注意力让多个查询头共享一小撮 KV 头——比如 32 个查询头由 8 个 KV 头服务——以可忽略的质量代价把缓存相对完整多头注意力缩小 4 倍。没有 GQA,下面的表会大 4–8 倍,24 GB 卡上的长上下文就是幻想。它是对本地长上下文工作最大的单项架构馈赠,也是现代 7–9B 模型根本能提供 32k–128k 窗口的原因。

它长得多快

8B 级 GQA 模型、fp16 KV、每词元 128 KB:

上下文 KV 缓存大小 在 8 GB 卡上
4k ~0.5 GB 不可见
16k ~2.1 GB 在 5 GB 权重旁可感
64k ~8.4 GB 装不下,句号
128k ~16.8 GB 模型本身的 3 倍

内存随词元线性增长,但注意力计算随上下文平方增长——所以长上下文同时花费显存和每词元时间。

KV 爆炸时的杠杆

  • 量化缓存。 q8_0 减半、q4_0 取四分之一,质量代价温和——常常是整个栈里最好的容量交易。llama.cpp 中 KV 量化需要 flash attention,见下。
  • 服务更短的上下文。 如果你的提示词 2k,-c 8192 一分钱不花。按宣传的 128k“以防万一”分配,是在保留你永远用不上的显存。
  • 滑动窗口模型。 一些架构不管名义上下文、按层封顶 KV 窗口——没有线性账单的长上下文行为,代价是对旧材料的一些召回损失。
  • Flash attention。 根本上是计算和内核效率的胜利——精确注意力而没有二次激活爆炸——而且在 llama.cpp 里它也是解锁 KV 量化的门。
llama-server -m model-8b-q4_k_m.gguf -c 65536 -fa --cache-type-k q8_0 --cache-type-v q8_0

宣传上下文 vs 有效上下文

宣传 128k 的模型会运行在 128k——缓存装得下、数学成立。它是否推理在 128k 是另一个主张。拉伸的 RoPE 和长上下文微调让针检召回分数保持高位,而更广泛的理解常常远在极限之前就垮。把宣传窗口当作物理最大值,假设质量在后半段变软,并在把工作流押上去之前寻找该检查点的社区长上下文评估。

迷失在中间,与卫生习惯

位置偏差是真的:模型对提示词的开头和结尾关注最强、在中段下垂。把指令和关键事实放开头或结尾;绝不把模型必须遵守的规格埋进粘贴的文档里。保持上下文小而锐利的习惯:

  • 修剪或摘要旧轮次,而不是重放整个聊天。
  • 检索并注入相关分块,而不是整个文件。
  • 系统提示词保持短;它随每个请求重发。
  • 长会话中盯着显存——KV 增长是沉默的变量(显存计算),控制它的服务标志编目在 引擎参数。

相关: 显存计算 · 引擎参数 · 速度