> ## Documentation Index
> Fetch the complete documentation index at: https://gccai.heqingsong.uk/llms.txt
> Use this file to discover all available pages before exploring further.

# Claude 上下文缓存使用指南

> 通过 Claude Messages API 或 OpenAI 兼容的 Chat Completions API 缓存重复使用的提示词前缀，减少重复处理长内容产生的 token 成本。

Claude 上下文缓存（Context Cache）适合重复使用系统提示、文档、代码库或对话历史等长前缀。为稳定前缀添加 `cache_control` 后，首次请求创建缓存，后续请求可以读取未过期的缓存。

使用前请设置 API 密钥：

```bash theme={null}
export API_KEY="你的 API 密钥"
```

<Note>本文示例使用 `claude-sonnet-5`。其他模型是否支持上下文缓存，请以平台中的模型说明为准。</Note>

## 适用场景

当多个请求会重复携带相同的大段内容时，可以缓存稳定前缀，例如：

* 长 system prompt
* 固定的知识库或产品文档
* 多轮对话中保持不变的历史消息
* 重复使用的代码库、工具定义和说明

上下文缓存适合“前面的内容保持不变，最后的问题持续变化”的请求。

## Claude Messages API

### 5 分钟缓存

在需要缓存的内容块上添加 `cache_control`：

```bash theme={null}
curl "https://gccai.heqingsong.uk/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": "请根据上面的内容回答问题。"
      }
    ]
  }'
```

<Warning>`system` 必须写成内容块数组。字符串形式的 `system` 无法添加 `cache_control`。</Warning>

省略 `ttl` 时，缓存有效期默认为 5 分钟。

### 1 小时缓存

使用 1 小时缓存时，需要同时添加 `anthropic-beta` 请求头，并将 `ttl` 设置为 `1h`：

```bash theme={null}
curl "https://gccai.heqingsong.uk/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：

```json theme={null}
{
  "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 的计算方式为：

```text theme={null}
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 类似：

```bash theme={null}
curl "https://gccai.heqingsong.uk/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"`：

```bash theme={null}
-H "anthropic-beta: extended-cache-ttl-2025-04-11"
```

```json theme={null}
"cache_control": {
  "type": "ephemeral",
  "ttl": "1h"
}
```

### `content` 必须使用数组

在 OpenAI 兼容格式中，`cache_control` 必须放在具体的内容块内，不能挂在字符串形式的消息上。

```json theme={null}
{
  "role": "system",
  "content": "这里放长前缀……",
  "cache_control": {
    "type": "ephemeral"
  }
}
```

上面的写法不会启用缓存，而且请求不会因此报错。正确写法如下：

```json theme={null}
{
  "role": "system",
  "content": [
    {
      "type": "text",
      "text": "这里放长前缀……",
      "cache_control": {
        "type": "ephemeral"
      }
    }
  ]
}
```

<Warning>如果 `content` 使用字符串，缓存标记会被忽略，输入内容仍按普通输入处理。请通过响应中的缓存用量字段确认是否命中。</Warning>

### 缓存 user 或 assistant 内容块

`cache_control` 也可以放在 `user` 或 `assistant` 消息的内容块上，用于缓存长文档或多轮对话前缀：

```json theme={null}
{
  "role": "user",
  "content": [
    {
      "type": "text",
      "text": "这里放需要重复使用的长文档……",
      "cache_control": {
        "type": "ephemeral"
      }
    },
    {
      "type": "text",
      "text": "请总结上面文档中的三个核心观点。"
    }
  ]
}
```

将稳定内容和当前问题拆成不同的内容块，并只在稳定内容块上添加 `cache_control`。

### 响应用量字段

OpenAI 兼容格式使用不同的字段报告缓存用量：

```json theme={null}
{
  "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`                                      |

<Note>如果 `prompt_tokens_details.cache_write_tokens` 为 `0`，仍需检查 `claude_cache_creation_5_m_tokens` 和 `claude_cache_creation_1_h_tokens`；存在 TTL 细分字段时，缓存写入量会通过对应字段返回。</Note>

<Note>`claude_cache_creation_5_m_tokens` 和 `claude_cache_creation_1_h_tokens` 中的数字与单位之间包含下划线，请直接使用响应返回的字段名。</Note>

<Warning>OpenAI 兼容接口即使没有显式传入 `stream: true`，也可能返回 SSE 流式响应。客户端应支持解析 `chat.completion.chunk`，用量位于最后一个包含 `usage` 的数据块中。</Warning>

## 缓存命中的条件

### 前缀长度达到最低门槛

示例模型的缓存前缀通常至少需要约 1024 token。前缀不足时，缓存标记可能被忽略且不会报错。

### 前缀保持逐字节一致

缓存前缀中的文字、空格、换行和内容块顺序必须保持一致。不要在稳定前缀中加入时间戳、随机 ID 或请求计数等动态内容。

### 请求未触发模型拒答

如果请求触发模型拒答，响应可能仍报告缓存创建 token，但该缓存不会在下一次请求中被读取。排查缓存未命中时，请同时检查 `stop_reason` 是否为 `refusal`。

### 缓存仍在有效期内

缓存有效期为 5 分钟或 1 小时，并从最后一次访问开始计算；缓存命中会刷新有效期。

## 计费用量

缓存相关用量分为三类：

| 用量   | 产生时机      |
| ---- | --------- |
| 缓存写入 | 首次建立缓存    |
| 缓存读取 | 后续请求命中缓存  |
| 普通输入 | 缓存前缀之外的输入 |

三类用量互不重叠。缓存写入的成本通常高于普通输入，缓存读取的成本通常低于普通输入，因此上下文缓存更适合会在 TTL 内重复使用的稳定前缀。

## 最小可复现示例

下面的脚本先生成一个足够长的稳定前缀，再连续发送两次相同请求。第二次响应应出现 `cache_read_input_tokens > 0`。

```bash theme={null}
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://gccai.heqingsong.uk/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
```

预期结果：

```text theme={null}
第 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
* 是否读取了当前接口对应的缓存用量字段
