# OpenAI 上下文缓存
> 重复的长前缀不再重复计费
> 缓存命中部分的输入 token 按折扣价结算
> 对长系统提示、固定文档、多轮同一背景的对话收益最大
## 原理
大模型对输入的处理是「逐 token 读一遍」。如果连续多次请求的前缀完全一致，网关可以把这段前缀的处理结果复用，省下重复计算。
命中条件有三条：
1. 前缀内容完全相同，一个字符都不能变
2. 前缀长度达到该模型的最小缓存门槛
3. 两次请求间隔在缓存有效期之内
> **Note:** 
> 缓存以「前缀」为单位，不是任意位置。如果只有中间一段相同、开头不同，是不会命中的。所以要把固定内容放在最前面，变化的内容放在最后面。
## 用法
不需要额外参数。只要请求结构满足前缀一致，网关会自动命中并在响应里报告。
- `usage.prompt_tokens_details.cached_tokens` (integer) — 本次请求命中缓存的输入 token 数。没有命中时为 0 或省略。
## 把命中率做高的写法
**玩具示例（几乎不命中）：**
```json
{
  "messages": [
    { "role": "user", "content": "文档内容……\n\n问题是 A" }
  ]
}
```
**正确写法（固定内容在前，变量在后）：**
```json
{
  "messages": [
    { "role": "system", "content": "【这一段是固定的产品手册，约 8000 token】" },
    { "role": "user", "content": "问题是 A" }
  ]
}
```
第二次请求只改最后一句，前面那一大段前缀不变，就能命中。
## 成本对比
| 项目 | 未命中 | 命中 |
|---|---|---|
| 输入计费 | 全价 | 缓存部分按折扣价 |
| 输出计费 | 全价 | 全价（输出不缓存） |
| 延迟 | 基准 | 通常更低 |
具体折扣比例取决于上游模型，不同模型不一样。
## 有效期
缓存不是永久的。长时间不请求会自动失效，届时同样的前缀会重新按全价计算一次。做定时批处理时，把同类请求集中在一个时间窗内跑完，命中率最高。
## 使用示例
### 让长前缀命中缓存
把稳定不变的长文本放在最前面，变化的部分放后面。以下例子里，产品手册全文固定，用户问题每次不同，缓存的前缀就能复用。
### 核对是否命中
响应里的 `usage.prompt_tokens_details.cached_tokens` 是本次命中缓存的 token 数。大于 0 表示命中，为 0 说明前缀变了或缓存已过期。
```bash
curl --request POST https://api.oairoute.com/v1/chat/completions \
  -H "Authorization: Bearer YOUR_OAIRoute_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "model": "gpt-4o-mini",
    "messages": [
      { "role": "system", "content": "以下是产品手册全文（约 8000 字）：……" },
      { "role": "user", "content": "退款流程需要几步" }
    ]
  }' | jq '.usage.prompt_tokens_details'
```
### 批量任务集中跑
同一批请求放在连续的时间窗内执行，缓存不容易过期。分散到不同时段，每批都要重新写入一次。
```bash
for q in "退款流程需要几步" "如何修改收货地址" "发票在哪里申请"; do
  curl --request POST https://api.oairoute.com/v1/chat/completions \
    -H "Authorization: Bearer $YOUR_OAIRoute_KEY" \
    -H "Content-Type: application/json" \
    -d "{\"model\":\"gpt-4o-mini\",\"messages\":[{\"role\":\"system\",\"content\":\"以下是产品手册全文：……\"},{\"role\":\"user\",\"content\":\"$q\"}]}"
done
```
**让长前缀命中缓存{Hit cache on long prefix}::cURL**
```
curl --request POST \
  --url 'https://api.oairoute.com/v1/chat/completions' \
  --header 'Authorization: Bearer YOUR_OAIRoute_KEY' \
  --header 'Content-Type: application/json' \
  --data '{
    "model": "gpt-4o-mini",
    "messages": [
      { "role": "system", "content": "以下是产品手册全文（约 8000 字）：……" },
      { "role": "user", "content": "退款流程需要几步" }
    ]
  }'
```
**让长前缀命中缓存{Hit cache on long prefix}::Python**
```
import requests
url = "https://api.oairoute.com/v1/chat/completions"
headers = {"Authorization": "Bearer YOUR_OAIRoute_KEY"}
payload = {
    "model": "gpt-4o-mini",
    "messages": [
      { "role": "system", "content": "以下是产品手册全文（约 8000 字）：……" },
      { "role": "user", "content": "退款流程需要几步" }
    ]
  }
res = requests.post(url, headers=headers, json=payload)
print(res.json())
```
**让长前缀命中缓存{Hit cache on long prefix}::JavaScript**
```
const res = await fetch("https://api.oairoute.com/v1/chat/completions", {
  method: "POST",
  headers: {
    Authorization: "Bearer YOUR_OAIRoute_KEY",
    "Content-Type": "application/json",
  },
  body: JSON.stringify({
    "model": "gpt-4o-mini",
    "messages": [
      { "role": "system", "content": "以下是产品手册全文（约 8000 字）：……" },
      { "role": "user", "content": "退款流程需要几步" }
    ]
  }),
});
console.log(await res.json());
```
**200 让长前缀命中缓存{Hit cache on long prefix}**
```
{
  "id": "chatcmpl-01KA",
  "object": "chat.completion",
  "created": 1763088289,
  "model": "gpt-4o-mini",
  "choices": [
    {
      "index": 0,
      "message": {
        "role": "assistant",
        "content": "退款流程分三步：提交申请、客服审核、原路退回。"
      },
      "finish_reason": "stop"
    }
  ],
  "usage": {
    "prompt_tokens": 8200,
    "completion_tokens": 120,
    "total_tokens": 8320,
    "prompt_tokens_details": {
      "cached_tokens": 8192
    }
  }
}
```
