English translation is not available yet. Showing Russian content.

Настроить A/B тестирование агентов

ТЕХНИЧЕСКОЕ ЗАДАНИЕ: Настроить A/B тестирование агентов

1. Цель задачи

Научиться проектировать и проводить A/B‑эксперимент для двух версий AI‑агента (control и treatment) в production‑подобном окружении. Эксперимент длится 2 недели, трафик делится 50/50. Ключевой результат — получение статистически значимого вывода о превосходстве или эквивалентности одной из версий по выбранным метрикам.

Ключевой результат Статистически значимый (p-value < 0.05) ответ на вопрос: «Улучшила ли новая версия агента выбранную бизнес‑метрику относительно текущей?» с документированным дизайном эксперимента и анализом.

2. Исходные данные

Что нужноОткуда взять
Две версии AI‑агента (control + treatment)Существующий пет‑проект или написанный заранее каркас агента (например, LangGraph / AutoGen)
Поток запросов (реальных или синтетических) на 2 неделиЕсли production нет — генерировать синтетические запросы, имитирующие реальное распределение
Инфраструктура для роутинга трафика 50/50Reverse‑прокси (Nginx, Envoy) или балансировщик (например, в коде Python с random split)
Система логирования и сбора метрикPrometheus + Grafana, либо ELK, либо Sentry для ошибок; собственные метрики агента (latency, success rate, cost)
Инструмент для статистического анализаPython (scipy, statsmodels, pingouin) или R; калькулятор sample size
Идентификатор пользователя/сессии для стабильного сплитаUser‑ID, session‑ID, random hash с seed (чтобы один пользователь не переключался между версиями)

Если нет реального инструмента — симулируем:

  1. Создать простого AI‑агента на LangChain (control), отвечающего на вопросы по документации.
  2. Сделать модифицированную версию (treatment), например, с другим промптом или другой LLM (GPT‑4o mini vs GPT‑4o).
  3. Написать скрипт, который генерирует 1000+ синтетических запросов из шаблонов с разными интентами.
  4. Реализовать балансировщик в Python: random_split(user_id) — по хешу от user_id распределяет запросы 50/50.
  5. Записать логи и метрики в CSV (latency, response length, user feedback — если есть).

3. Технологический стек

КомпонентИнструментыНазначение
AI‑агент (контрольная версия)LangChain / LangGraph / AutoGen + OpenAI APIИсполнение запросов
AI‑агент (экспериментальная версия)LangChain + изменённый промпт / другая LLMСравниваемая версия
Трафик‑сплиттерPython (random + hash), Nginx, Envoy, или Flask middlewareРазделение запросов 50/50
МониторингPrometheus + Grafana (или самописный дашборд)Сбор метрик в реальном времени
ЛогированиеJSON‑логи в файл / Loki / ElasticsearchХранение деталей каждого запроса
Статистический анализscipy, statsmodels, pingouin, pandasРасчёт p-value, power analysis, effect size
Трекинг экспериментовMLflow / Weights & Biases / собственный CSVФиксация конфигурации эксперимента и метрик

4. Этапы выполнения

Этап 1: Дизайн эксперимента (2–4 часа)

Действия

  1. Сформулировать гипотезу

    • H0: Treatment не отличается от Control по метрике.
    • H1: Treatment лучше/хуже Control (двусторонняя или односторонняя).
    • Пример: «Изменение промпта повышает долю успешных завершений диалога с 70% до 75%».
  2. Определить primary метрику (одну, ключевую) и secondary метрики.

  3. Оценить необходимый размер выборки (sample size)

    • Использовать statsmodels.stats.power.tt_ind_solve_power или онлайн‑калькулятор.
    • Входные: α = 0.05, power = 0.8, effect size (Cohen’s d) из пилота.
    • Если пилота нет — принять effect size = 0.2 (small) и посчитать:
      from statsmodels.stats.power import TTestIndPower
      analysis = TTestIndPower()
      n = analysis.solve_power(effect_size=0.2, power=0.8, alpha=0.05, ratio=1.0)
      print(int(n))  # ~ 393 на группу
      
    • С учётом 2 недель и ожидаемого трафика (например, 100 запросов/день → 1400) выборка достаточна.
  4. Спланировать сплит

    • Использовать стабильный хеш от user_id → версия.
    • Обеспечить, что один пользователь всегда попадает в одну группу.
  5. Задокументировать дизайн эксперимента в markdown:

    • Гипотеза, метрика, размер выборки, длительность, критерий остановки (не останавливать раньше срока, если нет очевидного вреда).

