Почему агент на самом деле дешевле RAG. 1С.. 1С. ai.. 1С. ai. python.. 1С. ai. python. rag.. 1С. ai. python. rag. агенты.. 1С. ai. python. rag. агенты. агенты ии.. 1С. ai. python. rag. агенты. агенты ии. ИИ.. 1С. ai. python. rag. агенты. агенты ии. ИИ. ии-ассистент.. 1С. ai. python. rag. агенты. агенты ии. ИИ. ии-ассистент. искусственный интеллект.. 1С. ai. python. rag. агенты. агенты ии. ИИ. ии-ассистент. искусственный интеллект. Экономика агента.

Наивная арифметика, которая всех обманывает

Классический RAG-ассистент работает так: пользователь пишет вопрос → эмбеддинг → поиск в векторе → один вызов LLM для синтеза. Одна итерация. Чисто, быстро, дёшево. Если ответ правильный.

Проблема в том, что с первой попытки он правильный не всегда. Пользователь переспрашивает: «нет, я имел в виду другое». Ассистент делает второй запрос. Потом третий. К четвёртому переспросу пользователь машет рукой и зовёт живого оператора. Оператор тратит 10–15 минут, находит нужный документ, копирует абзац в чат. Вопрос закрыт. Стоимость вопроса — не 1 вызов LLM, а:

  • 4 вызова LLM на переспросы

  • 10–15 минут времени оператора

  • испорченное настроение пользователя

А теперь представим агента, который сам перебирает гипотезы внутри ReAct-цикла. Он не ждёт переспроса пользователя — он сам понимает, что первый результат неполный, и копает дальше. 4 итерации — и ответ готов. Вызовов LLM может быть больше, чем у ассистента. Но пользователь получил ответ с первой попытки, а оператор вообще не понадобился.

Главный тезис этой статьи: считать надо не стоимость одного ответа, а стоимость закрытого вопроса. И в этой метрике агент часто выигрывает.

Как устроен ReAct-цикл в ISTOK

Ядро агента — класс AgentEngine с методом execute. На входе — вопрос пользователя и системный промпт, на выходе — финальный ответ и лог всех действий.

Почему агент на самом деле дешевле RAG - 1

Пять инструментов агента

Агент вооружён пятью инструментами, каждый под свою задачу:

  1. VectorSearch — семантический поиск. Гибрид Dense (эмбеддинг) + BM25 через Milvus. Для концептуальных запросов: «как настроить», «проблемы с производительностью».

  2. Search — полнотекстовый поиск. ILIKE по PostgreSQL, поддержка регулярных выражений (~*). Для точных терминов: коды ошибок, идентификаторы, названия.

  3. OpenChunk — открыть полный текст найденного чанка. После VectorSearch или Search агент видит только summary; чтобы прочитать содержимое, нужен OpenChunk.

  4. GetDocumentChunks — оглавление документа. Позволяет агенту понять структуру, не открывая всё подряд.

  5. CallOperator — вызов живого оператора. Разрешён только после 2–3 собственных попыток поиска.

Агент сам решает, какой инструмент вызвать следующим. Жёсткого сценария нет: в одном вопросе он начнёт с VectorSearch, в другом — с Search по точному коду ошибки.

Честная история: как мы контекст держали (и теряли)

У агента есть проблема: каждый вызов LLM в цикле добавляет сообщения в историю. 15 итераций с результатами поиска — и контекстное окно забито. Что делать?

Версия 1: LLM-суммаризация

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

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

Версия 2: скользящее окно

Переписали на тупое, зато надёжное решение — скользящее окно:

DEFAULT_MAX_TOKENS = 120_000    # ~120K токенов — порог срабатывания
MIN_KEEP_MESSAGES = 6           # Минимум сообщений всегда сохраняется

При достижении порога просто удаляем старейшие tool-сообщения. Системный промпт и последние 6 сообщений неприкосновенны. Никаких дополнительных вызовов LLM. Грубо, но дёшево и без потери данных.

Суммаризация не выброшена полностью — она осталась как fallback, но с жёстким лимитом:

  • До 2 суммаризаций за сессию (после — переход на скользящее окно)

  • Каждая успешная суммаризация добавляет +5 к лимиту итераций

  • Промпт суммаризации требует сохранить: исходный вопрос дословно, ключевые находки, текущий лучший частичный ответ и ровно 2–3 шага плана

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

Не все вызовы LLM стоят одинаково

