Каждая команда сейчас хочет заменить людей на AI. Но есть и другой подход - усилить текущие возможности с помощью AI. Это драйвер роста и масштабирования, а не повод увольнять людей.

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

Поговорим про RAG и GraphRAG, про развёртывание и выбор модели. Статья будет полезна как для больших компаний так и для маленьких. В конце посчитаем метрики через eval (Ragas, LLM-as-a-judge), и немного про LangSmith и LangChain.


Формулируем задачу

Первый шаг самый важный - чётко сформулировать задачу. Не "сделаем AI", а конкретно что он будет делать и какие цифры нужны на выходе.

Моя задача - автоматизировать обращения в поддержку по юридическим вопросам. Клиенты задают вопросы по законодательству РФ, AI агент отвечает на основе базы знаний. Простые вопросы закрываются автоматически, сложные идут к живым юристам.

Сразу определяем какие результаты нужны:

Бизнес-метрики:

  • Снизить нагрузку на юристов: -40% обращений

  • Время ответа: мгновенно (было 2-3 часа)

  • Стоимость обращения: ₽0.04 (было ₽66)

Технические метрики:

  • Точность (accuracy): >85%

  • Hallucinations: <5%

  • User satisfaction: >80%

Считаем деньги сразу. Сейчас юрист стоит 100 тысяч в месяц и обрабатывает примерно 50 запросов в день. Получается 66 рублей за запрос. С AI можем обработать 80% запросов за 10 рублей каждый. Экономия 60 тысяч в месяц. Разработка займёт 2 недели и будет стоить примерно 200-400 тысяч рублей.
Break-even через 2 месяца.

Если цифры сходятся - идём дальше.


Проектируем архитектуру агента

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

Первое - откуда вообще приходят запросы? У меня это Telegram. Клиент пишет в бот, бот должен ответить. Может быть почта, может веб-форма, может API для интеграции с CRM. Нужно понимать заранее.

Второе - какие типы вопросов хотим автоматизировать? Это называется интенты. "Какое наказание за кражу?" - это один интент. "Чем отличается кража от грабежа?" - другой, посложнее. Нужно понимать на что агент должен отвечать, а что сразу отправлять людям.

Третье - что у нас вообще с базой знаний? Есть ли документы? Где лежат? В каком формате? PDF? Word? Google Docs? Сколько их - 10 файлов или 10 тысяч? От этого зависит вся архитектура.

Четвёртое - сколько денег готовы потратить? Потому что можно сделать за 100 тысяч на коленке, а можно за миллион enterprise решение. Бюджет определяет подход.

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

Я качестве примера буду показывать как проектировать агента на открытых данных.
База знаний: Беру открытые данные - УК РФ, УПК, ГК РФ, Семейный кодекс, судебная практика. Примерно 3000 документов, 15 тысяч страниц. В боевом агенте, который мы используем в продакшене внутренние регламенты и процедуры. Но принцип построения один и тот же.

Канал: Telegram бот.

Бюджет: ~500 тысяч на разработку, ~35 тысяч в месяц на инфру.

Рисую архитектуру. Клиент пишет вопрос в Telegram → вопрос попадает в агента → агент ищет в базе знаний → генерирует ответ → отправляет обратно. Если уверенность низкая - эскалирует к живому юристу.

Выглядит просто. Но дьявол в деталях.


У нас есть два подхода: как обучить AI нашим документам

У нас есть 15 тысяч страниц законов. Как сделать чтобы AI знал что там написано?

Тут глобально два подхода.

Подход первый: дообучить модель.

Это называется fine-tuning. Берёшь базовую LLM, скармливаешь ей все наши документы и дообучаешь веса. Модель "запоминает" информацию прямо в параметрах.

Звучит круто. Но есть проблемы.

Дорого. От $500 за обучение, иногда тысячи долларов. Плюс нужны ML инженеры которые это умеют.

Долго. Недели на подготовку данных в правильном формате, потом обучение.

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

Catastrophic forgetting. Когда учишь модель на своих данных, она может "забыть" общие знания. Была умная, стала специализированная но тупая.

Для нашего кейса это слишком дорогое удовольствие. Законы меняются постоянно. Судебная практика обновляется каждый день. Нам нужно что-то динамичнее.

Подход второй: RAG.

RAG расшифровывается как Retrieval Augmented Generation. По-русски: поиск, извлечение и ге��ерация.

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

Модель не "знает" законы наизусть. Она читает кусок текста который мы ей дали и отвечает на его основе.

Плюсы очевидные:

Дёшево. Не нужно обучать модель. Просто индексируем документы - это копейки.

