Anthropic 发布 Prompt Caching 机制,复用 prompt 上下文可降低 API 调用成本 90%、延迟 50%。
Prompt 缓存允许从提示词中的特定前缀恢复处理,从而优化 API 使用方式。对于重复性任务或包含固定元素的提示词,这可以显著减少处理时间和成本。
有关零数据保留(ZDR)如何应用于此功能,请参阅 API 和数据保留。
启用 Prompt 缓存有两种方式:
自动缓存:在请求的顶层添加一个 cache_control 字段。系统会自动将缓存断点应用于最后一个可缓存块,并随着对话增长将其向前移动。最适合需要自动缓存不断增长的消息历史记录的多轮对话。
显式缓存断点:直接在各个内容块上放置 cache_control,精细控制具体缓存哪些内容。
最简单的入门方式是使用自动缓存:
client = anthropic.Anthropic()
response = client.messages.create(
model="claude-opus-5",
max_tokens=1024,
cache_control={"type": "ephemeral"},
system="You are an AI assistant tasked with analyzing literary works. Your goal is to provide insightful commentary on themes, characters, and writing style.",
messages=[
{
"role": "user",
"content": "Analyze the major themes in 'Pride and Prejudice'.",
}
],
)
print(response.usage.model_dump_json())
使用自动缓存时,系统会缓存截至并包括最后一个可缓存块在内的所有内容。后续请求具有相同前缀时,系统会自动复用缓存的内容。
发送启用了 Prompt 缓存的请求时:
系统会检查截至指定缓存断点的提示词前缀是否已被近期查询缓存。
如果找到,系统会使用缓存版本,从而减少处理时间和成本。
否则,系统会处理完整提示词,并在响应开始后缓存该前缀。
这尤其适用于:
包含大量示例的提示词
大量上下文或背景信息
具有固定指令的重复性任务
长时间的多轮对话
默认情况下,缓存的生命周期为 5 分钟。每次使用缓存内容时,都会免费刷新缓存。
如果你觉得 5 分钟太短,Anthropic 还提供需要额外付费的 1 小时缓存时长。
更多信息请参阅 1 小时缓存时长。
Prompt 缓存会引用整个提示词——依次包括工具、系统和消息——截至并包括通过 cache_control 指定的内容块。
Prompt 缓存引入了一种新的定价结构。下表列出了每个受支持模型每百万 token 的价格:
上表体现了 Prompt 缓存的以下定价倍数:
5 分钟缓存的写入 token 价格是基础输入 token 价格的 1.25 倍
1 小时缓存的写入 token 价格是基础输入 token 价格的 2 倍
缓存读取 token 的价格是基础输入 token 价格的 0.1 倍
这些倍数会与其他定价调整因素叠加,例如 Batch API 折扣和数据驻留。完整详情请参阅定价。
所有仍在使用的 Claude 模型都支持 Prompt 缓存,包括自动缓存和显式缓存。
自动缓存是启用 Prompt 缓存最简单的方式。你无需在各个内容块上放置 cache_control,只需在请求正文的顶层添加一个 cache_control 字段。系统会自动将缓存断点应用于最后一个可缓存块。
client = anthropic.Anthropic()
response = client.messages.create(
model="claude-opus-5",
max_tokens=1024,
cache_control={"type": "ephemeral"},
system="You are a helpful assistant that remembers our conversation.",
messages=[
{"role": "user", "content": "My name is Alex. I work on machine learning."},
{
"role": "assistant",
"content": "Nice to meet you, Alex! How can I help with your ML work today?",
},
{"role": "user", "content": "What did I say I work on?"},
],
)
print(response.usage.model_dump_json())
使用自动缓存时,缓存点会随着对话增长自动向前移动。每个新请求都会缓存截至最后一个可缓存块的所有内容,并从缓存中读取之前的内容。
缓存断点会在每个请求中自动移动到最后一个可缓存块,因此随着对话增长,你无需更新任何 cache_control 标记。
默认情况下,自动缓存使用 5 分钟的 TTL。你可以指定 1 小时的 TTL,其价格为基础输入 token 价格的 2 倍:
{ "cache_control": { "type": "ephemeral", "ttl": "1h" } }
自动缓存与显式缓存断点兼容。两者结合使用时,自动缓存断点会占用 4 个可用断点槽位中的一个。
这让你能够结合使用两种方式。例如,使用显式断点缓存系统提示词,同时使用自动缓存处理对话:
{
"model": "claude-opus-5",
"max_tokens": 1024,
"cache_control": { "type": "ephemeral" },
"system": [
{
"type": "text",
"text": "You are a helpful assistant.",
"cache_control": { "type": "ephemeral" }
}
],
"messages": [{ "role": "user", "content": "What are the key terms?" }]
}
自动缓存使用相同的底层缓存基础设施。定价、最低 token 阈值、上下文顺序要求以及 20 块回溯窗口都与显式断点相同。
如果最后一个块已有使用相同 TTL 的显式 cache_control,自动缓存不会执行任何操作。
如果最后一个块已有使用不同 TTL 的显式 cache_control,API 会返回 400 错误。
如果已经存在 4 个显式块级断点,API 会返回 400 错误(没有可供自动缓存使用的剩余槽位)。
如果最后一个块不符合自动缓存断点目标的条件,系统会静默向后查找最近的符合条件的块。如果找不到,则跳过缓存。
自动缓存可用于 Claude API、AWS 上的 Claude Platform、Google Cloud 和 Microsoft Foundry。Amazon Bedrock 不支持自动缓存。
为了更精细地控制缓存,你可以直接在各个内容块上放置 cache_control。当你需要缓存以不同频率变化的不同部分,或需要精细控制具体缓存哪些内容时,这种方式非常有用。
将静态内容(工具定义、系统指令、上下文、示例)放在提示词的开头。使用 cache_control 参数标记可复用内容的末尾,以便进行缓存。
缓存前缀按以下顺序创建:工具、系统,然后是消息。此顺序形成了一种层级结构,其中每一层都建立在前一层之上。
你可以只在静态内容末尾设置一个缓存断点,系统会自动查找先前请求已写入缓存的最长前缀。了解其工作原理有助于优化缓存策略。
三个核心原则:
缓存写入只发生在断点处。使用 cache_control 标记一个块,只会写入一个缓存条目:以该块结尾的前缀所对应的哈希值。系统不会为任何更早的位置写入条目。由于该哈希值是累积计算的,涵盖截至并包括断点的所有内容,因此更改断点处或断点之前的任何块,都会使下一次请求产生不同的哈希值。
缓存写入只发生在断点处。使用 cache_control 标记一个块,只会写入一个缓存条目:以该块结尾的前缀所对应的哈希值。系统不会为任何更早的位置写入条目。由于该哈希值是累积计算的,涵盖截至并包括断点的所有内容,因此更改断点处或断点之前的任何块,都会使下一次请求产生不同的哈希值。
缓存读取会向后查找先前请求写入的条目。每次请求时,系统都会计算断点处的前缀哈希值,并检查是否存在匹配的缓存条目。如果不存在,系统会逐块向后查找,检查每个更早位置的前缀哈希值是否与缓存中已有的条目匹配。系统查找的是先前写入的条目,而不是稳定不变的内容。
缓存读取会向后查找先前请求写入的条目。每次请求时,系统都会计算断点处的前缀哈希值,并检查是否存在匹配的缓存条目。如果不存在,系统会逐块向后查找,检查每个更早位置的前缀哈希值是否与缓存中已有的条目匹配。系统查找的是先前写入的条目,而不是稳定不变的内容。
回溯窗口包含 20 个块。系统对每个断点最多检查 20 个位置,并将断点本身计为第一个位置。如果系统在该窗口中找不到匹配的条目,检查就会停止(如果还有下一个显式断点,则从该断点继续检查)。
回溯窗口包含 20 个块。系统对每个断点最多检查 20 个位置,并将断点本身计为第一个位置。如果系统在该窗口中找不到匹配的条目,检查就会停止(如果还有下一个显式断点,则从该断点继续检查)。
示例:不断增长的对话中的回溯
你在每一轮追加新块,并在每次请求的最后一个块上设置 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)。你在块 6 上设置了 cache_control:
请求 1:在块 6 写入缓存。哈希中包含时间戳。
请求 2:时间戳不同,因此块 6 的前缀哈希也不同。回溯会依次检查块 5、4、3、2 和 1,但系统从未在这些位置写入过条目。缓存未命中。你每次请求都要为新的缓存写入付费,却从未获得缓存读取。
回溯机制不会找到断点之前的稳定内容并将其缓存。它寻找的是先前请求已经写入的条目,而写入只会发生在断点处。请将 cache_control 移到块 5,也就是跨请求保持不变的最后一个块,这样之后的每个请求都能读取已缓存的前缀。自动缓存也会陷入同样的问题:它会将断点放在最后一个可缓存块上,而在这种结构中,该块每次请求都会发生变化,因此应改为在块 5 上使用显式断点。
关键要点:应将 cache_control 放在这样一个块上:在你希望共享缓存的各个请求中,以该块结尾的前缀必须完全相同。在不断增长的对话中,只要每轮新增的块少于 20 个,将其放在最后一个块上即可:先前的内容永远不会改变,因此下一个请求的回溯能够找到上一次写入的条目。对于带有可变后缀的提示词(时间戳、逐请求上下文、传入的消息),应将断点放在静态前缀的末尾,而不是可变块上。
你最多可以定义 4 个缓存断点,以便:
重要限制:回溯只能找到先前请求已经写入的条目。如果不断增长的对话使断点距离上一次写入达到或超过 20 个块,回溯窗口就会错过该条目。请从一开始就在更靠近该位置的地方添加第二个断点,以便在实际需要之前,那里就已经逐步积累了写入条目。
缓存断点本身不会产生任何成本。你只需为以下内容付费:
添加更多 cache_control 断点不会增加成本——你仍然只需根据实际缓存和读取的内容支付相同的费用。断点让你能够控制哪些部分可以独立缓存。
在 Claude API、AWS 上的 Claude Platform、Google Cloud 和 Microsoft Foundry 上,可缓存提示词的最小长度为:
这些最低限制适用于每个模型可用的所有平台。
更短的提示词无法缓存,即使使用 cache_control 进行了标记。任何尝试缓存少于上述 token 数量的请求都将在不使用缓存的情况下处理,并且不会返回错误。要验证提示词是否已缓存,请检查响应中的用量字段:如果 cache_creation_input_tokens 和 cache_read_input_tokens 均为 0,则提示词未被缓存(很可能是因为没有达到最小长度要求)。
如果你的提示词只比所用模型和平台的最低要求略短,扩展缓存内容以达到阈值通常是值得的。缓存读取的成本远低于未缓存输入 token,因此对于频繁复用的提示词,达到最低要求可以降低成本。
Bedrock 是由 AWS 运营的平台。在 Bedrock 上,请参阅 Bedrock 提示词缓存文档,了解适用于各模型的最低要求、失败行为和用量字段名称。
对于并发请求,请注意,缓存条目只有在第一个响应开始后才可用。如果希望并行请求命中缓存,请等待第一个响应开始后,再发送后续请求。
目前,"ephemeral" 是唯一支持的缓存类型,其默认生命周期为 5 分钟。
请求中的大多数块都可以缓存,包括:
tools 数组中的工具定义system 数组中的内容块messages.content 数组中的内容块,包括用户轮次和助手轮次messages.content 数组内的内容块messages.content 数组内的内容块上述每种元素都可以通过自动方式缓存,也可以使用 cache_control 标记进行缓存。
虽然大多数请求块都可以缓存,但也存在一些例外:
思考块不能直接使用 cache_control 进行缓存。不过,当思考块出现在先前的助手轮次中时,可以与其他内容一起缓存。以这种方式缓存后,从缓存读取时,它们会计入输入 token。
思考块不能直接使用 cache_control 进行缓存。不过,当思考块出现在先前的助手轮次中时,可以与其他内容一起缓存。以这种方式缓存后,从缓存读取时,它们会计入输入 token。
子内容块(例如引用)本身不能直接缓存。应改为缓存顶层块。对于引用,可以缓存作为引用来源材料的顶层文档内容块。这样,通过缓存引用将要引用的文档,你就可以有效地将提示词缓存与引用功能结合使用。
子内容块(例如引用)本身不能直接缓存。应改为缓存顶层块。
对于引用,可以缓存作为引用来源材料的顶层文档内容块。这样,通过缓存引用将要引用的文档,你就可以有效地将提示词缓存与引用功能结合使用。
空文本块无法缓存。
空文本块无法缓存。
修改已缓存的内容可能导致部分或全部缓存失效。
如“构建提示词结构”中所述,缓存遵循以下层级:工具 → 系统 → 消息。对每一层的更改都会使该层以及所有后续层的缓存失效。
下表展示了不同类型的更改会使缓存的哪些部分失效。✘ 表示缓存失效,✓ 表示缓存仍然有效。
在 Claude Fable 5、Claude Mythos 5、Claude Opus 4.8 和 Claude Opus 5 上,你可以在对话进行过程中添加新的系统指令,而不会使系统或消息缓存失效。应向 messages 追加一条 {"role": "system"} 消息,而不是编辑顶层 system 字段,这样缓存的前缀就能保持不变。Claude Sonnet 5 不支持此功能;请改用顶层 system 字段。请参阅“对话中途的系统消息”。
使用响应中 usage 内的以下 API 响应字段(如果使用流式传输,则位于 message_start 事件中)监控缓存性能:
cache_creation_input_tokens:创建新条目时写入缓存的 token 数量。
cache_read_input_tokens:本次请求从缓存中读取的 token 数量。
input_tokens:未从缓存中读取,也未用于创建缓存的输入 token 数量(即最后一个缓存断点之后的 token)。
input_tokens 字段仅表示请求中最后一个缓存断点之后的 token,而不是你发送的全部输入 token。
总输入 token 数量的计算方式如下:
total_input_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(从缓存中读取)、0 个正在写入新缓存内容的 token,以及用户消息中的 50 个 token(位于缓存断点之后):
cache_read_input_tokens:100,000
cache_creation_input_tokens:0
处理的输入 token 总数:100,050 个 token
这对于理解成本和速率限制都很重要,因为在有效使用缓存时,input_tokens 通常会远小于你的总输入量。
将 thinking 与提示词缓存结合使用时,thinking 块具有特殊行为:
自动与其他内容一起缓存:虽然无法使用 cache_control 显式标记 thinking 块,但当你在后续 API 调用中携带工具结果时,它们会作为请求内容的一部分被缓存。这通常发生在使用工具的过程中,即你将 thinking 块传回以继续对话时。
输入 token 计数:从缓存中读取 thinking 块时,它们会在使用量指标中计为输入 token。这对于成本计算和 token 预算非常重要。
缓存失效模式:
cache_control 标记,也会发生这种缓存行为有关缓存失效的更多详细信息,请参阅“哪些情况会使缓存失效”。
工具使用示例:
Request 1: User: "What's the weather in Paris?"
Response: [thinking_block_1] + [tool_use block 1]
Request 2:
User: ["What's the weather in Paris?"],
Assistant: [thinking_block_1] + [tool_use block 1],
User: [tool_result_1, cache=True]
Response: [thinking_block_2] + [text block 2]
# Request 2 caches its request content (not the response)
# The cache includes: user message, thinking_block_1, tool_use block 1, and tool_result_1
Request 3:
User: ["What's the weather in Paris?"],
Assistant: [thinking_block_1] + [tool_use block 1],
User: [tool_result_1, cache=True],
Assistant: [thinking_block_2] + [text block 2],
User: [Text response, cache=True]
# On earlier Opus/Sonnet and all Haiku models, non-tool-result user block causes prior thinking blocks to be stripped; on Opus 4.5+/Sonnet 4.6+ they are kept
在较早的 Opus/Sonnet 模型以及所有 Haiku 模型上,此时会从上下文中移除之前的所有 thinking 块。在 Opus 4.5+ 和 Sonnet 4.6+ 上,之前的 thinking 块默认会被保留,并继续作为缓存前缀的一部分。
有关更详细的信息,请参阅“Thinking 与提示词缓存”。
提示词缓存采用工作区级隔离。缓存按工作区隔离,确保同一组织内不同工作区之间的数据相互分离。这适用于 Claude API、AWS 上的 Claude Platform 和 Microsoft Foundry;Bedrock 与 Google Cloud 则采用组织级缓存隔离。如果你使用多个工作区,请检查你的缓存策略,以将这种差异考虑在内。
组织与工作区隔离:不同组织之间的缓存相互隔离。即使使用完全相同的提示词,不同组织也绝不会共享缓存。在 Claude API、AWS 上的 Claude Platform 和 Microsoft Foundry 中,同一组织内的缓存还会按工作区隔离;Bedrock 与 Google Cloud 仅使用组织级隔离。
组织与工作区隔离:不同组织之间的缓存相互隔离。即使使用完全相同的提示词,不同组织也绝不会共享缓存。在 Claude API、AWS 上的 Claude Platform 和 Microsoft Foundry 中,同一组织内的缓存还会按工作区隔离;Bedrock 与 Google Cloud 仅使用组织级隔离。
精确匹配:要命中缓存,提示词片段必须 100% 完全相同,包括截至并包含标有缓存控制的块在内的所有文本和图像。
精确匹配:要命中缓存,提示词片段必须 100% 完全相同,包括截至并包含标有缓存控制的块在内的所有文本和图像。
输出 token 生成:提示词缓存不会影响输出 token 的生成。无论是否使用提示词缓存,你收到的响应都完全相同。
输出 token 生成:提示词缓存不会影响输出 token 的生成。无论是否使用提示词缓存,你收到的响应都完全相同。
要优化提示词缓存的性能: