Domain-routed agents vs naive RAG: экономика и риски архитектурного выбора

от автора

Недавно я решил провести настольную ролевую игру по Vampire: The Masquerade. Это был первый опыт и в роли Рассказчика, и по этой вселенной. Книги правил — сотни страниц текста: лор, механика, клановые особенности, исключения из исключений. Приходилось постоянно сверяться и с книгой, и с официальной вики, и на ходу отвечать игрокам, для которых мир был тоже в новинку.

Можно было бы спрашивать у LLM, но она уверенно галлюцинировала — мешала старые редакции с новой, путала факты, придумывала несуществующие механики. Зато для игры есть богатейшая официальная вики, в которой статьи ссылаются на официальные книги правил. Из боли начинающего Рассказчика и наличия отличной базы знаний родилась идея: собрать экспертную систему по VTM, которая отвечает строго по правилам. Очевидно — задача под RAG.

Но по причинам, описанным дальше, мы будем делать кое-что другое: domain-routed агента — мультиагентный граф, где Router направляет запрос экспертам по доменам знаний, а те через read_document сами выбирают и читают нужные файлы.

Контекст применения такого агента:

  1. Ограниченный объем данных — база знаний малого или среднего размера, которая физически помещается в контекстное окно современных моделей.

  2. Управляемая структура — информацию можно разбить на несколько крупных смысловых доменов и при необходимости поддерживать их вручную.

  3. Редкие обновления — данные относительно статичны, нет потребности в частом обновлении базы знаний.

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

Если убрать тематику Vampire: The Masquerade, под это описание отлично ложатся реальные корпоративные кейсы: юридические документы, compliance-политики, инженерные регламенты или медицинские протоколы.

База знаний

Источником стала официальная вики сообщества.

Здесь есть важный юридический нюанс. Правила франшизы (Dark Pack Agreement) строго запрещают публичным ботам выдавать прямые дословные цитаты из книг правил. Но статьи на вики изначально написаны в рамках безопасного пересказа, поэтому агент может спокойно цитировать их «как есть».

Правда, сама вики оказалась спрятана за защитой Fastly, которая отбрасывала простые HTTP-запросы ошибкой 403 Forbidden. Но поскольку материалы вики распространяются по лицензии Creative Commons (CC BY-SA 3.0), а у wiki-движка есть открытое API, я позволил себе спарсить содержимое с помощью Playwright — с сохранением атрибуции источника, как того требует лицензия.

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

Оставшееся разложил по 7 доменам:

Домен

Файлов

Объем (≈ токенов)

Что внутри

mechanics

49

~280K

Броски, боевка, Голод, Человечность, состояния

disciplines

17

~120K

Вампирская магия и ее эффекты

lore

38

~100K

Понятия мира, фракционные события, термины

clans

19

~100K

Слабости и особенности 14 кланов

factions

10

~70K

Камарилья, Анархи, Шабаш, Инквизиция

skills

29

~50K

Навыки и их применение

attributes

14

~30K

Атрибуты персонажа

Итого — 176 файлов примерно на ~750K токенов.

Все документы сохранены в формате .md. Я намеренно не стал вычищать текст от исходной вики-разметки, таблиц и специфичных тегов. Современные LLM отлично парсят Markdown и умеют извлекать полезный контекст из сложной структуры.

Профиль вопросов: с чем приходят пользователи

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

Уровень 1 — Поиск факта. Простой запрос конкретного правила или инструкции: «Как настроить корпоративный VPN?» или «Какие обязательные поля у сущности User?». Ответ содержится в одном конкретном абзаце базы знаний.

Уровень 2 — Синтез. Вопросы, требующие сопоставления нескольких фактов: «Чем процесс деплоя микросервисов на staging отличается от выкатки на production?». Для ответа нужно найти и объединить описания двух разных окружений и регламентов.

Уровень 3 — Кросс-доменные кейсы. Рабочие ситуации, где пересекаются несколько несвязанных напрямую областей. Например: «Разрешено ли оплатить услуги зарубежного подрядчика с корпоративной карты, если сумма закупки превышает базовый лимит, но проводится без тендера?». Здесь нужно одновременно учесть регламент отдела закупок, политику безопасности (комплаенс) и внутренние финансовые лимиты, которые могут работать как исключения из общих правил.