Быстро обновлять. Добавил новый документ в базу - он сразу в поиске. Никакого переобучения.

Прозрачно. Видно на каких кусках текста модель основывала ответ. Можно проверить, можно показать клиенту "вот откуда я это взял".

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

Мы выбираем RAG. Это единственный разумный вариант для нашего случая.


Два типа RAG: просто поиск или граф знаний

Окей, с RAG определились. Но тут начинается интересное.

RAG - это не одна технология. Есть разные подходы. Сегодня рассмотри два: классический векторный RAG и GraphRAG (граф знаний).

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

Давайте разберём оба.

Классический RAG - как работает

Представь: у тебя 3000 документов. Нужно как-то организовать их так чтобы быстро находить нужное.

Шаг 1: Режем на куски.

Берёшь документ и режешь на логические абзацы. Это называется чанкинг (chunking). Например статья закона - это один чанк. Или абзац судебной практики - ещё один чанк.

Почему нельзя весь документ целиком? Потому что LLM не может обработать 15 тысяч страниц за раз. Даже если может - это очень дорого (много токенов) и модель запутается в объёме.

Поэтому режем на куски по 800-1200 токенов каждый. Это примерно 2-3 абзаца текста.

Шаг 2: Превращаем в числа.

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

Например кусок "Статья 158. Кража - тайное хищение" превращается в вектор [0.23, -0.15, 0.67, ... ещё тысяча чисел].

Магия в том что похожие по смыслу тексты получают похожие векторы. "Кража" и "тайное хищение" будут рядом в числовом пространстве.

Шаг 3: Сохраняем в векторную БД.

Все эти векторы складываешь в специальную базу данных - Qdrant, Pinecone, ChromaDB. Это не обычная БД. Она умеет искать "ближайших соседей" в многомерном пространстве.

У меня получилось 12 тысяч векторов из 3 тысяч документов.

Шаг 4: Поиск.

Когда приходит вопрос от пользователя - скажем "Какое наказание за кражу?" - мы делаем то же самое: превращаем вопрос в вектор через ту же модель эмбединга.

Потом ищем в базе 5-10 ближайших векторов. Это называется Retrieval (поиск, извлечение).

Нашли? Берём соответствующие куски текста.

Шаг 5: Генерация.

Склеиваем найденные куски в один большой промпт:

Контекст:
[Кусок 1: Статья 158. Кража...]
[Кусок 2: ...наказывается штрафом...]
[Кусок 3: ...либо лишением свободы...]

Вопрос: Какое наказание за кражу?

Ответь на основе контекста выше.

Отправляем в LLM. Модель читает контекст и генерирует ответ. Это называется Generation.

RAG = Retrieval + Augmented + Generation.

Поиск кусков → Обогащение промпта → Генерация ответа.

Когда это работает отлично?

Когда вопрос простой и ответ лежит в одном-двух кусках.

"Какое наказание за кражу?" - отлично, найдёт статью 158, ответит.

"Когда доставка?" - отлично, найдёт кусок с условиями доставки, ответит.

"Есть ли товар в наличии?" - отлично, найдёт статус товара, ответит.

RAG живёт в парадигме "ищем просто похожие куски текста".

Но есть проблема.

Когда классический RAG начинает тупить

Попробуй спросить: "Чем отличается кража от грабежа?"

Что сделает RAG?

Найдёт два куска:

  • Кусок 1: "Кража - тайное хищение чужого имущества"

  • Кусок 2: "Грабёж - открытое хищение чужого иму��ества"

Подставит в промпт. LLM прочитает и скажет что-то типа "Кража это тайное, грабёж это открытое".

Технически правильно. Но неполно.

Модель не видит структуру:

  • Что оба это подвиды понятия "хищение"

  • Что есть иерархия: Хищение → Тайное хищение (кража) / Открытое хищение (грабёж)

  • Что отличие именно в способе изъятия

  • Что есть ещё разбой (открытое + насилие) и мошенничество (обман)

RAG видит два отдельных куска текста. Связей между ними не видит.

Или сложнее: "Какие виды хищения существуют и чем они различаются?"

Чтобы ответить, нужно:

  1. Понять что такое хищение (базовое понятие)

  2. Найти ВСЕ подтипы (кража, грабёж, разбой, мошенничество, присвоение, растрата...)

  3. Для каждого понять отличительный признак

  4. Собрать в структурированный ответ

RAG найдёт несколько кусков про разные виды. Но может упустить какие-то. Может не понять связи. Ответ будет неполный.

Проблема в том что RAG не понимает структуру знаний.

Он просто ищет похожие куски текста. А реальность сложнее. Понятия связаны между собой. Есть иерархии, есть зависимости, есть контекст.

