CNN TürkSerdal Adalı: Üzgünüz, takım yorgundu, iyi oynamadıkPunchJunk food ads flooded 2026 World Cup matches — ReportInquirerWATCH: Sara Duterte impeachment trial | Sept. 21, 2026Bollywood HungamaBigg Boss 20: Rohed Khan exits as FIRST eviction, Salman Khan says, "Well played with dignity"ESPN DeportesNFL: Jaxon Smith-Njigba se convirtió en la figura de la Semana 2Daily MaverickWHAT WE’RE WATCHING: JM Coetzee’s biblical trilogy comes to screen in daring cinematic saga한겨레추석 벌초, 예초기 돌리기 전 ‘10분’…말벌 움직임 살펴야SözcüDev giyim markası 1 ay boyunca yıkanmayan tişört satmaya başladıIl Fatto QuotidianoVasco Rossi esce dalla clinica dopo l’operazione: “Teniamo sempre duro”. I ringraziamenti dell’artista a medici e infermieri della strutturaХабр«Я свой, я агент»: как мы обновили RMON и добавили mTLS для результатов мониторингаNOSPolitieagent en schutter gewond bij aanval op synagoge in CanadaObservador DesportoPassos Coelho tornou-se o tema mais irritante no PSD?
The Daily Newsstand · Free, Always
Monday, September 21, 2026

Как ускорить ИИ-агента с RAG в проде и не слить бюджет: кэшируем ответы на примере ИИ-консультанта

Translate

Заметил, и вы наверное тоже, что сейчас почти каждый домен и почти каждый продукт развивает своего ИИ-агента. Яндекс Маркет запустил Маркет AI, который подбирает товары, у Авто.ру есть Авто.ру AI, в Лавке появился ассистент, вот у одного только Яндекса их сколько. А кто-то уже начал перестраивать CJM вокруг агента: пользователь не ходит по фильтрам и каталогу, а просто пишет, что ему нужно. Назвать это полным переходом на агентские интерфейсы или на агентский поиск, конечно, пока нельзя. Но первые шаги уже есть.

Я и сам, собственно, «владелец» нескольких таких агентов в е-коме.

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

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

С какими проблемами такие агенты сталкиваются в проде

Про каждую можно писать отдельную статью, поэтому коротко:

  • Скорость (латенси). Каждый поход за данными добавляет время: поиск по базе, обход графа, вызов инструмента. А после каждого шага модель заново читает всю переписку и конечно заявленные 20-30 секунды редко получается держать.

  • Пустые и неверные ответы. Модель может передать в поиск мусор и ничего не найти или найти не то.

  • Устаревшие данные. Цены, наличие и статусы заказов меняются постоянно, а агент отвечает по тому, что нашёл десять минут назад. В е-коме это самая дорогая ошибка: человек выбрал товар по одной цене, а в корзине видит другую и уходит

  • Надёжность. Провайдер тормозит, инструмент отвалился, и без запасного сценария агент просто молчит. Авто.ру AI, например, при снижении производительности переключается на другую модель.

По моему опыту, самая больная проблема из этого списка это латенси.

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

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

Эксперимент

Давайте представим, что у нас есть ИИ-консультант магазина электроники: покупатель пишет, что ему нужно, консультант ищет товары в каталоге, смотрит отзывы и объясняет, какие подходят и почему.

Первый шаг, конечно, замер точки отсчёта. Как замеряю я, если коротко: снимаете показатели скорости ответа p50 и p95 времени на своём трафике. Если цифры вас не устраивают,
то три лайфхака, которыми я ускоряю ответ агента,

  • Пакетные передача данных. Отзывы сразу по всем кандидатам одним вызовом, а не по товару за раз. Меньше вызовов модели и меньше перечитываний переписки.

  • Быстрый путь вместо агентного цикла. Понятные запросы вроде «наушники с шумоподавлением до 5000» разбираю правилами: код сам собирает фильтры и ищет товары, модель вызывается один раз объяснить выбор. Агентный цикл остаётся для длинных личных запросов.

  • Короткие объяснения. Прошу описывать товар не длиннее 12-16 слов. Звучит мелко, а по времени даёт больше, чем два предыдущих приёма вместе. И 16 слов более чем достаточно для описания коротких характеристик

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

