PROMPT CACHING
Claude 提示缓存(Prompt Caching)
Claude 提示缓存中文文档:自动缓存与显式断点、5 分钟和 1 小时 TTL、计费倍率、缓存失效规则、usage 字段与命中率计算,以及经 RootFlowAI 调用的注意事项。
最后验证:2026-11-04
提示缓存让 Claude 从请求中已经处理过的前缀继续处理,重复的系统提示、工具定义、长文档和多轮对话历史不必每次重新计算,可以降低费用和首字延迟。
本文译自 Anthropic 官方文档 Prompt caching,资料核对日期为 2026-11-04。示例地址和认证方式已改为 RootFlowAI,并补充了经本站调用时的差异。官方价格表未搬运,实际单价以模型价格页为准。
启用提示缓存有两种方式:
- 自动缓存:在请求顶层加一个
cache_control字段。系统会把缓存断点放在最后一个可缓存的块上,并随对话增长自动后移,适合多轮对话。 - 显式缓存断点:直接在单个内容块上放
cache_control,精确控制缓存哪些内容。
经 RootFlowAI 调用前须知
- 接口:使用 Anthropic Messages 协议
POST https://api.rootflowai.com/v1/messages。本文的cache_control写法只适用于这个接口;通过/v1/chat/completions调用 Claude 时,不保证消息里的cache_control会被转换到上游。 - 认证:使用本站 API Key(见获取 API Key)。curl 可以用
Authorization: Bearer或x-api-key请求头。Anthropic 官方 SDK 的 Base URL 填https://api.rootflowai.com,不要带/v1。 - 缓存位置:缓存保存在实际处理请求的上游账号中。切换分组、切换模型或上游故障切换后,第一次请求通常要重新写入缓存。
- 分组差异:不同分组的上游不同,自动缓存、1 小时 TTL、最低缓存长度和命中表现可能与官方不完全一致。例如经 AWS Bedrock 线路转发时,顶层
cache_control可能不会被转发。需要在各分组稳定生效时,优先使用显式断点,并用响应里的 usage 字段确认。 - 预热:官方的
max_tokens: 0预热请求经本站转发时,可能被当作未填写max_tokens,按默认输出上限正常生成回复并产生输出费用。预热做法见下文“缓存预热”。 - 费用:缓存读取、缓存创建的实际单价见模型价格页,扣费以消费日志为准。
快速开始
最简单的做法是使用自动缓存。以下示例先在环境变量 ROOTFLOWAI_API_KEY 中设置本站 API Key。
curl https://api.rootflowai.com/v1/messages \
-H "Authorization: Bearer $ROOTFLOWAI_API_KEY" \
-H "anthropic-version: 2023-06-01" \
-H "content-type: application/json" \
-d '{
"model": "claude-opus-5-5",
"max_tokens": 1024,
"cache_control": {"type": "ephemeral"},
"system": "你是一名文学作品分析助手,负责点评作品的主题、人物和写作风格。",
"messages": [
{
"role": "user",
"content": "分析《傲慢与偏见》的主要主题。"
}
]
}'Python(需要 pip install anthropic):
import os
import anthropic
client = anthropic.Anthropic(
api_key=os.environ["ROOTFLOWAI_API_KEY"],
base_url="https://api.rootflowai.com",
)
response = client.messages.create(
model="claude-opus-5-5",
max_tokens=1024,
cache_control={"type": "ephemeral"},
system="你是一名文学作品分析助手,负责点评作品的主题、人物和写作风格。",
messages=[
{"role": "user", "content": "分析《傲慢与偏见》的主要主题。"},
],
)
print(response.usage.model_dump_json())TypeScript(需要 npm install @anthropic-ai/sdk):
import Anthropic from "@anthropic-ai/sdk";
const client = new Anthropic({
apiKey: process.env.ROOTFLOWAI_API_KEY,
baseURL: "https://api.rootflowai.com",
});
const response = await client.messages.create({
model: "claude-opus-5-5",
max_tokens: 1024,
cache_control: { type: "ephemeral" },
system: "你是一名文学作品分析助手,负责点评作品的主题、人物和写作风格。",
messages: [{ role: "user", content: "分析《傲慢与偏见》的主要主题。" }],
});
console.log(response.usage);使用自动缓存时,系统会缓存到最后一个可缓存块为止的全部内容。之后前缀相同的请求会自动复用缓存。
提示缓存如何工作
发送启用了提示缓存的请求时:
- 系统检查到缓存断点为止的提示前缀,是否已被最近的请求缓存。
- 如果找到,就使用缓存版本,减少处理时间和费用。
- 如果没有,就处理完整提示,并在响应开始时缓存该前缀。
以下场景尤其适合提示缓存:
- 包含大量示例的提示
- 大段上下文或背景资料
- 指令固定、反复执行的任务
- 很长的多轮对话
缓存默认有效期为 5 分钟。每次使用缓存内容都会免费刷新有效期。
有效期从写入或读取该缓存的请求开始时计算,而不是从响应结束时计算。生成响应的时间也会计入有效期:如果一次响应流式输出用了 4 分钟,复用同一前缀的下一次请求必须在响应结束后约 1 分钟内发出。
如果 5 分钟太短,可以使用费用更高的 1 小时缓存,见下文“1 小时缓存”。
计费倍率
提示缓存把输入分成普通输入、缓存写入和缓存读取三类计费。官方倍率以基础输入单价为基准:
| 计费项 | 官方倍率 |
|---|---|
| 5 分钟缓存写入 | 基础输入单价的 1.25 倍 |
| 1 小时缓存写入 | 基础输入单价的 2 倍 |
| 缓存命中与刷新(读取) | 基础输入单价的 0.1 倍 |
| 读取倍率例外:Claude Opus 5.5、Claude Sonnet 5.5 | 基础输入单价的 0.05 倍 |
| 读取倍率例外:Claude Fable 5.1、Claude Mythos 5.1 | 基础输入单价的 0.025 倍 |
官方说明这些倍率会与 Batch API 折扣、长上下文定价、数据驻留等其他价格调整叠加;按提示长度分档定价的模型,缓存读取和写入也计入请求的提示长度。
在 RootFlowAI:
- 各模型、各分组的输入、缓存读取和缓存创建单价见模型价格页。部分模型或分组的缓存价格与上述官方倍率不同,以价格页为准。
- 价格页的“缓存创建”是 5 分钟写入的单价。按倍率计费的 Claude 模型,1 小时写入按该单价的 1.6 倍计算;缓存创建为基础输入 1.25 倍时,1 小时写入即为基础输入的 2 倍,与官方一致。
- 计费口径和核对方法见服务定价与计费说明。
支持的模型
官方说明,自动缓存和显式断点都支持所有在售的 Claude 模型。经 RootFlowAI 调用时,模型是否可用以模型价格页和 API Key 的分组权限为准。
自动缓存
自动缓存是启用提示缓存最简单的方式。不需要在单个内容块上放 cache_control,只在请求体顶层加一个 cache_control 字段,系统会自动把缓存断点放到最后一个可缓存的块上。
curl https://api.rootflowai.com/v1/messages \
-H "Authorization: Bearer $ROOTFLOWAI_API_KEY" \
-H "anthropic-version: 2023-06-01" \
-H "content-type: application/json" \
-d '{
"model": "claude-opus-5-5",
"max_tokens": 1024,
"cache_control": {"type": "ephemeral"},
"system": "你是一个会记住对话内容的助手。",
"messages": [
{"role": "user", "content": "我叫 Alex,从事机器学习工作。"},
{"role": "assistant", "content": "你好 Alex!今天有什么机器学习问题需要帮忙?"},
{"role": "user", "content": "我刚才说我做什么工作?"}
]
}'多轮对话中的自动缓存
使用自动缓存时,缓存点会随对话增长自动后移。每个新请求都缓存到最后一个可缓存块为止的全部内容,之前的内容从缓存读取。
| 请求 | 内容 | 缓存行为 |
|---|---|---|
| 请求 1 | System + User(1) + Asst(1) + User(2) ◀ 缓存点 | 全部写入缓存 |
| 请求 2 | System + User(1) + Asst(1) + User(2) + Asst(2) + User(3) ◀ 缓存点 | System 到 User(2) 从缓存读取;Asst(2) + User(3) 写入缓存 |
| 请求 3 | System + User(1) + Asst(1) + User(2) + Asst(2) + User(3) + Asst(3) + User(4) ◀ 缓存点 | System 到 User(3) 从缓存读取;Asst(3) + User(4) 写入缓存 |
缓存断点每次都会自动移到最后一个可缓存块,对话变长时不需要更新任何 cache_control 标记。
TTL 设置
自动缓存默认使用 5 分钟 TTL。也可以指定 1 小时 TTL,写入价格为基础输入单价的 2 倍:
{ "cache_control": { "type": "ephemeral", "ttl": "1h" } }与块级缓存组合
自动缓存可以和显式缓存断点一起使用。一起使用时,自动缓存断点占用 4 个断点名额中的 1 个。
例如用显式断点缓存系统提示,同时让自动缓存处理对话:
{
"model": "claude-opus-5-5",
"max_tokens": 1024,
"cache_control": { "type": "ephemeral" },
"system": [
{
"type": "text",
"text": "你是一个乐于助人的助手。",
"cache_control": { "type": "ephemeral" }
}
],
"messages": [{ "role": "user", "content": "这份协议的关键条款有哪些?" }]
}与显式断点相同的规则
自动缓存使用同一套缓存机制。价格、最低 token 数、内容顺序要求和 20 个块的回溯窗口,都与显式断点相同。
边界情况
- 最后一个块已经带有相同 TTL 的显式
cache_control时,自动缓存不产生额外效果。 - 最后一个块带有不同 TTL 的显式
cache_control时,API 返回 400 错误。 - 已经有 4 个显式块级断点时,API 返回 400 错误(没有名额留给自动缓存)。
- 最后一个块不能作为自动缓存断点时,系统会静默向前查找最近的可用块;找不到就跳过缓存。
显式缓存断点
需要更细的控制时,可以直接在单个内容块上放 cache_control。适用于需要分别缓存变化频率不同的内容,或要精确控制缓存范围的场景。
组织提示结构
把固定内容(工具定义、系统指令、上下文、示例)放在提示开头,用 cache_control 标记可复用内容的结尾。
缓存前缀按 tools、system、messages 的顺序生成。这个顺序形成层级,后一层建立在前一层之上。
自动前缀检查如何工作
只在固定内容的末尾放一个缓存断点即可,系统会自动找到之前的请求已经写入缓存的最长前缀。理解下面的机制有助于设计缓存策略。
三个核心原则:
- 只在断点处写入缓存。 给一个块加上
cache_control,就只写入一个缓存条目:以该块结尾的前缀的哈希。系统不会为更早的位置写入条目。哈希是累积的,覆盖从开头到断点(含断点)的全部内容,所以修改断点处或之前的任何块,下一次请求都会得到不同的哈希。 - 读取时向前查找之前写入的条目。 每次请求,系统计算断点处的前缀哈希并查找匹配的缓存条目。如果没有,就一次后退一个块,检查更早位置的前缀哈希是否与已有缓存匹配。它查找的是之前的写入,而不是内容是否稳定。
- 回溯窗口为 20 个块。 每个断点最多检查 20 个位置,断点本身算第一个。窗口内找不到匹配条目就停止检查(如果还有更早的显式断点,就从那个断点继续)。在官方 Claude API 上,连续的
tool_use块算一个位置,连续的tool_result块也算一个位置,所以一轮里有很多并行工具调用,不会单独把上一请求的条目挤出窗口。
示例:在增长的对话中回溯
每轮追加新块,并把 cache_control 放在每次请求的最后一个块上:
- 第 1 轮:10 个块,断点在第 10 块。还没有缓存条目,系统在第 10 块写入条目。
- 第 2 轮:15 个块,断点在第 15 块。第 15 块没有条目,系统回溯到第 10 块,找到第 1 轮的条目,在第 10 块命中。系统只重新处理第 11 到 15 块,并在第 15 块写入新条目。
- 第 3 轮:35 个块,断点在第 35 块。系统检查 20 个位置(第 35 到 16 块),什么也没找到。第 2 轮在第 15 块的条目正好在窗口外一个位置,因此没有命中。在第 15 块再加一个断点,会从那里开始第二个回溯窗口,找到第 2 轮的条目。
常见错误:把断点放在每次都变化的内容上
提示里有一段大的固定系统上下文(第 1 到 5 块),后面是每次请求都不同的块,包含时间戳和用户消息(第 6 块)。你把 cache_control 放在第 6 块:
- 请求 1:在第 6 块写入缓存,哈希包含时间戳。
- 请求 2:时间戳不同,第 6 块的前缀哈希也不同。回溯依次检查第 5、4、3、2、1 块,但系统从未在这些位置写入过条目,所以没有命中。每次请求都付一次缓存写入费用,却从不读取。
回溯不会自动找到断点之前的稳定内容并缓存它,只会找到之前请求已经写入的条目,而写入只发生在断点处。把 cache_control 移到第 5 块,也就是各次请求都相同的最后一个块,之后每次请求都能读取缓存的前缀。自动缓存也有同样的问题:它把断点放在最后一个可缓存块,而在这种结构里,那正是每次都变化的块,所以应改用放在第 5 块的显式断点。
要点:把 cache_control 放在“希望共享缓存的各次请求中,前缀完全相同的最后一个块”上。在持续增长的对话中,只要每轮新增少于 20 个块,放在最后一个块就可以:之前的内容不会变,下一次请求的回溯能找到上一次的写入。如果提示后面有变化的部分(时间戳、按请求变化的上下文、新来的消息),断点应放在固定前缀的末尾,而不是变化的块上。
何时使用多个断点
最多可以定义 4 个缓存断点,适用于:
- 分别缓存变化频率不同的部分(例如工具很少变,上下文每天更新)
- 更精确地控制缓存内容
- 对话增长使断点距离上次缓存写入 20 个块或更多时,仍能命中
缓存断点的费用
缓存断点本身不收费。 只对以下内容计费:
- 缓存写入:新内容写入缓存时(5 分钟 TTL 比基础输入贵 25%)
- 缓存读取:使用缓存内容时(基础输入单价的 10%,部分模型例外,见“计费倍率”)
- 普通输入:未缓存的内容
增加 cache_control 断点不会增加费用,费用只取决于实际缓存和读取的内容。断点的作用是让不同部分可以独立缓存。
缓存策略与注意事项
缓存限制
官方 Claude API 上,最低可缓存提示长度如下:
| 最低长度 | 模型 |
|---|---|
| 512 tokens | Claude Fable 5.1、Claude Mythos 5.1、Claude Opus 5.5、Claude Opus 5、Claude Sonnet 5.5、Claude Fable 5、Claude Mythos 5、Claude Haiku 5.5 |
| 1,024 tokens | Claude Opus 4.8、Claude Sonnet 5、Claude Sonnet 4.6、Claude Sonnet 4.5、Claude Opus 4.1、Claude Opus 4、Claude Sonnet 4 |
| 2,048 tokens | Claude Mythos Preview、Claude Opus 4.7、Claude Haiku 3.5 |
| 4,096 tokens | Claude Opus 4.6、Claude Opus 4.5、Claude Haiku 4.5 |
其中 Opus 4.1、Opus 4、Sonnet 4、Haiku 3.5 已在官方 API 退役,仅部分云平台仍提供。Amazon Bedrock 的最低长度、失败行为和 usage 字段名以 AWS 文档为准。
更短的提示即使标记了 cache_control 也不会被缓存。这类请求按不缓存处理,不会返回错误。要确认提示是否被缓存,查看响应中的 usage 字段:cache_creation_input_tokens 和 cache_read_input_tokens 都为 0,说明没有缓存(多半是没达到最低长度)。
如果提示只差一点达到所用模型的最低长度,扩充缓存内容凑够门槛往往是值得的。缓存读取比未缓存输入便宜得多,对经常复用的提示能降低费用。
并发请求时注意:缓存条目要等第一个响应开始后才可用。如果希望并行请求也能命中缓存,先等第一个请求开始返回,再发送后续请求。
目前 ephemeral 是唯一支持的缓存类型,默认有效期 5 分钟。
可以缓存的内容
请求中的大多数块都可以缓存,包括:
- 工具:
tools数组中的工具定义 - 系统消息:
system数组中的内容块 - 文本消息:
messages.content数组中的内容块,用户和助手轮次都可以 - 图片和文档:用户轮次
messages.content数组中的内容块 - 工具调用和工具结果:
messages.content数组中的内容块,用户和助手轮次都可以
这些元素都可以通过自动缓存或 cache_control 标记来缓存。
不能缓存的内容
- thinking 块不能直接用
cache_control缓存。但当它们出现在之前的助手轮次中时,可以和其他内容一起被缓存;这样从缓存读取时,它们计入输入 token。 - 子内容块(例如引用 citations)本身不能直接缓存,应缓存顶层块。对于引用,可以缓存作为引用来源的顶层 document 内容块,从而在使用引用时也能利用提示缓存。
- 空的文本块不能缓存。
导致缓存失效的变更
修改已缓存的内容,可能让部分或全部缓存失效。
缓存遵循 tools → system → messages 的层级。某一层发生变化,会使该层及之后各层的缓存失效。
下表列出不同变更影响哪部分缓存。“工具”“系统”“消息”三列分别指这三层的缓存,✘ 表示缓存失效,✓ 表示缓存仍然有效。
| 变更内容 | 工具 | 系统 | 消息 | 说明 |
|---|---|---|---|---|
| 工具定义 | ✘ | ✘ | ✘ | 修改工具定义(名称、描述、参数)会使整个缓存失效 |
| 联网搜索开关 | ✓ | ✘ | ✘ | 开启或关闭联网搜索会修改系统提示 |
| 引用开关 | ✓ | ✘ | ✘ | 开启或关闭 citations 会修改系统提示 |
| 速度设置 | ✓ | ✘ | ✘ | 在 speed: "fast" 与标准速度之间切换,会使系统和消息缓存失效 |
| tool_choice | ✓ | ✓ | ✘ | 修改 tool_choice 参数只影响消息块 |
| 图片 | ✓ | ✓ | ✘ | 在提示任意位置增加或删除图片,会影响消息块 |
| thinking 参数 | 视模型而定 | 视模型而定 | ✘ | thinking 配置(模式,以及扩展模式下的 budget_tokens)会渲染进提示,修改后一定使消息缓存失效;在把该配置渲染到工具和系统之前的模型上,工具和系统缓存也会失效 |
| effort 设置 | 视模型而定 | 视模型而定 | ✘ | 修改 output_config.effort 一定使消息缓存失效,对工具和系统缓存的影响与 thinking 参数相同。把 effort 显式设为模型默认值等同于不设置,不会失效。支持按消息调整 effort 的模型上,通过 messages 中 role: "system" 消息携带的 effort 变更不影响已缓存前缀 |
| 向带 thinking 的请求传入非工具结果内容 | ✓ | ✓ | 视模型而定 | Opus 4.5 及以上、Sonnet 4.6 及以上和 Haiku 5.5 默认保留 thinking 块,缓存仍有效。更早的 Opus/Sonnet 模型,以及 Haiku 4.5 及更早的 Haiku 模型,会剥离之前缓存的 thinking 块,这些块之后的消息也会从缓存中移除 |
| 被丢弃的 thinking 块 | ✓ | ✓ | ✘ | API 丢弃 Claude 5.1 及更新模型在本次请求中未被保留的 thinking 块时,缓存前缀从该块的位置起发生变化。接收模型能读取、且原样回传的块不影响缓存 |
官方说明,在支持对话中途修改工具的模型上,可以用 inline-tools-2026-09-15 beta 请求头,在对话中途新增工具或修改工具定义,而不改动 tools:把定义放在对话中途 system 消息的 tool_addition 块里,tools 保持第一次发送时的样子。缓存前缀仍然匹配,只有追加的消息按新输入处理。唯一的例外是 tools 数组中没有任何非延迟加载(non-deferred)工具时,第一个这样定义的工具会让该请求完全不命中缓存一次。经 RootFlowAI 调用时,beta 功能是否可用取决于所选分组的上游。
跟踪缓存效果
通过响应 usage 中的字段监控缓存效果(流式响应在 message_start 事件中):
cache_creation_input_tokens:本次新建缓存条目时写入缓存的 token 数cache_read_input_tokens:本次从缓存读取的 token 数input_tokens:既没有从缓存读取、也没有用于创建缓存的输入 token 数,即最后一个缓存断点之后的 token
input_tokens 只表示最后一个缓存断点之后的 token,不是你发送的全部输入。计算总输入:
总输入 tokens = cache_read_input_tokens + cache_creation_input_tokens + input_tokens按位置理解:
cache_read_input_tokens:断点之前、已经缓存的 token(读取)cache_creation_input_tokens:断点之前、本次正在缓存的 token(写入)input_tokens:最后一个断点之后的 token(不参与缓存)
示例:一个请求有 100,000 个 token 的缓存内容(从缓存读取),没有新写入的内容,用户消息在断点之后有 50 个 token:
cache_read_input_tokens:100,000cache_creation_input_tokens:0input_tokens:50- 实际处理的总输入:100,050 tokens
这一点对理解费用和速率限制都很重要:缓存用得好时,input_tokens 通常远小于总输入。
计算缓存命中率时,分母应是全部输入:
缓存命中率 = cache_read_input_tokens ÷ (input_tokens + cache_read_input_tokens + cache_creation_input_tokens)不要把“缓存读取 ÷(缓存读取 + 缓存创建)”当作命中率,它忽略了未缓存的普通输入。OpenAI 和 Gemini 协议的 usage 中,输入总量已包含缓存命中部分,口径与 Claude 不同,不能用同一公式混算。在本站消费日志中也可以逐条核对缓存读取与缓存创建的用量。
thinking 块与缓存
在扩展思考中使用提示缓存时,thinking 块有特殊行为:
随其他内容一起缓存:thinking 块不能用 cache_control 显式标记,但在后续请求中随工具结果一起回传时,会作为请求内容的一部分被缓存。这在工具调用场景中很常见:你把 thinking 块传回去继续对话。
输入 token 计数:thinking 块从缓存读取时,计入 usage 中的输入 token。计算费用和规划 token 预算时要考虑这一点。
缓存失效规则:
- 用户消息只包含工具结果时,缓存保持有效。
- Opus 4.5 及以上、Sonnet 4.6 及以上和 Haiku 5.5 默认保留 thinking 块,即使加入非工具结果的用户内容,缓存仍有效。
- 更早的 Opus/Sonnet 模型,以及 Haiku 4.5 及更早的 Haiku 模型,加入非工具结果的用户内容时缓存失效,之前所有 thinking 块都会从上下文中剥离。
- 即使没有显式的
cache_control标记,上述缓存行为也会发生。
工具调用示例:
请求 1:User: "巴黎天气怎么样?"
响应:[thinking_block_1] + [tool_use block 1]
请求 2:
User: ["巴黎天气怎么样?"],
Assistant: [thinking_block_1] + [tool_use block 1],
User: [tool_result_1, cache=True]
响应:[thinking_block_2] + [text block 2]
# 请求 2 缓存的是请求内容(不是响应)
# 缓存包括:用户消息、thinking_block_1、tool_use block 1 和 tool_result_1
请求 3:
User: ["巴黎天气怎么样?"],
Assistant: [thinking_block_1] + [tool_use block 1],
User: [tool_result_1, cache=True],
Assistant: [thinking_block_2] + [text block 2],
User: [文本回复, cache=True]
# 这条非工具结果的用户内容,会根据模型保留或剥离之前的 thinking 块在更早的 Opus/Sonnet 模型和 Haiku 4.5 及更早的 Haiku 模型上,此时所有之前的 thinking 块都会从上下文中移除。在 Opus 4.5 及以上、Sonnet 4.6 及以上和 Haiku 5.5 上,之前的 thinking 块默认保留,仍是缓存前缀的一部分。
缓存隔离与共享
- 组织与工作区隔离:官方说明,缓存在不同组织之间隔离,提示完全相同也不会共享。在 Claude API、Claude Platform on AWS 和 Microsoft Foundry 上,同一组织内的缓存还按工作区隔离;Google Cloud(Google 托管)和 Bedrock 只按组织隔离。
- 经 RootFlowAI 转发:缓存保存在实际处理请求的上游账号中。分组、模型或上游账号发生变化时,之前的缓存不会跟随迁移,需要重新写入。
- 完全匹配:缓存命中要求提示片段 100% 相同,包括到
cache_control所在块为止的全部文本和图片。 - 不影响输出:提示缓存不影响输出 token 的生成。返回的内容与不使用缓存时相同。
最佳实践
- 多轮对话先用自动缓存,它会自动管理断点。
- 需要分别缓存变化频率不同的部分时,使用显式块级断点。
- 缓存稳定、可复用的内容,例如系统指令、背景资料、大段上下文和常用工具定义。
- 把要缓存的内容放在提示开头。
- 用缓存断点分隔不同的可缓存前缀。
- 把断点放在各次请求都相同的最后一个块上。如果提示由固定前缀和变化的后缀(时间戳、按请求变化的上下文、新来的消息)组成,断点应放在前缀末尾,而不是变化的块上。
- 定期分析缓存命中率,按需调整策略。
不同场景的用法
- 对话类智能体:降低长对话的费用和延迟,尤其是包含长指令或上传文档的对话。
- 编程助手:在提示中保留代码库的相关部分或摘要,改进自动补全和代码库问答。
- 长文档处理:把包括图片在内的完整长篇材料放进提示,而不明显增加响应延迟。
- 详细指令集:共享大量指令、流程和示例。开发者通常只放一两个示例,有了提示缓存,可以放 20 个以上多样的高质量示例来获得更好的效果。
- 工具调用型智能体:多次工具调用和反复修改代码时,每一步通常都要新的 API 调用,缓存能提升这类场景的性能。
- 书籍、论文、文档、播客文字稿等长内容:把整份文档放进提示,让用户直接提问。
常见问题排查
如果缓存表现不符合预期:
- 确认各次调用中被缓存的部分完全相同。使用显式断点时,确认
cache_control标记位置一致。 - 确认调用发生在缓存有效期内(默认 5 分钟)。
- 确认
tool_choice、图片使用情况、thinking 配置和output_config.effort在各次调用中保持一致。 - 确认缓存内容达到所用模型的最低 token 数(见“缓存限制”)。
- 确认断点所在的块在各次请求中保持不变。写入只发生在断点处,如果该块变化(时间戳、按请求变化的上下文、新来的消息),前缀哈希永远对不上。回溯不会找到断点之前的稳定内容,只会找到之前请求在各自断点处写入的条目。
- 确认
tool_use内容块中的键顺序稳定。某些语言(例如 Swift、Go)在 JSON 转换时会打乱键顺序,导致缓存失效。 - 经 RootFlowAI 调用时,确认使用的是
/v1/messages,并且各次请求使用同一 API Key 分组和同一模型。切换分组或模型后的第一次请求会重新写入缓存。
1 小时缓存
如果 5 分钟太短,可以使用费用更高的 1 小时缓存。官方说明,1 小时缓存可在 Claude API、Amazon Bedrock、Claude Platform on AWS、Google Cloud(Google 托管)和 Microsoft Foundry 上使用。经 RootFlowAI 调用时是否生效取决于分组上游,以 usage 中的 cache_creation 明细为准。
在 cache_control 中加入 ttl:
"cache_control": {
"type": "ephemeral",
"ttl": "1h"
}响应会包含详细的缓存信息,例如:
{
"usage": {
"input_tokens": 2048,
"cache_read_input_tokens": 1800,
"cache_creation_input_tokens": 248,
"output_tokens": 503,
"cache_creation": {
"ephemeral_5m_input_tokens": 148,
"ephemeral_1h_input_tokens": 100
}
}
}cache_creation_input_tokens 等于 cache_creation 对象中各值之和。
如果使用联网搜索等服务端工具时,看到了自己没有请求的 ephemeral_5m_input_tokens 写入,原因是服务端工具结果会被自动缓存,详见官方文档 Tool use with prompt caching。
何时使用 1 小时缓存
如果提示按固定节奏使用(例如系统提示的使用间隔短于 5 分钟),继续使用 5 分钟缓存即可,它每次使用都会免费刷新。
1 小时缓存适合以下场景:
- 提示的使用间隔可能超过 5 分钟,但短于 1 小时。例如某个辅助智能体的任务要运行 5 分钟以上,或保存和用户的长对话、而用户通常不会在 5 分钟内回复。
- 延迟很重要,而后续请求可能在 5 分钟之后才发出。
- 希望提高速率限制的利用率。官方说明,缓存命中不计入速率限制。
5 分钟和 1 小时缓存的延迟表现相同。对长文档,通常都能看到首字延迟改善。
混合使用不同 TTL
同一请求中可以同时使用 1 小时和 5 分钟缓存,但有一个限制:TTL 更长的缓存条目必须出现在更短的之前,即 1 小时缓存条目必须在所有 5 分钟缓存条目之前。
混合使用时,API 在提示中确定三个计费位置:
- 位置 A:最高缓存命中处的 token 数(没有命中时为 0)。
- 位置 B:A 之后最高的 1 小时
cache_control块处的 token 数(没有则等于 A)。 - 位置 C:最后一个
cache_control块处的 token 数。
B 或 C 大于 A 时,那一段必然是缓存未命中,因为 A 是最高命中处。
计费方式:
- A 部分按缓存读取计费。
- (B - A) 部分按 1 小时缓存写入计费。
- (C - B) 部分按 5 分钟缓存写入计费。
官方文档用一张示意图说明三种情况,下表是按同一规则整理的文字示例:提示在 30,000 tokens 处有一个 1 小时断点,在 35,000 tokens 处有一个 5 分钟断点。
| 情况 | A | B | C | 计费 |
|---|---|---|---|---|
| 首次请求,没有任何命中 | 0 | 30,000 | 35,000 | 1 小时写入 30,000;5 分钟写入 5,000 |
| 5 分钟后、1 小时内再次请求(5 分钟缓存已过期) | 30,000 | 30,000 | 35,000 | 读取 30,000;5 分钟写入 5,000 |
| 5 分钟内再次请求 | 35,000 | 35,000 | 35,000 | 读取 35,000 |
缓存预热
缓存预热让你在用户发出真实请求之前,先把系统提示或工具定义写入缓存。这样用户第一次交互就不会因缓存未命中而变慢,适合对首字延迟敏感的应用。
官方做法:max_tokens 为 0
官方 API 支持在请求中设置 max_tokens: 0。API 读取提示并在各个 cache_control 断点写入缓存,然后立即返回、不生成任何输出。响应的 content 为空数组,stop_reason 为 "max_tokens",usage 字段完整。
以下设置与 max_tokens: 0 冲突,官方 API 会返回 invalid_request_error:
stream: true- 扩展思考(
thinking.type: "enabled") - 结构化输出(
output_config.format) tool_choice为{"type": "tool", ...}或{"type": "any"}
max_tokens: 0 在 Message Batches 请求中也会被拒绝。
在 RootFlowAI 预热
把 cache_control 断点放在与后续请求共享的最后一个块上(通常是系统提示或工具定义),不要放在占位用户消息上,否则缓存条目会以占位消息为键,后续请求命中不了。因此这里要用显式断点,而不是自动缓存:自动缓存会把断点放在最后一个块,也就是占位消息上。占位用户消息可以是任何非空白字符串(示例用 "warmup")。
预热请求的 thinking 配置和 output_config.effort 也要与后续请求一致。这些值会渲染进提示,配置不同的预热可能写入一个真实请求永远命中不了的条目。正式请求开启扩展思考(thinking.type: "enabled")或使用名称带 -thinking 的模型时,max_tokens 必须大于思考预算,无法用 max_tokens: 1 预热;这种情况可以让第一个真实请求写入缓存,或改用 1 小时缓存减少过期。
# 应用启动时或按固定间隔预热
curl https://api.rootflowai.com/v1/messages \
-H "Authorization: Bearer $ROOTFLOWAI_API_KEY" \
-H "anthropic-version: 2023-06-01" \
-H "content-type: application/json" \
-d '{
"model": "claude-opus-5-5",
"max_tokens": 1,
"system": [
{
"type": "text",
"text": "你是一名熟悉分布式系统的资深软件工程师……",
"cache_control": {"type": "ephemeral"}
}
],
"messages": [{"role": "user", "content": "warmup"}]
}'
# 之后用户发来消息时,系统提示前缀已经在缓存中
curl https://api.rootflowai.com/v1/messages \
-H "Authorization: Bearer $ROOTFLOWAI_API_KEY" \
-H "anthropic-version: 2023-06-01" \
-H "content-type: application/json" \
-d '{
"model": "claude-opus-5-5",
"max_tokens": 1024,
"system": [
{
"type": "text",
"text": "你是一名熟悉分布式系统的资深软件工程师……",
"cache_control": {"type": "ephemeral"}
}
],
"messages": [{"role": "user", "content": "如何实现一棵二叉搜索树?"}]
}'Python 写法:
import os
import anthropic
client = anthropic.Anthropic(
api_key=os.environ["ROOTFLOWAI_API_KEY"],
base_url="https://api.rootflowai.com",
)
SYSTEM_PROMPT = [
{
"type": "text",
"text": "你是一名熟悉分布式系统的资深软件工程师……",
"cache_control": {"type": "ephemeral"},
}
]
def prewarm_cache():
"""在应用启动时或按固定间隔调用。"""
response = client.messages.create(
model="claude-opus-5-5",
max_tokens=1,
system=SYSTEM_PROMPT,
messages=[{"role": "user", "content": "warmup"}],
)
# 首次预热应看到 cache_creation_input_tokens 大于 0
print(response.usage.model_dump_json())
def respond(user_message: str):
return client.messages.create(
model="claude-opus-5-5",
max_tokens=1024,
system=SYSTEM_PROMPT,
messages=[{"role": "user", "content": user_message}],
)
prewarm_cache()
response = respond("如何实现一棵二叉搜索树?")
print(response.usage.model_dump_json())预热请求在前缀尚未缓存时,和其他请求一样收取缓存写入费用。用响应中的 usage.cache_creation_input_tokens 确认写入成功,用后续请求的 cache_read_input_tokens 确认命中。
缓存 TTL 仍然适用。使用默认 5 分钟缓存时,至少每 5 分钟发一次预热请求才能保持缓存;用户请求间隔更长时,改用 1 小时缓存。
提示缓存示例
官方 Claude Cookbook 中的 prompt caching recipe 提供了更多示例和最佳实践。以下示例展示几种常见的缓存模式。
缓存大段上下文
curl https://api.rootflowai.com/v1/messages \
-H "Authorization: Bearer $ROOTFLOWAI_API_KEY" \
-H "anthropic-version: 2023-06-01" \
-H "content-type: application/json" \
-d '{
"model": "claude-opus-5-5",
"max_tokens": 1024,
"system": [
{
"type": "text",
"text": "你是一名法律文书分析助手。"
},
{
"type": "text",
"text": "以下是一份复杂法律协议的全文:[此处放入 50 页协议全文]",
"cache_control": {"type": "ephemeral"}
}
],
"messages": [
{
"role": "user",
"content": "这份协议的关键条款和条件有哪些?"
}
]
}'这个示例缓存了法律协议全文作为前缀,用户问题不缓存。
第一次请求:
input_tokens:只有用户消息的 token 数cache_creation_input_tokens:整个系统消息(包括法律文书)的 token 数cache_read_input_tokens:0(第一次请求没有命中)
有效期内的后续请求:
input_tokens:只有用户消息的 token 数cache_creation_input_tokens:0(没有新建缓存)cache_read_input_tokens:整个已缓存系统消息的 token 数
缓存工具定义
在 tools 数组的最后一个工具上放 cache_control,就能缓存工具定义。该工具及之前定义的所有工具作为一个前缀被缓存。
{
"model": "claude-opus-5-5",
"max_tokens": 1024,
"tools": [
{
"name": "get_weather",
"description": "Get the current weather in a given location",
"input_schema": {
"type": "object",
"properties": { "location": { "type": "string" } },
"required": ["location"]
}
},
{
"name": "get_time",
"description": "Get the current time in a given time zone",
"input_schema": {
"type": "object",
"properties": { "timezone": { "type": "string" } },
"required": ["timezone"]
},
"cache_control": { "type": "ephemeral" }
}
],
"messages": [{ "role": "user", "content": "纽约现在的天气和时间是多少?" }]
}第一次请求时,cache_creation_input_tokens 等于全部工具定义的 token 数。有效期内的后续请求中,这些 token 改为出现在 cache_read_input_tokens 中。
工具定义、defer_loading 与缓存失效的关系,见官方文档 Tool use with prompt caching。
继续多轮对话
import os
import anthropic
client = anthropic.Anthropic(
api_key=os.environ["ROOTFLOWAI_API_KEY"],
base_url="https://api.rootflowai.com",
)
response = client.messages.create(
model="claude-opus-5-5",
max_tokens=1024,
system=[
{
"type": "text",
"text": "……很长的系统提示",
"cache_control": {"type": "ephemeral"},
}
],
messages=[
# ……之前的长对话
{
"role": "user",
"content": [{"type": "text", "text": "你好,能介绍一下太阳系吗?"}],
},
{
"role": "assistant",
"content": "当然。太阳系由太阳以及围绕它运行的天体组成,包括八大行星、众多卫星、小行星和彗星……你想了解哪方面?",
},
{
"role": "user",
"content": [
{"type": "text", "text": "了解了。"},
{
"type": "text",
"text": "再多讲讲火星。",
"cache_control": {"type": "ephemeral"},
},
],
},
],
)
print(response.usage.model_dump_json())每一轮都把最后一条消息的最后一个块标记为 cache_control,让对话可以增量缓存。系统会自动查找并使用之前缓存过的最长块序列。之前带过 cache_control 的块,后来即使不再标记,只要在 5 分钟内被用到,仍算缓存命中(同时刷新缓存)。
系统消息上也放了 cache_control。这样即使它因超过 5 分钟未使用而被移出缓存,下一次请求也会把它重新加入缓存。
设置正确时,每次请求的 usage 应该是:
input_tokens:新用户消息的 token 数(很少)cache_creation_input_tokens:新的助手轮次和用户轮次的 token 数cache_read_input_tokens:到上一轮为止的对话 token 数
组合使用 4 个缓存断点
curl https://api.rootflowai.com/v1/messages \
-H "Authorization: Bearer $ROOTFLOWAI_API_KEY" \
-H "anthropic-version: 2023-06-01" \
-H "content-type: application/json" \
-d '{
"model": "claude-opus-5-5",
"max_tokens": 1024,
"tools": [
{
"name": "search_documents",
"description": "Search through the knowledge base",
"input_schema": {
"type": "object",
"properties": {
"query": {"type": "string", "description": "Search query"}
},
"required": ["query"]
}
},
{
"name": "get_document",
"description": "Retrieve a specific document by ID",
"input_schema": {
"type": "object",
"properties": {
"doc_id": {"type": "string", "description": "Document ID"}
},
"required": ["doc_id"]
},
"cache_control": {"type": "ephemeral"}
}
],
"system": [
{
"type": "text",
"text": "你是一名可以访问文档知识库的研究助手。\n\n# 指令\n- 回答前先搜索相关文档\n- 注明信息来源\n- 回答客观准确\n- 多份文档都相关时综合整理\n- 知识库中没有的信息要明确说明",
"cache_control": {"type": "ephemeral"}
},
{
"type": "text",
"text": "# 知识库上下文\n\n## 文档 1:太阳系概览\n太阳系由太阳及所有围绕它运行的天体组成……\n\n## 文档 2:行星特征\n每颗行星都有独特之处,水星是最小的行星……\n\n## 文档 3:火星探索\n几十年来火星一直是探索目标……\n\n[更多文档……]",
"cache_control": {"type": "ephemeral"}
}
],
"messages": [
{"role": "user", "content": "能搜索一下火星车的资料吗?"},
{
"role": "assistant",
"content": [
{"type": "tool_use", "id": "tool_1", "name": "search_documents", "input": {"query": "Mars rovers"}}
]
},
{
"role": "user",
"content": [
{"type": "tool_result", "tool_use_id": "tool_1", "content": "找到 3 份相关文档:文档 3(火星探索)、文档 7(火星车技术)、文档 9(任务历史)"}
]
},
{
"role": "assistant",
"content": [
{"type": "text", "text": "我找到了 3 份关于火星车的文档,接下来从火星探索文档中获取更多细节。"}
]
},
{
"role": "user",
"content": [
{"type": "text", "text": "好的,请重点介绍毅力号火星车。", "cache_control": {"type": "ephemeral"}}
]
}
]
}'这个示例用满了 4 个缓存断点,分别优化提示的不同部分:
- 工具缓存(断点 1):最后一个工具定义上的
cache_control缓存全部工具定义。 - 固定指令缓存(断点 2):系统提示中的固定指令单独缓存,这部分很少变化。
- RAG 上下文缓存(断点 3):知识库文档独立缓存,更新文档时不影响工具和指令的缓存。
- 对话历史缓存(断点 4):最后一条用户消息带
cache_control,让对话随进展增量缓存。
这样做的灵活性:
- 只追加新一轮对话、不改之前的内容时,4 段缓存全部复用。
- 更新 RAG 文档、但工具和指令不变时,复用前两段缓存。
- 对话变化、但工具、指令和文档不变时,复用前三段缓存。
- 任一断点处发生变化,会使该段及之后的缓存失效,之前的缓存段仍然有效。
第一次请求:
input_tokens:很少(最后一个断点之后的 token,本例中接近 0)cache_creation_input_tokens:所有缓存段的 token(工具 + 指令 + RAG 文档 + 对话历史)cache_read_input_tokens:0(没有命中)
之后只追加一条新用户消息,并把第 4 个断点移到这条新消息上:
input_tokens:很少(最后一个断点之后的 token,本例中接近 0)cache_creation_input_tokens:新用户消息和上一轮助手回复的 token(正在缓存的新对话段)cache_read_input_tokens:之前已缓存的全部 token(工具 + 指令 + RAG 文档 + 之前的对话)
这种模式特别适合:
- 带大段文档上下文的 RAG 应用
- 使用多个工具的智能体系统
- 需要保持上下文的长对话
- 需要分别优化提示不同部分的应用
常见问题
需要多个缓存断点吗?只在末尾放一个够不够?
大多数情况下,在固定内容末尾放一个缓存断点就够了。 写入只发生在你标记的块上。把它放在各次请求都相同的最后一个块上,之后每次请求都会读取同一个条目。如果后面的块每次都变化(时间戳、新来的消息),断点放在它之前的最后一个稳定块上。
只有以下情况才需要多个断点:
- 对话增长使断点距上次缓存写入 20 个块或更多,之前的条目落在回溯窗口之外
- 希望分别缓存更新频率不同的部分
- 为了优化费用,需要明确控制缓存哪些内容
例如系统指令很少变化、RAG 上下文每天更新,可以用两个断点分别缓存。
缓存断点会额外收费吗?
不会,断点本身免费。只对以下内容收费:
- 写入缓存的内容(5 分钟 TTL 比基础输入贵 25%)
- 从缓存读取的内容(基础输入单价的一小部分,见“计费倍率”)
- 未缓存内容的普通输入
断点数量不影响价格,只有缓存和读取的内容量有影响。
如何从 usage 字段计算总输入 token?
usage 中三个输入字段合起来是全部输入:
总输入 tokens = cache_read_input_tokens + cache_creation_input_tokens + input_tokensinput_tokens 不是全部输入,只是最后一个缓存断点之后的部分。例如缓存了 200k token 的文档、用户问题 50 token:cache_read_input_tokens 为 200,000,cache_creation_input_tokens 为 0,input_tokens 为 50,总计 200,050 tokens。
缓存有效期多长?从什么时候开始算?
默认最短有效期(TTL)为 5 分钟,每次使用缓存内容都会刷新。也可以使用 1 小时 TTL。
有效期从写入或读取缓存的请求开始时计算,而不是响应结束时。生成响应的时间也计入有效期,所以下一次请求复用缓存的时间窗口等于有效期减去生成时间。响应很长、下一次请求可能在有效期之后才开始时,使用 1 小时 TTL。
最多能用几个缓存断点?
提示中最多可以定义 4 个缓存断点(cache_control 参数)。
提示缓存和 thinking 一起用会怎样?
修改 thinking 参数(切换模式,或修改扩展模式下的 budget)会使已缓存的消息前缀失效,也可能使缓存的系统提示和工具失效,因为 thinking 配置会渲染进提示。output_config.effort 的行为相同。详见“导致缓存失效的变更”。
如何启用提示缓存?
最简单的方式是在请求体顶层加 "cache_control": {"type": "ephemeral"}(自动缓存)。也可以在单个内容块上至少放一个 cache_control 断点(显式缓存断点)。经 RootFlowAI 调用时,两种方式都只适用于 /v1/messages。
能和其他 API 功能一起用吗?
可以,提示缓存能和工具调用、图片理解等功能一起使用。但改变提示中是否包含图片,或修改工具调用设置,会使缓存失效。
能手动清除缓存吗?
目前不能手动清除。缓存的前缀在至少 5 分钟未使用后自动过期。
如何判断缓存策略是否有效?
查看响应中的 cache_creation_input_tokens 和 cache_read_input_tokens 字段,并按“跟踪缓存效果”中的公式计算命中率。在本站也可以到消费日志按时间和模型核对缓存用量与扣费。
提示缓存如何保证隐私和数据隔离?
官方说明:缓存键由到缓存控制点为止的提示的加密哈希生成,只有提示完全相同的请求才能访问对应缓存;缓存永远不会跨组织共享。在任何位置使用 cache_control 都是安全的。要产生缓存读取,断点应放在稳定前缀的末尾;放在每次都变化的块上(例如时间戳或用户任意输入)会每次写入新条目,永远不会命中。
RootFlowAI 如何处理你的请求数据,见隐私政策。
Message Batches 能用提示缓存吗?
官方 Batches API 支持提示缓存,但批量请求会并发且无序处理,缓存命中只能尽力而为。RootFlowAI 当前没有开放 Message Batches 接口。
Python 报错 AttributeError: 'Beta' object has no attribute 'prompt_caching'
这通常是升级了 SDK 或沿用了旧示例代码。提示缓存已经不需要 beta 前缀。把 client.beta.prompt_caching.messages.create(**params) 改为 client.messages.create(**params)。
TypeScript 报错 TypeError: Cannot read properties of undefined (reading 'messages')
原因同上。把 client.beta.promptCaching.messages.create(...) 改为 client.messages.create(...)。
官方数据保留说明
以下是 Anthropic 对其官方平台的说明:提示缓存(自动缓存和显式断点)符合零数据保留(ZDR)条件,Anthropic 不存储提示和 Claude 回复的原始文本。缓存内容的 KV(key-value)表示和加密哈希只保存在内存中,不落盘。缓存条目的最短生命周期为 5 分钟(标准)或 1 小时(扩展),过期后会尽快删除,但不是立即删除。
RootFlowAI 的数据处理方式以本站隐私政策为准。
相关文档
- API 接口参考:选择协议、地址与认证方式。
- 服务定价与计费说明:理解缓存读取、缓存创建的计费口径。
- Claude Code 省 Token 指南:在 Claude Code 中利用提示缓存。
- Claude Code 安装与配置:配置 RootFlowAI 地址与凭据。