Gemini 显式缓存(cachedContents)
Gemini 的缓存分两种:
- 隐式缓存(自动)— 模型自动识别重复的 prompt 前缀并复用,无需任何配置。这是 提示缓存 一文讲的默认行为,命中是「尽力而为」(best-effort),前缀有任何微小变化都可能不命中。
- 显式缓存(本文)— 你主动把一段大上下文创建为一个缓存对象,拿到一个
cachedContents/{id}句柄,之后的generateContent请求显式引用它。命中是确定性的,只要缓存未过期,引用就一定命中。
当你有一份反复使用、内容稳定的大上下文(长文档、代码库、知识库、固定 system 指令),且希望命中率可控、计费可预期时,用显式缓存。
OfoxAI 支持 Gemini 原生 cachedContents 的 创建 / 引用 / 查询 / 删除,兼容 Google GenAI SDK。端点级参考见 cachedContents API。
何时用显式缓存
| 场景 | 推荐 |
|---|---|
| 大段固定上下文反复问答(文档 QA、代码助手) | ✅ 显式缓存 |
| 需要确定命中、不能容忍偶发未命中 | ✅ 显式缓存 |
| 短小、低频、前缀多变的请求 | ❌ 用隐式缓存即可,无需管理缓存对象 |
| 上下文每次都变 | ❌ 缓存无意义 |
显式缓存要求被缓存的内容达到最小 token 门槛(约 2048~4096 token 起,因模型而异)。内容太小创建会失败或无收益。
端点
OfoxAI 在 Gemini 原生协议下提供完整 cachedContents 端点:
POST https://api.ofox.ai/gemini/v1beta/cachedContents # 创建
GET https://api.ofox.ai/gemini/v1beta/cachedContents/{id} # 查询
DELETE https://api.ofox.ai/gemini/v1beta/cachedContents/{id} # 删除引用缓存做内容生成,仍走标准 generateContent 端点,只是在请求体里带上 cachedContent:
POST https://api.ofox.ai/gemini/v1beta/models/{model}:generateContent认证
与其他 Gemini 端点一致,使用 x-goog-api-key Header:
x-goog-api-key: <你的 OFOXAI_API_KEY>完整流程
下面演示一条完整链路:创建缓存 → 引用缓存生成 → 删除缓存。
1. 创建缓存
把要复用的大段上下文放进 contents,指定 model 和 ttl(存活时长):
Python
from google import genai
from google.genai import types
client = genai.Client(
api_key="<你的 OFOXAI_API_KEY>",
http_options={"api_version": "v1beta", "base_url": "https://api.ofox.ai/gemini"},
)
# 一份反复使用的大文档(需达到最小 token 门槛)
LONG_DOCUMENT = open("knowledge_base.txt").read()
cache = client.caches.create(
model="google/gemini-3.1-pro-preview",
config=types.CreateCachedContentConfig(
contents=[LONG_DOCUMENT],
ttl="600s", # 缓存存活 10 分钟
),
)
print(cache.name) # cachedContents/xxxxxxxx —— 后续引用的句柄返回的 name(形如 cachedContents/xxxxxxxx)是缓存句柄,请保存它用于后续引用与管理。
2. 引用缓存生成
在 generateContent 请求里通过 cachedContent 引用缓存句柄,contents 只需放本次新增的问题:
Python
response = client.models.generate_content(
model="google/gemini-3.1-pro-preview",
contents="根据上面的文档,总结三条要点",
config=types.GenerateContentConfig(
cached_content=cache.name, # 引用缓存
),
)
print(response.text)
# 缓存命中:被缓存的部分按更低的「读」价计费
print(response.usage_metadata.cached_content_token_count)命中时,响应 usageMetadata.cachedContentTokenCount 会显示走缓存的 token 数。同一缓存可被任意多次引用,每次都确定性命中,直到过期。
3. 查询与删除
查询缓存元信息、或在不再需要时主动删除(无需等 TTL 到期):
Python
# 查询
info = client.caches.get(name=cache.name)
print(info.expire_time)
# 删除
client.caches.delete(name=cache.name)查询 / 删除不需要再传 model。OfoxAI 凭缓存句柄即可定位到这条缓存。
生命周期与 TTL
创建时通过 ttl 指定存活时长,格式为以 s 结尾的秒数字符串(如 "600s")。
| 参数 | 取值 |
|---|---|
| 最小 / 默认 TTL | 600s(10 分钟) |
| 最大 TTL | 3600s(1 小时) |
- 缓存在 TTL 内可被反复引用、确定性命中。
- TTL 到期后缓存自动失效,再引用会报错(缓存已不存在)。
- 可随时主动
delete提前释放。
TTL 过期或已删除的缓存被引用时,请求会失败。请在客户端处理「缓存失效」的情况(捕获错误后重新创建缓存或退回普通请求)。
计费
显式缓存按 token 透明计费,分三部分:
| 阶段 | 计费公式 | 说明 |
|---|---|---|
| 创建缓存 | totalTokenCount × cache_write 单价 | 按「缓存写入」价计费,totalTokenCount 来自创建响应的 usageMetadata,即被缓存的 token 数 |
| 引用命中 | cachedContentTokenCount × cache_read 单价 | 被缓存部分按「缓存读取」价计费,约为标准输入价的 0.10x,大幅低于全量重发 |
| 引用时的新内容 | 本次新增的 prompt / 输出按标准价 | 即你每次提的新问题、模型的新回答 |
收益模型:创建时付一次「写」费,之后每次引用被缓存的内容都按低价的「读」价计费,省下「整段上下文按全价重发」的开销。引用次数越多,越划算。 各模型的 cache_write / cache_read 单价以 模型目录 与控制台用量统计为准。
在 OfoxAI 上的增强:确定性路由
OfoxAI 在多 GCP 区域 / 多 Vertex 项目间做负载均衡。显式缓存是 region-scoped(区域绑定) 的:缓存创建在哪个 GCP 项目,引用就必须命中同一个项目,否则会 404。
OfoxAI 自动处理了这一点:创建缓存时记录该缓存绑定的上游实例,后续凭缓存句柄反查并硬锁回同一上游。无论你的引用请求是否带 user 标识、负载如何调度,引用都会被精确路由到创建缓存的那个项目,零漂移。你无需关心底层区域分布。
缓存归属做了越权保护:缓存句柄只能被创建它的 API Key(及同归属)引用 / 查询 / 删除,跨账户访问会被拒绝(403)。
显式缓存 vs 隐式缓存
| 维度 | 隐式缓存(自动) | 显式缓存(cachedContents) |
|---|---|---|
| 触发方式 | 自动识别重复前缀 | 主动创建缓存对象并引用 |
| 命中确定性 | 尽力而为,前缀微变即可能未命中 | 确定性,未过期必命中 |
| 需要管理 | 无 | 需创建 / 引用 / 删除句柄 |
| 适用 | 短小、前缀偶尔重复 | 大段、稳定、反复复用的上下文 |
| 计费 | 命中即享读价折扣 | 创建付写价 + 引用享读价折扣 |
两者可叠加使用。日常请求让隐式缓存自动生效即可;对确定要反复复用的大上下文,再用显式缓存锁定命中。隐式缓存的细节见 提示缓存。