Уровень 4 — Out-of-scope. Вопросы о том, чего в базе нет. Это могут быть как вопросы смежной специфики (например, запрос HR-регламента об отпусках в базе технической документации), так и запросы абсолютно вне домена (рецепт пиццы или советы по ремонту авто). Система должна не придумывать ответ из общих знаний LLM, а сказать, что нужной информации не существует в базе знаний или она вне домена.

Агентская архитектура

Вернемся к вампирам и посмотрим, как задачу решает живой Рассказчик:

  1. Выслушал вопрос игрока.

  2. Понял, о каких областях речь: «ага, здесь про механики бросков, а здесь про особенности клана.»

  3. Открыл нужную книгу в разделе «Механики» — нашел правило.

  4. Открыл раздел «Кланы» — нашел исключение.

  5. Сопоставил их в голове и выдал игроку итоговый вердикт.

Классический RAG здесь ломается по дизайну. Векторный поиск, оперирующий чанками по 800 токенов (overlap 120), ищет смысловое сходство текста, а не логические зависимости. Он отлично находит базовое правило (так как его вектор ближе всего к словам из вопроса), но семантически «не видит» исключений, разбросанных по другим разделам. Исключения часто сформулированы в иных терминах и документах другой тематики. Из-за этого их векторы оказываются слишком «далеко» от исходного запроса, и они просто не попадают в top-6 выдачи, которую ретривер передает в LLM. Чтобы заставить RAG решать кросс-доменные кейсы, понадобится выстраивать сложный GraphRAG (Knowledge Graphs) — это дорого и долго в переводе на трудовые часы разработчиков.