Ещё одно упрощение из наивной арифметики: считать, что каждый вызов LLM стоит одну и ту же цену. В ISTOK запросы к LLM-шлюзу разделены по типам:

class RequestType(str, Enum):
    EMBEDDING = "EMBEDDING"                 # Эмбеддинги — дёшево
    GENERATION_LIGHT = "GENERATION_LIGHT"   # Простые шаги цикла — дёшево
    GENERATION_MEDIUM = "GENERATION_MEDIUM" # Основной режим (по умолчанию)
    GENERATION_HEAVY = "GENERATION_HEAVY"   # Сложный синтез — дорого
    RERANK = "RERANK"                       # Реранжирование — дёшево

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

Правильная арифметика: стоимость закрытого вопроса

Давайте соберём всё вместе. Считаем не стоимость ответа, а стоимость вопроса, после которого пользователю больше не нужна помощь.

Вопрос пользователя — типичный для линии поддержки 1С-продуктов:

«После обновления на релиз 2.4 перестали создаваться обращения из писем. В журнале регистрации ошибка “Поле объекта не обнаружено (КаналСвязи)”. Настройки обмена не трогали. Что случилось?»

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

Сценарий A: ассистент (один запрос → синтез)

Попытка 1: ассистент находит общую инструкцию «Настройка загрузки
           писем» и отвечает: проверьте учётную запись, пароль
           и расписание регламентного задания            — 1 × LLM
Пользователь: «настройки не менялись, ошибка про поле КаналСвязи,
              появилась сразу после обновления»
Попытка 2: ассистент находит описание справочника «Каналы связи»
           и советует проверить его заполнение          — 1 × LLM
Пользователь: «справочник заполнен, ошибка именно при загрузке писем»
Попытка 3: ассистент добирается до заметок релиза 2.4 и наконец
           отвечает про переименование поля             — 1 × LLM
──────────────────────────────────────────────────────────────
Итого: 3 вызова LLM + 2 переспроса пользователя
Время пользователя до получения ответа: ~5–8 минут

Сценарий Б: агент (ReAct-цикл) — тот же вопрос, та же база знаний:

Итерация 1: VectorSearch по полному тексту вопроса → 5 чанков: общая
            инструкция по загрузке писем, справочник каналов и заметки
            релиза 2.4. Агент видит по summary: в заметках релиза,
            скорее всего, причина                       — 1 × LLM (GENERATION_MEDIUM)
Итерация 2: OpenChunk «Изменения в релизе 2.4» → находит: «поле
            КаналСвязи переименовано в КаналСвязиИсточника, требуется
            обновление соответствий в настройках обмена»
                                                      — 1 × LLM (GENERATION_MEDIUM)
Итерация 3: Search по точному термину «КаналСвязиИсточника» →
            инструкция «Миграция настроек обмена после обновления 2.4»
                                                      — 1 × LLM (GENERATION_MEDIUM)
Итерация 4: OpenChunk инструкции по миграции → три конкретных шага
            для обмена с почтой                         — 1 × LLM (GENERATION_MEDIUM)
Итерация 5: синтез финального ответа со ссылками      — 1 × LLM (GENERATION_HEAVY)
──────────────────────────────────────────────────────────────
Итого: 5 вызовов LLM (4 средних + 1 тяжёлый)

Ответ, который пользователь получил через ~40 секунд:

Причина найдена: в релизе 2.4 поле «КаналСвязи» переименовано в «КаналСвязиИсточника», поэтому настройки обмена, созданные до обновления, больше не совпадают со структурой данных [1]. Чтобы восстановить загрузку писем:

  1. откройте настройки обмена,

  2. запустите обработку «Обновление соответствий каналов связи»,

  3. перезапустите регламентное задание загрузки [2].

Источники: [1] «Изменения в релизе 2.4», [2] «Миграция настроек обмена после обновления 2.4».

Да, у агента на два вызова LLM больше. Но:

  • 4 из 5 вызовов идут как GENERATION_MEDIUM (дешевле тяжёлого синтеза)

  • Пользователь получил ответ с первой попытки — и не абстрактный «проверьте настройки», а причину, три шага решения и ссылки на источники

  • Ни один оператор не отвлёкся от своей работы

А теперь добавим сценарий, где ассистент не справляется вообще:

  • 4 переспроса × LLM → ответа нет

  • Эскалация на оператора → 15 минут рабочего времени → стоимость ~150₽ (при средней ставке 600₽/час)

  • Агент справляется за 6 итераций → меньше минуты → стоимость только LLM-токенов

