Оценка ИИ-Агента: 10 000 сообщений и Метрики в проде
Как мы научили ИИ-агента отвечать за свои слова: 10 000 сообщений, Венгерский алгоритм и немного магии

На связи Сергей Смирнов, AI-инженер и основатель LLMStart.ru. Мы делаем AI-системы для бизнеса. И сегодня я расскажу, откуда мы точно знаем, что наш production-агент для компании «Айтон» (консультирует по 1С:УНФ) реально умнеет, а не делает вид.

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

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

Что у нас под капотом?

  • Фреймворк: Langchain.

  • Среда обитания: Telegram-бот для клиентов «Айтона» (компания больше 20 лет внедряет 1С:УНФ).

  • Что спрашивают пользователи: Раньше они мучали живых менеджеров вопросами вроде: «Как настроить склад с учетом резерва?» или «Можно ли вести производство по серийникам?».

  • Типы вопросов: Половина — это конкретное «как сделать», другая половина — разбор сложных терминов и проверка, есть ли вообще такая функция в системе.

Ниже я покажу изнанку: четыре области оценки, две уникальные метрики, Венгерский алгоритм (да-да, тот самый, ради честного F1) и разбор боевого цикла. А еще расскажу про тот неловкий момент, когда метрика рухнула просто потому, что наш ИИ оказался умнее старого эталона!

Проверка «глазами»: почему интуиция больше не работает

Обычно разговоры про evaluation (оценку) начинаются с фразы: «Давайте просто посмотрим пару ответов». Команда лениво листает 10-15 примеров. Один говорит: «О, тут круто ответил!», другой морщится: «А вот тут чушь какая-то». И на основе этих эмоций принимается решение — катить новый промпт в прод или нет.

Так вот, ручная проверка — это не начало пути. Это глухой потолок. Выше вы не прыгнете, пока не построите нормальную систему оценки. Я сам долго этого не понимал, пока просто не взял калькулятор.

Смотрите, на одном из боевых датасетов проекта у нас сейчас 33 кейса. Они разбиты на четыре функциональные области. Мы выжали их из Excel-файла заказчика до последней капли. Но 33 кейса для статистики — это просто слезы. Представьте: у вас 15 кейсов в одной области. Если агент стал отвечать лучше всего на один вопрос, метрика прыгает сразу на ≈7%. Ого, рост на 7%! Но что это значит? Может, мы реально починили логику. А может, просто случайно угадали, и на следующем вопросе агент эпично провалится.

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

Пока у вас есть только «ощущение» команды, красивые скриншоты и демо — у вас нет ничего. Настоящий аргумент появится только вместе с инструментом, который измеряет качество в цифрах. Эмоции и десяток ручных проверок — это ваш предел.

Чтобы пробить этот потолок, мы создали инструмент замера. Для нашего агента понадобилось целых четыре области оценки, и стандартными метриками RAG тут было не обойтись.

Анатомия оценки: на какие четыре части мы распилили агента

Признаюсь, в начале пути я был наивен. Думал: «Возьму RAGAS из коробки, и всё взлетит!». На второй неделе розовые очки разбились.

Казалось бы, всё просто: подключаем RAGAS к Langfuse, прогоняем сотню вопросов и любуемся графиками. Да, это сработало бы, будь наш агент простой искалкой по базе знаний (чистый RAG). Но в реальном проде всё гораздо хитрее.

Мы разбили систему оценки на четыре функциональные области. Каждая проверяет свой аспект работы:

  • 1. RAG (Поиск по базе). Агент тут — черный ящик. Дали вопрос, получили ответ и куски найденного текста. Проверяем всё стандартными метриками RAGAS (faithfulness, answer_correctness, answer_relevancy). Это фундамент для любого бота-поисковика.

  • 2. Agent (Работа с инструментами). Здесь нас волнует не красивый текст ответа, а механика: тот ли инструмент взял агент? Правильные ли данные в него передал? Спойлер: тут RAGAS работает по принципу «всё или ничего», поэтому нам пришлось засучить рукава и переписать парочку метрик.

  • 3. Clarifying (Уточняющие вопросы). Если пользователь пишет что-то непонятное, агент может либо пальнуть наугад, либо переспросить. В 1С:УНФ это боль! Например, слово «резерв» может быть товарным, финансовым или оценочным. Мы измеряем, умеет ли ИИ вовремя остановиться и задать уточняющий вопрос по делу.

  • 4. No-feature (Работа с отсутствующим функционалом). Клиент просит фичу, которой нет. У агента три пути: сказать «есть», сказать «нет» или честно поднять лапки — «не знаю». Последнее — суперважный исход для случаев, когда инфы нет вообще. Самое страшное — когда агент начинает галлюцинировать и придумывать функционал. Эта область бьет его по рукам за такие фантазии.

