主题
大模型缓存是什么
用 Claude Code、Cursor 这类工具时,你可能在用量明细里见过"缓存读取""Cache Read"这样的字样,费用还特别低。这一篇讲清楚:这个缓存到底是什么、为什么它能省钱提速、以及什么样的对话才能命中它。
1. 先理解一个问题:模型很"健忘"
大模型本身是无状态的——它不记得你们之前聊过什么。
你在客户端里看到的"连续对话",实际是这样运作的:
text
第 1 轮请求:[系统提示词] + [你的问题 1]
第 2 轮请求:[系统提示词] + [问题 1] + [回答 1] + [你的问题 2]
第 3 轮请求:[系统提示词] + [问题 1] + [回答 1] + [问题 2] + [回答 2] + [问题 3]
……每一轮,客户端都要把从头到尾的全部历史重新发送一遍。对话滚到几万 token 后,每次请求携带的内容都非常大(《效率与省钱技巧》里说的"输入也在花钱"就是这个道理)。
更麻烦的是,模型收到这些内容后,要把每一部分从头计算一遍才能开始回答。这部分计算叫"预填充"(Prefill),它发生在你看到第一个字之前——内容越多,等待越久。
2. 缓存:算过的部分别再算一遍
模型处理文本时,会为每个 token 生成一份中间计算结果(技术上的名字叫 KV 状态),后面的 token 都要用到前面 token 的这些结果。
上下文缓存(Context Cache,也叫 Prompt Cache)做的事:服务端把这些中间结果存下来。下次请求进来时,先比对新内容的开头部分——如果和上次请求的开头一字不差,这部分直接复用上次的结果,跳过重复计算。
回到第 1 节的例子:
text
第 2 轮请求:[系统提示词 + 问题 1 + 回答 1] ← 这段和上一轮完全相同,命中缓存
[问题 2] ← 只有新增部分需要真正计算对话越长,开头相同的部分越大,缓存省掉的重复计算就越多。Claude Code、Codex CLI 这类编程工具之所以把系统提示词和工具定义固定放在对话最前面,并且每一轮都保持不变,正是为了让这个最大的"公共开头"能被缓存。
3. 对话的实际影响:更快、更便宜
3.1 更便宜
缓存命中的部分按大幅折扣计费,不按正常输入价收。以主流 API 为参考:
| 部分 | 计费方式 |
|---|---|
| 命中缓存的输入 | 约为正常输入价的 1/10 ~ 1/2(各平台不同) |
| 未命中的输入 | 正常输入价 |
| 输出 | 不受缓存影响 |
在第三方中转平台(如 STJAPI)上,用量明细里的"缓存读取"通常也是单独一列、单价明显更低。长会话中,命中缓存的部分往往占每次请求输入的绝大部分,实际费用可能只有"全部按原价算"的几分之一。
3.2 一笔账:命中与不命中差多少
假设一轮对话要重发 50,000 token 的历史输入,其中 45,000 token 与上一轮完全相同(命中),5,000 token 是新增内容:
text
不命中:50,000 × 全价 = 100% 输入费用
命中后:45,000 × 1/10 + 5,000 × 全价 ≈ 19% 输入费用(按 1/10 折扣示意)一轮就省下约 8 成输入费用;一场几十轮的长会话,总费用差距就是几倍。折扣比例各平台不同(见上表),但"长会话里命中占大头"是共同的。这是笔示意账——你自己的真实比例,按第 6 节的方法查一次用量明细就知道。
3.3 更快
缓存跳过的是"预填充"计算——也就是你等第一个字出现的那段时间。会话越长、命中率越高,首字响应越明显地变快。
3.4 对话质量没有影响
缓存复用的只是中间计算结果,结果和现算一模一样。命中缓存不会让回答变差,也和上下文窗口大小无关——它影响的是速度和费用,不是模型的"记忆容量"。
4. 什么情况下缓存会失效
缓存命中的条件非常严格:从第一个 token 开始的前缀必须完全一致。常见的不命中原因:
| 场景 | 结果 |
|---|---|
| 系统提示词里写了当前时间、随机 ID 等动态内容 | 开头就变了,后面全部缓存作废 |
| 客户端修改了系统提示词或工具定义(如升级版本后) | 从变化处开始缓存失效 |
| 距离上次对话超过几分钟(缓存有过期时间) | 缓存被清除,下一轮全价 |
| 切换了模型 | 不同模型不共享缓存 |
其中过期时间(TTL)值得注意:主流平台的缓存一般只保留几分钟到一小时不等。这也是"中途停下来吃个饭,回来继续聊第一句会明显变慢变贵"的原因。
5. 怎么让对话尽量命中缓存
不需要手动操作任何东西——缓存由客户端和服务端自动完成。你能做的是不破坏它:
- 保持前缀稳定。如果是自己写程序调 API,把固定内容(系统提示词、工具定义、文档)放最前面,把每次变化的内容(用户消息、时间戳)放最后。
- 同一个会话里连续对话。隔几分钟就断开重聊,等于每次都重新付全价预填充。
- 别频繁切换模型。同一个任务尽量用同一个模型跑完,切换即缓存作废。
- 长会话主动压缩。用
/compact压缩历史,压缩后前缀变短,但后续轮次又能稳定命中了——具体操作见第 6.2 节。
6. 动手:确认缓存真的在帮你
6.1 查一次用量明细
花五分钟,把你"感觉省了"变成"看到省了":
- 打开所用平台的控制台用量或日志页(STJAPI 的入口见《接入实战》第 5 节);
- 找一次多轮对话的请求,看输入是否拆成了三部分:缓存写入、缓存读取、未命中输入;
- 对比同一会话的第 1 轮和第 3 轮:第 1 轮几乎全是未命中,之后"缓存读取"应占大头;
- 如果几轮之后命中率仍然很低,回到第 4 节逐条排查失效原因——最常见的是系统提示词里带了时间戳等动态内容。
用 Claude Code 的可以直接输入 /cost,查看当前会话的 token 与费用统计。
6.2 长会话压缩的标准动作
出现任一信号就该压缩:响应明显变慢、模型开始忘开头的要求、输入费用比前几轮明显上涨。
- 输入
/compact,可附带重点提示,例如/compact 保留当前重构方案和剩余步骤,比默认压缩更保关键信息; - 压缩把历史变成摘要,前缀变短——接下来几轮会重新建立缓存,之后继续稳定命中;
- 压缩那次请求本身要付全价,所以不要每轮都压,攒到信号出现再做。
压缩会丢细节。关键决定和数字先让模型复述一遍、确认进了摘要,再执行压缩。
7. 一页速查
- 模型无状态,每轮对话都重发全部历史并重新计算——缓存就是"算过的开头别重算"。
- 命中条件:从第一个 token 起完全一致的前缀;命中部分按 1/10 ~ 1/2 的价格计费,且首字响应更快。
- 缓存几分钟不用就过期;开头有动态内容(时间戳等)会从那里开始全部作废。
- 缓存不影响回答质量,也不增加记忆容量,只影响速度和费用。
- 实践上:连续对话、不频繁切模型、长会话主动压缩,就是在"喂"缓存。
想看这三层缓存的底层实现——KV Cache 的显存账、Prefill 与 Decode 为什么性能特征完全不同——读《LLM 推理全链路剖析》第 4 节。