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

Почему окупаемость не видна сразу
Кэш кажется простой экономией только на словах. На деле он помогает не всегда. Если запросы редко повторяются, кэш почти пустует, а команда все равно платит за хранение, проверку совпадений и дополнительную логику в приложении. Поэтому окупаемость кэша запросов нельзя определить на глаз.
Ошибка обычно начинается с мысли: "раз ответы можно переиспользовать, значит станет дешевле". Это работает только там, где люди или системы задают один и тот же вопрос достаточно часто. Если формулировки постоянно меняются, кэш почти не срабатывает.
Разница хорошо видна на обычных сценариях. В поддержке часто повторяются вопросы о статусе заказа, возврате и графике работы. Там кэш нередко дает заметный эффект уже при среднем трафике. В поиске все сложнее: один пользователь пишет "кроссовки 42", другой - "черные беговые кеды мужские", и формально это уже другой запрос. В генерации писем результат зависит от шаблонов. Если команда отправляет похожие письма по одному каркасу, повторы есть. Если каждое письмо собирают с нуля, пользы меньше.
Поэтому спор "кэш нужен" или "кэш не нужен" обычно ни к чему не ведет. Один человек смотрит на поток однотипных обращений в поддержке, другой - на редкие и длинные запросы в поиске, и оба говорят о реальных вещах. Просто данные у них разные.
Если команда работает с несколькими моделями через один шлюз, путаницы становится больше. Запросы уходят по разным маршрутам, цены отличаются, а ощущение экономии легко вводит в заблуждение. Сначала нужно понять не размер кэша, а природу трафика. Именно она показывает, даст ли кэш экономию или просто добавит еще один слой системы.
Что входит в расчет
Чтобы понять, когда кэш окупается, не нужен большой финансовый файл. Обычно хватает пяти чисел за один и тот же период: день, неделю или месяц.
Сначала возьмите цену обычного запроса без кэша. Для поиска это может быть вызов модели плюс поиск по базе. Для поддержки - ответ модели с системным промптом и историей диалога. Для генерации писем - полный запрос с шаблоном, тоном и данными клиента.
Потом добавьте цену повтора. Она бывает разной. Иногда попадание в собственный кэш почти бесплатно, потому что вы просто отдаете готовый ответ. Иногда повтор все же что-то стоит, но дешевле полного вызова, если провайдер снижает цену на повторяющуюся часть запроса.
Дальше нужна доля повторов. Считать лучше не "вообще", а по конкретному типу задач и за выбранный период. В поддержке повторы обычно видны по частым темам. В генерации писем они ниже, если менеджеры каждый раз меняют вводные. В поиске многое зависит от того, как часто люди задают один и тот же запрос и как вы нормализуете формулировки.
Еще один параметр - срок жизни записи в кэше. Если держать ответ слишком мало, вы потеряете часть повторов. Если слишком долго, начнете отдавать устаревший результат. Для поиска по каталогу TTL часто короче. Для типовых ответов поддержки он может быть длиннее.
Наконец, в расчет нужно включить потери. Важно понять, сколько запросов не попадает в кэш, сколько стоит сама проверка кэша перед обычным вызовом и как часто система отдает старый ответ. Последний пункт часто ломает слишком оптимистичные расчеты. Если команда кэширует ответы поддержки, а правила возврата уже изменились, дешевый ответ быстро превращается в дорогую ошибку.
Простая формула без лишней математики
Считать можно без сложной статистики. Нужны четыре числа:
P- цена полного вызова модели без кэшаH- цена запроса при попадании в кэшK- разовый расход на запись ответа в кэшR- сколько раз один и тот же запрос реально повторяется
Без кэша средняя цена одного запроса всегда равна P. Если один и тот же запрос пришел 10 раз, вы 10 раз платите полную цену.
С кэшем цена делится на две части: первый промах и все следующие попадания. Тогда общая стоимость для повторяющегося запроса такая:
C_cache = P + K + (R - 1) * H
Средняя цена одного обращения будет такой:
Avg_cache = (P + K + (R - 1) * H) / R
Кэш окупается, когда средняя цена с кэшем ниже обычной цены без кэша:
(P + K + (R - 1) * H) / R < P
Если упростить выражение, получим порог повторов:
R > (P + K - H) / (P - H)
Это и есть простая проверка на окупаемость кэша запросов. Если K почти равен нулю, кэш начинает экономить уже со второго одинакового запроса. Если запись в кэш, проверка похожести или хранение стоят заметно дороже, повторов нужно больше.
Пример. Пусть полный вызов стоит 0.10, попадание в кэш стоит 0.01, а запись в кэш стоит 0.02. Тогда:
R > (0.10 + 0.02 - 0.01) / (0.10 - 0.01) = 1.22
Значит, двух повторов уже хватает.
Теперь возьмем более дешевую модель: P = 0.03, а H и K оставим теми же. Получаем:
R > (0.03 + 0.02 - 0.01) / (0.03 - 0.01) = 2
Тут двух обращений уже мало, нужен как минимум третий запрос. Логика простая: чем дешевле модель, тем меньше экономия на каждом попадании.
Как посчитать по шагам
Считать лучше на свежих данных, а не по ощущениям. Возьмите выборку из недавних логов за 2-4 недели. Если трафик большой, хватит нескольких тысяч запросов. Если трафик небольшой, берите все, что есть.
Потом приведите запросы к одному виду. Уберите разницу в регистре, лишние пробелы, очевидные опечатки и мелкие хвосты вроде номера заказа, если смысл от этого не меняется. После этого соберите вместе не только одинаковые фразы, но и очень близкие по смыслу запросы. Для поддержки это могут быть "где мой заказ" и "когда привезут заказ". Для поиска - "кроссовки nike 42" и "nike кроссовки размер 42".
Дальше схема простая. Сначала посчитайте, сколько запросов повторились хотя бы один раз. Затем разбейте повторы по окнам времени: в тот же день, за 7 дней и за 30 дней. Для каждого окна найдите долю попаданий в кэш: hits / all requests. После этого подставьте деньги: цену обычного ответа модели, цену записи в кэш и цену чтения из кэша. Финальная проверка выглядит так:
экономия = hits * (цена модели - цена чтения) - записи * цена записи
Считать лучше отдельно по типам задач. У поиска одна структура повторов, у поддержки другая, у генерации писем третья. Если все смешать, средняя цифра получится красивой, но бесполезной.
После расчета не раскатывайте кэш сразу на весь поток. Запустите его на небольшой доле трафика, например на 5-10%, и проверьте две вещи: совпала ли фактическая доля попаданий с расчетом и не упало ли качество ответов. Иногда кэш вроде бы экономит деньги, но начинает отдавать устаревшие данные. На бумаге это выглядит хорошо, а в работе быстро ломается.
Если вы ведете LLM-трафик через единый шлюз, цену модели удобно брать по маршруту к конкретному провайдеру, а цену кэша считать отдельно в своей инфраструктуре. Так легче увидеть, при какой повторяемости запросов кэш действительно окупается.
Что показывает простой пример
Интернет-магазин редко живет с одним типом запросов. В одной системе работают поиск по каталогу, чат поддержки и письма, которые менеджеры просят сгенерировать по похожим поводам.
На бумаге все это можно свести в один средний процент повторов. На деле такой показатель часто только мешает. Днем покупатели снова и снова ищут одни и те же товары: "айфон 128 гб", "белые кроссовки 39", "пылесос беспроводной". В это же время поддержка получает одинаковые вопросы про доставку, возврат и статус заказа. Ночью картина меняется: трафика меньше, запросы реже совпадают, и повторы падают.
С письмами еще проще. Менеджеры часто просят одни и те же тексты с небольшими правками: ответ на жалобу о задержке, письмо о брошенной корзине, подтверждение возврата.
Если смотреть только на общий поток, можно увидеть, например, 28% повторов и решить, что кэш сомнителен. Но внутри этого среднего числа поиск может давать лишь 12% повторов ночью, поддержка - 40% днем, а письма - 65%, потому что шаблоны повторяются почти каждый час.
Именно здесь общий отчет прячет деньги. Команда думает, что все три направления ведут себя одинаково, хотя это не так. Даже небольшому магазину полезно разнести запросы по трем группам и посмотреть повторы отдельно по дню и по ночи. Обычно после такого деления видно: кэш для писем окупается первым, поддержка идет следом, а поиск нужно считать осторожнее, потому что там много близких, но не полностью одинаковых формулировок.
Как считать для поиска
Для поиска лучше считать окупаемость по отдельным типам запросов и по короткому периоду, например по дням или неделям. Короткие фразы повторяются чаще, чем кажется: доставка, возврат, iphone 15, qwen. Поэтому кэш в поиске иногда начинает работать раньше, чем в более длинных сценариях.
Базовый расчет простой:
экономия за период = число поисковых запросов * доля попаданий в кэш * (полная цена поиска - цена чтения из кэша) - стоимость самого кэша за тот же период
Для поиска важна не только повторяемость строк, но и нормализация. Если убрать лишние пробелы, привести регистр и склеить частые варианты вроде iphone15 и iphone 15, доля попаданий обычно растет. Но перегибать нельзя. Иногда одно слово полностью меняет смысл, и запись из кэша даст уже не тот результат.
В расчет поискового запроса обычно включают сам нормализованный текст, фильтры и сортировку, язык или регион, а также тип поиска - по сайту или по каталогу. Эти поля часто решают, можно ли безопасно считать два запроса одинаковыми.
Небольшой пример. Допустим, поиск по каталогу получает 100 000 запросов в неделю. Полный поиск стоит 0,12 тенге, чтение из кэша - 0,01 тенге, поддержка кэша - 1 800 тенге в неделю. Если после нормализации доля попаданий дошла до 28%, экономия составит:
100 000 * 0,28 * (0,12 - 0,01) = 3 080 тенге
После вычета 1 800 тенге остается 1 280 тенге. Значит, кэш уже окупается.
Если взять те же числа, но без нормализации и с попаданиями только 12%, экономия будет 1 320 тенге. Это ниже затрат. Идея та же, а результат уже отрицательный.
Поиск по сайту и поиск по каталогу лучше не смешивать. У поиска по сайту чаще повторяются запросы вроде "доставка" или "оплата". У каталога сильнее влияют остатки, цены и акции. Сезонность тоже меняет картину очень резко: школьная форма в августе и подарки в декабре дают совсем другие повторы, чем средний месяц.
Как считать для поддержки
Кэш в поддержке считают не по одинаковым фразам, а по одинаковому смыслу. Один клиент пишет "где мой заказ", другой - "когда привезут", третий - "почему доставка молчит". Для расчета это один тип вопроса. Если сравнивать только строки, повторяемость запросов окажется слишком низкой.
У поддержки есть понятный плюс: ответы часто строятся из одних и тех же шаблонов. Возврат, статус доставки, смена тарифа, восстановление доступа - такие темы повторяются каждый день. Поэтому кэш в поддержке нередко окупается быстрее, чем в свободной генерации текста.
Считать удобно так: возьмите число обращений по одному сценарию за месяц, оцените долю повторов после группировки по смыслу, посчитайте цену полного ответа модели и цену кэш-хита вместе с короткой проверкой актуальности. Отдельно оцените цену одной ошибки.
Формула выглядит так:
экономия = повторы * (цена полного ответа - цена кэш-хита - цена проверки) - ошибочные выдачи * цена ошибки
Проверка актуальности здесь почти обязательна. В поддержке ответы быстро стареют после смены правил, акций, лимитов или условий возврата. Если не заложить эту проверку в расчет, цифры будут слишком красивыми и почти бесполезными.
Пример. Команда обрабатывает 20 000 обращений в месяц. После группировки видно, что 40% вопросов повторяются. Полный ответ модели стоит 4 тенге, выдача из кэша - 0,5 тенге, проверка актуальности - еще 0,7. Экономия с одного повтора равна 2,8 тенге. Тогда грубая месячная экономия составляет:
20 000 * 40% * 2,8 = 22 400 тенге
Теперь добавим риск. Если 1% кэшированных ответов устарел, а одна ошибка в среднем дает 30 тенге на повторное обращение и ручную обработку, потери составят:
20 000 * 40% * 1% * 30 = 2 400 тенге
Чистая экономия все еще есть, но уже 20 000 тенге, а не 22 400.
Для простых тем кэш обычно выгоден. Для выплат, медицины и юридических правил сначала снижайте риск ошибки, а уже потом считайте токены.
Как считать для генерации писем
Точный кэш всего запроса для писем срабатывает реже, чем кажется. Обычно у команды повторяется каркас: роль модели, тон, правила бренда, структура письма и ограничения по стилю. А имя клиента, товар, дата, сумма и история заказа делают весь запрос уникальным.
Поэтому для кэша в генерации писем лучше считать не весь промпт, а его общую часть. Если кэшировать только полный запрос целиком, персонализация почти всегда сильно поднимает порог окупаемости.
Подходит простая оценка:
экономия = число писем * доля повторов общей части * разница в цене между обычным и кэшированным вводом
Пример. Команда отправляет 6 000 писем в месяц. В каждом письме есть 2 000 токенов общего каркаса и 400 токенов переменных данных. Обычный ввод для этих 2 000 токенов стоит 2 тенге, кэшированный - 0,5 тенге. Если одна и та же общая часть повторяется в 65% писем, расчет такой:
6 000 * 0,65 = 3 900кэш-попаданий- экономия на одном письме =
1,5тенге - месячная экономия =
3 900 * 1,5 = 5 850тенге
Это уже заметный эффект. Но если добавить глубокую персонализацию, общий блок может сжаться, например, до 700 токенов. Тогда экономия с одного письма станет ниже, и кэш начнет окупаться только при более частых повторах.
Промпты для продаж и сервиса лучше считать отдельно. У продаж обычно больше сегментов, офферов и персональных вставок, поэтому совпадений меньше. У сервисных писем каркас строже: подтверждение заказа, статус доставки, напоминание об оплате. Там кэш чаще дает результат раньше.
Практическое правило простое: сначала вынесите в отдельный блок все, что не меняется неделями, а потом измерьте повторы именно этого блока.
Где чаще всего ошибаются
Окупаемость кэша запросов часто считают слишком грубо. На бумаге цифра выглядит хорошо, а после запуска экономия оказывается заметно ниже. Обычно проблема не в самом кэше, а в том, как команда считает повторяемость, цену промаха и цену попадания.
Самая частая ошибка - брать среднюю цену запроса по всем обращениям. Среднее скрывает длинные и дорогие запросы, а именно они часто дают большую часть расходов. Если поиск или поддержка обрабатывают и короткие фразы, и большие обращения с историей переписки, считайте хотя бы по группам.
Еще один промах - считать повторы только по точному совпадению текста. В жизни люди пишут одно и то же по-разному: "Где мой заказ?", "Когда привезут заказ?", "Статус доставки". Для бизнеса это почти один сценарий. Для простого строкового сравнения это три разных запроса, и вы занижаете долю попаданий.
Есть и другие типичные ошибки. Команды часто не разделяют короткие и длинные запросы, не учитывают близкие по смыслу повторы, ставят один и тот же TTL для каталога и поддержки, смешивают в одном расчете дешевые и дорогие модели, а еще забывают заложить цену устаревшего ответа. Последняя ошибка особенно неприятна. Если кэш отдает вчерашний остаток на складе, старый тариф или неактуальный статус заявки, вы экономите на API, но теряете на продукте и поддержке.
Опасно и смешивать в одном отчете разные модели и разных провайдеров. У них разная цена токенов, разная задержка и разная польза от кэша. Если вы работаете через единый OpenAI-совместимый шлюз, соблазн сложить весь трафик в одну таблицу особенно велик. Лучше строить расчет по маршрутам: модель, тип запроса, срок жизни кэша и доля повторов.
Если после такого разбиения экономика стала хуже, это не плохая новость. Это честная цифра, на которую уже можно опираться.
Проверка перед запуском
Кэш имеет смысл включать не тогда, когда запросы "похожи на глаз", а когда это видно в цифрах. Если явных повторов нет, кэш просто добавит еще один слой логики и не даст заметной экономии.
Сначала посмотрите на повторяемость в разных окнах времени. Для поиска это может быть час или день. Для поддержки часто важна смена или неделя. Для генерации писем полезно смотреть на повтор шаблонов за день. Если одни и те же вводные приходят снова и снова, кэш уже может окупаться.
Потом проверьте сам промпт. Если половина потока использует один и тот же шаблон с мелкими заменами вроде имени клиента, города или номера заказа, это хороший знак. Если каждый запрос сильно отличается по структуре, тону и набору полей, высокой доли попаданий ждать не стоит.
До запуска команда должна договориться о простых правилах: что считать достаточно одинаковым ответом для кэша, кто и после каких событий очищает записи, как долго хранить результат и какие метрики смотреть каждый день. Обычно хватает двух: hit rate и доля ошибок. Еще нужен понятный способ быстро отключить чтение из кэша, если качество просело.
Правило очистки лучше описывать не общими словами, а через события. В поддержке кэш очищают после смены статуса заказа. В поиске - после обновления каталога. В письмах - после правки шаблона или оффера. Если такого правила нет, команда быстро получает устаревшие ответы и перестает доверять системе.
План отката нужен даже для маленького запуска. Самый простой вариант - флаг, который отключает чтение из кэша, но не ломает основной путь запроса. Тогда можно быстро сравнить качество, цену и задержку без долгого разбора.
Что делать дальше
Не пытайтесь сразу кэшировать все запросы. Возьмите один поток, где повторы уже заметны по логам: поиск по каталогу, ответы поддержки или генерацию типовых писем. Недели логов обычно хватает, чтобы увидеть частоту повторов, среднюю цену запроса и обычную задержку без догадок.
Потом сравните работу до и после по трем метрикам: цена, задержка и доля попаданий в кэш. Смотрите не только на экономию. Иногда кэш немного снижает расходы, но добавляет лишнюю сложность и почти не ускоряет ответ. Такой вариант лучше остановить сразу.
Самая частая ошибка на этом этапе - снова считать все вместе. Поиск, поддержка и письма дают разный профиль повторов. То же самое касается моделей: одна модель дорогая, но вызывается редко, другая дешевая, но получает тысячи похожих запросов. Если смешать эти группы, выводы будут слабыми.
Рабочий порядок простой: выберите один поток, соберите по нему 7 дней логов, посчитайте цену и задержку без кэша, включите кэш на ограниченной доле трафика и сравните результат отдельно по каждой модели и типу задачи.
Если запросы идут через единый OpenAI-совместимый шлюз, считать проще: логи и тарифы по маршрутам легче свести в одном месте. Для команд в Казахстане такой тест можно быстро проверить через AI Router на airouter.kz - достаточно сменить base_url на api.airouter.kz, а SDK, код и промпты оставить без изменений.
Если один поток дал понятную экономию или заметно более быстрый ответ, переносите схему на соседние задачи. Если нет, не масштабируйте эксперимент. Сначала поправьте правила кэша, срок жизни записей и разбиение запросов по типам.