В этом и есть суть: агент сам перебирает гипотезы вместо того, чтобы заставлять пользователя делать это вручную через переспросы.

Почему агент на самом деле дешевле RAG - 2

Контроль: что мы считаем и как

Выводить экономику «на глаз» мы не стали — агент сам ведёт бухгалтерию по каждой сессии. Что попадает в лог:

  • Каждый вызов LLM фиксируется вместе с usage из ответа провайдера: сколько токенов ушло в промпт, сколько вернулось в ответе. Ни один вызов не теряется — ни поисковый, ни синтез, ни суммаризация.

  • Итоги по сессии. По завершении ReAct-цикла агент складывает всё в четыре числа: prompt-токены, completion-токены, общая сумма и количество вызовов LLM. Умножаем на тариф модели — получаем себестоимость сессии с точностью до копейки.

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

Сверху всё это накрыто трейсингом: каждый ReAct-цикл уходит в Arize Phoenix, где можно разложить сессию по итерациям — каждый вызов инструмента, каждый запрос к LLM, итоговые токены. Именно оттуда взяты цифры из следующего раздела.

Результаты: цифры одного небольшого проекта

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

Метрика

Ассистент

Агент

Вызовов LLM на сессию

1

6,4

Переспросов пользователя до закрытия вопроса

2,3

0,3

Сессий с эскалацией на оператора

34%

11%

Среднее время до закрытия вопроса

27 минут

4 минуты

Токенов на закрытый вопрос

~18 000

~15 500

Наивная арифметика из начала статьи подтвердилась: агент действительно делает в 6 раз больше вызовов LLM. Но дальше цифры расходятся с интуицией. Переспросы — главный скрытый множитель стоимости ассистента — упали в 7 раз: агент перебирает гипотезы сам, не дожидаясь уточнений пользователя. Эскалации упали втрое. А токены оказались почти одинаковыми: у ассистента каждый переспрос — это повторный вызов с раздутым контекстом, а у агента бо́льшая часть вызовов дешёвые.

Теперь переведём в деньги. Сами токены стоят копейки: закрытый вопрос ассистента обходится в ~0,9₽ токенов, агента — в ~0,5₽. Другое дело — оператор. Пятнадцать минут работы специалиста при средней ставке ~600₽/час — это 150₽ на каждую эскалацию. Раскладываем на все вопросы:

  • Ассистент: 0,34 × 150₽ + 0,9₽ ≈ 52₽ за закрытый вопрос

  • Агент: 0,11 × 150₽ + 0,5₽ ≈ 17₽ за закрытый вопрос

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

Почему агент на самом деле дешевле RAG - 3

Ограничения

Агент — не серебряная пуля, и у нашей арифметики есть границы. Честно про все три.

Простые фактологические вопросы. «Какой порт у сервиса X?», «Какая версия PostgreSQL поддерживается?» — на таких вопросах агент объективно проигрывает. Ассистент отвечает за один запрос и пару секунд. Агент сделает минимум две итерации — поиск и синтез — и потратит вдвое больше токенов за ровно тот же результат. Если вся ваша входящая линия состоит из справочных вопросов, ReAct-цикл вам не нужен: хватит простого ассистента. Экономия агента рождается из сложности — там, где ответ не лежит в одном чанке, а собирается из трёх документов и кода ошибки.

Пустая или нерелевантная база знаний. Никакой цикл рассуждений не компенсирует отсутствие данных. Если искать нечего, ассистент честно скажет «не знаю» за один вызов, а агент перед тем же ответом пройдёт 2–3 итерации вхолостую: переберёт VectorSearch, Search, попробует синонимы — и только потом признает поражение. Дороже и медленнее при том же исходе. Поэтому агент включается там, где база знаний уже наполнена — в нашем случае импортом истории обращений, но это тема отдельной статьи.

Неопределённые вопросы. «Расскажите что-нибудь про интеграции» — худший сценарий для агента. У него нет точки опоры: любой поиск что-то вернёт, любой результат можно «уточнить». Агент добросовестно исследует все направления, пока не упрётся в лимит итераций, и выдаст обзор, который пользователю, скорее всего, не нужен. Хорошая новость: на реальной линии поддержки таких вопросов немного — люди приходят с конкретной болью, а не за лекцией.

Заключение

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

Автор: Semen-Chernov

Источник