English translation is not available yet. Showing Russian content.

Агент с A/B тестированием

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

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

Разработать агента, который автоматически проводит A/B-эксперимент между двумя версиями (v1 и v2) одного компонента (например, промпта, модели, параметра постобработки) в LLM-приложении. Агент управляет распределением трафика 50/50 в течение одной недели, собирает метрики пользовательского взаимодействия (например, оценка ответа, конверсия) и по окончании эксперимента рассчитывает статистическую значимость различий. Задача развивает навыки проектирования экспериментов, работы с LLM-пайплайнами, сбора логов и применения статистических критериев.

Ключевой результат Агент, способный запустить A/B-тест, собрать данные, вычислить p-value и сформировать отчёт с рекомендацией (победитель или отсутствие значимых различий).

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

Перед началом необходимо иметь:

Что нужноОткуда взять
LLM-приложение (чат-бот, генератор текста)Существующий пет-проект или созданный заранее (например, простой бот на FastAPI)
Два варианта изменяемого компонента (v1 и v2)Определяются самостоятельно: разные промпты, разные temperature / top_p, разные модели (через OpenAI / Ollama)
Канал поступления запросов (пользовательские сессии)Симулятор запросов (Python-скрипт) или реальный пользовательский трафик (если приложение в продакшене)
Метрика успеха (ключевой показатель)Чётко определённая метрика (например, оценка "лайк/дизлайк", 5-балльная шкала, время до клика)
Хранилище логов экспериментовSQLite / PostgreSQL / CSV-файл

Если нет реального пользовательского трафика — симулируем:

  1. Написать скрипт-генератор, который отправляет N запросов (например, 1000) в день с равномерным распределением по времени.
  2. Для каждого запроса случайным образом выбрать вариант (v1 или v2) и сэмулировать ответную метрику с известным эффектом (например, средняя оценка v1 = 3.5, v2 = 4.0 с нормальным шумом).
  3. Сохранить все события (timestamp, variant, metric_value) в лог.
  4. Убедиться, что симулятор может работать 7 дней подряд (или ускоренно — сжать время, обрабатывая пакетно).

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

КомпонентИнструментыНазначение
LLM (для генерации ответов)OpenAI API / Ollama (локально)Генерация вариантов ответов
Фреймворк агентаPython + pydantic + asyncioОркестрация эксперимента
Статистикаscipy (ttest_ind, mannwhitneyu) или statsmodelsРасчёт p-value, доверительных интервалов
Хранилище логовSQLite (через sqlite3 / SQLAlchemy)Фиксация каждого события
Симулятор трафика (опционально)Python (random, numpy)Генерация запросов с заданным эффектом
ОтчётыJinja2 / Markdown + matplotlibВизуализация результатов

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

Этап 1: Проектирование эксперимента и подготовка окружения (2–3 часа)

Действия

  1. Определить, что тестируется. Выбрать один компонент для A/B-теста. Примеры:

    • Разные системные промпты для чат-бота (v1 — краткий, v2 — подробный).
    • Разные значения temperature: v1 = 0.7, v2 = 1.2.
    • Использование разных моделей: gpt-3.5-turbo vs gpt-4o-mini (если есть доступ).
  2. Зафиксировать метрику успеха Она должна быть бинарной или числовой, собираемой для каждого вызова. Примеры:

    • “Пользователь поставил лайк” (1/0).
    • “Время до первого ответа пользователя после генерации” (число).
    • “Оценка ответа от 1 до 5” (число, собираемая через симуляцию).
  3. Выбрать тип статистического теста в зависимости от метрики:

    • Для бинарной — z-тест пропорций.
    • Для числовой (нормальное распределение) — t-тест Стьюдента.
    • Для числовой (нeнормальное) — U-тест Манна-Уитни.
    from scipy.stats import ttest_ind, mannwhitneyu
    # Пример для t-теста
    stat, p_val = ttest_ind(group_a, group_b, equal_var=False)
    
  4. Разработать схему хранения логов

    CREATE TABLE experiment_events (
        id INTEGER PRIMARY KEY AUTOINCREMENT,
        timestamp TEXT NOT NULL,
        user_session TEXT,
        variant TEXT NOT NULL CHECK(variant IN ('v1','v2')),
        metric_value REAL,
        metadata TEXT
    );
    
  5. Инициализировать проект создать структуру папок, requirements.txt (pydantic, scipy, numpy, sqlite3, fastapi/uvicorn для сервера), настроить виртуальное окружение.

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

Этап 2: Разработка агента — распределение трафика и генерация ответов (4–6 часов)

