通过 Claude Messages API 或 OpenAI 兼容的 Chat Completions API 缓存重复使用的提示词前缀,减少重复处理长内容产生的 token 成本。
Claude 上下文缓存(Context Cache)适合重复使用系统提示、文档、代码库或对话历史等长前缀。为稳定前缀添加 cache_control 后,首次请求创建缓存,后续请求可以读取未过期的缓存。
使用前请设置 API 密钥:
export API_KEY="你的 API 密钥"
适用场景
当多个请求会重复携带相同的大段内容时,可以缓存稳定前缀,例如:
- 长 system prompt
- 固定的知识库或产品文档
- 多轮对话中保持不变的历史消息
- 重复使用的代码库、工具定义和说明
上下文缓存适合“前面的内容保持不变,最后的问题持续变化”的请求。
Claude Messages API
5 分钟缓存
在需要缓存的内容块上添加 cache_control:
curl "https://api.openveer.com/v1/messages" \
-H "x-api-key: $API_KEY" \
-H "anthropic-version: 2023-06-01" \
-H "Content-Type: application/json" \
-d '{
"model": "claude-sonnet-5",
"max_tokens": 1024,
"system": [
{
"type": "text",
"text": "这里放需要重复使用的长前缀……",
"cache_control": {
"type": "ephemeral"
}
}
],
"messages": [
{
"role": "user",
"content": "请根据上面的内容回答问题。"
}
]
}'
省略 ttl 时,缓存有效期默认为 5 分钟。
1 小时缓存
使用 1 小时缓存时,需要同时添加 anthropic-beta 请求头,并将 ttl 设置为 1h:
curl "https://api.openveer.com/v1/messages" \
-H "x-api-key: $API_KEY" \
-H "anthropic-version: 2023-06-01" \
-H "anthropic-beta: extended-cache-ttl-2025-04-11" \
-H "Content-Type: application/json" \
-d '{
"model": "claude-sonnet-5",
"max_tokens": 1024,
"system": [
{
"type": "text",
"text": "这里放需要重复使用的长前缀……",
"cache_control": {
"type": "ephemeral",
"ttl": "1h"
}
}
],
"messages": [
{
"role": "user",
"content": "请根据上面的内容回答问题。"
}
]
}'
支持的 TTL:
| TTL | 含义 |
|---|---|
5m |
缓存 5 分钟;省略 ttl 时使用此值 |
1h |
缓存 1 小时;需要同时添加对应的 anthropic-beta 请求头 |
响应用量字段
Claude Messages API 会在 usage 中分别返回普通输入、缓存写入和缓存读取 token:
{
"usage": {
"input_tokens": 23,
"cache_creation_input_tokens": 2619,
"cache_read_input_tokens": 0,
"cache_creation": {
"ephemeral_5m_input_tokens": 2619,
"ephemeral_1h_input_tokens": 0
},
"output_tokens": 24
}
}
总输入 token 的计算方式为:
input_tokens
+ cache_creation_input_tokens
+ cache_read_input_tokens
这三项互不重叠。第一次请求通常会出现 cache_creation_input_tokens > 0;再次发送相同稳定前缀时,应看到 cache_read_input_tokens > 0。
OpenAI 兼容 API
请求示例
通过 /v1/chat/completions 使用缓存时,cache_control 的写法与 Claude Messages API 类似:
curl "https://api.openveer.com/v1/chat/completions" \
-H "Authorization: Bearer $API_KEY" \
-H "Content-Type: application/json" \
-d '{
"model": "claude-sonnet-5",
"max_tokens": 1024,
"messages": [
{
"role": "system",
"content": [
{
"type": "text",
"text": "这里放需要重复使用的长前缀……",
"cache_control": {
"type": "ephemeral"
}
}
]
},
{
"role": "user",
"content": "请根据上面的内容回答问题。"
}
]
}'
1 小时缓存
OpenAI 兼容格式同样支持 1 小时缓存。只需在请求中增加 anthropic-beta 请求头,并在 cache_control 中设置 ttl: "1h":
-H "anthropic-beta: extended-cache-ttl-2025-04-11"
"cache_control": {
"type": "ephemeral",
"ttl": "1h"
}
content 必须使用数组
在 OpenAI 兼容格式中,cache_control 必须放在具体的内容块内,不能挂在字符串形式的消息上。
{
"role": "system",
"content": "这里放长前缀……",
"cache_control": {
"type": "ephemeral"
}
}
上面的写法不会启用缓存,而且请求不会因此报错。正确写法如下:
{
"role": "system",
"content": [
{
"type": "text",
"text": "这里放长前缀……",
"cache_control": {
"type": "ephemeral"
}
}
]
}
缓存 user 或 assistant 内容块
cache_control 也可以放在 user 或 assistant 消息的内容块上,用于缓存长文档或多轮对话前缀:
{
"role": "user",
"content": [
{
"type": "text",
"text": "这里放需要重复使用的长文档……",
"cache_control": {
"type": "ephemeral"
}
},
{
"type": "text",
"text": "请总结上面文档中的三个核心观点。"
}
]
}
将稳定内容和当前问题拆成不同的内容块,并只在稳定内容块上添加 cache_control。
响应用量字段
OpenAI 兼容格式使用不同的字段报告缓存用量:
{
"usage": {
"prompt_tokens": 1942,
"completion_tokens": 22,
"prompt_tokens_details": {
"cached_tokens": 1921,
"cache_write_tokens": 0
},
"claude_cache_creation_5_m_tokens": 0,
"claude_cache_creation_1_h_tokens": 0
}
}
字段对照:
| 含义 | Claude Messages API | OpenAI 兼容 API |
|---|---|---|
| 总输入 | 三个输入字段之和 | prompt_tokens |
| 缓存读取 | cache_read_input_tokens |
prompt_tokens_details.cached_tokens |
| 通用缓存写入字段 | cache_creation_input_tokens |
prompt_tokens_details.cache_write_tokens(无 TTL 细分时才有值) |
| 5 分钟缓存写入 | cache_creation.ephemeral_5m_input_tokens |
claude_cache_creation_5_m_tokens |
| 1 小时缓存写入 | cache_creation.ephemeral_1h_input_tokens |
claude_cache_creation_1_h_tokens |
| 输出 | output_tokens |
completion_tokens |
缓存命中的条件
前缀长度达到最低门槛
示例模型的缓存前缀通常至少需要约 1024 token。前缀不足时,缓存标记可能被忽略且不会报错。
前缀保持逐字节一致
缓存前缀中的文字、空格、换行和内容块顺序必须保持一致。不要在稳定前缀中加入时间戳、随机 ID 或请求计数等动态内容。
请求未触发模型拒答
如果请求触发模型拒答,响应可能仍报告缓存创建 token,但该缓存不会在下一次请求中被读取。排查缓存未命中时,请同时检查 stop_reason 是否为 refusal。
缓存仍在有效期内
缓存有效期为 5 分钟或 1 小时,并从最后一次访问开始计算;缓存命中会刷新有效期。
计费用量
缓存相关用量分为三类:
| 用量 | 产生时机 |
|---|---|
| 缓存写入 | 首次建立缓存 |
| 缓存读取 | 后续请求命中缓存 |
| 普通输入 | 缓存前缀之外的输入 |
三类用量互不重叠。缓存写入的成本通常高于普通输入,缓存读取的成本通常低于普通输入,因此上下文缓存更适合会在 TTL 内重复使用的稳定前缀。
最小可复现示例
下面的脚本先生成一个足够长的稳定前缀,再连续发送两次相同请求。第二次响应应出现 cache_read_input_tokens > 0。
python3 - <<'PY' > /tmp/claude-cache-request.json
import json
paragraph = (
"Prompt caching stores a prefix of the request so that later requests "
"can reuse the same byte-identical prefix without processing it again. "
)
system_text = (
"You are a documentation assistant. Reference material follows.\n\n"
+ paragraph * 40
)
print(json.dumps({
"model": "claude-sonnet-5",
"max_tokens": 32,
"system": [{
"type": "text",
"text": system_text,
"cache_control": {"type": "ephemeral"}
}],
"messages": [{
"role": "user",
"content": "In one sentence, what must remain unchanged?"
}]
}))
PY
for request_number in 1 2; do
echo "第 ${request_number} 次请求"
curl -s "https://api.openveer.com/v1/messages" \
-H "x-api-key: $API_KEY" \
-H "anthropic-version: 2023-06-01" \
-H "Content-Type: application/json" \
--data @/tmp/claude-cache-request.json \
| python3 -c "import json, sys; print(json.load(sys.stdin)['usage'])"
done
预期结果:
第 1 次请求:cache_creation_input_tokens > 0,cache_read_input_tokens = 0
第 2 次请求:cache_creation_input_tokens = 0,cache_read_input_tokens > 0
排查清单
缓存未命中时,请按顺序检查:
stop_reason是否为refusal- 缓存前缀是否达到模型要求的最低 token 数
- 两次请求的稳定前缀是否逐字节相同
- OpenAI 兼容格式中的
content是否为数组 cache_control是否位于具体的内容块内- 1 小时缓存是否同时设置
ttl: "1h"和对应的anthropic-beta请求头 - 缓存是否已经超过 TTL
- 是否读取了当前接口对应的缓存用量字段