文档

Gemini 上下文缓存使用指南

通过 OpenAI 兼容的 Chat Completions API 或原生 Gemini API 创建和复用 Gemini 上下文缓存(Context Cache),用 cache_control 缓存稳定前缀,降低重复长内容的 token 成本。

通过 OpenAI 兼容的 Chat Completions API 或原生 Gemini API 创建和复用 Gemini 上下文缓存(Context Cache),用 cache_control 缓存稳定前缀,降低重复长内容的 token 成本。

本文介绍如何通过 OpenAI 兼容的 Chat Completions API 或原生 Gemini API 创建和复用 Gemini 上下文缓存(Context Cache)。

使用前准备:

export API_KEY="你的API密钥"
注意
本文示例使用 `gemini-3.6-flash`。其他模型是否支持 Context Cache,请以平台模型说明和价格页面为准。

适用场景

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

  • 超长 system prompt
  • 固定的知识库或产品文档
  • 多轮对话中的稳定历史消息
  • 重复使用的工具定义和说明

Context Cache 适合“前面内容保持不变,最后的问题持续变化”的请求。

核心用法

在稳定前缀最后一条消息的 content block 上添加 cache_control

{
  "type": "text",
  "text": "这是稳定前缀的最后一段内容",
  "cache_control": {
    "type": "ephemeral",
    "ttl": "5m"
  }
}

支持的 TTL:

TTL 含义
5m 缓存 5 分钟
1h 缓存 1 小时
注意
省略 `ttl` 时默认使用 `5m`。

消息结构

推荐使用以下结构:

system
→ 稳定的长文本或历史消息
→ 带 cache_control 的稳定前缀边界
→ 当前用户问题(不缓存)

cache_control 所在消息及它之前的所有消息组成缓存前缀。它后面必须至少有一条实时消息。

OpenAI 兼容请求示例

curl "https://api.openveer.com/v1/chat/completions" \
  -H "Authorization: Bearer $API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "model": "gemini-3.6-flash",
    "stream": false,
    "messages": [
      {
        "role": "system",
        "content": "请严格根据提供的参考资料回答问题。"
      },
      {
        "role": "user",
        "content": "这里放需要重复使用的长篇参考资料……"
      },
      {
        "role": "assistant",
        "content": [
          {
            "type": "text",
            "text": "我已阅读并理解以上参考资料。",
            "cache_control": {
              "type": "ephemeral",
              "ttl": "5m"
            }
          }
        ]
      },
      {
        "role": "user",
        "content": "请总结参考资料中的三个核心观点。"
      }
    ]
  }'

第一次发送时,系统会尝试创建缓存,并使用新缓存完成当前请求。

注意
不需要单独调用缓存创建接口。`cache_control` 同时表达“缓存边界”和“缓存有效期”。

原生 Gemini 请求示例

原生 Gemini generateContent 接口同样支持在 contents[].parts[] 中添加 cache_control

curl "https://api.openveer.com/v1beta/models/gemini-3.6-flash:generateContent" \
  -H "x-goog-api-key: $API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "systemInstruction": {
      "parts": [
        {
          "text": "请严格根据提供的参考资料回答问题。"
        }
      ]
    },
    "contents": [
      {
        "role": "user",
        "parts": [
          {
            "text": "这里放需要重复使用的长篇参考资料……"
          }
        ]
      },
      {
        "role": "model",
        "parts": [
          {
            "text": "我已阅读并理解以上参考资料。",
            "cache_control": {
              "type": "ephemeral",
              "ttl": "5m"
            }
          }
        ]
      },
      {
        "role": "user",
        "parts": [
          {
            "text": "请总结参考资料中的三个核心观点。"
          }
        ]
      }
    ]
  }'

cache_control 是平台在 Gemini 请求格式上的扩展字段。平台识别边界后会在转发前移除该字段,并自动创建或复用缓存内容(cachedContent)。

流式接口使用相同请求体,只需将地址改为:

curl -N "https://api.openveer.com/v1beta/models/gemini-3.6-flash:streamGenerateContent?alt=sse" \
  -H "x-goog-api-key: $API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "contents": [
      {
        "role": "user",
        "parts": [
          {
            "text": "这里放需要重复使用的长篇参考资料……",
            "cache_control": {
              "type": "ephemeral",
              "ttl": "5m"
            }
          }
        ]
      },
      {
        "role": "user",
        "parts": [
          {
            "text": "请总结参考资料中的三个核心观点。"
          }
        ]
      }
    ]
  }'

复用时保持 systemInstruction、边界之前的 contents、TTL 和 tools 不变,只修改边界之后的实时内容。

创建和复用流程

第一次发送带 cache_control 的请求时:

识别稳定前缀
→ 创建 Context Cache
→ 在当前请求中引用新缓存
→ 返回模型结果

再次发送相同稳定前缀时:

识别相同稳定前缀
→ 复用未过期的 Context Cache
→ 只发送当前实时内容
→ 返回模型结果

因此,第一次请求也可能直接返回较大的缓存命中 token。这是正常行为,并不要求先发送一次“预热请求”。

复用缓存

再次请求时,保持以下内容不变:

  • 模型
  • cache_control 之前的所有消息
  • cache_control.ttl
  • 工具定义(如果使用 tools)
  • 原生 Gemini 请求中的 systemInstruction

只修改边界之后的实时问题:

{
  "role": "user",
  "content": "参考资料中提到了哪些风险?"
}