Пример из другого домена. E-commerce. Клиент спрашивает: "Я заказал товар, оплатил картой, хочу вернуть. Сколько ждать деньги?"

Чтобы ответить правильно нужно понять:

  • Способ оплаты (карта) → срок возврата 5-10 банковских дней

  • Тип товара → можно ли вообще вернуть (не еда, не нижнее бельё)

  • Статус заказа → товар получен или ещё в доставке

  • Канал доставки → как оформи��ь возврат (СДЭК, курьер, почта)

  • Политика магазина → есть ли особые условия

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

И вот тут на сцену выходит GraphRAG.

GraphRAG - карта знаний вместо кучи кусков

GraphRAG делает всё то же самое что обычный RAG. Режем на чанки, делаем эмбединги, кладём в векторную БД. Но добавляем ещё один критический шаг.

Мы строим граф знаний.

Как это работает?

Этап 1: Извлекаем сущности и связи.

Берём каждый чанк и отправляем в мощную LLM (у меня Mistral Large) с таким промптом:

Вот кусок текста:
"Статья 158. Кража, то есть тайное хищение чужого имущества, 
наказывается штрафом до 80 000 рублей либо лишением свободы до двух лет."

Извлеки:
1. Все важные сущности (понятия, термины, объекты)
2. Связи между ними

Верни JSON.

LLM возвращает:

{
  "сущности": [
    {"название": "кража", "тип": "преступление"},
    {"название": "тайное хищение", "тип": "понятие"},
    {"название": "хищение", "тип": "понятие"},
    {"название": "статья 158", "тип": "статья"},
    {"название": "штраф до 80000", "тип": "наказание"},
    {"название": "лишение свободы до 2 лет", "тип": "наказание"}
  ],
  "связи": [
    {"от": "кража", "к": "тайное хищение", "тип": "является"},
    {"от": "тайное хищение", "к": "хищение", "тип": "подтип"},
    {"от": "кража", "к": "статья 158", "тип": "регулируется"},
    {"от": "кража", "к": "штраф до 80000", "тип": "наказывается"},
    {"от": "кража", "к": "лишение свободы до 2 лет", "тип": "наказывается"}
  ]
}

Делаем это для всех 12 тысяч чанков.

Да, это дорого. У меня ушло примерно $29 на Mistral Large API. Но это один раз. Дальше граф просто используется.

Время: 40-60 минут на 12 тысяч чанков (зависит от rate limits API).

Этап 2: Строим граф.

Теперь из всех этих сущностей и связей строим настоящий граф.

Каждая сущность → узел графа.
Каждая связь → ребро графа.

Важный момент: одна и та же сущность из разных чанков приводится к одному имени. Например "кража", "Кража", "статья 158 о краже" - это всё один узел "кража". Чтобы не было десяти дублей.

Для построения использую NetworkX - это Python библиотека для работы с графами.

Почему NetworkX а не Neo4j?

NetworkX - хранит граф в оперативной памяти, быстрый для графов меньше 100 тысяч узлов, простой API, бес��латный, отлично подходит для MVP.

Neo4j - это graph database на диске, быстрый для графов больше миллиона узлов, сложнее настройка, платный для production. Для нашего кейса это overkill.

Есть ещё LightRAG - упрощённая версия GraphRAG, использует более простые алгоритмы извлечения, строится быстрее. Подходит для первого этапа и MVP. Если результаты хороши - можно остаться на LightRAG. Если нужна максимальная точность - переходить на полный GraphRAG с NetworkX.

Результат: граф из ~2800 узлов (уникальных сущностей) и ~5100 рёбер (связей). Размер 8 мегабайт в JSON.

Этап 3: Находим communities (сообщества).

Смотрю на граф. Он огромный. Тысячи узлов, тысячи связей. Как в этом ориентироваться?

Запускаю алгоритм Louvain - это стандарт для community detection. Он автоматически находит группы узлов которые плотно связаны между собой.

Что находит?

Community 0 (имущественные преступления):
Кража, грабёж, разбой, мошенничество, тайное хищение, открытое хищение, насилие, обман, статьи 158, 159, 161, 162.

Community 1 (насильственные преступления):
Убийство, причинение вреда здоровью, побои, истязание, статьи 105, 111, 116, 117.

Community 2 (половые преступления):
Изнасилование, насильственные действия сексуального характера, статьи 131, 132.

И так далее. Всего получается примерно 15 communities.

Зачем это нужно?

Когда пользователь спрашивает "Какие виды имущественных преступлений существуют?" - я могу вернуть всю Community 0 сразу. Не собирать по кускам из векторной БД, а дать целую тему.

