0Pricing
AI Agents · Урок

Почему тестирование агентов отличается

Недетерминированность, стоимость LLM и причины, по которым стандартных модульных тестов недостаточно.

«Почему тестирование агентов отличается» — бесплатный урок AI Agents на CoddyKit. Это урок 1 из 4. Ты можешь прочитать весь урок бесплатно ниже — а потом практиковать его прямо в браузере с встроенным редактором кода и ИИ-репетитором 24/7. Это часть пути обучения AI Agents, и твой прогресс синхронизируется между веб-версией и приложением CoddyKit. Курс AI Agents содержит 4 уроков всего.

Тестирование программного обеспечения и агентов

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

ИИ-агенты нарушают это предположение. Один и тот же запрос может выдавать разные результаты при каждом запуске, поэтому стандартных подходов к тестированию недостаточно.

Недетерминированность: одинаковые входные данные, разные результаты

LLM по своей природе вероятностны. Параметр temperature управляет случайностью — даже при значении temperature=0 результаты могут различаться между версиями модели или изменениями инфраструктуры.

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

import openai

client = openai.OpenAI(api_key='YOUR_API_KEY')

# Same prompt, potentially different outputs each run
for i in range(3):
    response = client.chat.completions.create(
        model='gpt-4o-mini',
        messages=[{'role': 'user', 'content': 'Name a planet.'}],
        temperature=0.9  # High randomness
    )
    print(f'Run {i+1}: {response.choices[0].message.content}')
# Run 1: Mars
# Run 2: Jupiter
# Run 3: Saturn

Проблема стоимости: реальные вызовы LLM дороги

Запуск набора тестов, выполняющего реальные вызовы программных интерфейсов OpenAI или Антропик, может стоить несколько долларов за один запуск. Конвейер непрерывной интеграции, выполняющий 100 тестов × 10 итераций, может обходиться в сотни долларов в месяц.

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

# A test that calls the real API costs tokens every run
# 100 tests x 500 tokens each x 10 CI runs/day = 500,000 tokens/day
# At $0.15/1M tokens (gpt-4o-mini): ~$0.075/day = ~$27/year for a tiny suite
# For gpt-4o: 15x more expensive = ~$400/year

# This is why mocking and recording API responses is essential
print('Real API calls in tests = expensive and slow')
print('Solution: Mock or record LLM responses in unit tests')
print('Reserve real calls for scheduled integration tests')

Проблема задержки

Реальные вызовы программных интерфейсов LLM обычно занимают от 2 до 20 секунд. Набору из 50 тестов потребуется от 100 до 1000 секунд. Это снижает продуктивность разработчиков — быстрая обратная связь является ключевым свойством хороших тестов.

Имитация вызовов LLM позволяет выполнять тесты за миллисекунды.

import time

# Simulating what a test suite looks like with real vs mocked calls
num_tests = 50

# Real API calls
real_time = num_tests * 5  # avg 5 seconds per call
print(f'With real API calls: {real_time}s = {real_time/60:.1f} minutes')

# Mocked calls
mock_time = num_tests * 0.001  # <1ms per mock
print(f'With mocked calls: {mock_time:.3f}s = nearly instant')

# Conclusion: mock in unit tests, use real calls in integration tests

Внешние зависимости в тестах агентов

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

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

В модульных тестах ими необходимо управлять или заменять их имитациями.

# An agent might call multiple external services
# Each is a potential test failure point

def agent_pipeline(query: str) -> str:
    search_results = search_web(query)       # External: Tavily/Serper API
    documents = fetch_documents(search_results)  # External: HTTP calls
    answer = llm_summarize(documents)        # External: OpenAI API
    saved = database_store(answer)           # External: PostgreSQL
    return answer

# In unit tests: mock ALL of these
# In integration tests: use sandboxed versions of real services
print('Each external call is a test reliability risk')

Что предполагают стандартные модульные тесты

