10.2 提示缓存

Prompt Caching 是 2024 年 LLM 架构层面最大的创新之一。 它打破了“无状态 API”的魔咒,让长上下文应用变得既 便宜快速

10.2.1 什么是 Prompt Caching?

通俗类比:图书馆模式

  • 没有缓存 (No Cache):每次你去图书馆(Claude),都让你带一整车书(Context)过去。图书管理员必须一本本读完这些书,才能回答你的问题。这既费时(Token 计算慢)又费运费(Token 计费贵)。

  • 有了缓存 (With Cache):你只需要第一次把车开过去,告诉管理员:“这车书先放你这儿存 5 分钟”。接下来 5 分钟内,你再来问问题,只要报个书名,管理员直接就能回答,因为书已经在架子上了。

技术原理:KV Cache 重用

要理解缓存为什么能省钱,必须深入到 Transformer 架构的底层。

  1. 注意力机制 (Self-Attention): LLM 在处理每一个 Token 时,都需要“回头看”之前所有的 Token,以理解上下文关系。这个“回头看”的过程,在数学上就是计算 Attention 矩阵

    Attention(Q,K,V)=softmax(QKTdk)VAttention(Q, K, V) = \text{softmax}(\frac{QK^T}{\sqrt{d_k}})V

    其中:

    • Q (Query): 当前 Token 的查询向量(“我在找什么?”)。

    • K (Key): 历史 Token 的索引向量(“我有这个特征”)。

    • V (Value): 历史 Token 的内容向量(“这是我的具体信息”)。

  2. Prefill (预填充) 的代价: 当我们发送一段 10k 字的 Prompt 给模型时,模型必须计算这 10k 个 Token 每一层的 Q、K、V 向量。这个过程被称为 Prefill

    • 计算量巨大: 随着长度增加,计算量呈 $O(N^2)$ 或 $O(N)$ 增长(取决于实现),消耗大量的 GPU 算力。

    • 显存占用: 计算出的 Q, K, V 矩阵需要存放在 GPU 显存(VRAM)中。

  3. Cache Hit (缓存命中): Prompt Caching 的核心逻辑是:“只要前缀(Prefix)不变,K 和 V 矩阵就不变。”

    • 无缓存: 每次请求,GPU 都要重新把 10k 字算一遍矩阵。

    • 有缓存: 第一次算完后,我们将这 10k 字对应的 K 矩阵和 V 矩阵 (即 KV Cache) 直接“冻结”在显存里。

    • 复用: 下次请求如果前缀相同,直接把显存里的 KV Cache 拿来用,GPU 只需要从第 10,001 个 Token 开始计算。这不仅节省了算力(Write Cost),更极大地减少了内存搬运时间(Latency)。

spinner

10.2.2 缓存计费模型

Prompt Caching 的定价策略非常激进,旨在鼓励长 Context 复用。

状态
写入成本 (Write)
读取成本 (Read)
只有在...时发生

Cache Write

$3.75 / MTok

-

第一次请求,或缓存过期后重新写入。比普通 Input 贵 25%。

Cache Read

-

$0.30 / MTok

后续请求命中缓存。比普通 Input 便宜 90%!

划算临界点: 由于写入比普通请求贵 25%,通过简单计算可知,你需要 至少复用 2 次(1次写入 + 1次读取),总成本才会低于普通请求。复用次数越多,边际成本越接近 $0.30。

10.2.3 如何使用:代码实战

在 API 中,缓存不是自动的,你需要显式地标记 断点 (Checkpoints)。目前 Claude 支持最多 4 个 cache breakpoints。

SDK 示例

关键点: cache_control: {"type": "ephemeral"} 就是告诉 Claude:“到这里为止,前面的内容帮我存起来。”

10.2.4 最佳实践:结构化缓存

为了最大化命中率,必须遵循 “静态在前,动态在后” 的原则。因为缓存是基于 前缀匹配 (Prefix Matching) 的。

推荐结构

  1. System Prompt (Base) [Cache 1]

    • 内容: 角色定义、Tool Definition(这是最稳定的,所有用户共用)。

  2. Huge Context (Docs/Code) [Cache 2]

    • 内容: RAG 检索到的文档、整个代码库文件(相对稳定)。

  3. Conversation History (Turns) [Cache 3]

    • 内容: 之前的多轮对话历史。

  4. User Query [No Cache]

    • 内容: 用户当前最新的提问(完全动态)。

图解命中逻辑

即使 Request B 的历史记录变了,但前面的 System 和 Docs 依然能命中缓存,依然能省大钱。

10.2.5 生命周期 与驱逐

Claude 支持两种缓存 TTL 选项,对应不同的使用场景:

5 分钟缓存

  • TTL: 5 分钟

  • 写入成本: 1.25x (比普通输入贵 25%)

  • 读取成本: 0.1x (比普通输入便宜 90%)

  • 自动续期: 每次 Cache Hit,TTL 会自动重置为 5 分钟

  • 场景: 高频对话、快速迭代开发、用户在短时间内多次询问同一份文档

  • 只要请求不断(比如高频对话),缓存就可以一直存活