Дальше остаётся менять модель, и смотреть при выборе надо на две метрики. Скорость генерации, токенов в секунду на вашем железе или по API, она решает, сколько человек ждёт готовый ответ. И TTFT, время до первого токена, она решает, как быстро в чате вообще начнёт что-то печататься.

Первая важнее: стриминг маскирует ожидание, только если есть что показывать сразу, а у агента с RAG показывать нечего, пока идёт поиск.

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

Можно ли кэшировать ответ агента, если это товары? Короткий ответ: можно, но.....

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

  • Ядро: какие товары подходят и почему. Меняется медленно, вместе с ассортиментом и отзывами. Может жить сутки.

  • Цена, наличие, доставка. Меняются постоянно. Например если взять те же маркетплейсах, продавцы с репрайсерами меняют цены десятки раз в день.

  • Персонализация: порядок товаров и акценты под конкретного человека, под запрос и т.д

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

Из каких слоев состоит кэш моего ИИ-консультанта магазина электроники?

  1. Точный кэш. Для того чтобы искать по словам.

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

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

Если в двух слоях кэши ничего не нашли только тогда идем к агенту, а ядро его ответа кладём в кэш.

Давайте разберем сначала два слоя кэша: точный по ключевому слову и семантический, а слоты разберем в конце, так будет проще и понятнее

Схема как запрос пользователя обрабатывается с помощью архитектуры кэширования. Разбор ниже

Схема как запрос пользователя обрабатывается с помощью архитектуры кэширования. Разбор ниже

Точный кэш

Самый простой слой: ключ это текст запроса, значение это готовый ответ. У каждой записи свой срок жизни. Хранилище я буду использовать знакомый всем Redis но экспериментировал на его форк Valkey.

Тексты (запросы) перед этим причёсываем: нижний регистр, «ё» меняем на «е», лишние пробелы убираем, «5 000 ₽» превращаем в «5000 руб» и т.д

Два правила, за которые я дебажил со слезами:

  • Числа и отрицания не выкидываем. Заманчиво убрать «до 5000» как мусор и получить один ключ на бюджет пять тысяч и десять. Так не нужно оставляйте

  • В ключ кладём не только текст, но и версию промпта, модель и город. Иначе выкатили новый промпт, а люди ещё сутки получают ответы от старого.

Работает это слой кэша с дословными повторами, и их оказалось больше, чем кажется, например: «телевизор 55 дюймов» все пишут одинаково. У меня этот слой покарывает порядка 20-25% всех запросов. Это прям много и хорошо

Кстати писать руками этот сервис совсем не обязательно: в RedisVL и GPTCache это уже есть из коробки.

Семантический кэш: отвечает на вопрос насколько этот запрос похож на то что у нас есть в сохраненных ответах?

Семантический слой работает так: Приходит запрос пользователя, переводим в числовое представление – в вектора, далее вызываем поиск, поиск возвращает одно число косинусное сходство, от 0 до 1: единица значит «тексты про одно и то же», ноль «про разное». И всё решение, отдать ответ из кэша или идти к агенту, сводится к одному порогу: выше отдаём, ниже считаем заново. Вопрос только в том, где этот порог поставить. У меня порог 0.75

Как этот слой собран у меня:

  • Модель эмбеддингов bge-m3: знает русский, работает локально, влезает в маленькую тачку.

  • Векторы лежат там же, в Redis: векторный поиск в нём встроенный, отдельная база не нужна.

  • Порядок слоёв: сначала точный кэш, на промахе семантический, и только потом агент. Дешёвое первым: эмбеддинг стоит десятки миллисекунд, вызов модели секунды.

Порога, который ловит перефразы и при этом не склеивает соседние товары, не существует. На 0,75 находится 97% перефраз и склеивается 60% разных товаров. На 0,9 склеек меньше, но и перефраз находится всего 38%. Другая модель эмбеддингов не помогает, добавление поиска по ключевым словам тоже: я перебрал гибрид BM25 с векторами во всех весах и порогах, рабочей точки нет ни одной.

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