Этап 4: Делаем резюме.

Для каждой community отправляю список узлов в LLM (Mistral Small, дешевле) с просьбой:

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

Опиши общую тему в 2-3 предложениях.

LLM возвращает:

"Группа объединяет имущественные преступления связанные с хищением 
чужого имущества. Различаются способом изъятия: тайно (кража), 
открыто (грабёж), с применением насилия (разбой) или обманом (мошенничество)."

Это резюме сохраняю для каждой community. Стоимость: ~$0.50 на все 15 резюме.

Граф готов. Теперь можно по нему искать.

Как работает поиск в GraphRAG

Приходит вопрос: "Чем отличается кража от грабежа?"

Что делает система?

Шаг 1: Entity matching.

Ищем в графе узлы похожие на слова из вопроса.

Через эмбединги сравниваем вопрос со всеми узлами графа. Находим топ-5:

  1. "кража" (similarity: 0.94)

  2. "грабёж" (similarity: 0.91)

  3. "хищение" (similarity: 0.85)

  4. "тайное хищение" (similarity: 0.82)

  5. "открытое хищение" (similarity: 0.79)

Шаг 2: Path finding.

Ищем путь в графе от "кража" до "грабёж".

Используем shortest path algorithm из NetworkX.

Находим:

кража → тайное хищение → хищение → открытое хищение → грабёж

Длина пути: 5 hops (переходов).

Это показывает КАК понятия связаны.

Шаг 3: Neighbors expansion.

Для каждого узла в пути берём соседей (связанные узлы).

Для "кража":

  • статья 158 (регулируется)

  • штраф до 80000 (наказывается)

  • группа лиц (отягчающее обстоятельство)

Для "грабёж":

  • статья 161 (регулируется)

  • насилие (может содержать)

  • открытое хищение (является)

Шаг 4: Собираем контекст.

Формируем промпт для LLM:

Контекст из графа знаний:

ПУТЬ СВЯЗЕЙ:
кража (преступление) → тайное хищение (понятие) → 
хищение (понятие) → открытое хищение (понятие) → 
грабёж (преступление)

СВЯЗАННЫЕ ПОНЯТИЯ:
Кража: статья 158, штраф до 80000, группа лиц
Грабёж: статья 161, насилие, открытое хищение

ОБЩИЙ КОНТЕКСТ:
Community "Имущественные преступления": "Группа объединяет 
имущественные преступления связанные с хищением..."

Вопрос: Чем отличается кража от грабежа?

Используй связи из графа для объяснения.

Шаг 5: Генерация.

LLM видит не просто два куска текста, а явную структуру. И генерирует ответ:

Кража и грабёж - оба вида хищения чужого имущества,
но отличаются способом изъятия:

- Кража (статья 158) - ТАЙНОЕ хищение, то есть скрытно 
  от владельца или окружающих.

- Грабёж (статья 161) - ОТКРЫТОЕ хищение, то есть явно,
  в присутствии владельца или свидетелей.

Граф показывает: кража связана с "тайным хищением",
а грабёж с "открытым хищением". Оба являются подтипами 
понятия "хищение". Ключевое отличие в способе - 
тайно против открыто.

Разница очевидна. LLM теперь понимает структуру, а не просто читает два куска.

GraphRAG нужен когда:

  • Сравнительные вопросы: "Чем А отличается от Б?"

  • Multi-hop рассуждения: "Какие виды X существуют?"

  • Понимание структуры: "Как устроен процесс от начала до конца?"

  • Объяснение по полочкам: "Разложи тему на составляющие"

Классический RAG нужен когда:

  • Простые факты: "Какое наказание?"

  • Прямые вопросы: "Есть ли в наличии?"

  • Статус: "Когда доставка?"

Для AI юриста я буду тестировать оба подхода чтобы показать разницу в качестве.


Парсим документы и режем на чанки

Окей, теория понятна. Теперь руки в код.

Первое что нужно - превратить 3000 PDF файлов в текст.

Выбор парсера:

Если у вас нет требований к кибербезопасности - используйте LlamaParse. Это API от LlamaIndex. Отлично парсит таблицы, сноски, сложную разметку. Стоит $0.003 за страницу. Качество 95%+ для русского.

Если есть требования (как у меня) - берите dedoc и ставьте локально. Это лучшее что может быть для парсинга в безопасном контуре.

Я использовал dedoc. Прогоняю все документы - у меня были PDF, DOC, DOCX. На выходе получаю чистый текст.

Стоимость: ноль (только время сервера).

Время: ~2 часа на 3000 документов.

Результат: 3000 текстовых файлов, готовых к резке.

Chunking - режем на куски.

