Привет, Хабр! Меня зовут Сергей Нотевский, я AI Platform Lead в Битрикс24.
Мы строим AI-платформу на self-hosted инференсе - vLLM, свои модели, своя оптимизация. Кэш - одна из ключевых метрик: hit rate напрямую влияет на нагрузку GPU и latency для пользователя. И как следствие - на количество ресурсов которые нам требуются.
В сообществе часто пишут о том что KV-cache hit rate - один из главных приоритетов при оптимизации стоимости. Manus в той-самой статье про context engineering и своего агента, TikTok в кейсе про оптимизацию AI-агента для тестирования, AiSDR в статье про перестройку шаблонов генерации писем.
Стало интересно стало: а как это считается у MaaS-провайдеров? Я знаком со скидкой за кэш токены, но никогда не садился детально разбирать экономику кэша у OpenAI, Anthropic, Gemini, DeepSeek - с цифрами, сценариями, сравнением.
Сел считать. Первый же результат удивил: два запроса к одной и той же модели с одним и тем же объёмом токенов - разница в цене в 3 раза. Зависит только от того, попали ли токены в кэш.
Про то как KV-кэш устроен внутри - уже хорошо написано на Хабре, ссылки в конце. Здесь только про деньги и токены: как считать реальную стоимость и почему прайс-лист для этого не подходит только прайс-лист.
TL;DR
Прайс часто показывает только стоимость input и output токенов. Реальная стоимость зависит ещё от того, какая доля промпта повторяется между запросами (S), сколько токенов в ответе (O) и как часто кэш срабатывает (h, hit rate). Без этих трёх параметров сравнение провайдеров бессмысленно.
При переезде на другого провайдера архитектура кэша меняется. То что давало 90% hit rate может давать 40–50% без переработки промптов - из-за разной логики кэширования: OpenAI кэширует только префикс, Anthropic требует явной разметки, Gemini implicit вообще не гарантирует хит.
Перед миграцией: посчитайте текущий effective cost, потом новый - с hit rate 30%.
Быстро про механику - только то, что нужно для расчётов
При каждом запросе к LLM модель обрабатывает весь входной промпт заново - это фаза prefill (вычисление KV-пар для каждого входного токена). Если часть промпта из запроса в запрос не меняется (системный промпт, RAG-контекст, tool definitions), провайдер может сохранять результаты её обработки в KV-кэше. При следующем запросе берёт оттуда.
Токены с cache hit стоят в 4–10 раз дешевле - отсюда и расхождение между тем что написано в прайсе и тем что приходит в счёте.
Одна формула, которая нужна для сравнения
Где:
S- токены повторяющейся части входа (system prompt, tool definitions, память, уже загруженный контекст и другие блоки, которые переиспользуются между вызовами без изменений)D- токены динамики (пользовательский запрос, переменные)O- токены outputh- cache hit rate (0–1): доля запросов, в которых статическая часть попала в кэшP_miss,P_hit,P_out- цены провайдера
Важно для Anthropic: в формуле выше P_miss используется и для cache miss, и для динамики. У провайдеров с write surcharge (Anthropic) первый запрос на запись в кэш стоит дороже: P_write = P_miss × 1.25 для 5-минутного TTL. Точнее, первое слагаемое для таких провайдеров выглядит так:
Во всех расчётах ниже это учтено. Если подставляете свои цифры - не забудьте про множитель.
Прайс-лист в основном показывает только P_miss и P_out. Без S, O и h - бесполезен для сравнения.
Практическое замечание про hit rate: в логах вы обычно видите cached_tokens / total_input_tokens. У Anthropic total_input_tokens - это сумма cache_read_input_tokens + cache_creation_input_tokens + input_tokens.
Формула одна, но P_hit и P_miss берутся не из воздуха — у провайдеров принципиально разные схемы кэширования, и от схемы зависит за что вы платите.
Три «контракта кэширования»
Провайдеры работают по разным схемам.
Auto, без наценки за запись
OpenAI (GPT-5 mini, GPT-5.2, GPT-5.4), Gemini 2.5, DeepSeek V3.2
Кэш включается сам, за запись не доплачиваете. При miss - обычная цена, при hit - дешевле. Для нерегулярного трафика безопаснее всего: нет риска переплатить за write, который никогда не прочитают.
Explicit, наценка за запись
Anthropic (Claude Haiku 3.5, Sonnet 4, Opus 4.1)
Вы явно размечаете что кэшировать через cache_control.
Anthropic позволяет ставить точки кэширования не только на весь запрос целиком, но и на отдельные стабильные блоки промпта - например, на system prompt, tool definitions или RAG-блок. Ниже я бу��у называть такие точки per-block breakpoints. Это важно: в отличие от префиксного кэша, здесь можно кэшировать не только непрерывное начало запроса, но и отдельные куски запроса, если они стабильно повторяются.
За 5-минутный TTL (время жизни кэша) +25% к цене input. За 1-часовой TTL ×2 к цене input. Зато скидка при hit - 90%.
С февраля 2026 Anthropic также поддерживает автоматический кэш: один cache_control на уровне запроса, без ручной разметки блоков - система сама управляет точками кэширования по мере роста диалога. Для простых случаев этого достаточно. Per-block breakpoints дают больше контроля - например, кэшировать какой-то блок отдельно от system prompt.
Break-even для 5-минутного TTL (k=1.25):
Для Claude Sonnet 4 ($3/M miss, $0.30/M hit):
Кэш Anthropic окупается при hit rate > 22%. Не окупается только при абсолютно уникальных запросах каждый раз с новым контекстом.
А если через агрегатор - OpenRouter и подобные?
Многие используют OpenRouter как единую точку доступа к разным моделям. Кэш там работает - механика и цены те же что у провайдеров напрямую. Но есть детали которые влияют на стоимость.
OpenRouter использует sticky routing: повторные запросы он старается направлять на тот же бэкенд, где уже лежит прогретый кэш.
Под «одним и тем же диалогом» здесь понимается conversation, который определяется по хэшу первого system-сообщения и первого пользовательского сообщения.
Но это best-effort, а не гарантия. Если нужный бэкенд недоступен, запрос уйдёт на другой сервер - без прогретого кэша. В этот момент hit rate обнуляется, и префикс придется прогревать заново.
Самое неприятное, что такое может произойти в плохой момент: при росте нагрузки или деградации провайдера, когда кэш особенно нужен.
С Anthropic через OpenRouter есть отдельный нюанс.
Top-level cache_control работает только тогда, когда запрос идёт напрямую в Anthropic. Если OpenRouter может отправить его через Bedrock или Vertex, такой режим кэша там не поддерживается - и эти маршруты просто исключаются.
Per-block breakpoints в этом смысле надёжнее: они поддерживаются шире и не так жёстко завязаны на прямую маршрутизацию в Anthropic.
Практический вывод неприятный: можно думать, что кэш у вас включён, а в реальности запрос уходит по маршруту, где эта схема вообще не работает.
Для экспериментов и нерегулярного трафика разница с прямым API несущественна. Для продакшена где кэш закрывает UX-требования по TTFT - аргумент ходить напрямую.
Три сценария, которые показывают, почему прайс врёт
Ниже - cost-only сценарии. Они сравнивают экономику токенов при заданном hit rate, без поправки на качество модели. Сравнивать Flash-Lite с флагманской моделью напрямую бессмысленно - это разные весовые категории. Поэтому сценарий 1 оставлен как чистый пример на одной модели, а в сценариях 2 и 3 модели сгруппированы по приблизительно сопоставимому ценовому классу: важно не "кто абсолютно дешевле", а как кэш и структура промпта меняют стоимость внутри одного класса.
Во всех сценариях ниже для Anthropic учтён write surcharge за 5-минутный TTL: cache write считается по цене input ×1.25, cache read - по discounted rate.
Сценарий 1: та же модель - цена отличается в 3 раза
Вот тот самый пример из введения. RAG-агент с append-only контекстом (новые данные дописываются в конец, старые не удаляются): 10 000 токенов повторяющейся части промпта, 200 токенов запрос, 300 токенов ответ, 2 000 запросов/день.
Вариант | Hit rate | Итого/день |
|---|---|---|
DeepSeek V3.2 — timestamp в system prompt | 30% | $4.45 |
DeepSeek V3.2 — кэш настроен правильно | 90% | $1.43 |
Claude Haiku 3.5 — кэш настроен правильно | 90% | $6.16 |
Смотрите на первые две строки. Одна и та же модель, один и тот же объём токенов - разница больше чем в 3 раза. Всё решает hit rate, а hit rate решает структура промпта.
Реальный кейс: команда Manus перешла с $3/MTok на $0.30/MTok на Claude Sonnet - снижение стоимости инференса в 10 раз. Три практики: append-only контекст, sort_keys=True при сериализации tool definitions, инструменты в промпте всегда. Ничего сложного - только стабильный префикс.
Сценарий 2: короткий output меняет всю картину
Классификация документов: 8 000 токенов повторяющейся части промпта, 200 токенов запрос, 20 токенов ответ, 5 000 запросов/день, hit rate 90%.
Низкий ценовой класс
Модель | Cache miss | Cache read | Динамика | Output | Итого/день |
|---|---|---|---|---|---|
Gemini 2.5 Flash-Lite | $0.40 | $0.36 | $0.10 | $0.04 | $0.90 |
DeepSeek V3.2 | $1.12 | $1.01 | $0.28 | $0.04 | $2.45 |
GPT-5 mini | $1.00 | $0.90 | $0.25 | $0.20 | $2.35 |
Средний ценовой класс
Модель | Cache miss | Cache read | Динамика | Output | Итого/день |
|---|---|---|---|---|---|
Gemini 2.5 Flash | $1.20 | $1.08 | $0.30 | $0.25 | $2.83 |
Claude Haiku 3.5 | $4.00 | $2.88 | $0.80 | $0.40 | $8.08 |
GPT-5.2 | $7.00 | $6.30 | $1.75 | $1.40 | $16.45 |
Флагманский класс
Модель | Cache miss | Cache read | Динамика | Output | Итого/день |
|---|---|---|---|---|---|
GPT-5.4 | $10.00 | $9.00 | $2.50 | $1.50 | $23.00 |
Claude Sonnet 4 | $15.00 | $10.80 | $3.00 | $1.50 | $30.30 |
При коротком output цена ответа перестаёт быть главным фактором - начинает решать стоимость input и cache read. В низком ценовом классе Flash-Lite с cache hit $0.01/M выигрывает у DeepSeek и GPT-5 mini за счёт самой дешёвой стоимости кэшируемого input. В среднем классе Gemini 2.5 Flash дешевле Claude Haiku 3.5 и GPT-5.2 потому, что при 20 токенах ответа базовая цена input оказывается важнее output. Во флагманском классе GPT-5.4 дешевле Claude Sonnet 4 прежде всего за счёт отсутствия write surcharge.
Сценарий 3: большой контекст
AI-агент с базой знаний: 50 000 токенов повторяющейся части промпта, 500 токенов запрос, 500 токенов ответ, 1 000 запросов/день, hit rate 95%.
Низкий ценовой класс
Модель | Cache miss | Cache read | Динамика | Output | Итого/день |
|---|---|---|---|---|---|
Gemini 2.5 Flash-Lite | $0.25 | $0.48 | $0.05 | $0.20 | $0.98 |
DeepSeek V3.2 | $0.70 | $1.33 | $0.14 | $0.21 | $2.38 |
GPT-5 mini | $0.62 | $1.19 | $0.12 | $1.00 | $2.94 |
Средний ценовой класс
Модель | Cache miss | Cache read | Динамика | Output | Итого/день |
|---|---|---|---|---|---|
Gemini 2.5 Flash | $0.75 | $1.43 | $0.15 | $1.25 | $3.58 |
Claude Haiku 3.5 | $2.50 | $3.80 | $0.40 | $2.00 | $8.70 |
GPT-5.2 | $4.38 | $8.31 | $0.88 | $7.00 | $20.57 |
Флагманский класс
Модель | Cache miss | Cache read | Динамика | Output | Итого/день |
|---|---|---|---|---|---|
GPT-5.4 | $6.25 | $11.88 | $1.25 | $7.50 | $26.88 |
Claude Sonnet 4 | $9.38 | $14.25 | $1.50 | $7.50 | $32.63 |
При 50k повторяющегося контекста input и cache read начинают доминировать вместе с output. В низком ценовом классе Flash-Lite остаётся самым дешёвым вариантом, DeepSeek - вторым, GPT-5 mini - третьим: разницу здесь делает прежде всего цена cache read. В среднем классе Gemini 2.5 Flash существенно дешевле Claude Haiku 3.5 и GPT-5.2 за счёт дешёвого input и output одновременно. Во флагманском классе GPT-5.4 дешевле Claude Sonnet 4, но оба остаются на другом уровне стоимости по сравнению со средним классом.
Как снять S, D, O из собственных логов
Подставлять в формулу круглые числа из головы - плохая идея. Ниже пример для Anthropic API (поля для остальных провайдеров - в FAQ):
# Anthropic — из usage каждого ответа S_approx = response.usage.cache_read_input_tokens # статика в кэше D_approx = response.usage.input_tokens # динамика (не кэшировалась) O = response.usage.output_tokens total_input = S_approx + response.usage.cache_creation_input_tokens + D_approx h = S_approx / total_input if total_input > 0 else 0
На выборке из 1 000 запросов возьмите медиану cache_read_input_tokens — это ваш реальный S при стабильном промпте. Если медиана близка к нулю — кэш не работает, смотрите антипаттерны ниже.
Скрытый налог миграции
Сам кэш прогревается быстро - первый же батч запросов заполнит его. Это не проблема.
Проблема в другом: у каждого провайдера своя архитектура кэширования, и промпт который давал 90% hit rate на одном стеке может давать 40% на другом без переработки.
OpenAI кэширует только непрерывный префикс с начала промпта. Официально задокументировано: "cache hits are only possible for exact prefix matches". Практически это означает: если у вас структура [system prompt] → [user query] → [RAG блок], то RAG блок в конце не попадёт в кэш никогда — он идёт после динамической части. На Anthropic с explicit cache_control вы могли пометить RAG-блок отдельной точкой кэширования (per-block breakpoint) и кэшировать его независимо. При переезде на OpenAI эта логика ломается и её надо переписывать.
Gemini implicit - это best-effort, но не гарантия. В официальных доках написано "to increase the chances of a cache hit" — именно так, не "гарантирует хит". На практике это подтверждается: в Google AI Developer Forum есть треды где люди получали 25 хитов из 100 при "идентичном промпте", 0 хитов на Flash-Lite при формально выполненном пороге в 1024 токена, "random 40–60%" на Vertex при префиксе 9k+ токенов. Если закладывать в расчёт 90% hit rate на Gemini implicit - есть реальный шанс получить 40% в продакшене и не сразу понять почему.
У Anthropic дефолтный TTL - 5 минут. При нерегулярном трафике (утренний пик, ночной простой) кэш тухнет каждую ночь и вы платите за write заново каждое утро. У OpenAI сложнее: in-memory кэш живёт 5–10 минут бездействия (иногда до часа), но на моделях gpt-5 и gpt-5.2, а также gpt-4.1 доступен extended retention до 24 часов - это принципиально другой разговор для нерегулярного трафика. У DeepSeek - диск, живёт дольше всех без дополнительных настроек.
Перед миграцией: посчитайте текущий effective cost с реальным hit rate, потом новый - с hit rate 40–50% вместо текущего. Структура промптов под новую архитектуру кэша может потребовать переработки - это не час работы, заложите время.
TTFT (Time to First Token): почему при 50k токенов кэш важнее денег (ну или почти важнее)
Prefill-фаза блокирующая - пользователь стоит и ждёт, пока модель прочитает весь контекст перед первым токеном ответа. Cache hit пропускает эту фазу для статичной части целиком. При 50k токенов это разница между 0.8 с и 12 с до первого слова.
Длина статики | TTFT без кэша | TTFT с кэшем | Снижение |
|---|---|---|---|
4 000 токенов | ~1.2 с | ~0.4 с | −67% |
10 000 токенов | ~2.8 с | ~0.5 с | −82% |
50 000 токенов | ~12 с | ~0.8 с | −93% |
Источник: данные Anthropic и кейс Caylent + Bedrock (опубликован в блоге AWS, 2025)
RAG-агент с 30k контекста и требованием TTFT < 1 с - без кэша это недостижимо физически на большинстве провайдеров, плати хоть больше, хоть меньше.
Три антипаттерна, которые убивают hit rate полностью
Полный список - тема отдельной статьи. Три самых частых, и первый встречается буквально везде:
Временные метки в системном промпте
# hit rate = 0 - каждый запрос уникален system = f"Сегодня: {datetime.now()}. Ты помощник..." # правильно - время в user-сообщение user = f"[Время: {datetime.now()}] {user_query}"
Специфичные пользовательские данные в начале system prompt
Это менее очевидно. Кажется что "Ты помогаешь {user.name} из {user.company}" - нормальная такая персонализация. Но это делает каждый системный промпт уникальным. В таком случае cache hit между запросами разным пользователей невозможен физически.
# плохо system = f"Ты помогаешь {user.name} из {user.company}..." # всё про пользователя - в user-сообщение system = "Ты корпоративный ассистент..." user = f"[Контекст: {user.name}, {user.company}] {query}"
Нестабильная JSON-сериализация tool definitions
Один символ разницы в префиксе - кэш сбрасывается. Это не только про timestamp. У Pydantic и dataclasses порядок ключей при сериализации может меняться между версиями. Обнаруживается не сразу - hit rate просто чуть ниже ожидаемого, и непонятно почему.
json.dumps(tool_params) # порядок не гарантирован json.dumps(tool_params, sort_keys=True) # правильно
Перед каждым деплоем стоит проверять хэш промпта - если изменился, кэш сбросится:
import hashlib, json def prompt_hash(system: str, tools: list) -> str: content = json.dumps({"system": system, "tools": tools}, sort_keys=True) return hashlib.sha256(content.encode()).hexdigest()
Справочник: актуальные цены кэширования (март 2026)
Провайдер / Модель | Тип кэша | Input miss | Input hit | Output | Мин. токенов | TTL |
|---|---|---|---|---|---|---|
GPT-5 mini | Авто | $0.25/M | $0.025/M (−90%) | $2/M | 1 024 | 5-10 мин / до 1 ч |
GPT-5.2 | Авто | $1.75/M | $0.175/M (−90%) | $14/M | 1 024 | 5-10 мин / до 1 ч* |
GPT-5.4 | Авто | $2.50/M | $0.25/M (−90%) | $15/M | 1 024 | 5-10 мин / до 1 ч |
Claude Opus 4.1 | Явный | $15.00/M | $1.50/M (−90%) | $75/M | 1 024 | 5 мин / 1 ч |
Claude Sonnet 4 | Явный | $3.00/M | $0.30/M (−90%) | $15/M | 1 024 | 5 мин / 1 ч |
Claude Haiku 3.5 | Явный | $0.80/M | $0.08/M (−90%) | $4/M | 2 048 | 5 мин / 1 ч |
Gemini 2.5 Pro | Авто + явный | $1.25/M | $0.125/M (−90%) | $10/M | 2 048 | до 1 ч |
Gemini 2.5 Flash | Авто + явный | $0.30/M | $0.03/M (−90%) | $2.50/M | 1 024 | до 1 ч |
Gemini 2.5 Flash-Lite | Авто + явный | $0.10/M | $0.01/M (−90%) | $0.40/M | 1 024 | до 1 ч |
DeepSeek V3.2 | Авто (disk) | $0.28/M | $0.028/M (−90%) | $0.42/M | ~64 | Авто |
vLLM (self-hosted) | Авто (APC) | compute | — | — | ~16 | LRU |
Что не видно из таблицы:
У Haiku 3.5 минимальный порог - 2 048 токенов, вдвое больше чем у Sonnet/Opus. Системный промпт меньше 2k - кэш не работает вообще.
Write surcharge у Anthropic зависит от TTL: за 5-минутный +25%, за 1-часовой ×2. Если трафик нерегулярный и кэш тухнет раньше чем окупится write - считайте TTL отдельно.
У OpenAI стандартный in-memory кэш живёт 5-10 минут бездействия, иногда до часа. Для части моделей (например, gpt-5 и gpt-5.2) доступен extended retention до 24 часов - в таблице выше для сравнимости указан стандартный режим, кроме пометки *.
У Gemini два режима. Implicit (авто) не гарантирует hit - провайдер сам решает что кэшировать. Explicit требует создания cache-объекта и имеет отдельную storage price. В таблице только стоимость использования; для длинных TTL добавьте storage. Отдельная деталь: минимальные пороги у Gemini нестабильны между версиями документации - официальный блог и актуальный doc-гайд дают разные числа для одних и тех же моделей. Правильнее проверять по фактическим логам.
DeepSeek хранит KV-кэш на диске за счёт компактного MLA-формата - в отличие от западных провайдеров где кэш живёт в GPU-памяти. На практике это значит что кэш не вытесняется так быстро при высокой нагрузке. Плюс минимальный порог около 64 токенов - кэшируется практически любой промпт.
FAQ
Кэш - это хранение моих данных у провайдера?
Нет. KV-кэш хранит тензоры промежуточных вычислений - не текст промпта, а результат его обработки моделью. Изоляция по API-ключу у Anthropic, по аккаунту у OpenAI. Для compliance - документация провайдера, там это прописано явно.
Высокий hit rate, но счёт не уменьшился. Почему?
Скорее всего output съедает всё. Возьмите любые 100 запросов из логов и посчитайте долю output_tokens в суммарном cost. Если больше 60% - кэш на входящие запросы не поможет: GPT-5.2 с $14/M output будет дорогим при любом hit rate. В этом случае смотреть надо на output price, а не на скидку кэша.
Что важнее - скидка на read или отсутствие наценки на write?
Зависит от паттерна трафика. Постоянный трафик, кэш не тухнет - берёте максимальную скидку на read, сейчас все топовые провайдеры дают −90%. Пиковый с паузами, TTL 5 минут - кэш тухнет, вы платите за write снова и снова, смотрите на OpenAI/Gemini/DeepSeek без write surcharge.
Как проверить что кэш вообще работает?
OpenAI: usage.prompt_tokens_details.cached_tokens Anthropic: cache_read_input_tokens (+ cache_creation_input_tokens) Google: usage_metadata.cached_tokens DeepSeek: prompt_cache_hit_tokens OpenRouter: usage.prompt_tokens_details.cached_tokens + usage.prompt_tokens_details.cache_write_tokens + поле cache_discount в ответе (сколько сэкономили на этом запросе)
cached_tokens / total_input_tokens - hit rate. Для RAG и агентов целевой показатель выше 70%. Ниже 50% - смотрите антипаттерны выше, там почти наверняка один из трёх.
Итог
Когда я начал считать, думал что всё очевидно: есть прайс, есть скидка на кэш, дальше включаем математику. Но оказалось что без S, O и h это нормально не посчитать. Gemini Flash-Lite с $0.01/M за cache read побеждает DeepSeek в двух из трёх сценариев - кто бы подумал глядя на прайс.
По механике кэша — как устроено внутри:
Как работает кэширование промптов - PagedAttention и автоматическое кэширование префикса - OTUS, январь 2026
Источники по поведению кэша в продакшене:
OpenAI: Prompt Caching guide - официальная документация
Google: Context caching - Gemini API docs
Implicit caching inconsistencies - реальные кейсы из Google AI Developer Forum
В своем tg-канале иногда выкладываю расчёты, но чаще про инженерные практики и инсайты построения AI платформы.