Противоположная крайность — свалить все 176 файлов (~750K токенов) в один гигантский промпт современной LLM. Да, технически контекстное окно в 1 миллион токенов позволяют это сделать, но на практике такой подход ломается по двум причинам:

  1. Эффект «Lost in the Middle». Когда модель получает «простыню» ее внимание размывается. Она неплохо помнит начало и конец контекста, но начинает терять факты в середине. На практике это выглядит так: модель улавливает общую суть (например, базовый процесс), но «забывает» применить точный числовой лимит или важное исключение, спрятанное где-то на 40-й странице сырого текста.

  2. Экономика и Latency (скорость ответа). Прогонять почти миллион токенов на каждый вопрос пользователя — это не только дорого. Это еще и медленно. Время до первого токена (Time To First Token) при обработке огромного контекста неизбежно растет.

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

  • Blackboard (Общая доска) — хранилище состояния графа. Сюда складываются извлеченные факты, из которых будет формироваться ответ.

  • Router (Роутер) — узел анализирует исходный вопрос и текущее состояние Blackboard. Его единственная задача — вернуть список экспертов, которых нужно подключить к работе (например, ["ClansExpert", "MechanicsExpert«]), либо вернуть пустой список [], если информации уже достаточно.

  • Experts (Эксперты) — параллельные агенты, каждый из которых отвечает за свой домен знаний. На старте работы эксперт получает в системный промпт только свой манифест — названия файлов и краткое описание содержимого. Он решает, какие файлы ему нужны, и вызывает инструмент read_document(doc_id). Прочитав нужные файлы, эксперт извлекает из них полезные факты и кладет в Blackboard.

  • Synthesizer (Синтезатор) — узел вступает в работу последним, забирает все факты с Blackboard и формирует итоговый ответ.

Архитектура графа LangGraph: Router -> Experts -> Synthesizer

Архитектура графа LangGraph: Router -> Experts -> Synthesizer

Как это работает в динамике (на примере кросс-доменного кейса про Тореадора):

  1. Старт: Пользователь задает вопрос: «Я играю Тореадора-художника. Что произойдет, если я провалю проверку Голода во время создания картины в галерее?».

  2. Маршрутизация: Роутер видит пустой Blackboard и ключевые слова «Тореадор», «проверку Голода» и контекст «создание картины». Он принимает решение запустить параллельно трех экспертов: ClansExpert, MechanicsExpert и SkillsExpert.

  3. Параллельное извлечение:

  • ClansExpert смотрит в свой манифест, понимает, что ему нужен файл Toreador. md, и вызывает инструмент read_document("Toreador«). Прочитав файл, он пишет на Blackboard факт: «Бестиальный провал вызывает клановую Компульсию Тореадоров — Одержимость (Obsession), при которой они зацикливаются на одном объекте и получают штраф в 2 кубика».

  • MechanicsExpert параллельно смотрит в свой манифест, вызывает read_document("Hunger_system«) и после прочтения файла пишет факт: «Выпадение единицы на кубиках Голода вызывает бестиальный провал (Bestial Failure) или потерю контроля».

  • SkillsExpert тоже подключается: из контекста «художник» и «создание картины» он смотрит в свой манифест и вызывает read_document("Craft«), но после прочтения файла не находит ничего, что относится к последствиям провала проверки Голода, — и на Blackboard ничего не добавляет.

  1. Проверка достаточности: Граф заходит на второй цикл. Роутер снова читает Blackboard, видит, что оба нужных правила уже найдены, и возвращает пустой список []. Примечание: для защиты от бесконечного поиска установлен лимит итераций.

  2. Синтез финала: Синтезатор берет факты с Blackboard, связывает их с контекстом ситуации (галерея) и выдает итоговый ответ: «Если вы выкинете единицу на кубиках Голода, произойдет бестиальный провал. Из-за вашей клановой слабости это спровоцирует Одержимость: ваш Тореадор полностью зациклится на картине и получит штраф в 2 кубика на любые другие действия, сорвав сцену».

Граф работает, но за каждое усложнение пайплайна мы платим задержкой и токенами. Чтобы оправдать эти затраты, мы должны быть уверены, что качество ответов агента превосходит дешевый векторный RAG. Нам нужны измеримые метрики.

Оценка качества: RAG против Агентов

Обычные юнит-тесты в мире LLM не работают. Нельзя просто написать assert answer == "Тореадор бросает кубик", потому что генеративная модель каждый раз будет формулировать ответ иначе. Вместо сравнения строк оценивают смысловую полноту: присутствует ли в ответе нужный факт и не придумала ли модель лишнего. Но прежде чем настраивать такие проверки, нам нужен «золотой стандарт» — качественный и репрезентативный датасет.

Я собрал стартовый датасет из 40 вопросов. В него вошли по 10 вопросов на поиск конкретных фактов (Уровень 1), на синтез информации (Уровень 2) и на кросс-доменные кейсы (Уровень 3). Еще 5 проверяли защиту от галлюцинаций (вопросы по старому лору, которого нет в текущей базе), а последние 5 представляли собой вопросы вне домена — вроде кулинарных рецептов или программирования.

Почему именно 40? Ждать «идеальный» датасет на сотни примеров — значит неделями не трогать архитектуру. Для первой итерации достаточно собрать 10–50 кейсов «быстро и грязно» и прогнать через пайплайн. 40 ответов можно вдумчиво разобрать за 15–20 минут — этого хватает, чтобы отловить большинство системных проблем. 500 — это уже выгорание и заброшенный проект.

Для каждого из этих 40 вопросов я вручную составил чек-лист: список фактов, которые обязательно должны присутствовать в ответе. Затем я загрузил этот мини-датасет в Langfuse. Это позволило запускать Langfuse Dataset Run, автоматически логируя сами ответы, время генерации, промпты и стоимость каждого вызова.

Получив такой пайплайн для оценки, я прогнал датасет через две разные архитектуры: собранный на коленке наивный векторный RAG и нашего LangGraph-агента.

Важная оговорка про бейзлайн: это не production RAG и не потолок того, что можно выжать из retrieval месяцами тюнинга. Baseline — нижняя граница «из коробки»: Chroma + multilingual-e5-small, чанки 800 токенов (overlap 120), top-6, чистый semantic search без BM25, без фильтрации по домену, без reranker. Мы сравниваем domain-routed агента с намеренно простым оппонентом — чтобы показать, где ломается наивный подход, а не доказать, что любой RAG хуже агента.

Если посмотреть на сухие цифры, получается следующая картина:

  • Уровень 1 (Поиск факта): Точность RAG составила 18% (4 из 22 фактов), Агента — 86% (19 из 22).

  • Уровень 2 (Синтез): RAG справился на 32% (9 из 28 фактов), Агент — на 64% (18 из 28).

  • Уровень 3 (Кросс-домен): RAG выдал лишь 10% верных утверждений (3 из 31), Агент — 77% (24 из 31).

  • Защита от галлюцинаций (лор): RAG выполнил 60% критериев (9 из 15), Агент — 80% (12 из 15).

  • Вне домена (Out-of-Domain): RAG соблюдал инструкции безопасного отказа в 40% случаев (4 из 10 критериев), Агент — лишь в 20% (2 из 10).

Вот более детальный разбор:

1. RAG провалился на простых фактах (Уровень 1) Казалось бы, обычный векторный поиск должен легко справляться. Но на практике «из коробки» чистый семантический поиск без BM25 работает не очень хорошо. Слепому чанку часто не хватает контекста и метаданных. Агент же вытягивал целые документы экспертами и находил ответы с высокой точностью (86%).

2. Преимущество Агента на кросс-домене (Уровень 3) На вопросах, где требовалось связать несколько механик из разных разделов, RAG находил только одно из ограничений (то, которое имело наибольшее векторное сходство), но игнорировал остальные условия. Агент понимал, что нужно учесть и базовые правила, и специфические модификаторы, выстраивая из них логичную цепочку следствий.

3. Избыточная креативность Агента (Ловушка Out-of-Domain) На вопросах вне контекста базы знаний RAG оказался безопаснее: не найдя релевантных чанков, он просто следовал системному промпту и отвечал «в базе нет информации». Агент же отвечал на бытовой вопрос через игровые механики. Ответ про замену масла через бросок кубиков на Ремесло формально валиден внутри RPG, но это именно нарушение продуктового контракта: при разметке датасета мы жестко определили, что подобные бытовые вопросы считаются «вне домена» (out-of-domain) и должны получать отказ. Поэтому мы считаем такой ответ неверным.

Observability: пошаговая отладка графа

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

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

Открыв дерево вызовов для вопроса про моторное масло, я смог пошагово отследить весь путь:

  1. Роутер честно затриггерил экспертов по навыкам (skills_expert) и базовым механикам (mechanics_expert).

  2. Эксперты прочитали документы. В файле skills_craft сказано, что навык Craft отвечает за создание, сборку и починку вещей. Он положил на Blackboard факт: «Техническое обслуживание автомобиля, такое как замена масла, попадает под навык Ремесло (Craft)». Второй эксперт добавил к этому общие правила бросков кубиков Голода.

  3. А вот Синтезатор ошибся: получив эти факты из Blackboard, он не распознал бытовой контекст вопроса и описал замену моторного масла через игровые механики. Такой ответ может быть верным (в рамках ролевой сессии персонаж действительно может чинить машину), но в нашем датасете они отнесены к категории out-of-domain, поэтому засчитываем его как неверный. Ожидаем, что пользователь точнее сформулирует вопрос, если такое возникнет в игре, т. к. это экспертная система, а не чат бот.

Поняв, в каком именно узле кроется проблема, я добавил инструкцию в системный промпт Синтезатора: «Если вопрос касается реального мира (out-of-domain) — прямо откажись отвечать, не пытайся натягивать реальные задачи на игровые механики».

Запуск нового эксперимента на датасете подтвердил, что на нерелевантные вопросы Агент стал вежливо отказывать.

Но исправление промпта неожиданно улучшило не только out-of-domain:

  • Out-of-Domain: резкий рост с 20% до 70% (Агент перестал применять игровые правила к реальному миру).

  • Синтез: рост с 64% до 79%.

  • Защита от галлюцинаций: рост с 80% до 87%. Остальные категории (Поиск факта и Кросс-домен) остались без изменений (86% и 77%).

Недетерминированность LLM и стабильность оценки

Дело в том, что LLM недетерминированы и генерируют разные ответы на один и тот же запрос. И проблема не в том, что промпт Синтезатора магически повлиял на другие узлы. Оценивать качество системы по одному прогону некорректно. Чтобы получить статистически достоверную картину, нужно оценивать стабильность и воспроизводимость ответов на нескольких запусках.

Поэтому мы провели по 5 независимых экспериментов на всем датасете с дефолтной и нулевой температурой генерации и посчитали среднюю точность:

  • Дефолтная температура: средний score 78.8% (разброс 6.9 п. п. — от 74.3% до 81.2%).

  • Нулевая температура: средний score 79.8% (разброс 5.0 п. п. — от 76.2% до 81.2%).

Как видно, даже при temperature=0.0 сохраняется заметная недетерминированность: разброс результатов между лучшим и худшим прогоном составляет 5.0 п. п. (в сравнении с 6.9 п. п. при дефолтной температуре). По 5 прогонам на режим тенденция складывается в пользу нулевой температуры: средний результат на ~1 п. п. выше, а размах меньше. Оговорюсь, что выборки из 5 запусков мало для строгого статистического вывода — это скорее ориентир, чем доказанный факт. Тем не менее temperature=0.0 не ухудшает результат и интуитивно стабильнее, поэтому в дальнейшем мы будем использовать именно ее.

Для офлайн-оценки стабильности и поиска узких мест в пайплайне Langfuse подходит отлично. Но в продакшене его роль сводится скорее к расследованию инцидентов: собирать задержки, стоимость и качество ответов через Metrics API платформа умеет, а вот отправлять пороговые алерты в self-hosted-версии — нет. В облаке Langfuse этот функционал есть (инструмент Monitors с уведомлениями в Slack или вебхуки), но для полноценного онлайн-мониторинга лучше использовать Prometheus + Grafana. С ними мы можем в реальном времени отслеживать p95 стоимости успешных ответов, сквозную задержку и частоту превышения лимита шагов для выявления зациклившихся агентов.

Задержки, лимиты и скорость генерации токенов

Качество — половина истории. На eval-прогоне датасета (40 вопросов, Gemini 3.1 Flash-Lite) Langfuse дает такую картину по сквозной задержке (end-to-end latency) — от вопроса на входе до финального ответа Синтезатора:

Перцентиль

Latency

p50

12,7 с

p90

29,0 с

p95

39,2 с

p99

55,6 с

Медианный ответ укладывается в ~13 секунд — терпимо для Telegram-бота во время игровой сессии. Но хвост распределения жесткий: каждый двадцатый запрос (p95) ждет почти 40 секунд, а на p99 — почти минуту.

Откуда берется такая задержка? Ведь сама Gemini 3.1 Flash-Lite очень быстрая — ее скорость генерации достигает 107 токенов в секунду. Дело в том, что узкое место здесь — не скорость генерации, а количество последовательных обращений к модели на критическом пути выполнения графа.

На кросс-доменном вопросе вроде примера с Тореадором граф проходит два цикла Router, три параллельных Expert (один из которых не находит полезных фактов) и один Synthesizer. При этом один узел графа не равен одному вызову LLM: каждый эксперт сначала выбирает файл через tool call (первый вызов), а затем отдельным запросом извлекает факты из прочитанного документа (второй вызов). Итого для сценария, когда три эксперта читают по одному файлу, мы получаем 9 обращений к модели (Router 1 + Expert × 6 + Router 2 + Synthesizer), часть из которых выполняется параллельно, а часть — строго последовательно.

Если замерить задержки одиночных вызовов модели, мы получим вполне стандартную картину:

  • p50 (медиана): ~1,19 с

  • p90: ~2,75 с

  • p95: ~4,01 с

  • p99: ~8,66 с

А теперь сложим это в цепочку. Даже с учетом параллельного запуска экспертов, критический путь (critical path) последовательных вызовов в нашем графе в идеальном случае состоит из 5 шагов (Router 1 → Шаг 1 Экспертов → Шаг 2 Экспертов → Router 2 → Synthesizer).

Но на сложных, спорных или неоднозначных вопросах (которые как раз и формируют «хвост» задержек на p95) поведение агента меняется. Он начинает искать ответ гораздо старательнее: роутер уходит на дополнительные круги, а эксперты последовательно открывают и читают новые файлы, совершая до 8 и более вызовов за один прогон. В результате количество последовательных шагов на критическом пути легко вырастает до 10–12.

Реальная динамика объясняет итоговые перцентили:

  • В медианном сценарии (p50) критический путь укладывается в стандартные 5–7 шагов. При медианной задержке одиночного запроса к модели в ~1,19 с, с учетом сетевых задержек, накладных расходов LangGraph и времени на извлечение данных, мы получаем наблюдаемые 12,7 с.

  • На p95 латентность возрастает до 39,2 с. Дело в том, что на сложных вопросах поведение агента меняется: роутер уходит на дополнительные круги, а эксперты последовательно открывают и читают новые файлы. Количество последовательных шагов на критическом пути вырастает до 10–12. Кроме того, на таких запросах модель обрабатывает намного больше контекста и генерирует длинные детальные ответы, что резко увеличивает TTFT (Time to First Token) и время генерации на стороне LLM-провайдера.

  • На p99 (55,6 с) к максимальному количеству шагов и огромному контексту добавляются сетевые таймауты, просадки производительности самого API-провайдера и повторные попытки (retries) после получения ошибок вроде 429 (Too Many Requests).

Архитектурно наивный RAG работает в разы быстрее: по грубой оценке (один retrieval + один вызов модели), он укладывается в 5-10 секунд. Мы сознательно платим десятками секунд за точность на кросс-домене, но этот компромисс нужно учитывать при проектировании интерфейса. Если продукт требует мгновенного синхронного отклика, задержка в 40 секунд убьет пользовательский опыт, и здесь безальтернативно нужен быстрый RAG. Эта агентская архитектура подходит только для асинхронных сценариев (мессенджеры, фоновые отчеты), где качество ответа важнее времени ожидания.

Если говорить о нагрузке и лимитах запросов, то один кросс-доменный ответ — это в среднем 7 обращений к модели на нашей стороне. Что касается лимитов, то OpenRouter не публикует конкретных цифр и не накладывает собственных ограничений, транслируя лишь лимиты конечного провайдера. Точных лимитов для Gemini 3.1 Flash-Lite мне найти не удалось, но порядок величин можно грубо оценить по аналогичным моделям. Например, у gpt-5.4-mini на максимальном уровне (Tier 5) лимиты составляют 30 000 RPM (запросов в минуту) и 180M TPM (токенов в минуту).

Если предположить, что лимиты провайдера Gemini находятся в том же порядке величин, то по RPM один кросс-доменный ответ «стоит» 7 слотов: 30 000 ÷ 7 ≈ 4 300 полных ответов бота в минуту до исчерпания квоты. По TPM потолок наступит раньше только в патологическом сценарии: ~240 параллельных запросов, каждый из которых за один прогон прочитает всю базу (~750K токенов): 180M ÷ 750K ≈ 240.

Для Telegram-бота запас по квотам огромный. На практике единственный наблюдаемый сигнал перегрузки — ошибки 429 (Too Many Requests) от провайдера моделей. После их получения политика повторных попыток откладывает ответ еще на десятки секунд, дополнительно увеличивая задержку для пользователя.

Экономика

Стоимость работы агента рассчитывалась по всем корневым трейсам Langfuse с totalCost > 0 (суммарная стоимость trace, а не отдельный LLM-вызов) для модели Gemini 3.1 Flash-Lite:

Метрика

Значение

n

1137

Суммарно

8,48 $

Среднее

0,75 ¢

Мин. / Макс.

0,04 ¢ / 5,10 ¢

Перцентиль

p10

p25

p50

p75

p90

p95

p99

Стоимость

0,09 ¢

0,38 ¢

0,62 ¢

0,97 ¢

1,49 ¢

1,76 ¢

2,82 ¢

Распределение по корзинам:

Корзина

Доля

< 0,5 ¢

38,1%

0,5 — < 1,0 ¢

38,1%

1,0 — < 1,5 ¢

14,1%

1,5 — < 2,0 ¢

6,0%

2,0 — < 2,5 ¢

2,0%

2,5 — < 3,0 ¢

1,1%

≥ 3,0 ¢

0,7%

76% запросов укладываются в < 1 ¢, 90% — в < 1,5 ¢. Хвост начинается после 2 ¢ (~3,8% трейсов).

Медианный ответ обходится в 0,62 ¢, «тяжелый» — около 1,76 ¢ (p95) и до 2,82 ¢ (p99). Для планирования совокупных затрат ориентируемся на среднее — 0,75 ¢ за ответ. А p95/p99 — это worst-case на один запрос: они нужны для оценки пиковой нагрузки.

Много это или мало? Смотря с чем сравнивать. Если мы говорим о пет-проекте, где за игровую сессию игроки задают от силы 30 вопросов (что даже по тарифу p99 составит меньше 1 $ за вечер), или о корпоративном инструменте, экономящем часы работы высокооплачиваемого эксперта, — эти несколько центов за запрос кажутся несущественными. Сбереженное время окупает стоимость API в тысячи раз.

С наивным RAG картина, конечно, иная. Там один вызов модели с контекстом около тысячи токенов обходится в доли цента за запрос (по грубой оценке — порядка 0,00015 $). На уровне p95 (1,76 ¢) агентский ответ обходится примерно в сто раз дороже простого RAG-запроса.

Но здесь важно смотреть на экономику шире и разделять расходы на разработку (разовые инвестиции в создание и тюнинг системы) и расходы на эксплуатацию (текущие счета за инфраструктуру и API).

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

Чтобы заставить обычный RAG стабильно и качественно решать сложные кросс-доменные задачи, вам придется выстраивать Advanced RAG или даже разворачивать GraphRAG. И в этот момент разработчики погружаются в бесконечный цикл тонкой настройки: подбор оптимального размера чанков, шага перекрытия (overlap), балансировка top-K, калибровка весов гибридного поиска и порогов реранкера. Пытаясь починить ответ на один сложный вопрос, вы меняете параметры нарезки — и тут же ломаете выдачу по трем другим. На то, чтобы довести такой поисковый пайплайн до ума, у команды инженеров могут уйти недели или даже месяцы кропотливого труда.

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

Агентная архитектура переворачивает эту логику. Она позволяет максимально сократить расходы на разработку: мы собираем рабочий прототип за несколько дней, используя простые Markdown-файлы и готовые промпты, практически не тратя время на тонкую настройку поиска. Всю тяжелую работу по сопоставлению фактов мы перекладываем на саму модель LLM во время выполнения.

Да, мы соглашаемся на более высокие расходы на эксплуатацию — до 2–3 центов за самый дорогой ответ (p99). Но давайте посчитаем точку окупаемости:

  • Если это пет-проект или внутренний корпоративный инструмент для компании из 100–200 человек, где ботом пользуются умеренно (скажем, 5000 запросов в месяц), суммарный счет за API составит около 38 $ в месяц (5000 × среднюю стоимость 0,75 ¢). Даже если предположить, что каждый запрос окажется «тяжелым» по p99, верхняя граница не превысит ~140 $ в месяц. За год это порядка 450–1700 $. Нанимать инженера ради экономии такой суммы — экономически бессмысленно. Выигрыш в расходах на разработку мгновенно окупает дорогую эксплуатацию.

  • Другое дело, если вы строите массовый B2C-сервис с миллионами запросов в день. Там даже 2–3 цента за запрос быстро выльются в астрономические счета, способные разорить проект. В этом сценарии математика работает в обратную сторону: вам жизненно необходимо вложиться в дорогую разработку Advanced RAG, нанять сильную команду и потратить месяцы на оптимизацию, чтобы сбить стоимость эксплуатации до долей цента.

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

Заключение: как выбрать оптимальную архитектуру

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

1. Продвинутый RAG (Advanced RAG)

  • Ниша: Средние и крупные базы данных с высокой нагрузкой (миллионы запросов, B2C-масштаб).

  • Сценарии: Когда пользователям нужен качественный поиск или базовый синтез информации (Уровни 1–2) в предсказуемых рамках.

  • Задержка: Минимальная (синхронный отклик за считанные секунды).

  • Стоимость эксплуатации: Минимальная (доли цента за запрос).

  • Сложность разработки: Высокая. Требует сильной ML-команды и бесконечных циклов тонкой настройки поискового пайплайна (размеры чанков, веса гибридного поиска, калибровка реранкера).

2. GraphRAG

  • Ниша: Крупные, относительно статичные базы знаний.

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

  • Задержка: Низкая на этапе запроса (поиск по уже построенному графу укладывается в секунды).

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

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

3. Доменно-маршрутизируемые агенты (Domain-Routed Agents)

Наша агентская архитектура с плоскими Markdown-файлами занимает принципиально иную нишу. Она наиболее практична на малых и средних базах знаний (до десятков мегабайт или нескольких миллионов токенов) с преобладанием сложных кросс-доменных вопросов (Уровень 3), когда поток запросов умерен (B2B, внутренние порталы, пет-проекты).

В этой точке мы соглашаемся на компромиссы:

  • Задержка (Latency): Высокая (медианные 12–13 секунд, до 30–40 секунд в хвосте p95/p99 из-за последовательных шагов рассуждения).

  • Стоимость эксплуатации: Высокая (2–3 цента на p99).

Но взамен мы минимизируем Сложность разработки: систему может запустить и поддерживать один разработчик. База знаний обновляется простым коммитом в Git без переиндексации. В масштабах небольших или средних проектов копеечная экономия на API при использовании RAG физически не способна окупить недели работы дорогого инженера по его настройке. Агентская архитектура побеждает за счет радикального сокращения времени выхода на рынок и стоимости поддержки.

Код проекта, промпты агентов и структура базы знаний открыты и лежат на GitHub: 👉 snakerzr/vtm_loremaster

ссылка на оригинал статьи https://habr.com/ru/articles/1059564/