Явное кэширование Gemini (cachedContents)
Кэширование в Gemini бывает двух видов:
- Неявное кэширование (автоматическое) — модель сама обнаруживает и переиспользует повторяющиеся префиксы промптов, без какой-либо настройки. Это поведение по умолчанию, описанное в статье Кэширование промптов; попадание работает по принципу «best-effort», и любое незначительное изменение префикса может привести к промаху.
- Явное кэширование (эта статья) — вы самостоятельно создаёте из большого контекста объект-кэш, получаете дескриптор
cachedContents/{id}и ссылаетесь на него в последующих запросахgenerateContent. Попадание детерминированное: пока кэш не истёк, ссылка всегда попадает.
Используйте явное кэширование, когда у вас есть большой, стабильный контекст, который переиспользуется многократно (длинные документы, кодовые базы, базы знаний, фиксированные system-инструкции) и нужны управляемый показатель попаданий и предсказуемая тарификация.
OfoxAI поддерживает нативные операции cachedContents Gemini — создание / ссылку / запрос / удаление, совместимо с Google GenAI SDK. Справочник на уровне эндпоинтов см. в API cachedContents.
Когда использовать явное кэширование
| Сценарий | Рекомендация |
|---|---|
| Многократные вопросы-ответы по большому фиксированному контексту (QA по документам, кодовый ассистент) | ✅ Явное кэширование |
| Нужны гарантированные попадания, недопустимы случайные промахи | ✅ Явное кэширование |
| Короткие, редкие запросы с меняющимися префиксами | ❌ Достаточно неявного кэширования, объектом-кэшем управлять не нужно |
| Контекст меняется каждый раз | ❌ Кэширование бессмысленно |
Явное кэширование требует, чтобы кэшируемое содержимое достигало минимального порога по токенам (примерно от 2048 до 4096 токенов, зависит от модели). Слишком малое содержимое не создастся или не даст выгоды.
Эндпоинты
OfoxAI предоставляет полный набор эндпоинтов cachedContents в нативном протоколе Gemini:
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:
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"},
)
# Большой документ для многократного переиспользования (должен достигать минимального порога по токенам)
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 показывает число токенов, взятых из кэша. На один и тот же кэш можно ссылаться сколько угодно раз, каждый раз с детерминированным попаданием, пока он не истечёт.
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, чтобы освободить его заранее.
Ссылка на истёкший или удалённый кэш завершится ошибкой. Обрабатывайте случай «кэш недействителен» на стороне клиента (перехватите ошибку и пересоздайте кэш либо вернитесь к обычному запросу).
Тарификация
Явное кэширование тарифицируется прозрачно по токенам и состоит из трёх частей:
| Этап | Формула | Пояснение |
|---|---|---|
| Создание кэша | totalTokenCount × цена cache_write | Тарифицируется по цене «записи в кэш»; totalTokenCount берётся из usageMetadata ответа на создание — это число кэшированных токенов |
| Попадание по ссылке | cachedContentTokenCount × цена cache_read | Кэшированная часть тарифицируется по цене «чтения из кэша», примерно 0.10x от стандартной цены ввода — значительно дешевле полной переотправки |
| Новое содержимое при ссылке | Новые prompt / вывод этого хода по стандартной цене | То есть каждый новый заданный вами вопрос и новый ответ модели |
Модель выгоды: при создании платите единожды за «запись», после чего каждая ссылка на кэшированное содержимое тарифицируется по низкой цене «чтения», экономя на «переотправке всего контекста по полной цене». Чем больше ссылок, тем выгоднее. Цены cache_write / cache_read для каждой модели уточняйте в каталоге моделей и в статистике использования в консоли.
Усиление в OfoxAI: детерминированная маршрутизация
OfoxAI балансирует нагрузку между несколькими регионами GCP / проектами Vertex. Явный кэш привязан к региону (region-scoped): в каком проекте GCP кэш создан, в том же проекте он и должен попадать по ссылке, иначе вернётся 404.
OfoxAI обрабатывает это автоматически: при создании кэша записывается привязанный к нему upstream-инстанс, после чего по дескриптору кэша он находится и жёстко фиксируется обратно на тот же upstream. Независимо от того, несёт ли ваш запрос-ссылка идентификатор user и как распределяется нагрузка, ссылка точно маршрутизируется в проект, где был создан кэш, с нулевым дрейфом. Вам не нужно думать о нижележащем распределении по регионам.
Принадлежность кэша защищена от несанкционированного доступа: на дескриптор кэша можно ссылаться / запрашивать / удалять только тем API Key (и его владельцем), который его создал; межаккаунтный доступ отклоняется (403).
Явное против неявного кэширования
| Параметр | Неявное (автоматическое) | Явное (cachedContents) |
|---|---|---|
| Способ срабатывания | Автоопределение повторяющихся префиксов | Самостоятельное создание объекта-кэша и ссылка на него |
| Детерминированность попадания | Best-effort, при микроизменении префикса возможен промах | Детерминированное, до истечения всегда попадает |
| Управление | Не требуется | Нужно создавать / ссылаться / удалять дескриптор |
| Применимо | Короткое содержимое с изредка повторяющимися префиксами | Большой, стабильный, многократно переиспользуемый контекст |
| Тарификация | Скидка по цене чтения при попадании | Цена записи при создании + скидка по цене чтения при ссылке |
Оба подхода можно сочетать. В повседневных запросах достаточно, чтобы неявное кэширование срабатывало автоматически; для контекста, который точно переиспользуется многократно, добавьте явное кэширование, чтобы зафиксировать попадание. Подробности неявного кэширования см. в статье Кэширование промптов.