Реализация кэширования LLM-ответов: Exact и Semantic Cache

Высокая нагрузка на модель замедляет ответы и перегружает инфраструктуру. Мы настраиваем кэширование LLM-ответов под ключ: точное и смысловое сопоставление запросов, политики инвалидации и замеры эффекта. Задержка ответа сокращается в разы, а нагрузка на модель перестаёт расти вместе с числом обращений.
Часто задаваемые вопросы

Что ломается без кэширования LLM-ответов при росте нагрузки

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

Каждый такой запрос заново проходит весь путь: сборку промпта, обращение к модели, генерацию. Самая ресурсоёмкая часть конвейера тратится на ответ, который уже был получен минуту назад и лежит без дела.

Дальше растёт время ответа модели, и причина не в самой модели, а в очереди. Одновременных обращений больше, чем доступных слотов обработки, поэтому запросы ждут, а не считаются. Хвост задержек удлиняется у всех — включая тех, кто пришёл с уникальным вопросом.

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

Кэширование LLM-ответов снимает именно эту механику: повторяющийся запрос получает готовый ответ, не доходя до модели. Ниже разбираем, как это закрывается — от точного совпадения до семантического.

Что даёт кэширование LLM: скорость ответа и нагрузка на модель

Кэш работает на двух уровнях: точное совпадение нормализованного запроса и семантическая близость векторов. Первый уровень ловит дословные повторы — типовые вопросы в поддержке, шаблонные запросы к документации, повторные вызовы из одного сценария. Второй сравнивает эмбеддинги и отдаёт ответ при близости выше заданного порога, поэтому перефразировки («как оформить возврат» и «возврат товара — как сделать») попадают в одну запись.

Доля попаданий в корпоративных ассистентах обычно держится в диапазоне 30–60% и зависит от разнообразия формулировок и длины системного промпта. Именно эта доля определяет сокращение времени ответа: попадание отдаётся из хранилища за десятки миллисекунд, тогда как генерация занимает секунды. Пользователь видит разницу не в среднем времени, а в хвосте — тяжёлые запросы перестают быть нормой.

Число обращений к модели падает пропорционально доле попаданий. Освободившаяся мощность становится запасом по мощности: ассистент выдерживает рост числа пользователей без расширения контура, а пики — утренний наплыв, массовую рассылку, старт кампании — проходит без отказов по лимиту запросов. Этот класс отказов уходит целиком, а не маскируется повторами на клиенте.

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

Два режима сопоставления запросов: точный и по смыслу

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

Нормализация запроса — общий слой для обоих режимов: регистр, лишние пробелы, служебные поля, порядок параметров. Без неё точное совпадение теряет попадания на пустом месте: «Сколько стоит доставка?» и «сколько стоит доставка» уходят в модель дважды.

Вариант Когда подходит Ограничения
Точное совпадение Шаблонные повторы: формы, автодополнение, повторный вызов с теми же параметрами Не ловит перефразировки и опечатки, требует нормализации
Поиск по смыслу Свободные вопросы, где важна суть, а не формулировка Порог близости: заниженный даёт ложные попадания
Гибрид по уровням Разнородный трафик: сначала точный уровень, затем смысловой Сложнее отладка и выборочный сброс кэша при смене модели

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

Порядок внедрения: от профиля запросов до передачи в поддержку

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

  1. Аудит потока запросов. Снимаем выгрузку обращений за 2-4 недели: доля повторов, разброс формулировок одного и того же вопроса, длина контекста, набор параметров генерации, доля запросов с персональными данными. На выходе — карта сценариев с потенциалом кэширования.
  2. Схема ключей запроса. Определяем, что входит в ключ точного совпадения (нормализованный текст, системная инструкция, параметры генерации, идентификатор версии модели) и что считаем близостью для семантического слоя. Отдельно помечаем сценарии, которые не кэшируются вовсе.
  3. Политики хранения. Задаём время жизни записей по типам сценариев, правила инвалидации при смене промпта или модели, объём индекса и лимиты на хранение.
  4. Настройка слоя кэша. Ставим его перед моделью, поднимаем индекс близости, настраиваем прогрев на исторических запросах и логирование попаданий.
  5. Проверка на теневом трафике. Боевой поток идёт как обычно, а решения кэша считаются параллельно, без влияния на ответ. Смотрим долю попаданий, расхождения ответов и поведение на редких формулировках.
  6. Замеры после включения. Сравниваем с базовой линией: доля запросов, дошедших до модели, время ответа, нагрузка на генерацию, доля ответов с признаками деградации качества.
  7. Передача в поддержку. Регламент инвалидации, дашборд с метриками, пороги оповещений и порядок быстрого отключения слоя — чтобы эксплуатация не зависела от авторов решения.

Артефакты внедрения: конфигурации, схемы, политики, регламенты

