Кеширование промптов
Как работает кеш промптов, почему cached_tokens бывает 0 и как добиться стабильной экономии на повторных запросах.
Кеширование промптов экономит деньги, когда вы много раз отправляете запросы с одним и тем же длинным началом — системной инструкцией, описанием инструментов, большим документом. Провайдер запоминает обработанное начало промпта, и при повторном запросе эти токены оплачиваются по сниженной ставке — обычно в разы дешевле обычного входа.
Скидка применяется автоматически: Hubris списывает стоимость по фактической цене исполнения, в которой кеш уже учтён. Отдельно ничего включать и оплачивать не нужно.
Два вида кеширования
Автоматическое — у большинства современных моделей (DeepSeek, GPT, Gemini, Qwen и другие). Провайдер сам находит совпадающее начало промпта и применяет скидку. От вас требуется одно: начало промпта должно повторяться байт в байт.
Явное — у Anthropic-моделей (Claude). Кешируемый блок надо пометить маркером cache_control — см. ниже.
Как проверить, что кеш сработал
Смотрите поле usage.prompt_tokens_details.cached_tokens в ответе:
{
"usage": {
"prompt_tokens": 351,
"completion_tokens": 16,
"prompt_tokens_details": {
"cached_tokens": 256
}
}
}cached_tokens — сколько входных токенов прочитано из кеша по сниженной ставке. Ноль — кеш в этом запросе не сработал.
Почему cached_tokens бывает 0
Это самый частый вопрос, поэтому по пунктам.
1. Кеш живёт у конкретного провайдера инференса. Открытые модели (DeepSeek, Qwen, Llama и т. п.) обслуживают десятки независимых дата-центров, и каждый запрос маршрутизируется на доступный в этот момент. Кеш одного провайдера невидим для другого: если первый запрос обработал один дата-центр, а повторный улетел в другой — кеша там нет. Часть провайдеров кеширование вообще не поддерживает. Какие провайдеры обслуживают модель, видно в её карточке в каталоге.
2. Минимальная длина и блочность. Кешируется только достаточно длинное начало промпта, причём блоками фиксированного размера (обычно кратно 64–256 токенам, у некоторых провайдеров минимум — 1024 токена). Промпт на 100–200 токенов может не закешироваться нигде.
3. Начало промпта должно совпадать точно. Любое изменение в начале — дата в системной инструкции, перестановка инструментов, другой порядок сообщений — сбрасывает совпадение с этой позиции. Всё переменное ставьте в конец промпта.
4. Кеш не вечен. Время жизни — от минут до часов в зависимости от провайдера. Редкие запросы (раз в час) в кеш обычно не попадают.
Как добиться стабильных кеш-хитов
Главный инструмент — закрепить провайдера полем provider в запросе, тогда повторные запросы будут попадать в один и тот же дата-центр:
curl -s https://api.hubris.pw/v1/chat/completions \
-H "Authorization: Bearer sk-gw-..." \
-H "Content-Type: application/json" \
-d '{
"model": "deepseek/deepseek-v4-flash",
"provider": {"order": ["deepinfra"], "allow_fallbacks": false},
"messages": [
{"role": "system", "content": "Длинная стабильная инструкция..."},
{"role": "user", "content": "Вопрос"}
]
}'order— список провайдеров в порядке предпочтения. Имя — в нижнем регистре, без пробелов (провайдерDeepInfra→deepinfra); список провайдеров модели есть в её карточке в каталоге.allow_fallbacks: false— не переключаться на других провайдеров. Надёжно для кеша, но если выбранный провайдер недоступен, запрос вернёт ошибку вместо ответа от другого. Без этого флагаorderзадаёт приоритет, но при недоступности запрос уйдёт к следующему доступному.
Живой пример: два одинаковых запроса к deepseek/deepseek-v4-flash (промпт 351 токен) с закреплённым deepinfra — первый вернул cached_tokens: 64, повторный — cached_tokens: 256. Тот же тест без закрепления провайдера легко даёт 0: запросы разлетаются по разным дата-центрам.
Поле provider работает одинаково в /v1/chat/completions и /v1/responses — в том числе у Codex CLI и других клиентов на Responses API.
Потолок цены вместо закрепления
Стоимость запроса считается по тарифу провайдера, который его исполнил: у одной модели тарифы провайдеров различаются (они показаны в карточке модели), и когда провайдер с базовым тарифом перегружен, запрос автоматически уходит к следующему доступному — и может стоить дороже. Если важнее цена, чем конкретный провайдер, задайте потолок max_price в долларах за миллион токенов:
{
"model": "deepseek/deepseek-v4-flash",
"provider": {"max_price": {"prompt": 0.15, "completion": 0.6}},
"input": "..."
}Запрос уйдёт только к провайдеру не дороже потолка. Если таких сейчас нет, придёт 404 «No endpoints found that satisfy the max price» — запрос можно повторить позже, дорогой ответ вы не получите. Значения — в долларах за 1M токенов до наценки Hubris, как в карточке модели и в GET /v1/models; удобно ставить потолок равным базовому тарифу модели. max_price сочетается с order: закрепить провайдера и ограничить цену можно одновременно.
И общие правила, независимо от провайдера:
- Стабильное начало. Системная инструкция и инструменты — в начале и без изменений, всё переменное (данные пользователя, текущая дата) — в конце.
- Частота. Серии запросов подряд кешируются отлично, одиночные редкие — нет.
- Длина. Чем длиннее общий префикс, тем больше экономия.
Явное кеширование (Anthropic)
Claude-модели кешируют только помеченные блоки. Поставьте cache_control на content-блок, который хотите закешировать:
curl -s https://api.hubris.pw/v1/chat/completions \
-H "Authorization: Bearer sk-gw-..." \
-H "Content-Type: application/json" \
-d '{
"model": "anthropic/claude-haiku-4.5",
"messages": [
{
"role": "system",
"content": [
{
"type": "text",
"text": "Очень длинная инструкция на 5000 токенов...",
"cache_control": {"type": "ephemeral"}
}
]
},
{
"role": "user",
"content": "Ваш вопрос"
}
]
}'Требования Anthropic: блок от 1024 токенов, время жизни кеша ~5 минут (продлевается при каждом попадании). Чтение из кеша заметно дешевле обычного входа, запись в кеш — немного дороже (примерно +25 %), поэтому кешировать имеет смысл то, что будет переиспользовано.
Часовой кеш (TTL 1h)
Если между запросами проходит больше пяти минут (долгие агентные сессии, редкие обращения к одному и тому же контексту), закажите часовое время жизни — поле ttl в маркере:
"cache_control": {"type": "ephemeral", "ttl": "1h"}Запись в такой кеш стоит примерно вдвое дороже обычного входа (против +25 % у пятиминутного), чтение — по той же низкой цене. Работает на Claude Opus 5, Sonnet 5 и остальных актуальных Claude в обоих API — /v1/chat/completions и /v1/messages. Значения ttl: "5m" (по умолчанию) и "1h"; блоки с часовым кешем ставьте раньше пятиминутных — таково требование Anthropic.
Кеш в статистике
В ответе GET /v1/usage и в кабинете (вкладка «Активность») видна сводка по кешу за период:
| Поле | Описание |
|---|---|
cache_read_tokens | Токены, прочитанные из кеша. |
cache_write_tokens | Токены, записанные в кеш (у моделей с явным кешированием). |
cache_hit_rate | Доля входных токенов, пришедшихся на кеш (0..1). |
cache_savings_rub | Сколько сэкономлено за период относительно полной входной ставки. |
Что кешировать
Эффективные кандидаты:
- Системная инструкция с правилами и примерами (1–20 тыс. токенов) — основная экономия.
- RAG-контекст — одни и те же документы во многих запросах подряд.
- История долгого диалога — каждый следующий ход переиспользует общий префикс.
- Длинный few-shot пример — для классификаторов и агентов.
Не даст экономии:
- Уникальные короткие запросы без общего начала.
- Промпты меньше минимального порога кеширования.
- Редкие запросы — кеш истекает между ними.
Что дальше
- POST /v1/chat/completions — полная схема запроса.
- Каталог моделей — провайдеры и цены каждой модели, включая ставку кеш-чтения.
- Отслеживание расходов — как смотреть статистику.
Обновлено:
Reasoning токены
Размышление у Claude Opus 5 и Sonnet 5 включено по умолчанию; глубина — через reasoning_effort или объект reasoning, ход мысли — в reasoning_details, биллинг — как за выходные токены.
Стриминг ответов
Когда включать `stream: true`, как корректно собирать ответ модели и показывать прогресс пользователю.