Действия

  1. Создать класс ExperimentAgent с методами:

    • get_variant(user_session: str) -> str — возвращает случайный вариант с вероятностью 50/50 (фиксированный seed для воспроизводимости).
    • record_event(user_session, variant, metric_value, metadata) — запись в БД.
    • run_inference(user_query, variant) -> str — вызов LLM с соответствующими параметрами.
  2. Реализовать выборку варианта без дисбаланса Использовать фиксированный seed на основе user_session, чтобы один и тот же пользователь всегда видел один вариант (или наоборот — случайный на каждый запрос; в пет-проекте допустим второй вариант).

    import hashlib
    def get_variant(user_session: str) -> str:
        hash_int = int(hashlib.md5(user_session.encode()).hexdigest(), 16)
        return 'v1' if hash_int % 2 == 0 else 'v2'
    
  3. Интеграция с LLM Создать функцию, которая принимает промпт (или конфигурацию) и возвращает ответ. Для симуляции (если нет реального API) можно использовать задержку и возврат фиктивного ответа.

  4. Написать эндпоинт (например, FastAPI /chat), который принимает user_query, вызывает агента, получает вариант, генерирует ответ, логирует метрику (в симуляции — генерирует случайную оценку с заданным сдвигом).

  5. Протестировать работу агента в ручном режиме: отправить 10–20 запросов, убедиться, что запись в БД корректна, варианты распределены примерно поровну.

Ожидаемый результат этапа Работающий API endpoint, который возвращает ответ LLM (реальный или симулированный) и записывает событие в лог.

Этап 3: Сбор данных — запуск симуляции на неделю (2–4 часа, в основном ожидание)

Действия

  1. Написать скрипт симуляции трафика (если используются симулированные данные). Параметры:

    • Количество запросов в день: N (например, 1000).
    • Распределение метрики для v1 и v2 (например, v1: mean=3.5, std=1.0; v2: mean=4.0, std=1.0).
    • Запись в ту же БД, что и агент.
    import sqlite3, random, time, numpy as np
    conn = sqlite3.connect('experiment.db')
    cursor = conn.cursor()
    for i in range(7000):  # 7 дней * 1000
        variant = random.choice(['v1','v2'])
        mean = 3.5 if variant=='v1' else 4.0
        value = np.random.normal(mean, 1.0)
        cursor.execute(
            "INSERT INTO experiment_events (timestamp, user_session, variant, metric_value) "
            "VALUES (datetime('now'), ?, ?, ?)",
            (f'sim_user_{i}', variant, value)
        )
        time.sleep(0.001)  # небольшая задержка
    conn.commit()
    conn.close()
    
  2. Запустить симуляцию в фоне (можно на ускоренном времени, пропуская паузы). Убедиться, что данные записываются без ошибок.

  3. Если трафик реальный — оставить агента работать 7 дней в продакшене (или на staging). В пет-проекте часто используется симуляция, поэтому этот этап можно выполнить за час, сгенерировав все данные сразу.

  4. Мониторинг процесса каждые 1000 записей выводить распределение вариантов и среднее метрики.

Ожидаемый результат этапа База данных (или CSV) с ~7000 событий, где варианты v1 и v2 сбалансированы.

Этап 4: Статистический анализ и формирование отчёта (3–4 часа)

Действия

  1. Загрузить данные из БД в pandas DataFrame.

    import pandas as pd, sqlite3
    conn = sqlite3.connect('experiment.db')
    df = pd.read_sql_query("SELECT * FROM experiment_events", conn)
    conn.close()
    
  2. Проверить баланс вариантов

    df['variant'].value_counts()
    
  3. Рассчитать описательные статистики для каждой группы:

    summary = df.groupby('variant')['metric_value'].agg(['count','mean','std','median'])
    print(summary)
    
  4. Выполнить статистический тест Для числовой метрики (нормальное распределение) — t-тест:

    from scipy.stats import ttest_ind
    v1 = df[df['variant']=='v1']['metric_value']
    v2 = df[df['variant']=='v2']['metric_value']
    stat, p_value = ttest_ind(v1, v2, equal_var=False)
    
  5. Интерпретировать результат

    • Если p_value < 0.05 — отвергаем нулевую гипотезу, есть значимое различие.
    • Иначе — различия не обнаружены на данном уровне значимости.
  6. Построить визуализации boxplot, гистограммы распределений, доверительные интервалы средних.

    import matplotlib.pyplot as plt
    df.boxplot(column='metric_value', by='variant')
    plt.title('Распределение метрики по вариантам')
    plt.show()
    
  7. Сформировать итоговый отчёт в Markdown с разделами:

    • Цель эксперимента
    • Описание вариантов
    • Объём выборки
    • Результаты статистического теста (p-value, эффект)
    • Вывод (какой вариант победил или нет)
    • Рекомендации (например, перейти на v2, если результат значим)

Ожидаемый результат этапа Отчёт с p-value, визуализациями и выводом.

