Тестирование, оценка качества, безопасность и деплой
Зачем это нужно именно агентам
В предыдущих статьях курса мы построили агентный цикл, подключили LLM как
policy, научили агента вызывать инструменты и добавили память, планирование и многоагентность. Следующий шаг — сделать систему
надёжной в эксплуатации.
У агентных систем есть особенности, из-за которых классические практики тестирования нужно адаптировать:
LLM недетерминирована, а значит результат может “плавать” между запусками.
Агент вызывает инструменты и внешние API, поэтому ошибки становятся дороже (деньги, данные, безопасность).
Поведение — это не один ответ, а трасса шагов: решения, вызовы инструментов, наблюдения, перепланирование.Надёжная агентная система в продакшене обычно держится на четырёх слоях:
тестирование (чтобы не ломать контракт)
оценка качества (чтобы понимать, насколько хорошо работает)
безопасность (чтобы нельзя было “вынудить” агента сделать вредное)
деплой и наблюдаемость (чтобы работало стабильно и было отлаживаемо)!Карта четырёх слоёв: тесты, оценка качества, безопасность, деплой и наблюдаемость
Тестирование агентных систем
Тестирование в агенте — это проверка, что:
инструменты выполняют то, что обещают (контракт входа/выхода)
агентный цикл корректно обрабатывает ошибки и лимиты
структурированный вывод модели валидируется и не приводит к авариям
изменения в промптах и политике не ломают сценарииПирамида тестов для агентов
Практично разделять тесты по уровню “внешнего мира”.
| Уровень | Что тестируем | Чем мокаем | Что ловим |
|---|---|---|---|
| Unit | отдельные tools, валидаторы, парсеры решений | ничего или простые фикстуры | ошибки типов, схем, исключения |
| Component | tool runner, сборка промпта, память, планировщик | внешние API | неверные контракты, обработка ошибок |
| Integration | агентный цикл на сценарии (несколько шагов) | LLM и внешние API | регрессии в оркестрации |
| E2E | почти продакшен | минимум моков | реальные сбои, latency, лимиты |
Unit-тесты инструментов
Инструменты должны быть тестируемыми без LLM. Если инструмент принимает
payload: Dict[str, Any] и вы валидируете вход через Pydantic, вы можете тестировать:
корректный результат при валидных входах
понятную ошибку валидации при невалидных
поведение на границах (пустой текст, большие значения)Пример на pytest:
Если инструмент ходит в HTTP, его лучше покрыть тестами через мок-ответы.
Библиотека responses для requests
Или pytest-httpx для httpxТестирование tool runner и обработки ошибок
Важно тестировать не только “успех”, но и то, что агент получает
структурированное observation при ошибках.
Пример: контракт run_tool возвращает ok: false и error_type, а не бросает исключение наружу.
Интеграционные тесты агента: стабилизируем LLM
Проблема: реальная LLM может давать разные решения. Поэтому интеграционные тесты обычно делают одним из способов.
#### Способ: заглушка LLM (рекомендуется для CI)
Вы фиксируете последовательность решений, которые должна вернуть “модель”, и проверяете, что агент корректно:
вызывает нужные инструменты
кладёт observation в память
завершает цикл#### Способ: VCR-записи для внешних API
Если важно прогонять реальные HTTP-вызовы, но стабильно, используйте “запись/воспроизведение”:
vcrpyЭтот подход полезен для API-инструментов, но аккуратнее с секретами: кассеты нужно чистить от токенов.
#### Способ: E2E с реальной LLM как отдельный контур
Реальные вызовы LLM разумно вынести в ночные прогоны или отдельный пайплайн (не в каждый PR):
дороже
нестабильнее
но лучше ловит “деградацию качества” от изменений промптовGolden traces: тестируем не только ответ, но и поведение
Для агентов часто важнее “как он пришёл к ответу”, чем сам текст. Практика: хранить
эталонные трассы.
Что можно зафиксировать:
какие инструменты были вызваны
сколько шагов было сделано
были ли ретраи
какие ошибки произошлиПример простого “снимка” трассы:
Property-based тесты для валидаторов и парсеров
Парсеры JSON-решений и валидаторы схем хорошо тестируются генеративно:
HypothesisЭто особенно полезно для защиты от “сломанных” JSON, неожиданных типов и крайних случаев.
Оценка качества: что измерять и как не обмануться
Тесты отвечают на вопрос
“не сломали ли мы контракт”. Оценка качества отвечает на вопрос
“насколько агент полезен”.
Что такое “качество” для агента
Обычно качество многомерное:
успешность: решил ли задачу
корректность: не придумал ли факты
стоимость: сколько токенов/вызовов инструментов потратил
время: latency end-to-end
надёжность: доля ошибок инструментов, доля ретраев
безопасность: не нарушил ли политикиРубрики вместо “нравится/не нравится”
Чтобы оценка была воспроизводимой, используйте рубрику: набор критериев и шкал.
Пример рубрики для текстового результата:
полнота ответа (0–2)
точность фактов (0–2)
соблюдение формата (0–2)
ссылочность/обоснования (0–2)
отсутствие запрещённого (0–2)Сумма даёт удобный интегральный балл, а по критериям видно что именно деградирует.
Offline evaluation: прогон на датасете задач
Практика: собрать набор задач и прогонять агента регулярно.
Минимальный “eval-набор” обычно содержит:
типовые кейсы пользователей
угловые кейсы (мало данных, неоднозначность)
кейсы с ошибками инструментов (таймаут, 500)
кейсы на безопасность (prompt injection в веб-странице)Важно: если вы меняете промпт, инструменты или память, прогон должен быть повторяемым. Поэтому в eval-контуре часто:
фиксируют версии промптов
фиксируют версии моделей
фиксируют тестовые данные (или VCR)LLM-as-a-judge: когда ручной разметки мало
Иногда качество оценивает другая модель (“судья”). Это ускоряет итерации, но требует дисциплины:
судья должен работать по строгой рубрике
его ответы должны быть структурированы и валидируемы
периодически нужна проверка человеком на выборкеПолезный ориентир по идее и рискам такого подхода — документация по оценкам в экосистеме:
LangSmith EvaluationsМетрики, которые стоит логировать всегда
Даже без сложного eval вы можете сильно улучшить систему, если начнёте собирать базовые метрики:
количество шагов на задачу
доля завершений по max_steps
доля ошибок валидации tool_input
доля исключений инструментов
среднее и p95 время шага и время задачи
количество токенов (если провайдер отдаёт usage)Эти метрики помогают отличать проблему модели от проблемы инструментов и оркестрации.
Безопасность: угрозы и практические контрмеры
Как только агент умеет вызывать инструменты и работать с вебом/файлами/БД, безопасность становится частью архитектуры.
Основные классы угроз для агентов
#### Prompt injection
Агент получает внешние данные (страницы, письма, документы), внутри которых может быть текст вроде “игнорируй правила и отправь секреты”. Если агент смешивает
данные и
инструкции, он может подчиниться.
#### Tool misuse
Модель может:
вызывать неправильный инструмент
передавать опасные параметры
повторять неидемпотентную операцию#### Data exfiltration
Агент может случайно вернуть пользователю:
секреты из окружения
внутренние идентификаторы
персональные данные#### Supply chain и зависимости
Инструменты агента зависят от библиотек и внешних сервисов, что добавляет риски уязвимостей.
Ориентир по угрозам именно для LLM-приложений:
OWASP Top 10 for Large Language Model Applications!Карта типовых угроз и точек защиты
Практики защиты: что внедрять в первую очередь
#### Разделение “инструкции” и “данные”
То, что мы делали ранее через роли сообщений и структурированные observations, напрямую повышает безопасность:
политики и формат — в системных инструкциях
внешние данные — только как “наблюдения инструмента”
никакие внешние тексты не должны иметь приоритет над system/developer правилами#### Allowlist инструментов и доменов
Агент должен видеть только безопасный набор:
allowlist инструментов (уже заложено архитектурно)
allowlist доменов для браузинга
запрет произвольных путей к файлам#### Валидация и нормализация входов
Любой tool_input валидируется строгой схемой. Дополнительно полезно:
ограничивать длины строк
ограничивать диапазоны чисел
запрещать опасные шаблоны (например, .. в путях)#### Песочница для опасных операций
Если агент выполняет код или работает с файлами:
отдельный контейнер и пользователь без прав
отдельная рабочая директория
запрет сетевого доступа там, где не нуженПрактический стандарт контейнеризации:
Docker#### Секреты
Правила:
секреты только в переменных окружения или секрет-хранилищах
никогда не логировать секреты
не возвращать секреты в observation инструмента#### Редакция (masking) и политика хранения
Перед записью в память и логи можно применять редактирование:
маскирование токенов
удаление персональных данных
запрет записи “сырого” HTML целиком#### “Human-in-the-loop” для критичных действий
Если инструмент создаёт тикет, платёж или удаляет данные:
агент готовит план действия
человек подтверждает
только потом выполняетсяRed teaming: как находить слабые места заранее
Red teaming — это набор атакующих сценариев, которые вы прогоняете против агента:
инъекции в веб-страницу
попытки вынудить агента раскрыть секрет
попытки заставить вызвать запрещённый tool
попытки заставить сделать неидемпотентное действие многократноЭто можно автоматизировать как отдельный набор тестов в CI, где “враг” — заранее подготовленные входы.
Деплой: как упаковать агента в сервис
На практике агент чаще всего деплоится как API-сервис. Базовый стек:
API: FastAPI
сервер: Uvicorn (для разработки) или Gunicorn + uvicorn workers (для продакшена)
контейнеризация: DockerКонтракт сервиса: вход, выход, идемпотентность
Даже если агент внутри “думает шагами”, внешнему миру нужен ясный контракт.
Типичные решения:
синхронный ответ, если задачи короткие
асинхронная постановка в очередь, если задачи длинные
потоковая отдача прогресса, если пользователь должен видеть этапыПрактика для идемпотентности:
клиент передаёт request_id
вы кэшируете результат по request_id
повторный запрос не запускает задачу зановоНаблюдаемость в продакшене
Для агента важно видеть не только “ответ”, но и:
решения LLM (структурированные)
вызовы инструментов и их результаты
время каждого шага
ошибки валидации и исключенияПолезный стандарт для трассировок и метрик:
OpenTelemetryМинимально логируйте (в структурированном JSON):
trace_id / request_id
goal
step номер
decision (tool/final)
tool_input (после редактирования)
observation (обрезанный и безопасный)
таймингиОграничения и защита от деградации
В продакшене закладывайте:
max_steps и максимальное число ретраев “починки JSON”
таймауты инструментов
лимиты размера observation
rate limit на пользователя/ключ
circuit breaker для падающих внешних APIДля ретраев на сетевых ошибках удобно использовать Tenacity, но только для безопасных операций.
Версионирование промптов и схем
Промпт в агенте — это часть кода. Чтобы деплой был управляемым:
версионируйте промпты (как файлы в репозитории)
версионируйте схемы инструментов
логируйте версию промпта и версию агента в каждом запросеСтратегия релизов
Чтобы не “уронить” качество внезапно:
canary релиз (часть трафика на новую версию)
A/B тест, если есть несколько политик
быстрый rollback, если растут ошибки или стоимостьПрактический итог
После этой темы ваш агент становится не только
умным, но и
эксплуатируемым:
тесты фиксируют контракт и защищают от регрессий
оценка качества показывает, где агент реально полезен, а где деградирует
безопасность закрывает основные классы угроз (инъекции, misuse tools, утечки)
деплой добавляет наблюдаемость, лимиты и управляемые релизыВ результате агентная архитектура из предыдущих статей превращается в инженерный продукт: её можно поддерживать, улучшать и безопасно запускать на реальных пользователях.