Внедрение заканчивается не фактом включения кэша, а передачей пакета артефактов, по которому служба эксплуатации может вести решение без автора. Ниже — состав этого пакета; каждый пункт закрывает конкретный класс отказов, а не «для галочки».

  • Конфигурации сервиса — рабочие файлы с порогом семантического совпадения, временем жизни записи по классам запросов, лимитами размера хранилища и правилами разделения пространств ключей. Каждое значение снабжено комментарием: диапазон, в котором его можно менять, и что деградирует при выходе за границы.
  • Схема потока запроса — от нормализации входящего текста через поиск точного совпадения и векторный поиск до обращения к модели и записи ответа. На схеме отмечены точки логирования и место, где ответ помечается как полученный из кэша.
  • Политики исключений и приватности — перечень запросов, которые не кэшируются вообще: с персональными данными, с контекстом текущей сессии, с учётными данными клиента. Плюс правила изоляции ключей по арендатору, чтобы ответ одного пользователя не всплыл у другого.
  • Правила инвалидации — автоматический сброс при смене версии модели или системного запроса, ручная очистка по тегу и по пространству ключей, аварийное отключение кэша одним переключателем. Описано, что происходит с уже отданными ответами.
  • Панель метрик — доля попаданий, доля ложных семантических совпадений, время ответа, число обращений к модели. По этим показателям видно, где порог подобран слишком мягко.
  • Документация для дежурной смены — пошаговые инструкции на типовые ситуации: рост ложных совпадений, переполнение хранилища, недоступность векторного индекса. Для каждой — признак, действие, порядок отката к режиму без кэша.
  • Регламент проверки — набор регрессионных запросов с эталонными ответами и порядок прогона перед изменением конфигурации, а также доступы и роли для команды заказчика.

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

Кейс: как за месяц снизили задержку и нагрузку на модель

До: поток запросов без кэша

У заказчика — диалоговый помощник первой линии поддержки. Обращения массово повторяются, но каждый запрос всё равно уходил в модель: среднее время ответа держалось около 3,4 с, на пиках доходило до 9 с. В часы нагрузки часть обращений обрывалась из-за лимита у поставщика модели, и пользователи уходили в форму тикета вместо ответа в диалоге.

После: два уровня кэша

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

На сопоставимом профиле доля попаданий вышла 41%, из них 27% — семантические. Среднее время ответа упало с 3,4 до 0,6 с, верхний перцентиль — с 9 до 1,4 с, число обращений к модели сократилось на 43%. Класс отказов «лимит у поставщика на пике» ушёл: нагрузка на модель больше не растёт от повторов.

Замеры снимали на одном и том же наборе запросов — две недели до внедрения и две недели после, с разбивкой по категориям обращений и отдельно по прогреву в первые минуты после перезапуска. Инвалидация по версии промпта не дала разъехаться ответам после правок инструкции. Полный разбор замеров — ниже: профиль запросов, доля попаданий и распределение задержек по каждой категории.

Что делать при ложных попаданиях в уже работающей системе

Ложное попадание почти никогда не означает, что сопоставление настроено неправильно. В работающей системе это обычно значит, что порог близости задан один на все типы запросов, а решения нигде не записываются: сбой виден, причина — нет. Первый шаг — не крутить порог, а логировать каждое попадание: исходный запрос, найденного «соседа», значение близости и признак, был ли ответ принят.

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

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

Точечные исключения работают точнее, чем подъём порога для всех подряд. В список исключений уходят запросы с числами, датами, названиями и отрицаниями: там близость обманывает чаще всего, а подстановка чужого ответа обходится дороже, чем лишний вызов модели.

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

Частые технические вопросы: инвалидация, приватность, замеры

Кэш ответов ломается не на записи, а на сопровождении: записи переживают смену модели, ключи клиентов пересекаются, а эффект мерят по среднему времени ответа.

Какой срок жизни ставить записи?

Задаём двумя слоями: истечение по времени и порог по числу обращений. Справочные ответы живут дольше, фактические — короче, поэтому срок привязан к типу запроса, а не задан одним числом для всего кэша.

Как разделяются данные разных клиентов и арендаторов?

Ключ строится как «арендатор → клиент → версия модели → запрос»: одинаковые вопросы разных клиентов дают разные записи, пересечение исключено. Хранилище (например, Redis) держим раздельными наборами с отдельными политиками вытеснения.

Что происходит при смене версии модели?

Версия модели входит в ключ: новая версия не читает старый кэш, а пишет свой, прежние записи доживают срок параллельно и не мешают. Откат на предыдущую версию возвращает её кэш целиком.

Как честно замерить эффект?

Считаем долю обращений, закрытых из кэша, и время до первого токена по промахам. Замер идёт на живом трафике с теневой веткой: часть запросов всегда уходит в модель напрямую, и разница между ветками показывает реальный выигрыш.

Обсудим задачу: сверим требования и вернёмся с планом

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

  • Исходные данные по нагрузке: сколько обращений в сутки, как выглядит пиковый профиль, какая доля формулировок повторяется дословно, а какая — перефразируется.
  • Где именно теряется время и стоимость: задержка ответа, доля запросов к модели, объём переплат за повторные генерации.
  • Требования к свежести: через сколько после обновления источника ответ обязан перестать отдаваться из кэша, есть ли запросы, которые кэшировать нельзя в принципе.
  • Инфраструктура и ограничения: где живут сервисы, какие требования к изоляции данных, есть ли правила хранения персональных данных и аудита доступа.
  • Приоритеты по срокам: что должно заработать первым, что можно отложить на второй этап, к какой дате нужен результат.
  • Кто со стороны заказчика принимает решения по спорным местам — например, по порогу семантического сходства и правилам инвалидации.

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

Направления AI-разработки

Последние работы

  • Разработка сайта компании B2B ADVANCE
    Разработка сайта компании B2B ADVANCE
    1542
  • Разработка веб-приложения для компании FEEDME
    Разработка веб-приложения для компании FEEDME
    1394
  • Разработка веб-сайта для компании БЕЛФИНГРУПП
    Разработка веб-сайта для компании БЕЛФИНГРУПП
    1081
  • Разработка интернет магазина для компании FURNORO
    Разработка интернет магазина для компании FURNORO
    1369
  • Разработка логотипа компании B2B Advance
    Разработка логотипа компании B2B Advance
    816
  • Разработка веб-приложения для компании Enviok
    Разработка веб-приложения для компании Enviok
    1142