# 不是存答案，而是存「计算进度」：KV Cache 为什么能省钱？

> 作者：晨旭｜发布：2026-09-07｜系列：AI技术理解
> 来源：https://chenxu.xin/writing/kv-cache-why-cheaper

KV Cache 缓存的不是答案，而是模型处理上下文时产生的中间计算结果。从这一句出发，解释改动前文为什么会让缓存失效、换模型为什么要重新付费，以及它和上下文压缩之间的取舍。

---

## 开篇

做 Agent 产品的时候，大概都听过这句话：

> 命中缓存，计费就会少很多。

用 AI 产品的时候，可能也会看到这样的小提示：

> 如果切换模型，花费会更多哦～

这两句话其实指向同一件事：KV Cache 可以改变一次请求要花多少钱。

第一次听到 KV cache 可能会下意识地觉得必须先把 Transformer、注意力机制、矩阵运算都搞明白，才有资格理解它。但如果只是想在做产品时把它用对，完全不需要这些术语。

下面可以从我们听到最多的那个问题开始：

为什么同一段上下文，第一次交给大模型处理比较贵，再次使用却能便宜很多？难道是模型把答案提前存好了吗？🤔

不是这样的。

KV Cache 缓存的是模型处理这些内容时产生的中间计算结果。下一次遇到相同的开头，系统可以直接复用这些结果，不必从头再算。

接下来解决的每一件事：为什么改动前面的内容会让缓存失效、为什么换模型就要重新付费、它和上下文压缩是什么关系，都是从这一句推出来的。👇

## 模型「读一遍」并不便宜

首先我们平时和大模型聊天，它为什么会一直记得前面说过的话？这个我在之前的文章中有写到～（一定要先理解这个原理才能理解下面的内容🌟）[深度解析 Memory 本质](/writing/agent-memory-essence)（在第二部分：记忆的本质）

人读一份一百页的资料需要花时间理解，大模型也一样。

模型在收到一段文字后，它不能直接开始回答。它需要先处理所有输入，理解每句话之间的关系：

- 这句话是谁说的？
- 它和前面的要求有什么关系？
- 哪些信息比较重要？
- 当前问题应该参考哪些内容？

这个「阅读和理解输入」的过程需要大量计算。

一段几百字的对话可能不明显，但在编程、办公助手这种长程任务 Agent 中，输入经常包含：

- 几十轮聊天记录
- 大量代码
- 文件内容
- 搜索结果
- 命令执行日志

一轮请求可能包含几万甚至几十万字。

如果每次请求都从头计算一遍，这会浪费大量时间和算力。

于是，KV Cache 出现了。👇

## KV Cache：把已经算过的部分保存下来

大模型在收到一段文字之后，不能马上给出回答。它需要先处理整段输入，通过大量计算建立各部分内容之间的关系，再在这些计算结果的基础上生成回复。

而且，后面的计算会受到前面内容的影响。

即，大模型处理一次请求，可以粗略分成两个阶段：

1. 处理输入，建立对上下文的计算结果；
2. 根据这些结果生成回答。

第一阶段也叫预填充。KV Cache 主要节省的就是这一阶段中重复发生的计算。

可以把这个第一阶段想象成一张很长的电子表格。表格中有一百行公式，后面每一行都需要参考前面的结果。

```text
第 1 行   → 计算结果 1
第 2 行   → 计算结果 2
……
第 100 行 → 计算结果 100
```

第一次打开表格时，电脑需要把一百行全部计算一遍。

如果我们只在末尾新增第 101 行，前面一百行完全没有变化，电脑就不必从头重算，只需要读取以前保存的结果，再计算新增的一行。

👉 KV Cache 保存的，就是大模型在阅读和理解已有内容时产生、并会在后续生成中反复使用的一部分中间计算结果。

它不是对原文的摘要，也不是模型对过去的记忆，而是模型服务替它保存下来的计算结果。

### 顺便说一句：为什么叫 KV Cache 呢？

KV 中的 K 和 V，分别来自两个英文单词：

- K：Key
- V：Value

它们是模型处理上下文时产生、并会在后续生成中反复使用的两组内部数据。

不理解背后的数学公式没关系～只要记住：

KV Cache 保存的不是聊天记录、摘要或者最终答案，而是模型处理上下文时产生的部分中间计算结果。

所以，可以把 KV Cache 简单理解为：

**大模型的上下文计算缓存。**

把这个过程放到真实对话中看，就更容易理解了～👇

第一次请求是：

