Кэш ответов X-Zukko-Cache: когда запрос бесплатный

Одинаковый запрос от одного пользователя можно не оплачивать второй раз. Разбираем, как включается кэш и как проверить, сработал ли он.

5 мин · · Обновлено · API · экономия

Если один и тот же запрос от одного и того же пользователя повторяется — в тестах, в CI, при повторных запусках одного и того же промпта в разработке — платить за него второй раз бессмысленно. Для этого случая есть встроенный кэш ответов.

Когда запрос кэшируется

Кэширование срабатывает в двух случаях:

  • запрос содержит заголовок X-Zukko-Cache: true — основной и универсальный способ, работает для любой модели;
  • запрос отправлен с "temperature": 0 — только для моделей, которые принимают такое значение. Модели Claude (claude-opus-5-5, claude-sonnet-5) могут отклонить temperature, отличный от 1, и top_p ниже 0.99 с ошибкой 400, поэтому для них не передавайте temperature/top_p, а используйте заголовок.

В обоих случаях одинаковые запросы одного и того же пользователя кэшируются — для чата время жизни кэша до 7 суток. Повторный идентичный запрос в это окно возвращается мгновенно и бесплатно. Работает кэш для POST /v1/chat/completions, /v1/messages и /v1/responses.

bash
curl https://api.zukko.pro/v1/chat/completions \
  -H "Authorization: Bearer fetch_ваш_ключ" \
  -H "Content-Type: application/json" \
  -H "X-Zukko-Cache: true" \
  -d '{
    "model": "claude-sonnet-5",
    "messages": [{"role": "user", "content": "Объясни разницу между 401 и 403"}]
  }'

Второй вызов с точно таким же телом от того же ключа/аккаунта попадёт в кэш.

Как проверить, что сработало

Ответ приходит с заголовком X-Zukko-Cache: hit, если запрос был обслужен из кэша. Если заголовка нет или он отсутствует — запрос дошёл до модели и был оплачен как обычно.

bash
import requests

resp = requests.post(
    "https://api.zukko.pro/v1/chat/completions",
    headers={
        "Authorization": "Bearer fetch_ваш_ключ",
        "X-Zukko-Cache": "true",
    },
    json={
        "model": "claude-sonnet-5",
        "messages": [{"role": "user", "content": "Объясни разницу между 401 и 403"}],
    },
)

print("cache:", resp.headers.get("X-Zukko-Cache", "miss"))
print("cost micros:", resp.headers.get("X-Zukko-Cost-Micros"))
print("balance micros:", resp.headers.get("X-Fetch-Balance-Cents"))  # несмотря на название — микродоллары

Заголовок X-Zukko-Cost-Micros показывает стоимость запроса в микродолларах (1 000 000 = $1); X-Fetch-Balance-Cents, несмотря на название, тоже в микродолларах. При попадании в кэш стоимость должна быть нулевой или отсутствовать — удобно проверять оба заголовка вместе, а не полагаться на один X-Zukko-Cache. Попадания в кэш не пишутся в /v1/usage.

Почему temperature: 0 тоже включает кэш (для моделей, которые его принимают)

temperature: 0 означает детерминированный, максимально предсказуемый вывод — при одинаковом вводе модель и так стремится вернуть один и тот же ответ. Раз результат и без кэша почти не меняется от запроса к запросу, кэшировать его безопасно по смыслу: пользователь получает тот же ответ, что получил бы при обычном вызове, только быстрее и бесплатно.

Если вам нужна вариативность ответов (creative-writing промпты, чат с случайностью), не выставляйте temperature: 0 только ради экономии — вы получите одинаковые ответы там, где хотели разные. В этом случае используйте X-Zukko-Cache: true осознанно, только на тех промптах, где повтор ответа — ожидаемое и желаемое поведение.

Где это реально экономит

CI и автотесты. Пайплайн, который на каждый пуш гоняет один и тот же тестовый промпт к модели (например, проверка, что интеграция вообще отвечает), может гонять его хоть на каждый коммит — если тело запроса не меняется, оплата будет только за первый прогон в пределах окна кэша.

Повторные запуски при разработке. Отладка промпта локально часто означает десятки перезапусков одного и того же кода с одним и тем же вводом, пока не поправишь остальную логику приложения. Пока сам промпт не меняется, каждый перезапуск после первого — бесплатный.

Демо и презентации. Если демо-сценарий заранее известен и повторяется дословно, первый прогон оплачивается, все последующие в течение недели — нет.

Что не кэшируется

Кэш привязан к пользователю (аккаунту/ключу) и к точному телу запроса. Это не общий кэш «одинаковый промпт от кого угодно» — если два разных клиента отправят одинаковый текст, каждый получит собственную оплаченную генерацию, если только это не один и тот же ключ. Кэш срабатывает только при полном совпадении тела запроса — не на «почти одинаковых» запросах и не на общем префиксе. Малейшее отличие в теле запроса — другой system-промпт, другой порядок сообщений, лишний пробел в тексте, другое значение max_tokens — это уже другой запрос, кэш не сработает, спишется полная стоимость (поля metadata, user и stream_options на сравнение не влияют).

Генерация изображений через Zukko сейчас временно недоступна, так что всё сказанное относится к текстовым запросам.

Кэш и Idempotency-Key — не одно и то же

Их легко перепутать, потому что оба защищают от лишней оплаты. Разница в том, от чего именно: Idempotency-Key защищает от повторной оплаты одного и того же запроса при ретрае после сбоя (сеть оборвалась, клиент не дождался ответа). Кэш через X-Zukko-Cache — про намеренно повторяющиеся запросы, которые вы отправляете снова и снова осознанно, потому что вход не меняется. Первый — про надёжность, второй — про экономию на предсказуемой нагрузке. Их можно использовать одновременно в одном запросе, они не конфликтуют.

Практический пример: тестовый набор промптов

Если у вас есть набор из, скажем, двадцати эталонных промптов для регрессионного тестирования качества ответов модели после смены версии, и вы гоняете их каждую ночь одним и тем же CI-джобом, добавление X-Zukko-Cache: true ко всем запросам, кроме первого прогона после реального изменения промптов, превращает большинство ночных прогонов в бесплатные. Оплата случится только тогда, когда текст промпта или системный промпт действительно изменится — то есть именно тогда, когда результат стоит проверить заново.

Итог

Кэш — это не отдельная настройка в кабинете, а два способа пометить конкретный запрос как кэшируемый: заголовок X-Zukko-Cache: true (основной, для любой модели) или temperature: 0 (только у моделей, которые его принимают, — не у Claude). Проверяйте X-Zukko-Cache: hit в ответе, чтобы убедиться, что сработало, и X-Zukko-Cost-Micros, чтобы увидеть реальную стоимость (или её отсутствие) конкретного вызова.

zukko

Платите в 25×
меньше

за Claude Code & ChatGPT

Один ключ fetch_* и base URL api.zukko.pro — в Cursor, Claude Code, Codex и любом SDK.