Теперь нужно порезать длинные документы на логические куски.

Главный вопрос: какой размер чанка?

Это критически влияет на качество. Слишком маленькие - теряется контекст. Слишком большие - смешиваются темы.

Мой подход: эксперимент.

Пробую три варианта:

  • 500 токенов

  • 800 токенов

  • 1000 токенов

По опыту золотая середина 800-1200 токенов. Для русского текста 800 токенов это примерно 1760 символов или 250-280 слов.

Режу через RecursiveCharacterTextSplitter из LangChain с умной резкой - не разрываю предложения посередине, сохраняю структуру статей.

Настройки:

  • Размер чанка: 800 токенов

  • Overlap (перекрытие): 80 токенов (10%)

Зачем overlap? Чтобы контекст на границах чанков не терялся. Если статья заканчивается в одном чанке и продолжается в другом - 80 токенов overlap помогут не потерять связь.

Результат: ~12,000 чанков из 3000 документов.


Embedding и векторная БД

Каждый чанк нужно превратить в вектор чисел.

Выбор embedding модели:

Это критически важный выбор. Плохая модель = плохой поиск = плохие ответы.

Для русского языка:

Если можно API:
OpenAI text-embedding-3-large (~$0.13 per 1M tokens). Хорошее качество.

Если нужно локально:
multilingual-e5-large-instruct от HuggingFace. Open-source, бесплатно, размерность 1024, отличное качество для русского.

Я развернул e5-large локально (требования б��зопасности).

Прогоняю все 12K чанков через модель. Каждый чанк → вектор из 1024 чисел.

Время: ~30 минут на 12K чанков.

Результат: 12,000 векторов, размер ~50 мегабайт.

Векторная БД:

Кладу все векторы в Qdrant.

Почему Qdrant?

Скорость: HNSW алгоритм даёт поиск <50ms на 12K векторов.

Точность: >95% recall при правильных настройках.

Фильтрация: Можно искать только в УК РФ или только актуальные версии.

Self-hosted: Бесплатный вариант, полный контроль.

Альтернативы:

ChromaDB - проще настроить, для dev/тестов, но медленнее на больших объёмах.

Pinecone - только cloud, от $70/мес, нет self-hosted.

Weaviate - похож на Qdrant, сложнее настройка, документация хуже.

Разворачиваю Qdrant в Docker контейнере у себя.

Стоимость: ноль (только сервер).

Скорость поиска: 40-60 миллисекунд.

Классический RAG готов.


Строим GraphRAG

Параллельно запускаю построение графа.

Извлечение сущностей:

Беру все 12K чанков. Для каждого отправляю запрос в Mistral Large:

prompt = f"""
Извлеки из текста:
1. Все важные сущности (понятия, термины, статьи, наказания)
2. Связи между ними (является, подтип, регулируется, наказывается)

Текст:
{chunk_text}

Верни JSON с полями: entities, relationships
"""

Mistral Large возвращает структурированный JSON для каждого чанка.

Стоимость: 12K чанков × ~800 токенов × 3 per 1M tokens ≈ **29**.

Время: 40-60 минут (зависит от rate limits).

Построение графа:

Загружаю все сущности и ��вязи в NetworkX.

import networkx as nx

G = nx.Graph()

# Добавляю узлы
for entity in entities:
    G.add_node(entity['name'], type=entity['type'])

# Добавляю рёбра
for rel in relationships:
    G.add_edge(rel['source'], rel['target'], type=rel['type'])

Результат: граф из 2891 узлов и 5124 рёбер.

Community detection:

import community as community_louvain

communities = community_louvain.best_partition(G)

Louvain находит 15 communities (тематических групп).

Summarization:

Для каждой community генерирую резюме через Mistral Small.

Стоимость: ~$0.50 на все резюме.

GraphRAG готов.

Сохраняю граф в JSON (8 мегабайт).


Выбор LLM модели

Теперь нужна модель которая будет генерировать ответы.

Варианты:

Если данные НЕ уязвимые (можно API):

YandexGPT 4 - отлично для русского, на уровне Qwen 32B по моим бенчмаркам, соответствует 152-ФЗ, ~₽2.0 per 1K tokens (≈₽3.15 за запрос). Подходит для маленьких команд без своей инфры.

GPT-4o-mini, Claude Sonnet - западные API, хорошее качество.

Если данные уязвимые (нужно локально):

Qwen 2.5 7B - open-source (Apache 2.0), отличное качество для русского, компактный (влезает в 1 GPU).

Требования:

  • GPU: Nvidia T4 16GB или лучше

  • RAM: 32GB

  • Disk: 20GB

Deployment через vLLM:

vLLM - это высокопроизводительный inference сервер.

Что даёт:

  • OpenAI-совместимый API endpoint

  • Continuous batching (ускорение в 2-3x)

  • Throughput: 10-15 запросов/сек

  • GPU utilization: 80-90%

Метрики:

  • Latency на запрос: 3-4 секунды

  • Стоимость GPU сервера: ~₽35,000/мес (аренда в облаке)

  • Настройка: 1 день

Я развернул Qwen 2.5 7B через vLLM локально (требования безопасности - данные не должны уходить наружу).


Собираем агента на LangGraph

Теперь собираем всё вместе.

Компоненты:

  • RAG система (векторная БД + поиск)

  • GraphRAG система (граф + path finding)

  • LLM (Qwen 7B)

  • Логика эскалации

  • История диалога

Использую LangGraph - фреймворк от LangChain для stateful агентов.

Что даёт:

  • State management: История диалогов, контекст сохраняется между сообщениями

  • Conditional routing: Если confidence <0.7 → эскалировать к человеку

  • Tool calling: Агент сам решает вызывать RAG или GraphRAG в зависимости от типа вопроса

  • Циклы: Может делать несколько шагов рассуждений

Альтернативы: чистый LangChain (проще но без state), CrewAI (для multi-agent систем), AutoGen (для сложных workflow).

Для моего кейса LangGraph оптимален.

Архитектура агента:

1. Получить вопрос от пользователя
2. Определить тип вопроса (classifier)
   - Простой вопрос → RAG
   - Сравнение/multi-hop → GraphRAG
3. Выполнить поиск
4. Сгенерировать ответ (LLM)
5. Проверить confidence
   - >0.7 → отправить пользователю
   - <0.7 → эскалировать к юристу
6. Сохранить в историю

Для маленьких команд: n8n

Если у вас нет инженеров - можно собрать в n8n (no-code платформа).

Визуальный workflow:

  • Webhook → получает вопрос

  • Vector Store node → ищет в Qdrant

  • LLM node → генерирует ответ

  • IF node → проверяет confidence

  • Telegram node → отправляет ответ

Ограничения: сложнее делать GraphRAG, меньше контроля над логикой, подходит до 1000-5000 запросов/день.

Если интересно - напишите в комментариях, сниму видео как собрать.


Трейсинг и мониторинг: LangSmith

Когда агент работает, критич��ски важно видеть что происходит внутри.

Без мониторинга отладка = ад. Агент выдал неправильный ответ - почему? Какие чанки нашлись? Какой промпт отправили? Где ошиблась модель?

Для этого использую LangSmith - платформа для мониторинга LLM приложений от LangChain.

Что записывает:

Каждый запрос записывается полностью:

  • Входной вопрос пользователя

  • Поиск в векторной БД (какие чанки нашлись, их scores)

  • Промпт в LLM (весь текст с контекстом)

  • Ответ LLM (полный текст)

  • Latency каждого шага (поиск, генерация, общее время)

  • Token usage и стоимость

Что можно делать:

Создавать eval датасеты - набор вопросов с правильными ответами для тестирования.

Сравнивать конфигурации - запустить 100 вопросов через RAG и через GraphRAG, сравнить метрики.

Собирать feedback - юристы могут ставить ?/? ответам, это записывается.

Debug в реалтайме - смотреть trace прямо во время разговора, видеть где застряло.

Стоимость:

  • Free: 5K traces/мес (хватает для dev/тестов)

  • Pro: $30/мес (50K traces)

Для production это must-have. Без LangSmith летите вслепую.


Eval и метрики: как проверить что агент не тупит

У меня есть два агента:

  • RAG агент (классический векторный поиск)

  • GraphRAG агент (граф знаний)

Вопрос: какой лучше? Какой отправлять в продакшен?

Нельзя просто "попробовать и посмотреть". Нужно измерить объективно.

Создаём eval датасет

Собираю 100 вопросов из реальной юридической поддержки.

Распределение по сложности:

  • 40% простые факты: "Какое наказание за кражу?"

  • 30% сравнения: "Чем отличается кража от грабежа?"

  • 20% multi-hop: "Какие виды хищения существуют и чем различаются?"

  • 10% обобщения: "Перечисли все имущественные преступления"

Для каждого вопроса юристы написали правильный ответ. Это golden standard для сравнения.

Метрика 1: Ragas

Ragas - фреймворк для автоматической оценки RAG систем.

Кто создал: команда Exploding Gradients в 2023 году. Open-source, активно развивается.

Что измеряет:

Faithfulness (верность источнику) - не выдумывает ли модель факты.