Тогда нужен ли этот слой? Я скажу да, перефразы она находит отлично, а это и есть весь хвост промахов после точного кэша. Семантический поиск просто не должен выбирать товар.

А как это сделать? С помощью тех самых слотов.

Слоты

Слот – это поле, которое правила вынимают из запроса и которое меняет ответ. Например: Запрос «наушники с шумоподавлением до 5000 для бега» разбирается так:

Слот

Значение

категория

наушники

особенность

шумоподавление

бюджет

5000

остаток

для бега

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

Отдельно про остаток – это все слова, которых правила не знают: «для бега», «водонепроницаемые», «шумкой». Выкинуть его нельзя: выкинете и «наушники до 5000» сравняются с «наушники до 5000 для бега», а человек с бегом получит чужую подборку. С остатком же запрос с незнакомыми словами просто не найдёт себе пары в кэше: промах, идём к агенту. Лишний вызов модели дешевле неправильного ответа.

Дальше слоты и остаток склеиваются в одну строку паспорт запроса: category=headphones|price_max=5000|rest=для,бега. Все прошлые запросы с таким же паспортом лежат на одной полке, я называю её партицией. Внутри полки товары гарантированно одни и те же: тот же бюджет, та же категория, те же характеристики.

Вот теперь включаем семантику, но только внутри полки. Раньше векторы искали похожий вопрос по всему складу и путали iPhone 15 с 15 Pro, а теперь товар зафиксирован полкой, и у векторов остаётся единственная работа, с которой они справляются отлично: узнать перефразу.

Вот кусочек кода:

def lookup(query: str):
    key = normalize(query)
    if entry := exact.get(key):             # 1. дословный повтор
        return entry
    part = signature(extract_slots(query))  # 2. паспорт запроса
    if part is None or part not in partitions:
        return None                         # категорию не поняли или полка пуста
    vec = embed(key)                        # 3. эмбеддинг считаем только здесь, ~75 мс
    entry, sim = partitions[part].nearest(vec)
    return entry if sim >= 0.75 else None   # порог низкий: товары уже развели слоты

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

И порог ранжирования семантического поиска упал до 0,75 вместо туториальных 0,95. Раньше высокий порог был единственной защитой от «перепутать товар» и он же мешал узнавать перефразы. Теперь товары разводят слоты, а семантике можно искать свободно.

Кэш инструментов

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

На моих прогонах две разные формулировки одного запроса приводили модель к одинаковым аргументам поиска в 15 интентах из 30, а отзывы по одним и тем же товарам пересекались примерно на две трети.

Проверка перед показом

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

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

Архитектура такая у меня получилась

финал

финал

Когда этим вообще стоит заниматься?

Честно: не всем. Ориентир по трафику простой. Больше 5 000 запросов в день эффект заметен и по деньгам, и по скорости. Меньше 1000 не тратьте ни деньги, ни время команды

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

Сколько это собирать и что даёт

Весь пайплайн я собрал за неделю плюс тесты. Это не квартальный проект, а спринт одного разработчика.

Цифры с прода: схема работает месяц, полёт нормальный. На A/B-тесте получили +12% к конверсии для нас это очень много, вложения окупились сразу. У вас будет иначе, но посчитать предел стоит до того, как начнёте: сколько стоит сэкономленная секунда именно в вашей воронке.

Апдейты по флоу выложу через пару месяцев теста, когда накопится статистика.

Статью я решил закончить на этой ноте ❤️ Спасибо, что потратили время и прочитали.

Полезные ссылки: Telegram-канал «AI-заметки продакта» — рассказываю про ИИ-агентов, лайфхаки и полезные инструменты: https://t.me/ai_vdel. Там же отвечаю на вопросы и консультирую.

View the original on Хабр

KioskNews shows a cleaned-up reading view extracted from the publisher’s page — the original always lives on their site, not ours.