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/50 | Reverse‑прокси (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 (чтобы один пользователь не переключался между версиями) |
Если нет реального инструмента — симулируем:
- Создать простого AI‑агента на LangChain (control), отвечающего на вопросы по документации.
- Сделать модифицированную версию (treatment), например, с другим промптом или другой LLM (GPT‑4o mini vs GPT‑4o).
- Написать скрипт, который генерирует 1000+ синтетических запросов из шаблонов с разными интентами.
- Реализовать балансировщик в Python: random_split(user_id) — по хешу от user_id распределяет запросы 50/50.
- Записать логи и метрики в 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 часа)
Действия
-
Сформулировать гипотезу
-
Определить primary метрику (одну, ключевую) и secondary метрики.
-
Оценить необходимый размер выборки (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) выборка достаточна.
- Использовать
-
Спланировать сплит
- Использовать стабильный хеш от user_id → версия.
- Обеспечить, что один пользователь всегда попадает в одну группу.
-
Задокументировать дизайн эксперимента в markdown:
- Гипотеза, метрика, размер выборки, длительность, критерий остановки (не останавливать раньше срока, если нет очевидного вреда).
Ожидаемый результат этапа Документ «Design Document A/B Test Agent v1 vs v2», содержащий все пункты дизайна.
Этап 2: Подготовка инфраструктуры (4–6 часов)
Действия
-
Развернуть две версии агента
-
Написать 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(...) -
Настроить логирование
-
Настроить мониторинг метрик
-
Провести smoke‑тест
- Отправить 10–20 тестовых запросов, проверить, что сплит работает и логи пишутся.
Ожидаемый результат этапа Запущенный API с двумя версиями, работающий сплит, логи, мониторинг.
Этап 3: Запуск эксперимента и сбор данных (2 недели + 1 час на запуск)
Действия
-
Запустить эксперимент
- Направить реальный (или синтетический) трафик на балансировщик.
- При синтетике: скрипт, который отправляет запросы с разными user_id каждые N секунд.
-
Ежедневно проверять
-
Не «подглядывать» p-value ежедневно (peeking) — ждать конца эксперимента.
- Можно смотреть только агрегированные метрики, не проводя тест.
-
Зафиксировать момент окончания (через 14 дней ровно). Остановить приём запросов или переключить весь трафик на победившую версию (только после анализа).
Ожидаемый результат этапа Собранный датасет из логов за 14 дней (минимум 1000 записей на группу).
Этап 4: Статистический анализ (2–4 часа)
Действия
-
Загрузить данные
import pandas as pd df = pd.read_json('logs_ab_test.jsonl', lines=True) control = df[df['version'] == 'control'] treatment = df[df['version'] == 'treatment'] -
Проверить assumption (предпосылки)
- Нормальность распределения primary метрики (Shapiro‑Wilk или Q‑Q plot). Если нет — использовать непараметрический тест (Mann‑Whitney).
- Однородность дисперсий (Levene test).
-
Выполнить тест
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']) -
Рассчитать effect size
- Cohen’s d, разница пропорций, 95% доверительный интервал.
-
Интерпретировать результат
- Если p < 0.05: отвергаем H0, версия с лучшим средним — победитель.
- Если p ≥ 0.05: нет статистически значимого различия.
- Дополнительно: анализ secondary метрик, проверка на неоднородность эффекта (подгруппы).
-
Написать отчёт
- Включить: гипотеза, дизайн, выборка, результаты теста, графики (boxplot, trend), выводы и рекомендации.
Ожидаемый результат этапа Отчёт «A/B Test Results Agent v1 vs v2» с p-value, эффектом и решением.
Этап 5: Принятие решения и документирование (1 час)
Действия
-
Принять решение
-
Зафиксировать выводы
- Заполнить шаблон post‑experiment review: что сработало, что нет, какие уроки.
-
Обновить код агента (если принято внедрить 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.) |
| 112 | A/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).
- Я проверил предпосылки статистического теста (нормальность, гомоскедастичность) и выбрал правильный тест.
- Я задокументировал все шаги и результаты в отчёте.
- Я принял обоснованное решение на основе статистики и бизнес‑контекста.