Как работает: Ragas берёт ответ модели и найденные чанки, отправляет в GPT-4: "Все ли факты в ответе есть в контексте?" Возвращает score от 0 до 1.

Answer Relevancy (релевантность) - отвечает ли на вопрос, нет ли воды.

Как работает: LLM проверяет "Ответ действительно про то о чём спрашивали?" Score от 0 до 1.

Context Precision - насколько найденные чанки релевантны, нет ли мусора.

Context Recall - всё ли нужное нашлось, ничего не упущено.

Удобство: не нужно вручную проверять каждый ответ, LLM делает это автоматически.

Метрика 2: LLM-as-a-Judge

Второй подход: используем более умный LLM для оценки ответов менее умного.

Процесс:

  1. Берём: вопрос, правильный ответ (от юриста), ответ агента

  2. Отправляем в судью (GPT-4 или Claude Opus):

Вопрос: Какое наказание за кражу?

Правильный ответ: "Кража наказывается штрафом до 80,000 рублей 
либо лишением свободы до 2 лет по статье 158 УК РФ."

Ответ агента: "За кражу предусмотрен штраф до 80 тысяч рублей 
или лишение свободы до двух лет."

Оцени ответ агента по шкале 0-10:
- Точность фактов
- Полнота
- Ясность формулировки

Объясни оценку.
  1. LLM-судья возвращает:

Оценка: 9/10

Обоснование:
✓ Факты верны (штраф и срок правильные)
✓ Полнота хорошая (оба наказания упомянуты)
✓ Ясность отличная
- Минус 1 балл: не упомянута статья 158 и понятие "тайное хищение"

Почему судья должен быть умнее:

Модель-судья должна иметь больше параметров и лучше понимать контекст.

Хорошо работают: GPT-4 Turbo, Claude Opus, GPT-o1 (лучший для рассуждений).

Плохо: GPT-3.5 (слабоват), модели <7B параметров (не справляются с оценкой).

Стоимость: ~$0.50-1.00 за оценку 100 ответов.


Эксперименты: RAG vs GraphRAG

Прогоняю 100 вопросов через оба агента.

Собираю метрики:

  • Точность по типам вопросов

  • Latency (время ответа)

  • Cost (стоимость запроса)

  • Hallucinations (процент выдумок)

Результаты:

Метрика

RAG

GraphRAG

Simple вопросы (40)

87%

86%

Comparison (30)

68%

92%

Multi-hop (20)

60%

88%

Aggregation (10)

55%

85%

Средняя точность

72%

88%

Avg latency

3.2s

5.8s

Cost/query

₽0.025

₽0.04

Hallucinations

5%

3%

Анализ:

На простых вопросах (40 штук) - почти одинаково. RAG даже чуть лучше (87% vs 86%). Это ожидаемо - когда ответ в одном куске, граф не даёт преимущества.

На сравнениях (30 вопросов) - GraphRAG уничтожает. 92% против 68%. Разница +24%. Тут граф показывает свою силу - он видит связи между понятиями.

На multi-hop (20 вопросов) - ещё больше разрыв. 88% против 60%. Разница +28%. Когда нужно собрать информацию из нескольких связанных понятий, граф незаменим.

На обобщениях (10 вопросов) - GraphRAG тоже впереди. 85% против 55%. Потому что может вернуть целую community сразу.

Средняя точность: 88% против 72%. GraphRAG выигрывает на +16%.

Latency: RAG быстрее - 3.2 секунды против 5.8 у GraphRAG. Разница 2.6 секунды. GraphRAG дольше потому что ищет путь в графе, обходит окрестности, собирает больше контекста.

Стоимость: RAG дешевле - 2.5 копейки против 4 копеек у GraphRAG. Разница полторы копейки. GraphRAG дороже потому что больше токенов в промпте (путь в графе + окрестности).

Hallucinations: GraphRAG меньше врёт - 3% против 5% у RAG. Потому что видит структуру и реже додумывает связи которых нет.

Выбор победителя

Решение: GraphRAG идёт в продакшен.

Почему:

1. Точность критична.

Для юридической поддержки ошибка = репутационный риск. Клиент может принять неправильное решение на основе ответа AI.

88% против 72% - это огромная разница. Это 16 дополнительных правильных ответов из каждых 100 запросов.

2. Сложные вопросы важнее простых.

Простые вопросы типа "Какое наказание за кражу?" клиенты и сами найдут в Google. К нам приходят со сравнениями, с цепочками рассуждений, с "объясни как это работает".

На этих вопросах GraphRAG даёт +24% и +28%. Это критично.

3. Latency приемлема.

5.8 секунд - это нормально для сложного юридического вопроса. Клиент не ждёт мгновенного ответа, он ждёт качественного ответа.

