此功能符合零数据保留(ZDR)的条件。当您的组织签订了 ZDR 协议时,通过此功能发送的数据在 API 响应返回后不会被存储。
系统指令通常位于顶层 system 字段中,排在对话中所有消息之前。这个位置非常适合提示缓存:系统提示是稳定前缀的一部分,因此后续轮次可以命中缓存。但对于那些您在会话进行到一半时才发现需要的指令来说,这个位置并不理想,因为编辑顶层 system 字段会改变提示的最开头部分,从而使其后所有内容的缓存失效。
对话中途系统消息(mid-conversation system messages)弥补了这一缺口。您可以在对话中新指令变得相关的位置追加一条 {"role": "system"} 消息,而不是编辑顶层 system 字段。缓存的前缀保持不变,因此下一个请求仍然可以从缓存中读取,而新指令仍会作为系统指令而非普通用户文本被应用。
对话中途系统消息在 Claude API 和 AWS 上的 Claude Platform 上可用。它们在 Amazon Bedrock、Vertex AI 或 Microsoft Foundry 上不可用。
此功能仅在 Claude Opus 4.8 上可用。无需 beta 标头。
提示缓存按顺序对请求前缀进行哈希处理:先是 tools,然后是 system,最后是 messages。缓存命中要求前缀与最近的某个请求逐字节完全匹配,直到缓存断点为止。
这种排序意味着顶层 system 字段位于哈希前缀的最开头附近。对它的任何更改,哪怕只是追加一句话,都会产生不同的哈希值,导致该请求在系统提示及其后所有已缓存消息上都无法命中缓存。
对话中途系统消息允许您将指令添加到消息历史的末尾。新指令之前的所有内容都保持不变,因此现有的缓存条目仍然匹配,只有新消息会作为全新输入被处理。
以下是几种适用的场景:
system 字段会导致整个历史记录被重新处理。在上述所有情况下,您都可以将指令放在常规的 user 消息中,Claude 确实会遵循用户轮次中传达的指令。区别在于优先级:user 消息被视为来自最终用户,而 system 消息被视为来自您——应用程序操作者。当两者冲突时,系统指令优先,因此对于即使最终用户提出不同要求也应保持有效的操作者级事实和约束,请使用 system 角色。对话中途系统消息保留了这种操作者级优先级,同时避免了编辑顶层 system 字段所带来的缓存未命中成本。
向 messages 数组添加一条 "role": "system" 的消息。content 可以使用纯字符串或内容块,与 user 或 assistant 轮次相同。该指令从对话中的该位置起生效。当指令发生冲突时,较晚的系统消息优先于较早的系统消息,对话中途系统消息在其后的轮次中优先于顶层 system 字段。
对于应适用于整个对话的指令,您仍然可以设置顶层 system 字段。将对话中途系统消息保留给那些只在后期才变得相关的指令,或者您希望在不使缓存前缀失效的情况下添加的指令。
client = anthropic.Anthropic()
response = client.messages.create(
model="claude-opus-4-8",
max_tokens=1024,
# 自动提示缓存:每个请求都会缓存到目前为止的对话,
# 下一个请求则从缓存中读取未更改的前缀。
cache_control={"type": "ephemeral"},
system="You are a code review assistant. Be concise.",
messages=[
{
"role": "user",
"content": "Review process() in utils.py for performance issues.",
},
{
"role": "assistant",
"content": "The list comprehension is fine for small inputs. For large inputs, consider a generator to avoid materializing the full list.",
},
{
"role": "user",
"content": "Now review the calling code that invokes process().",
},
# 审阅者在会话中途意识到所有建议还必须
# 符合团队的严格类型检查策略。在此处追加
# 该指令可使之前的轮次保持字节级一致,因此
# 上一个请求缓存的前缀仍可从缓存中读取。
{
"role": "system",
"content": "From now on, every suggestion must include explicit type annotations.",
},
],
)
print(response.content[0].text)此示例通过顶层 cache_control 字段启用了自动缓存。提示缓存是选择性启用的:如果请求没有 cache_control 字段(无论是自动缓存还是显式断点),则不会缓存任何内容,每个请求都需要为完整对话支付常规输入令牌价格。启用缓存后,追加系统消息不会改变已缓存的轮次,因此携带新指令的请求仍然从缓存中读取它们,而不是重新处理。缓存还要求对话达到最小可缓存提示长度;像本示例这样简短的对话低于该阈值,因此在对话增长之前,cache_creation_input_tokens 和 cache_read_input_tokens 会保持为 0。
对话中途系统消息必须紧跟在 user 轮次(或以服务器工具使用结尾的 assistant 轮次)之后,并且必须是 messages 中的最后一个条目,或者紧接着一个 assistant 轮次。携带 tool_result 块的 user 消息也算数:在智能体循环中,您可以将系统消息放在工具结果之后、Claude 的下一个轮次之前。唯一不允许的位置是在 assistant 的 tool_use 块与响应它的 tool_result 之间。
在智能体循环中,系统消息位于传递工具结果的 user 消息之后。这也是您的应用程序可以转发用户在 Claude 工作期间输入的内容的位置,从而在不重启轮次的情况下吸收新的上下文:
[
{ "role": "user", "content": "Run the test suite and fix any failures." },
{
"role": "assistant",
"content": [{ "type": "tool_use", "id": "toolu_01", "name": "run_tests", "input": {} }]
},
{
"role": "user",
"content": [
{ "type": "tool_result", "tool_use_id": "toolu_01", "content": "12 passed, 0 failed" }
]
},
{
"role": "system",
"content": "The user sent the following message while you were working: also update the changelog before you finish."
}
]将系统内容表述为上下文,而不是覆盖用户的命令。陈述事实("用户发来了新输入:X"、"剩余令牌预算现在为 Y"),让 Claude 据此行动。Claude 经过训练会抵制那些看似与用户对立的指令,这种保护机制同样适用于系统角色,因此"忽略用户所说的内容"这类措辞不如直接陈述发生了什么变化来得有效。
此模式用于转发来自对话自身最终用户的输入。请勿用它来传递工具输出、检索到的文档或其他第三方内容;请将这些内容保留在 tool_result 块中(参见限制)。
对话中途系统消息和提示缓存在设计上就是要配合使用的:
cache_control 时才会进行缓存,无论是顶层的自动缓存字段还是内容块上的显式断点。对话中途系统消息本身不会创建缓存条目,如果未启用缓存,也就没有可保留的节省。cache_control 放在跨请求保持不变的最后一个块上,无论是顶层 system 字段的末尾、工具定义的末尾,还是消息历史中的某个稳定位置。避免编辑或删除已发送的对话中途系统消息。与对早期消息的任何其他更改一样,这会使从该点开始的缓存失效。如果指令需要演变,请追加新的系统消息,而不是重写旧的。不允许连续的系统消息;请将指令合并到一条消息中,或等待下一个用户轮次后再追加。
system 消息不能是 messages 中的第一个条目。对于从一开始就应适用的指令,请使用顶层 system 字段。system 消息必须紧跟在 user 轮次(包括携带 tool_result 块的 user 轮次)或以服务器工具使用结尾的 assistant 轮次之后,并且必须位于 assistant 轮次之前或作为数组的结尾。它不能位于 tool_use 块与其 tool_result 之间。放置在其他位置会返回 400 错误。tool_result 块中,并继续遵循缓解越狱和提示注入的指导。缓存的工作原理、断点的放置位置以及如何读取缓存使用情况字段。
当预期的缓存命中未发生时,准确找出两个请求的分歧点。
消息结构、多轮对话和 system 字段。
编写有效的提示和系统指令。
tool_use 和 tool_result 块在 messages 数组中的结构。
Was this page helpful?