> 你是一名编程助手。项目使用 Go。数据库使用 MySQL。请帮我设计用户表。

第二次请求是：

> 你是一名编程助手。项目使用 Go。数据库使用 MySQL。请帮我设计用户表。接下来再帮我设计订单表。

第二次请求的开头与第一次完全相同，只在末尾增加了一个新问题。

这时，模型服务就可以直接复用前面那部分已经保存的计算结果，只处理新增加的内容。这就是所谓的「缓存命中」。

连续对话特别适合使用 KV Cache，正是因为每一轮通常都可以理解为：

> 上一轮的全部内容 + 本轮新增内容

👉 前面的聊天历史保持不变，新的消息不断追加在末尾，因此已经完成的计算可以被反复复用。

但如果我们把原来的「项目使用 Go」改成「项目使用 Python」，情况就不一样了。👇

这时，后面几句话可能就需要根据 Go 和 Python 这两个不同编程语言的特点，去重新理解。从发生变化的位置开始，后续计算结果通常都不能继续使用。（因为模型理解输入的方式是计算，而这个计算过程就是和上面比喻的表格一样，前后相互关联着。）

所以，KV Cache 并不要求整次请求从头到尾都与上一次完全相同，但它通常只能复用：

**从开头开始，连续保持相同的那一部分内容。**

不过，拥有相同的开头还不够。KV Cache 是某个具体模型计算出来的结果，因此能否复用，还与当前使用的是不是同一个模型有关。👇

## 为什么换了模型，花费通常会增加？

前面提到，聊天过程中只要上下文的开头保持不变，模型服务就可能复用之前保存的计算结果，只处理后来新增的内容。

但这些缓存并不只由聊天内容决定，它还属于生成它的具体模型。

不同模型使用不同的参数和计算方式。即使读取完全相同的聊天记录，产生的中间计算结果通常也不一样：

```text
模型 A：聊天历史        → 模型 A 的缓存
模型 B：同一段聊天历史  → 模型 B 的缓存
```

因此，模型 B 通常不能直接使用模型 A 生成的缓存。

如果在聊天途中切换模型，可能出现这样的过程：

- 切换前：模型 A 已有缓存 → 主要处理本轮新增内容
- 刚切换到模型 B：模型 B 没有对应缓存 → 需要重新处理整段聊天历史
- 继续使用模型 B：模型 B 已经建立自己的缓存 → 后续请求又可以复用相同的上下文前缀

这就是为什么聊天进行到一半时切换模型，花费往往会突然增加：聊天记录虽然没有消失，但新模型需要重新处理它。

那如果后来又切回模型 A，能不能重新使用原来的缓存呢？🤔

有可能，但也不能保证。还要看旧缓存是否仍然存在、是否已经过期，以及请求开头是否仍然完全一致等等。

所以，缓存能否复用，需要两件事同时成立：请求的开头没有变化，以及处理它的还是同一个模型。可以这样记：

**聊天历史属于这段对话，但缓存属于处理它的那个具体模型。**

不过，这里就有一个矛盾。KV Cache 能省钱，前提是前面的内容一直保持不变。但在真实的 Agent 产品里，有一件事专门在做相反的事情：上下文压缩。👇

## 上下文压缩与 KV cache

KV Cache，是在缓存模型处理上下文时产生的中间计算结果，回到前面说过的两个阶段，它只参与第一阶段：处理输入，完全不参与生成答案。

所以，即使前面的聊天记录命中了缓存，模型仍然需要根据本轮新增的问题生成回答。同一段历史后面接上不同的问题，当然会得到不同的答案；即使问题完全相同，由于生成过程可能存在随机性，两次回答也不一定一模一样。

如果输入完全相同，读取此前保存的中间计算结果，与重新计算这部分内容，理论上应该得到相同的效果。KV Cache 没有删除原始信息，也没有重新改写上下文，它只是让相同的内容不必重复计算。

这也是 KV Cache 和上下文压缩最重要的区别：

- KV Cache 是「相同的内容不重复算」
- 上下文压缩是「把原来的内容变短以后再算」

👉 KV Cache 通常是无损复用，而上下文压缩会删减、截断或总结历史信息，因此可能遗漏细节。

下面重点讨论一下最常见的摘要式压缩：👇

假设一段对话原本是：

```text
A + B + C + D + E + F
```

系统保留最近的 E、F，把前面的内容整理成「摘要 1」：

```text
摘要 1 + E + F
```

随后，对话又产生了 G、H、I：

```text
摘要 1 + E + F + G + H + I
```