Этап 5: Интеграция агента с отчётом и логирование результатов (1–2 часа)

Действия

  1. Создать в агенте метод run_experiment(), который автоматически запускает сбор данных (если ещё не собраны), а затем запускает анализ и генерирует отчёт.
  2. Добавить возможность сохранения отчёта в файл (report.md) и отправки уведомления (например, в Telegram-бота).
  3. Написать тесты для ключевых компонентов
    • Проверка распределения вариантов (хи-квадрат для 50/50).
    • Проверка, что p-value для данных с заведомым эффектом < 0.05.
    • Проверка, что при отсутствии эффекта p-value > 0.05 (с допустимой ошибкой).
  4. Документировать весь код (docstrings, README с инструкцией по запуску).

Ожидаемый результат этапа Полностью автоматизированный агент, который по команде проводит A/B-тест и выдаёт отчёт.

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

  • Агент запускает A/B-тест с распределением трафика 50/50.
  • Каждое обращение логируется в БД с меткой времени, вариантом и значением метрики.
  • Симуляция (или реальный сбор) данных за 7 дней даёт не менее 1000 событий на группу.
  • Статистический тест выполняется корректно (p-value вычислен, выбран правильный критерий).
  • Отчёт генерируется в Markdown формате с таблицами и графиками.
  • Код покрыт юнит-тестами (≥70% coverage на критических модулях).
  • README содержит инструкцию по запуску и пример использования.
  • Агент воспроизводим — при фиксированном seed даёт одинаковые результаты.
  • Реализована обработка ошибок (сбой записи в БД, недоступность LLM).
  • В отчёте указан объём выборки, средние, p-value и вывод (победитель или нет).

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

Основной артефакт Репозиторий с кодом агента, включающий:

  • agent.py — основной класс ExperimentAgent.
  • simulator.py — скрипт симуляции трафика (если используется).
  • analysis.py — функции статистического анализа и визуализации.
  • report.md — сгенерированный отчёт для одного запуска.
  • tests/ — юнит-тесты.
  • README.md — документация.

Дополнительно База данных SQLite с событиями (experiment.db) и графики в PNG.

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

СложностьРешение
Реальный трафик мал или отсутствуетИспользовать симулятор с заданным эффектом, чтобы проверить корректность работы агента
Статистический тест даёт ложноположительный результатУвеличить размер выборки, использовать correction множественных сравнений (если несколько метрик), уменьшить alpha до 0.01
Дисбаланс вариантов (не 50/50) из-за случайностиПроверить seed, увеличить N, использовать стохастический rounding (например, списки с точным соотношением)
LLM API возвращает ошибки или задержкиДобавить retry-логику, fallback на симуляцию, логировать ошибки отдельно
Зависимость от внешнего LLM-провайдераДля пет-проекта достаточно локальной модели (Ollama) или симуляции ответов
Неправильный выбор статистического критерия (нарушение нормальности)Использовать U-тест Манна-Уитни как более робастный, или предварительно проверить нормальность (Shapiro-Wilk)

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

ЭтапВремя
Этап 1: Проектирование и подготовка2–3 часа
Этап 2: Разработка агента4–6 часов
Этап 3: Сбор данных (симуляция)1–2 часа (реальное время ~15 минут)
Этап 4: Статистический анализ и отчёт3–4 часа
Этап 5: Интеграция и тесты1–2 часа
Итого11–17 часов

Примечание Если выполнять впервые, заложите дополнительно 50% времени на отладку и изучение документации.

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

ВопросТема
15Основы статистической проверки гипотез (p-value, alpha)
42A/B-тестирование в продакшене: дизайн экспериментов
87Выбор статистического критерия для разных типов данных
112Обработка логов и хранение событий в SQLite
156Интеграция LLM API (OpenAI, Ollama)
203Симуляция данных для тестирования ML-систем
248(Текущая задача)
301Оценка качества генерации текста (метрики)
356Автоматизация отчётов в Markdown
412Ошибки первого и второго рода, power analysis

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

  • Я чётко определил, что именно тестирую (v1 vs v2).
  • Метрика успеха выбрана и однозначно измеряется для каждого вызова.
  • Алгоритм распределения вариантов гарантирует баланс 50/50 в ожидании.
  • Я проверил, что данные записываются без потерь и с правильными метками.
  • В отчёте указаны объём выборки, средние, p-value и практическая значимость (effect size).
  • Код покрыт тестами на корректность статистического теста.
  • Я воспроизвёл эксперимент с фиксированным seed и получил те же результаты.
  • README позволяет другому человеку запустить агента за 15 минут.
  • Я обработал потенциальные ошибки (отсутствие LLM, сбой БД).
  • Отчёт содержит визуализацию распределения метрики по вариантам.