Стандартные среды модульного тестирования, такие как pytest, предполагают, что:

  • тесты выполняются быстро (за миллисекунды)
  • тесты детерминированы
  • тесты не имеют внешних побочных эффектов
  • тесты можно выполнять в любом порядке

Тесты агентов нарушают все четыре предположения, если специально не спроектировать систему с их учётом.

# Standard unit test — works perfectly for deterministic code
def add(a, b):
    return a + b

def test_add():
    assert add(2, 3) == 5  # Always passes — deterministic

# Agent 'unit test' that calls a real LLM — problematic
# def test_agent_answers_question():
#     response = agent.run('What is 2+2?')
#     assert response == '4'  # Might return 'The answer is 4' or 'Four'

print('Exact string matching fails for LLM outputs')
print('Need structural or semantic assertions instead')

Пирамида тестирования агентов

Практическая стратегия тестирования агентов строится по принципу пирамиды:

  • Модульные тесты (много, быстро): тестируйте отдельные инструменты и функции с имитацией вызовов LLM
  • Интеграционные тесты (меньше, медленнее): тестируйте конвейер агента целиком с изолированными службами
  • Оценочные тесты (редко, дорого): проверяйте качество результатов с помощью реальных вызовов LLM и оценки в стиле человеческой

Структурные и смысловые проверки

Вместо точного сопоставления строк тесты агентов должны использовать структурные проверки (вызвал ли агент правильный инструмент?) или смысловые проверки (содержит ли результат нужную концепцию?).

# Fragile: exact string match
# assert response.content == 'The capital of France is Paris.'

# Better: structural assertion
# assert response.tool_calls[0]['function']['name'] == 'search_web'

# Better: semantic check
def test_capital_in_response(response_text: str) -> bool:
    key_words = ['paris', 'france', 'capital']
    lower = response_text.lower()
    return all(word in lower for word in key_words)

response = 'Paris is the capital city of France.'
print(test_capital_in_response(response))  # True

Среды оценки и LLM в роли судьи

Для оценки качества в отрасли используют LLM в роли судьи: вторую LLM просят оценить результат агента. Такие среды, как DeepEval и RAGAS, автоматизируют этот подход.

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

import openai

client = openai.OpenAI(api_key='YOUR_API_KEY')

def llm_judge(question: str, answer: str) -> dict:
    prompt = f'Question: {question}\nAnswer: {answer}\nRate the answer 1-5 for accuracy. Reply with only a number.'
    response = client.chat.completions.create(
        model='gpt-4o-mini',
        messages=[{'role': 'user', 'content': prompt}]
    )
    score = int(response.choices[0].message.content.strip())
    return {'score': score, 'pass': score >= 4}

# result = llm_judge('What is the capital of France?', 'Paris')
# print(result)  # {'score': 5, 'pass': True}

Регрессионное тестирование агентов

Когда Вы обновляете запрос или изменяете логику агента, регрессионные тесты проверяют, что существующее поведение не нарушилось. Записывайте эталонные примеры (входные данные → ожидаемая структура) и автоматически запускайте их при каждом коммите.

# golden_examples.py
GOLDEN_EXAMPLES = [
    {
        'input': 'Search for the weather in Paris',
        'expected_tool': 'get_weather',
        'expected_args': {'city': 'Paris'}
    },
    {
        'input': 'Calculate 15% tip on $45',
        'expected_tool': 'calculate',
        'expected_args': {'expression': '45 * 0.15'}
    }
]

def run_regressions(agent, examples: list) -> int:
    failures = 0
    for ex in examples:
        result = agent.plan(ex['input'])  # mocked LLM
        if result['tool'] != ex['expected_tool']:
            print(f'FAIL: expected {ex["expected_tool"]}, got {result["tool"]}')
            failures += 1
    return failures