Как это всё живет вместе?

  • База — фреймворк RAGAS (поверх которого мы пишем свою магию).

  • Хранилище — Langfuse (держит датасеты и логи трейсов).

  • Запуск происходит из одной точки: скрипт сам раскидывает вопросы по областям и натравливает на них нужные метрики.

Если RAG и Agent — это классика, для которой есть готовые решения, то Clarifying и No-feature — наши авторские разработки. Эталоны для них мы не придумывали за кофе. Мы вытащили их из 10 000 реальных переписок менеджеров!

Четыре области оценки как отдельные мини-блоки: RAG из коробки RAGAS, остальные три — собственная инженерия
Четыре области оценки: RAG берётся из коробки RAGAS, Agent / Clarifying / No-feature — собственная инженерия

Как 10 000 сообщений подарили нам свои метрики

Наши авторские метрики не родились в вакууме. Мы не придумывали формулы, чтобы потом искать под них данные. Всё было ровно наоборот: сначала фактура, потом классификация, и только в конце — метрика.

Заказчик выгрузил нам 10 317 сообщений из Telegram. Это реальные переписки менеджеров с клиентами за несколько месяцев. Именно этих живых людей наш ИИ-агент должен был заменить или хотя бы подстраховать.

Мы скормили эти чаты в Gemini 3 Pro и запустили два промпта:

  1. Ищи паттерны, где менеджер задает уточняющие вопросы.

  2. Ищи вопросы от клиентов в духе «А есть ли у вас такая-то фича?».

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

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

  • technical_env — где сидим: Браузер или Тонкий клиент? Какая версия?

  • process_state — что делаем: закрываем месяц или проводим документы?

  • object_identification — дайте ID: ссылка, номер документа, артикул.

  • terminology_ambiguity — боль терминов: «резерв», «аванс», «база» (все это значит разное в разных местах).

  • true_goal — чего хотим на самом деле (классика: клиент спрашивает про X, а проблема в Y).

  • data_source — откуда дровишки: источник данных.

  • business_logic — как считаем: бизнес-логика.

  • visual_context — покажи скриншот, иначе не пойму.

  • configuration_dependency — зависит от конфигурации (та самая девятая категория из реальной боли).

Для фич, которых в системе может и не быть, мы выделили три железных вердикта:

  • «Есть» — нашли подтверждение в базе.

  • «Нет» — точно нет, пруфы на месте.

  • «Не знаю» — инфы нет вообще. И это важнейший исход! Раньше без него агент либо врал, что фича есть, либо лил воду в стиле «это возможно при правильных настройках». Теперь у него есть официальное право поднять лапки и честно признаться в неведении.

И вот из всего этого богатства родились наши звезды:

1. Clarifying Accuracy (Метрика Уточнений) Оценивает, как ловко агент распутывает неоднозначности. Оценка идет по трем ступеням: 0.0, 0.5 и 1.0. LLM-судья смотрит, должен ли был агент задать вопрос, и совпал ли он с нужной категорией из списка выше.

  • 1.0 — Красавчик! Спросил и попал в нужную категорию.

  • 0.5 — Молодец, что спросил, но промахнулся с темой (например, спросил про версию браузера, а проблема была в терминах).

  • 0.0 — Провал. Надо было уточнять, а он промолчал.

Половинчатый балл тут критически важен. Сам факт того, что ИИ понял необходимость вопроса — это уже половина успеха. Бинарная система (0 или 1) убила бы этот нюанс.

Девять категорий контекста, поднятых из переписки, и тернарная шкала: не уточнил, уточнил мимо, попал в категорию
Clarifying Accuracy: девять категорий контекста и тернарная шкала 0 / 0.5 / 1

