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

Юнит-тест устроен просто: подали на вход 2 + 2, ждём 4, получили не 4 — тест красный. Автономный агент на большой языковой модели не даёт такой роскоши. На один и тот же запрос он вернёт два разных текста, при повторе вызовет другой инструмент, а на третий раз зациклится в попытке уточнить условие. Детерминизм, на котором держится весь классический тестовый пайплайн, здесь отсутствует по устройству. Это меняет не отдельные проверки, а саму постановку вопроса «что значит, что система работает».
Где ломается привычная модель тестирования
Обычное ПО тестируют по контракту: вход, выход, побочные эффекты. Агент нарушает все три предпосылки сразу.
- Выход недетерминирован. Даже при
temperature=0у провайдеров возможны расхождения ответов между вызовами: сказываются версии модели, батчинг на стороне сервиса, изменения в железе. - Путь к результату — часть поведения. Агент сам решает, какой инструмент вызвать, сколько шагов сделать и когда остановиться. Правильный ответ, полученный за 40 вызовов API вместо 3, — это уже дефект, хотя выход формально верный.
- Среда живая. Агент ходит в поиск, дёргает сторонние API, читает файлы. Результат зависит от того, что вернул интернет в момент прогона, а не только от вашего кода.
Из-за этого падает не тест, а вера в тест. Красный прогон может означать регрессию, а может — что модель провайдера обновилась ночью или поисковая выдача сменилась. Разбор каждого падения превращается в расследование.
Что тестируют у агента вместо равенства выходов
Раз точного совпадения нет, проверяют свойства ответа и траектории. Полезно разделить объект тестирования на слои — каждый со своим подходом.
1. Детерминированная обвязка
Всё, что вокруг модели, тестируется обычными юнит-тестами: парсинг ответа модели в структуру, роутинг между инструментами, ретраи, обработка таймаутов, форматирование промпта из шаблона. Здесь LLM мокается заглушкой с фиксированным ответом, и вы проверяете свой код, а не модель. Эту часть покрытия недооценивают, а именно она ловит большинство «глупых» падений в проде.
2. Вызовы инструментов
Для агента критично, какой инструмент он выбрал и с какими аргументами. Это проверяемо строго: замокайте инструменты, зафиксируйте сценарий и утверждайте, что при запросе «отмени заказ 123» агент вызвал cancel_order с order_id=123, а не refund и не выдумал несуществующий номер.
3. Качество ответа (evals)
Сам текст оценивают наборами примеров — их называют evals. По сути это датасет «вход → ожидаемое свойство ответа» и функция-судья, которая решает, засчитан ли ответ. Судьёй может быть проверка по ключевым словам, схеме JSON, регулярному выражению — или другая модель.
LLM-as-a-judge и его ловушки
Модель-судья удобна: скормили ей ответ агента и критерий («содержит ли ответ корректный расчёт», «вежлив ли тон»), получили вердикт. Но судья сам недетерминирован и предвзят — например, склонен выше оценивать длинные ответы. Его вердикты стоит хотя бы раз сверить с разметкой живого человека на выборке, иначе вы автоматизируете собственные иллюзии.
Тест обычного кода отвечает «сломано или нет». Eval агента отвечает «стало лучше или хуже, чем на прошлой версии» — это не бинарный светофор, а метрика с шумом.
Сравнение двух миров
| Аспект | Классическое ПО | Автономный агент |
|---|---|---|
| Результат на одном входе | Всегда одинаковый | Варьируется от запуска к запуску |
| Критерий прохождения | Точное равенство | Свойство ответа + доля пройденных кейсов |
| Что проверяем | Выход и побочные эффекты | Выход, траекторию, выбор инструментов, стоимость |
| Причина падения | Изменение в вашем коде | Ваш код, версия модели или внешняя среда |
| Стоимость прогона | Секунды, бесплатно | Минуты, деньги за токены |
| Стабильность CI | Зелёный либо красный | Флаки по своей природе, нужен порог |
Практический подход к прогонам
Из-за шума один прогон ничего не доказывает. Работают статистические и пороговые приёмы.
- Запускайте кейс несколько раз и смотрите на долю успеха (pass@k). Порог вроде «не меньше 90% из 10 прогонов» честнее, чем требование зелёного с первого раза.
- Отделите оффлайн-evals от онлайна. Оффлайн — фиксированный датасет, гоняется на каждый коммит и ловит регрессии. Онлайн — метрики на реальном трафике: доля решённых задач, эскалации к человеку, стоимость на диалог.
- Замораживайте версию модели. Пиньте конкретную ревизию у провайдера, где это возможно, чтобы отличать свои изменения от чужих обновлений.
- Записывайте траектории. Логируйте каждый шаг: промпт, ответ модели, вызванный инструмент, аргументы, стоимость. Без этого разбор падения невозможен.
- Ставьте бюджет-предохранители. Тест должен падать не только по качеству, но и когда агент сделал 50 вызовов вместо ожидаемых 5 — это защита от зацикливания и от счёта за токены.
Регрессии, которых не было в мире детерминированного кода
Смена версии модели способна улучшить средний ответ и одновременно уронить конкретный сценарий — например, агент стал «умнее» и перестал буквально следовать вашему формату вывода. В обычном ПО такого не бывает: код не меняется сам. Поэтому набор evals — не разовая работа, а актив, который живёт вместе с продуктом. Каждый инцидент в проде стоит превращать в новый кейс, иначе одна и та же ошибка вернётся после следующего апдейта модели.
И держите в голове главное отличие: вы тестируете систему, часть которой вам не принадлежит и меняется без вашего ведома. Задача теста здесь — не доказать, что всё идеально, а быстро показать, что стало хуже, и на каком именно шаге.
Prompt-инженер: Идеальные запросы для Midjourney, ChatGPT и других моделей.
Спросить за 15 ₽Источники: OpenAI Evals — документация и репозиторий, Anthropic — Building effective agents
Частые вопросы
Можно ли добиться детерминизма, выставив temperature=0?
Что такое eval и чем он отличается от юнит-теста?
Стоит ли использовать другую модель как судью качества?
Как встроить прогон агента в CI, если тесты флаки?
Почему важно тестировать не только ответ, но и траекторию?
Как отличить регрессию в моём коде от обновления модели у провайдера?
Материал носит информационный характер и подготовлен редакцией «Агентуры». Он не является офертой, рекламой или индивидуальной консультацией. Упомянутые продукты, компании и торговые знаки принадлежат их правообладателям. Перед принятием решений, влекущих юридические или финансовые последствия, обратитесь к профильному специалисту.