1 小时缓存

  • TTL: 1 小时(3600 秒)

  • 写入成本: 2x (比普通输入贵 100%)

  • 读取成本: 0.1x (比普通输入便宜 90%)

  • 自动续期: 每次 Cache Hit,TTL 会自动重置为 1 小时

  • 场景: 系统 Prompt 稳定的应用、知识库 RAG、企业内部 API 集成

  • 长期复用: 适合一小时内多次调用同一份稳定的 Context

缓存 TTL 对比表

维度
5 分钟缓存
1 小时缓存

TTL 时长

5 分钟

1 小时

写入成本

1.25x

2x

读取成本

0.1x

0.1x

损益平衡点

2 次读取

3 次读取

推荐场景

开发者迭代、聊天机器人

RAG 系统、企业 API

命中概率

高(5分钟内高频)

中等(1小时跨度)

驱逐策略

  • 自动驱逐: TTL 过期后缓存自动删除

  • 显式驱逐: 可以通过不再引用来让其自然过期(API 目前不支持显式 delete)

  • 防止羊群效应: 当缓存在高流量场景下同时过期时,应使用随机抖动分散 TTL 重置时间

缓存续期与扩展机制

10.2.6 适用场景 checklist

✅ 适合用缓存
❌ 不适合用缓存

长文档问答: 针对同一本书问 10 个问题。

一次性任务: 传一本书总结一下,然后就再也不问了。

代码助手: 整个仓库代码作为 Context,反复修改。

低频客服: 凌晨 3 点,每小时只有 1 个用户来访(TTL 会过期)。

Few-Shot: 带 100 个 示例的 Prompt。

短文本: 总共才 500 token,没必要缓存。

Agent: 工具定义特别多、System Prompt 特别长。

10.2.7 缓存冷启动成本分析

Prompt Caching 虽然省钱,但 第一次请求要付出代价。理解成本结构对选择缓存策略至关重要。

冷启动的三层成本

第 1 次请求(Cache Write)

  • 必须从零开始计算 KV Cache

  • 成本 = 1.25x 基础输入价格(比普通请求贵 25%)

  • 无法逃脱这个成本

后续请求(Cache Read)

  • 复用已缓存的 KV Cache

  • 成本 = 0.1x 基础输入价格(便宜 90%)

  • 前提:5 分钟内至少被访问一次(否则 TTL 过期需要重写)

总成本分析

假设基础输入价格为 1x,缓存周期内有 N 次请求:

成本-效益临界点计算

关键问题:需要多少次缓存读取才能抵消写入的额外成本?

对于 5 分钟缓存(写入成本 1.25x)

对于 1 小时缓存(写入成本 2x)

成本对比图表

spinner

决策树:何时使用哪种缓存

现实中的三种场景

场景 1:高频文档问答(适合缓存)

场景 2:低频 API 集成(不适合缓存)

场景 3:批处理工作流(谨慎使用缓存)

缓存失效与雷鸣羊群问题

缓存驱逐

当 TTL 过期后,缓存会被自动清除。下一个请求将触发新的 Cache Write:

防止“雷鸣羊群”

当缓存在高流量场景下突然过期时,可能导致大量并发请求同时尝试重写缓存,造成成本爆炸:

最佳实践总结

场景
推荐策略
理由

高频文档问答

5 分钟缓存

临界点低(2 次读),高频访问保证命中

代码助手开发

5 分钟缓存

开发者通常 5 分钟内多次迭代

个人知识库

1 小时缓存

用户可能一小时内回头查阅

API 集成

条件缓存

仅当日均调用 >1000 次时

一次性任务

不缓存

成本不划算

RAG 检索

1 小时缓存

文档库相对稳定,用户集中访问

10.2.8 实战案例:Claude Code 的缓存架构

Claude Code 是 Prompt Caching 大规模应用的最佳范例。其系统提示词的静态部分约占 70%,意味着大多数请求能缓存约 70% 的系统提示词 Token,显著降低了长会话的成本。理解它的缓存架构,对构建任何长会话智能体都有借鉴意义。

“上下文税”:你看不见的最大支出

每当 AI 智能体执行一个步骤时,它都必须重新阅读所有内容:系统指令、工具定义、以及之前已经加载过的项目上下文。这种重复计算被称为 上下文税(Context Tax)

算一笔账:一个包含 20,000 Token 的系统提示词,如果运行 50 个回合,意味着有 100 万 Token 的冗余计算 在按全价计费,却不产生任何新价值。Prompt Caching 正是消除上下文税的核心手段。