# --- demo: a stub agent whose .plan() mimics an LLM's tool choice ---
class _StubAgent:
    def plan(self, text):
        if 'weather' in text.lower():
            return {'tool': 'get_weather'}
        if 'tip' in text.lower() or 'calculate' in text.lower():
            return {'tool': 'wrong_tool'}  # simulate a regression
        return {'tool': 'unknown'}

failures = run_regressions(_StubAgent(), GOLDEN_EXAMPLES)
print(f'{failures} of {len(GOLDEN_EXAMPLES)} golden examples failed')

Настройка базового файла тестов агента

Ниже приведена минимальная структура файла тестов агента для pytest. Она отделяет быстрые модульные тесты (с имитациями) от медленных интеграционных тестов (с реальными вызовами), позволяя запускать только необходимые проверки.

# tests/test_agent.py
import pytest

# Fast unit tests — run on every commit
class TestAgentTools:
    def test_tool_returns_dict(self, mock_llm):
        result = my_tool(query='test')
        assert isinstance(result, dict)
        assert 'data' in result

    def test_agent_selects_correct_tool(self, mock_llm):
        response = agent.run('Search for Python tutorials')
        assert response['tool_used'] == 'web_search'

# Slow integration tests — run nightly or on release
@pytest.mark.integration
class TestAgentIntegration:
    def test_full_pipeline_with_real_api(self):
        # Uses real OpenAI + sandboxed services
        result = agent.run('Summarize the Python docs')
        assert len(result['answer']) > 50

Проверка знаний: чем отличается тестирование агентов

Проверьте, насколько хорошо Вы понимаете уникальные сложности тестирования ИИ-агентов.

Итоги: почему тестирование агентов отличается

Тестирование ИИ-агентов требует иного подхода, чем стандартное модульное тестирование:

  • Недетерминированность: один и тот же ввод может приводить к разным допустимым результатам
  • Стоимость: реальные вызовы LLM обходятся дорого — в модульных тестах используйте имитации
  • Задержка: реальные вызовы API занимают секунды, а имитации выполняются за миллисекунды
  • Внешние зависимости: инструменты и API необходимо контролировать в тестах
  • Проверки: используйте структурные и смысловые проверки, а не точное сопоставление строк

Используйте пирамиду тестирования: много недорогих модульных тестов с имитациями и меньше дорогих интеграционных тестов с реальными вызовами.

Часто задаваемые вопросы

Урок «Почему тестирование агентов отличается» бесплатный?

Да — полный текст урока «Почему тестирование агентов отличается» бесплатно доступен здесь в веб-версии. Чтобы практиковать его интерактивно (встроенный редактор кода и ИИ-репетитор 24/7) и разблокировать остальной курс AI Agents, подпишись на CoddyKit PRO. Курс AI Agents содержит 4 уроков всего.

Чему я научусь в уроке «Почему тестирование агентов отличается»?

Недетерминированность, стоимость LLM и причины, по которым стандартных модульных тестов недостаточно. Ты практикуешь AI Agents с помощью реального кода, который запускаешь прямо в браузере, и ИИ-репетитор 24/7 отвечает на твои вопросы во время урока.

Нужен ли мне опыт, чтобы начать AI Agents?

Предыдущий опыт не требуется. AI Agents на CoddyKit структурирован для всех уровней — от новичков до продвинутых, поэтому ты можешь начать отсюда или с самого начала и учиться в своем темпе. Это урок 1 из 4.

Сколько времени занимает урок «Почему тестирование агентов отличается»?

Большинство уроков CoddyKit занимают около 5–10 минут. Каждый из них компактный и интерактивный, поэтому ты постоянно делаешь прогресс и продолжаешь с того же места в веб-версии и приложении.

Можно ли писать и запускать код в этом уроке AI Agents?

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

Все уроки этого курса

  1. Почему тестирование агентов отличается
  2. Имитация вызовов LLM в тестах
  3. Тестирование агентов на основе утверждений
  4. Интеграционные тесты для конвейеров агентов
← Назад к AI Agents