Ожидаемый результат этапа Документ «Design Document A/B Test Agent v1 vs v2», содержащий все пункты дизайна.

Этап 2: Подготовка инфраструктуры (4–6 часов)

Действия

  1. Развернуть две версии агента

  2. Написать middleware для сплита трафика

    REQUEST_SPLIT = {0: "control", 1: "treatment"}
    
    def get_version(user_id: str) -> str:
        hash_val = int(hashlib.md5(user_id.encode()).hexdigest(), 16)
        return REQUEST_SPLIT[hash_val % 2]
    
    # В эндпоинте:
    version = get_version(request.user_id)
    if version == "control":
        response = await call_control_agent(...)
    else:
        response = await call_treatment_agent(...)
    
  3. Настроить логирование

    • Каждый запрос пишет JSON‑строку с полями:
      timestamp, user_id, version, request_text, response_text, latency_ms, token_count, success_flag
    • Логи складываются в файл или отправляются в Loki.
  4. Настроить мониторинг метрик

    • Экспорт метрик в Prometheus: ab_requests_total{version="control/treatment"}, ab_latency_seconds_bucket{version=...}, ab_success_total{version=...}.
    • Grafana dashboard с двумя панелями (control vs treatment) для primary метрики.
  5. Провести smoke‑тест

    • Отправить 10–20 тестовых запросов, проверить, что сплит работает и логи пишутся.

Ожидаемый результат этапа Запущенный API с двумя версиями, работающий сплит, логи, мониторинг.

Этап 3: Запуск эксперимента и сбор данных (2 недели + 1 час на запуск)

Действия

  1. Запустить эксперимент

    • Направить реальный (или синтетический) трафик на балансировщик.
    • При синтетике: скрипт, который отправляет запросы с разными user_id каждые N секунд.
  2. Ежедневно проверять

    • Нет ли дисбаланса в количестве запросов между группами (должно быть ≈50/50).
    • Нет ли технических ошибок (5xx, таймауты).
    • Не превышен ли порог ухудшения secondary метрик (например, latency > 200% от control).
  3. Не «подглядывать» p-value ежедневно (peeking) — ждать конца эксперимента.

    • Можно смотреть только агрегированные метрики, не проводя тест.
  4. Зафиксировать момент окончания (через 14 дней ровно). Остановить приём запросов или переключить весь трафик на победившую версию (только после анализа).

Ожидаемый результат этапа Собранный датасет из логов за 14 дней (минимум 1000 записей на группу).

Этап 4: Статистический анализ (2–4 часа)

Действия

  1. Загрузить данные

    import pandas as pd
    df = pd.read_json('logs_ab_test.jsonl', lines=True)
    control = df[df['version'] == 'control']
    treatment = df[df['version'] == 'treatment']
    
  2. Проверить assumption (предпосылки)

    • Нормальность распределения primary метрики (Shapiro‑Wilk или Q‑Q plot). Если нет — использовать непараметрический тест (Mann‑Whitney).
    • Однородность дисперсий (Levene test).
  3. Выполнить тест

    from scipy.stats import ttest_ind, mannwhitneyu
    t_stat, p_value = ttest_ind(control['success_flag'], treatment['success_flag'], equal_var=False)
    # или
    u_stat, p_value = mannwhitneyu(control['success_flag'], treatment['success_flag'])
    
  4. Рассчитать effect size

    • Cohen’s d, разница пропорций, 95% доверительный интервал.
  5. Интерпретировать результат

    • Если p < 0.05: отвергаем H0, версия с лучшим средним — победитель.
    • Если p ≥ 0.05: нет статистически значимого различия.
    • Дополнительно: анализ secondary метрик, проверка на неоднородность эффекта (подгруппы).
  6. Написать отчёт

    • Включить: гипотеза, дизайн, выборка, результаты теста, графики (boxplot, trend), выводы и рекомендации.

Ожидаемый результат этапа Отчёт «A/B Test Results Agent v1 vs v2» с p-value, эффектом и решением.

Этап 5: Принятие решения и документирование (1 час)

Действия

  1. Принять решение

    • Внедрить treatment, если он значимо лучше.
    • Откатить, если хуже (или нет разницы).
    • Если treatment хуже по secondary метрике — не внедрять.
  2. Зафиксировать выводы

    • Заполнить шаблон post‑experiment review: что сработало, что нет, какие уроки.
  3. Обновить код агента (если принято внедрить treatment) и деплоить.

Ожидаемый результат этапа Решение о внедрении/откате, обновлённый код (опционально).

