AI-агенты и автоматизация Собрать руками
Как тестировать AI-агента
Тестирование AI-агента — это не про «работает или нет», а про надёжность, безопасность и предсказуемость в реальных сценариях. Разбираем инструменты, пайплайны и типичные ловушки.
Что тестировать у AI-агента?
AI-агент — это не просто API-вызов. Он состоит из цепочки: намерение → контекст → выбор инструмента → вызов инструмента → обработка результата → ответ пользователю. Тестировать нужно каждый этап: корректность парсинга намерений, правильность вызова инструментов, обработку ошибок, fallback-логику и итоговую релевантность ответа. Отсутствие тестов на этом уровне приводит к «тихим сбоям»: агент не падает, но делает неправильные действия.
Структура тестового пайплайна
flowchart TD
A[Сценарий: «Заказать кофе»] --> B[Unit-тесты инструментов]
B --> C[Mocked-вызов LLM с фиксированным контекстом]
C --> D[Проверка выбора инструмента]
D --> E[Интеграционный вызов реального инструмента]
E --> F[Валидация результата]
F --> G[Evals: релевантность, безопасность, юзабилити]
G --> H[Fallback: если инструмент недоступен]
Unit-тест инструмента (пример)
// test/tools/test_order_coffee.js
test('orderCoffee: возвращает ID заказа при валидных данных', () => {
const mockDB = { saveOrder: jest.fn().mockResolvedValue('order_123') };
const result = await orderCoffee({
user_id: 'u_777',
drink: 'latte',
size: 'm',
mockDB
});
expect(mockDB.saveOrder).toHaveBeenCalledWith({
drink: 'latte',
size: 'm',
status: 'pending'
});
expect(result).toEqual({ order_id: 'order_123' });
});
Важно: тестируйте инструменты как чистые функции — без LLM, без внешних зависимостей. Это гарантирует, что ошибка не в инструменте, а в его вызове.
Mocked-тест LLM-логики
Используйте фикстуры для имитации ответа LLM. Это позволяет проверить, как агент реагирует на разные формулировки и ошибки.
// test/agent/plan_step.js
test('агент выбирает orderCoffee при запросе «заказать латте»', () => {
const mockLLM = jest.fn().mockResolvedValue({
tool_name: 'orderCoffee',
tool_args: { drink: 'latte', size: 'm' }
});
const agent = new Agent({ tools: [orderCoffee], llm: mockLLM });
const plan = await agent.plan('Закажи, пожалуйста, латте среднего размера');
expect(plan.tool_name).toBe('orderCoffee');
expect(plan.tool_args.drink).toBe('latte');
});
Такие тесты ловят ошибки в промптах, парсинге JSON и логике выбора инструментов.
Типичные ошибки при тестировании
- Тестируем только «счастливый путь» — агент должен корректно обрабатывать: неясные запросы, недоступные инструменты, невалидные аргументы, таймауты.
- Игнорируем логи — без структурированных логов (trace_id, tool_call_id, confidence_score) невозможно отследить, где именно агент «сбился».
- Тестируем только на одном LLM — разные модели (GPT-4o, Claude 3.5 Sonnet) по-разному интерпретируют инструкции и возвращают JSON. Проверяйте на 2+ моделях.
- Нет тестов на fallback — если инструмент недоступен, агент должен либо переспросить, либо передать человеку. Это критично для безопасности.
Чеклист тестирования AI-агента
- ✅ Unit-тесты всех инструментов (включая edge-кейсы: пустой ID, отрицательная сумма)
- ✅ Mocked-тесты выбора инструмента и парсинга JSON
- ✅ End-to-end сценарии: «заказать кофе», «отменить заказ», «узнать статус»
- ✅ Тесты fallback: инструмент недоступен, LLM вернул невалидный JSON, таймаут
- ✅ Evals: релевантность ответа (LLM-as-a-judge), безопасность (prompt injection), юзабилити (ясность формулировок)
- ✅ Логирование: trace_id, timestamp, tool_call_id, confidence_score, error_type
Следующий шаг: evals-пайплайн
После unit- и интеграционных тестов запускайте автоматические evals на реальных или синтетических данных:
flowchart LR
A[Сценарий: 100 запросов] --> B[Запуск агента]
B --> C[Сохранение trace_id + логов]
C --> D[Evals-движок]
D --> E1[Релевантность]
D --> E2[Безопасность]
D --> E3[Tool-accuracy]
D --> E4[Latency]
E1 & E2 & E3 & E4 --> F[Отчёт: score, failure cases]
Пример инструментов: langfuse (трейсы), ragas (релевантность), guardrails-ai (безопасность), pytest-asyncio (авто-тесты).