在正常聊天阶段，前面的内容没有变化，只是在末尾不断增加新消息，因此已有缓存可以持续复用。

但当系统再次压缩时，就需要在两种方式之间选择。

（1）第一种方式是保留旧摘要，只压缩后来新增的历史：

```text
摘要 1 + 摘要 2 + H + I
```

👉 这种方式能够保留更稳定的输入前缀，有利于继续复用旧缓存。但随着压缩次数增加，摘要会越来越多，内容之间也可能出现重复、过时甚至矛盾。

（2）第二种方式是把旧摘要和新增历史重新整理成一份统一摘要：

```text
摘要 2 + H + I
```

👉 这样可以删除过时信息、合并重复内容，并让上下文长期保持简洁一致。不过，「摘要 1」变成「摘要 2」以后，输入前缀发生了变化，压缩后的对话就需要重新计算并建立新的缓存。

但是，（这里有个小分支）这难道就意味着之前的缓存完全浪费了吗？

不一定。🙂‍↔️

如果压缩系统设计得当，那么生成新摘要的请求这里就可以用到 KV cache 了～系统只需要继续处理新增内容和压缩指令，再生成新的摘要。

但是，（回到主线）新摘要替换旧内容以后，主对话模型处理请求就不能用之前的缓存了，因为「摘要 1」已经变成「摘要 2」，从变化的位置开始，旧缓存通常不能继续用于压缩后的对话。

整个过程可以概括为：

1. **正常对话**：前文不变，末尾增加消息 → 持续命中缓存
2. **生成摘要**：利用未变化的前缀生成新摘要 → 旧缓存仍可能降低压缩成本
3. **摘要替换**：新摘要改变了输入前缀 → 重新建立缓存
4. **继续对话**：新摘要保持不变，末尾增加消息 → 再次持续命中缓存

所以，摘要管理和缓存复用之间存在一个取舍：

- 保留所有旧摘要，缓存更加稳定，但上下文会越来越杂乱；
- 定期合并旧摘要，会暂时损失部分缓存，但上下文更加简洁一致。

👉 实际系统可能采用增量摘要、定期合并，或者两者结合。无论选择哪一种，核心目标都是在缓存成本、上下文长度和信息完整性之间取得平衡。

## 最后

KV Cache 是模型服务保存下来的中间计算结果。相同的上下文再次出现时，系统可以直接复用这些结果，只计算新增的内容。

但它不是完全免费，因为读取缓存、新增内容和生成答案仍然需要资源。

它也不是在缓存答案，更不是模型突然拥有了长期记忆。

完整过程可以概括为：

- **第一次请求**：处理全部内容 → 产生中间计算结果 → 保存可复用结果 → 生成回答
- **后续请求**：读取已有计算结果 → 处理新增内容 → 生成新回答

所以，「缓存命中为什么更便宜」的真正答案是：

因为大模型不必重新完成已经做过的计算。存储和读取依然有成本，但通常远低于重新调用 GPU 计算整段上下文的成本。

## 核心结论

- KV Cache 存的既不是聊天记录、摘要，也不是答案，而是模型读完输入后产生、并会在后续生成中反复使用的中间计算结果。它是上下文计算缓存，不是模型的记忆。（把握较大）
  永久链接：https://chenxu.xin/writing/kv-cache-why-cheaper#kv-cache-stores-computation
- 缓存只能复用从开头开始、连续保持相同的那一部分内容。从发生改动的位置起，后面的计算结果通常都不能继续使用。（把握较大）
  永久链接：https://chenxu.xin/writing/kv-cache-why-cheaper#cache-reuse-needs-identical-prefix
- 聊天历史属于这段对话，但缓存属于处理它的那个具体模型。中途切换模型，新模型必须把整段历史重新处理一遍，这就是花费突然增加的原因。（把握较大）
  永久链接：https://chenxu.xin/writing/kv-cache-why-cheaper#cache-belongs-to-the-model
- 上下文压缩和缓存复用天然冲突：保留旧摘要能维持稳定前缀、利于命中缓存，但上下文会越来越杂乱；合并成一份新摘要能让上下文简洁，却改写了前缀、让旧缓存作废。（判断 · 把握中等）
  永久链接：https://chenxu.xin/writing/kv-cache-why-cheaper#compression-conflicts-with-cache

---

本文出自晨光里的AI（https://chenxu.xin），作者晨旭。
引用时请保留来源链接。文中标注「判断」「假设」的部分是作者的个人看法，不是事实。