5. Критерии приемки (Definition of Done)

  • Дизайн эксперимента задокументирован (гипотеза, метрика, sample size, длительность).
  • Реализован стабильный сплит трафика 50/50 (на основе user_id).
  • Логирование каждого запроса с версией, метриками latency/tokens/success.
  • Мониторинг primary метрики в real‑time (Grafana).
  • Эксперимент проведён непрерывно в течение 14 дней (или симуляция с запланированными запросами).
  • Статистический тест выполнен корректно (с проверкой предпосылок).
  • Получен p-value и effect size.
  • Написан отчёт с выводами и рекомендациями.
  • Решение о внедрении/откате принято и аргументировано.

6. Ожидаемый результат

Основной артефакт Отчёт об A/B тестировании агентов в формате Markdown/PDF, содержащий:

  • Дизайн эксперимента (гипотеза, метрики, sample size).
  • Графики сравнения (boxplot распределения метрики по группам, cumulative average).
  • Результаты статистического теста (p-value, effect size, доверительный интервал).
  • Заключение: какая версия победила и почему.

Дополнительные артефакты

  • Код балансировщика и логирования.
  • Dockerfile для двух версий агента.
  • Логи эксперимента (JSONL).
  • Prometheus/Grafana конфиги (опционально).

7. Возможные сложности и их решение

СложностьРешение
Неравномерное распределение трафика между группамиИспользовать не случайный split по времени, а детерминированный хеш от user_id. Ежедневно проверять баланс через мониторинг.
Peeking (подглядывание в p-value до окончания эксперимента)Запретить себе смотреть p-value до конца; использовать only aggregate metrics дашборд. При необходимости — sequential testing (e.g., always valid p‑value).
Сезонность или external shock (например, выходные vs будни)Убедиться, что эксперимент длится полные 2 недели, захватывая все дни недели. Если трафик синтетический — генерировать равномерно.
Маленький эффект (effect size < 0.1) и нехватка выборкиИспользовать power analysis до эксперимента; если уже собраны данные — указать, что мощность была недостаточна, и предложить продлить эксперимент.
Зашумлённость primary метрики (high variance)Выбрать менее зашумлённую метрику (например, success rate вместо raw score), или увеличить размер выборки.
Технические сбои во время эксперимента (падение одного из агентов)Автоматически роутить трафик на работающий агент, но помечать запросы как «degraded» и исключать из анализа. Задокументировать инцидент.
Негативное влияние на пользователей (если treatment хуже)Отслеживать secondary метрики (latency, error rate) в real‑time; иметь план остановки эксперимента (stop rule).

8. Бюджет времени (оценка)

ЭтапВремя
Этап 1: Дизайн эксперимента2–4 часа
Этап 2: Подготовка инфраструктуры4–6 часов
Этап 3: Запуск и сбор данных2 недели (пассивное ожидание) + 1 час на запуск
Этап 4: Статистический анализ2–4 часа
Этап 5: Принятие решения и документирование1 час
Итого активной работы9–16 часов

Примечание: Если используется симуляция синтетическим трафиком, время сбора можно сократить до 1–2 часов, запустив скрипт в ускоренном режиме. Но для реалистичности рекомендуется 2 недели с реальным (или эмулированным) потоком.

9. Связанные вопросы из базы знаний

ВопросТема
45Как собрать датасет для оценки агента?
87Метрики для LLM‑агентов (success rate, F1, etc.)
112A/B тестирование: design, sample size, hypothesis
134Статистическая значимость: p-value, power, effect size
201Интеграция с Prometheus / Grafana для агентов
239Логирование запросов LLM в production
305Как избежать peeking в A/B тестах
388Непараметрические тесты для не‑нормальных данных
412Обработка выбросов и аномалий в метриках
501Бюджет токенов и cost per request как secondary метрика

10. Чек-лист самопроверки

  • Я сформулировал чёткую гипотезу и выбрал primary метрику до начала эксперимента.
  • Я проверил, что сплит трафика стабильный (один пользователь → одна версия).
  • Я убедился, что выбранный размер выборки достаточен для обнаружения ожидаемого эффекта (power ≥ 0.8).
  • Я настроил логирование всех запросов с метаданными (версия, latency, success).
  • Я заранее определил критерии досрочной остановки эксперимента (например, если latency treatment > 3x control).
  • Я не смотрел p-value до окончания эксперимента (или использовал sequential testing).
  • Я проверил предпосылки статистического теста (нормальность, гомоскедастичность) и выбрал правильный тест.
  • Я задокументировал все шаги и результаты в отчёте.
  • Я принял обоснованное решение на основе статистики и бизнес‑контекста.