2. No Feature Accuracy (Метрика Фантазий) Тут всё жестко: либо 1, либо 0. LLM-судья берет ответ агента про какую-то фичу, раскидывает его по корзинам («есть» / «нет» / «не знаю») и сверяет с эталоном. Совпало — молодец. Нет — ноль баллов. Без пощады.

Вопрос про существование функции и три исхода вердикта судьи, где «не знаю» — честный выбор
No Feature Accuracy: три класса вердикта — есть / нет / не знаю

Прелесть таких эталонов в том, что мы не требуем от агента отвечать слово в слово. Нам важна логика. Ситуация категоризирована правильно? Получи балл.

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

С логикой разобрались. Но чтобы оценивать техническую работу агента (вызов инструментов), нам пришлось залезть в высшую математику.

Бунт против RAGAS: зачем нам понадобился Венгерский алгоритм

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

В стандартном RAGAS есть две метрики: ToolCallAccuracy и ToolCallF1. Звучит логично: берем эталонный список вызовов инструментов, сравниваем с тем, что сделал агент, и ставим оценку. Но в суровой реальности это развалилось.

И вот почему:

Первый провал: дословное сравнение. ToolCallAccuracy сверяет данные байт в байт. Допустим, в эталоне написано: query="как настроить склад с резервом". Агент проявил смекалку и переформулировал: query="настройка склада, резерв". И всё! Метрика кричит: «Ошибка!» и ставит ноль. Хотя по смыслу агент всё сделал идеально. Наказывать ИИ за то, что он умнее скрипта — путь в никуда. Поэтому я переписал эту штуку, создав RouterToolCallAccuracy.

Теперь мы сами указываем, как сравнивать данные:

  • Для запросов (query) мы включили SemanticSimilarity — система смотрит на смысл, а не на буквы.

  • Для строгих вещей вроде id или phone оставили строгое совпадение (ExactMatch).

Никакой магии, просто жесткие правила для каждого параметра:

metric = RouterToolCallAccuracy(
    argument_metrics={
        # Смысл важнее букв
        "query": SemanticSimilarity(embeddings=..., threshold=0.7),
        # Только точное совпадение
        "document_id": ExactMatch(),
        "phone": ExactMatch(),
    },
    default_metric=ExactMatch(),
)

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

Так родилась метрика FuzzyToolCallF1. И вот тут на сцену выходит Венгерский алгоритм (привет, дискретная математика 1955 года!).

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

  1. Считаем «матрицу сходства» между тем, что сделал агент, и эталоном.

  2. Ищем идеальные пары (тут-то алгоритм и находит самое дешевое и точное совпадение).

  3. Оставляем только те совпадения, которые пробили нужный порог уверенности.

  4. Высчитываем итоговую метрику (precision, recall, F1).

async def ascore(self, references, predictions, callbacks=None):
    n_refs, n_preds = len(references), len(predictions)

    # 1. Строим матрицу сходства
    cost_matrix = np.zeros((n_refs, n_preds))
    for i, ref in enumerate(references):
        for j, pred in enumerate(predictions):
            cost_matrix[i, j] = await self._compare_tool_calls(pred, ref, callbacks)

    # 2. Вызываем магию Венгерского алгоритма
    row_ind, col_ind = linear_sum_assignment(-cost_matrix)

    # 3. Отсекаем мусор по порогу
    tp = sum(1 for r, c in zip(row_ind, col_ind)
             if cost_matrix[r, c] >= self.match_threshold)

    # 4. Считаем итоговые баллы
    precision = tp / n_preds
    recall = tp / n_refs
    return 2 * precision * recall / (precision + recall)

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

Идея FuzzyToolCallF1: от двух списков вызовов через матрицу сходства и оптимальное назначение к метрикам
FuzzyToolCallF1: матрица сходства, Венгерский алгоритм и честный F1 на множествах с дубликатами

Но одно дело — собрать красивые формулы на бумаге. Совсем другое — выкатить это в бой.

Боевое крещение: как метрика заставила агента поумнеть

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

Заказчик принес нам пачку «провалов» агента — те самые диалоги, где клиент Айтона ушел ни с чем или получил неверный ответ. Мы разобрали эту боль, разложили кейсы по нашим любимым областям (RAG / Clarifying / No-feature) и загнали в систему оценки. Схема простая: я запускаю тест -> смотрю метрики -> иду в Langfuse раскапывать трейсы (где агент споткнулся, что вытянул из базы) -> правлю промпты и логику -> запускаю заново.