只要稳定前缀一致且缓存未过期,系统就会复用已有缓存。

以下改动会生成不同的缓存:

  • 修改稳定前缀中的文字或消息顺序
  • 更换模型
  • 5m 改为 1h
  • 修改 tools 或工具参数定义
  • 使用不同的 API 用户或渠道

Python 示例

from openai import OpenAI

client = OpenAI(
    api_key="YOUR_API_KEY",
    base_url="https://api.openveer.com/v1",
)

stable_messages = [
    {
        "role": "system",
        "content": "请严格根据提供的参考资料回答问题。",
    },
    {
        "role": "user",
        "content": "这里放需要重复使用的长篇参考资料……",
    },
    {
        "role": "assistant",
        "content": [
            {
                "type": "text",
                "text": "我已阅读并理解以上参考资料。",
                "cache_control": {
                    "type": "ephemeral",
                    "ttl": "5m",
                },
            }
        ],
    },
]

response = client.chat.completions.create(
    model="gemini-3.6-flash",
    messages=[
        *stable_messages,
        {
            "role": "user",
            "content": "请总结参考资料中的三个核心观点。",
        },
    ],
)

print(response.choices[0].message.content)
print(response.usage)

后续请求复用同一个 stable_messages,只替换最后一条 user 消息即可。

判断是否命中

OpenAI 兼容响应

查看响应中的:

{
  "usage": {
    "prompt_tokens": 14430,
    "prompt_tokens_details": {
      "cached_tokens": 14420,
      "cache_write_tokens": 0
    }
  }
}

字段说明:

字段 含义
prompt_tokens 本次请求的全部输入 token
cached_tokens 本次从缓存读取的输入 token
cache_write_tokens 缓存写入 token;返回 0 是正常行为

首次请求也可能出现较大的 cached_tokens,因为系统可以先创建缓存,再在同一次模型调用中引用它。

原生 Gemini 响应

查看响应中的 usageMetadata.cachedContentTokenCount

{
  "usageMetadata": {
    "promptTokenCount": 13926,
    "cachedContentTokenCount": 13916,
    "totalTokenCount": 13954
  }
}

字段说明:

字段 含义
promptTokenCount 本次请求的全部输入 token
cachedContentTokenCount 本次从缓存读取的输入 token
totalTokenCount 本次请求的输入和输出 token 总数

streamGenerateContent 会在 SSE 响应帧中返回相同的 usageMetadata。客户端应读取包含该字段的响应帧,不要只检查第一段文本。

使用建议

提示
1. 只缓存真正稳定、会多次复用的长内容。 2. 将每次变化的问题放在 `cache_control` 边界之后。 3. 不要在稳定前缀中加入时间戳、随机 ID 或动态用户信息。 4. 预计短时间内重复调用时使用 `5m`。 5. 需要较长复用窗口时使用 `1h`。 6. 前缀太短、模型不支持或缓存暂时不可用时,请求可能自动按普通模式执行。 7. 原生 Gemini 的缓存边界必须放在 `contents[].parts[]` 中,不要放在 `systemInstruction` 中。

常见问题

原生 Gemini 请求格式可以自动创建缓存吗?
可以。`generateContent` 和 `streamGenerateContent` 使用相同的 `cache_control` 结构。边界必须放在 `contents[].parts[]` 中,且边界所在 content 后面必须保留至少一个实时 content。 如果请求已经显式提供原生 `cachedContent` 资源名,平台会优先使用用户提供的资源,不再执行自动缓存创建。
为什么没有命中缓存?
常见原因包括: * 稳定前缀与上一次请求不完全一致 * TTL 已过期 * 修改了模型或 tools * 缓存内容没有达到模型要求的最低 token 数 * `cache_control` 放在了最后一条消息上,没有留下实时问题
cache_control 可以放在最后一条消息上吗?
不建议。最后一条消息通常是当前实时问题,不应缓存。边界后没有实时消息时,请求会按普通模式执行。
可以设置其他 TTL 吗?
不可以。目前只支持 `5m` 和 `1h`。其他值会返回 HTTP 400。
可以设置多个缓存边界吗?
可以,但所有边界必须使用相同 TTL,系统会使用最后一个边界。一般建议每个请求只设置一个边界,结构更清晰。
缓存不可用会导致请求失败吗?
通常不会。缓存创建或复用条件不满足时,系统会自动使用普通请求。无效 TTL、混用不同 TTL 等参数错误除外。
模型没有开通 Context Cache 会怎样?
请求会自动按普通模式执行,不创建显式缓存,也不产生缓存存储费用。普通输入、输出和可能存在的隐式缓存继续按照该模型原有规则计费。
为什么 cache_write_tokens 是 0?
这是 Gemini 上下文缓存的正常行为。缓存创建成本通过独立的缓存存储费用记录,不使用 OpenAI/Claude 风格的 `cache_write_tokens` 表示缓存创建量。
cached_tokens 大于 0 就代表一定创建了显式缓存吗?
不一定。系统自身也可能产生隐式缓存命中。对普通用户而言,可以使用缓存读取 token 判断本次请求是否享受缓存读取;如需核对显式缓存创建费用,请查看平台消费日志中的 Context Cache storage 记录。
缓存如何计费?
创建缓存时可能产生一次缓存存储费用;使用缓存时,命中的 token 按缓存读取价格计费。具体价格以平台展示的模型价格为准。