Если нужна скорость для простых вопросов - можно сделать гибридный подход (об этом ниже).

4. Стоимость оправдана.

₽0.04 против ₽66 (человек) - это всё ещё экономия в 1650 раз.

Разница между RAG (₽0.025) и GraphRAG (₽0.04) - полторы копейки. На фоне экономии в 66 рублей это несущественно.

Компромисс для будущего:

Можно сделать гибридный подход:

  • Простые вопросы (факты, статусы) → RAG (быстро и дёшево)

  • Сложные вопросы (сравнения, multi-hop) → GraphRAG (точно и полно)

  • Classifier определяет тип вопроса и выбирает агента

Но для MVP иду с GraphRAG везде. Сначала качество, потом оптимизация.


Риски и как их минимизировать

Любой AI агент несёт риски. Давайте честно их разберём.

Репутационные риски

Риск 1: Hallucinations (выдумывание фактов)

AI может выдумать статью закона которой не существует. Клиент примет решение на основе этого - получит проблемы - обвинит вас.

Минимизация:

  • Disclaimer: "Это AI ассистент, не юридическая консультация"

  • Audit log: все ответы записываются, можно проверить

  • RAG/GraphRAG: опора на документы снижает риск

  • Human-in-the-loop: критичные ответы проверяет человек

  • Feedback loop: юристы помечают плохие ответы → улучшаем

Риск 2: Устаревшая информация

В базе старая версия закона. AI отвечает на основе неё - информация неактуальна.

Минимизация:

  • Автоматическое обновление: скрипт проверяет consultant.ru раз в неделю

  • Версионирование: каждый документ имеет дату актуальности

  • Пометка в ответе: "Информация актуальна на [дата]"

  • Алерты: если документ старше 3 месяцев - предупреждение

Риск 3: Leak конфиденциальных данных

AI процитирует внутренний документ в публичном ответе. Утечка конфиденциальной информации.

Минимизация:

  • Разделение баз: публичные документы отдельно от внутренних

  • Фильтрация по метаданным: поиск только в разрешённых источниках

  • Проверка перед отправкой: сканирование ответа на keywords

  • Права доступа: разные агенты для разных уровней доступа

Технические риски

Риск 4: Медленные ответы (>10s)

Клиент ждёт долго - уходит, не получив ответа.

Минимизация:

  • Кэширование: частые вопросы кэшируются

  • Оптимизация промптов: сокращаем лишние токены

  • Hybrid routing: простые → быстрый RAG, сложные → GraphRAG

  • Timeout: если >10s → "Вопрос сложный, передаю юристу"

Риск 5: Падение сервиса

Сервер упал - клиенты не могут получить ответы.

Минимизация:

  • Health checks: автоматическая проверка каждые 30 секунд

  • Auto-restart: при падении перезапуск через systemd

  • Fallback: если AI недоступен → сразу к человеку

  • Мониторинг: alerts в Telegram при проблемах

  • Redundancy: несколько инстансов для high availability

Финансовые риски

Риск 6: Превышение бюджета на токены

Стоимость запроса вырастает до ₽1 вместо ₽0.04 - бюджет сливается.

Минимизация:

  • Rate limiting: не более 100 запросов/час на пользователя

  • Мониторинг стоимости: alerts при превышении ₽0.10 за запрос

  • Token limits: максимум 2000 токенов в промпте

  • Caching: повторные запросы не идут в LLM

Риск 7: Низкая точность → всё равно нужны люди

AI не экономит деньги потому что точность низкая, всё эскалируется к людям.

Минимизация:

  • Eval до продакшена: запускаем только при >85% точности

  • Постепенный rollout: 10% трафика → 50% → 100%

  • A/B тесты: сравниваем с людьми

  • Continuous improvement: каждую неделю анализируем ошибки


Что дальше

У нас есть готовый AI агент:

  • Точность: 88%

  • Стоимость: ₽10 за запрос (против ₽66 у человека)

  • Работает 24/7

От идеи до работающего прототипа: 4 неделb.

Во второй части расскажу:

  • ROI и MRR расчёт с детальной экономикой

  • Production метрики за 3 месяца работы

  • Реальные кейсы и проблемы которые возникли

  • Что пошло не так и как фиксили

  • Как масштабировать на 10,000 запросов/день

  • Advanced фичи: multi-turn диалоги, personalization

--->

Полезные ссылки

Telegram канал: "AI-заметки продакта"
https://t.me/+NuwolVMjPgU3NGJi

Вопросы:
Пишите в комментарии или ТГ - отвечу всем.

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


Если было полезно - поделитесь с коллегами!

Комментарии (0)