Вот как развивались события:

  • Прогон 1 → Прогон 2. Мы перевели системный промпт в XML (модели так лучше соображают) и жестко запретили агенту фантазировать про несуществующий функционал. Ввели кучу фильтров. И… бац! Метрика честности (faithfulness) рухнула с 0.468 до 0.273. Почему? Потому что требования стали строже, и старые халтурные ответы перестали прокатывать. Это правильная боль роста.

  • Прогон 2 → Прогон 3. Тут мы поняли, что сломался сам датасет! Четыре кейса лежали в разделе RAG, но на деле клиенты писали настолько размыто, что агенту нужно было задавать уточняющие вопросы, а не искать инфу вслепую. Мы перекинули их в Clarifying. То есть система помогла нам вылечить собственные данные!

  • Прогон 3 → Прогон 4. Допилили логику до идеальных «трех исходов»: нашел пруфы / точно нет / честно не знаю. А еще увеличили агенту лимит на вызов инструментов, чтобы он успевал раскопать сложные цепочки до окончательного ответа. И добавили ту самую девятую категорию уточнений (configuration_dependency), потому что реальность подкинула новых сюрпризов.

А теперь посмотрите на цифры. Главный триллер здесь — это второй прогон, когда из-за новых жестких правил всё покраснело. Зато потом начался стабильный рост.

Метрика

Run 1

Run 2

Run 3

Run 4 (Gemini)

Run 4 (Claude)

faithfulness

0.468

0.273

0.633

0.509

0.693

answer_correctness

0.437

0.405

0.481

0.478

0.478

answer_relevancy

0.870

0.391

0.528

0.877

0.894

Clarifying Accuracy

0.273

0.182

0.367

0.400

0.467

No Feature Accuracy

0.615

0.538

0.538

0.769

0.615

Три метрики за четыре прогона: просадка на Run 2 от ужесточения требований и итоговый выход выше старта
Четыре прогона на боевом датасете: просадка на Run 2 после ужесточения требований и выход выше старта на Run 3–4

И вот тут начинается самое интересное. Иногда метрика ставит ноль не потому, что агент тупой, а потому, что он слишком умный!

И вот тут логика сломалась. Разбираю трейсы в Langfuse. Вижу кейс: в эталоне написано «такой функции в УНФ нет». А агент расписывает клиенту: «Есть такая функция! Зайдите в раздел X, настройте Y…». И что вы думаете? В свежем обновлении 1С:УНФ эту фичу реально добавили! А наш эталон был собран полгода назад. Агент оказался прав, прочитал свежую доку, а жесткая метрика влепила ему жирный ноль.

Или другой случай с уточнениями: по эталону агент должен был переспросить термин, а он копнул глубже и спросил клиента про бизнес-логику расчетов. Система поставила ему 0.5 балла («не та категория»). Но по здравому смыслу агент заслужил 10 из 10.

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

Именно поэтому я всегда говорю: оценка ИИ — это не бездушная автоматизация QA. Если тест покраснел, это не приговор, а повод засучить рукава и разобраться ручками.

Цифры вместо гаданий на кофейной гуще

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

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

Но сказок не бывает:

  • Эталоны придётся собирать руками (или выуживать из терабайтов реальной переписки, как это сделали мы).

  • Метрики часто придется переписывать под себя (даже если придется вспомнить Венгерский алгоритм), потому что готовые фреймворки слишком грубые.

  • И да, всё равно иногда придется садиться и разбирать провалы глазками, чтобы понять — ИИ сломался или просто мир изменился.

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

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

А теперь ваша очередь! Расскажите в комментариях: как вы сейчас измеряете качество своих ИИ-агентов? На какой выборке тестируете промпты? Какие костыли лезут из коробочных решений? Очень жду ваших историй!


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

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

Если хотите перенять опыт и научиться делать подобные системы самостоятельно, у нас есть онлайн-курсы, а ближайший живой поток курса Deep Agents, где evaluation и red teaming — один из четырёх ключевых блоков, стартует уже в четверг, 28 мая.

По любым вопросам пишите мне в личку: Telegram или ВК. Приглашаем также в наши соцсети про ИИ-кодинг ИИ-агентов: в ТГ-канал и ВК-сообщество

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