Gemini caching has two types: implicit cache (automatically detects repeated prefixes on a best-effort basis) and explicit cache (this article; explicitly creates a cache object for deterministic hits). It is suitable for repeated use with large, stable context.
When to use explicit cache#
| Scenario | Recommendation |
|---|---|
| Repeated Q&A over large fixed context (docs QA, code assistant) | ✅ Explicit cache |
| Need deterministic hits and cannot tolerate occasional misses | ✅ Explicit cache |
| Short, low-frequency requests with frequently changing prefixes | Use implicit cache instead |
| Context changes every time | ❌ Cache is not useful |
Note: cached content must meet the minimum token threshold (about 2048-4096 tokens, depending on the model).
Endpoint#
POST https://as.apinoma.com/gemini/v1beta/cachedContents # Create
GET https://as.apinoma.com/gemini/v1beta/cachedContents/{id} # query
DELETE https://as.apinoma.com/gemini/v1beta/cachedContents/{id} # delete
# Use the standard generation endpoint with cachedContent in the request body
POST https://as.apinoma.com/gemini/v1beta/models/{model}:generateContentComplete flow#
1. Create cache
from google import genai
from google.genai import types
client = genai.Client(
api_key="<your DATAMIND_API_KEY>",
http_options={"api_version": "v1beta", "base_url": "https://as.apinoma.com/gemini"},
)
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", # cache lives for 10 minutes
),
)
print(cache.name) # cachedContents/xxxxxxxx —— handle referenced latercurl "https://as.apinoma.com/gemini/v1beta/cachedContents" \
-H "x-goog-api-key: $DATAMIND_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"model": "google/gemini-3.1-pro-preview",
"contents": [
{ "role": "user", "parts": [{ "text": "<Place the large reusable context here>" }] }
],
"ttl": "600s"
}' 2. Generate with the cache reference
Use cachedContent to reference the cache handle. Put only the new question for this turn in contents:
response = client.models.generate_content(
model="google/gemini-3.1-pro-preview",
contents="Based on the document above, summarize three key points",
config=types.GenerateContentConfig(cached_content=cache.name),
)
print(response.text)
print(response.usage_metadata.cached_content_token_count)curl "https://as.apinoma.com/gemini/v1beta/models/google/gemini-3.1-pro-preview:generateContent" \
-H "x-goog-api-key: $DATAMIND_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"cachedContent": "cachedContents/xxxxxxxx",
"contents": [
{ "role": "user", "parts": [{ "text": "Based on the document above, summarize three key points" }] }
]
}' 3. query and delete
info = client.caches.get(name=cache.name)
print(info.expire_time)
client.caches.delete(name=cache.name)Lifetime and TTL#
ttl is a duration string in seconds ending with s, such as "600s".
| Parameter | Value |
|---|---|
| Minimum/default TTL | 600s (10 minutes) |
| Maximum TTL | 3600s (1 hour) |
- A cache can be referenced repeatedly within the TTL with deterministic hits
- The TTL expires automatically; referencing the cache again after expiry returns an error
- You can call
deleteto release the cache early
Billing#
| Stage | Billing formula | Description |
|---|---|---|
| Create cache | totalTokenCount × cache_write unit price | Cached content is billed at the write price |
| Reference hit | cachedContentTokenCount × cache_read unit price | About 0.10x the standard input price |
| New content when referencing | New content in this request is billed at the standard price | New question and new answer |
诺玛AI enhancement: deterministic routing#
Explicit cache is region-scoped (region binding). 诺玛AI automatically records the upstream instance bound to the cache. Later requests use the handle to lock back to the same upstream for zero drift. Cache handles are permission-protected: only the API Key that created the cache (and the same ownership scope) can reference, query, or delete it. Cross-account access is rejected (403).
Last updated on June 22, 2026