关键数据:Claude Code 中定义了一个 DANGEROUS_uncachedSystemPromptSection() 函数,用于显式声明某段内容会破坏缓存前缀。DANGEROUS_ 前缀是代码级警告——提醒开发者将易变内容放入静态区域会导致每次 API 调用都重新创建缓存,使输入 Token 成本从 cache_read 的 $0.30/MTok 上升到 cache_creation 的 $3.75/MTok(以 Sonnet 为例,差距达 12.5 倍)。

30 分钟编程会话拆解

以一个典型的 Claude Code 编程会话为例,观察缓存如何逐步发挥作用:

缓存成本模型深度分析

Claude Code 实现了分层的成本追踪系统,每个模型都有精确的定价表:

模型
输入 ($/MTok)
输出 ($/MTok)
缓存读取
缓存写入

Haiku 4.5

$1.00

$5.00

$0.10

$1.25

Sonnet 全系

$3.00

$15.00

$0.30

$3.75

Opus 4 / 4.1

$15.00

$75.00

$1.50

$18.75

Opus 4.5 / 4.6

$5.00

$25.00

$0.50

$6.25

Opus 4.6 快速模式

$30.00

$150.00

$3.00

$37.50

核心成本对比(针对 Sonnet):

  • 缓存写入 vs 正常输入:$3.75 / MTok vs $3.00 / MTok = +25%

  • 缓存读取 vs 正常输入:$0.30 / MTok vs $3.00 / MTok = -90%

  • 比值:读取成本仅为写入的 1/12.5

YOLO 分类器与缓存共享

Claude Code 包含一个内部的 YOLO(You Only Look Once)分类器,用于快速分类用户意图(代码问题、配置、依赖等)。这个分类器与主对话共享缓存前缀,实现 成本摊分

这种架构允许 Claude Code 进行快速的意图分类,而无需额外的缓存写入成本。

系统提示词的分层缓存架构

来源说明:以下内容基于社区对 Claude Code 源代码的逆向分析。具体分层结构可能随版本更新而调整。

Claude Code 的系统提示词由约 22 个独立片段组装而成,按缓存策略分为三层:

第一层:全局静态层(Global Cache)

这部分内容在所有用户、所有会话间完全相同,因此可以被全局缓存:

  • 角色定义和基本行为准则

  • 核心工具的 JSON Schema 定义

  • 安全策略和内容过滤规则

全局缓存的命中率最高,因为它对所有并发会话共享同一份 KV Cache。

第二层:组织/用户层(Org-level Cache)

这部分内容在同一组织或同一用户的不同会话间共享:

  • 企业管理策略(managed policies)

  • 用户级 CLAUDE.md 配置

  • MCP 服务器和自定义工具定义

第三层:会话动态层(Uncached / Volatile)

每次请求都可能变化,无法缓存:

  • 当前工作目录和 Git 状态

  • 最近的命令历史

  • 会话特定的性能指标

这种分层设计的经济意义在于:全局层的缓存写入成本被海量用户分摊,单个用户的边际成本趋近于零;组织层的成本在团队内分摊;只有动态层需要每次全价计费。这也解释了为什么 CLAUDE.md 的内容变更会影响缓存效率——它位于第二层,变更后该层及以下的缓存都会失效。

延迟工具加载优化

Claude Code 实现了 工具定义的延迟加载(Deferred Tool Loading),大幅减少初始化开销:

这个优化 节省约 60% 的工具描述 token。初始化时仅需加载 essential 工具,其他工具在用户首次使用对应功能时加载。

毁掉缓存的三条反模式

关于缓存,最反直觉的一点是:1 + 2 = 3,但 2 + 1 会导致缓存失效。基础设施对提示词进行哈希处理,如果顺序发生任何变化(即便元素相同),哈希值就会改变。

由此衍生三条关键准则:

反模式
后果
正确做法

在会话中途增删工具

前缀改变,所有后续缓存失效

始终预加载全部工具定义

在中途切换模型

缓存是模型特定的,无法跨模型复用

一个会话绑定一个模型

为了改状态修改前缀

前缀哈希变化,缓存全部作废

在下一条用户消息中追加 <system-reminder> 标签

缓存安全分叉:压缩时的高级技巧

当达到上下文限制需要压缩历史时,不要截断前缀。正确做法是保持完全相同的系统提示词、工具和对话结构,将压缩请求作为新消息添加:

这样重组后的请求几乎完全复用了原有的缓存前缀。

自动缓存与监控指标

Anthropic 已在 API 中加入了 自动缓存(Auto-caching) 功能,缓存断点会自动向前移动,无需手动设置 cache_control

无论使用手动还是自动缓存,都应密切关注每个 API 响应中的三个字段:

像监控系统正常运行时间(uptime)一样去监控缓存效率。如果效率低于 80%,应检查是否存在上述三种反模式。


缓存解决了静态上下文的成本问题。但对于不断增长的动态对话历史,我们无法无限期地缓存下去,这就需要更高级的管理策略。

➡️ 上下文窗口管理

最后更新于