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-файл |
Если нет реального пользовательского трафика — симулируем:
- Написать скрипт-генератор, который отправляет N запросов (например, 1000) в день с равномерным распределением по времени.
- Для каждого запроса случайным образом выбрать вариант (v1 или v2) и сэмулировать ответную метрику с известным эффектом (например, средняя оценка v1 = 3.5, v2 = 4.0 с нормальным шумом).
- Сохранить все события (timestamp, variant, metric_value) в лог.
- Убедиться, что симулятор может работать 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 часа)
Действия
-
Определить, что тестируется. Выбрать один компонент для A/B-теста. Примеры:
- Разные системные промпты для чат-бота (v1 — краткий, v2 — подробный).
- Разные значения temperature: v1 = 0.7, v2 = 1.2.
- Использование разных моделей: gpt-3.5-turbo vs gpt-4o-mini (если есть доступ).
-
Зафиксировать метрику успеха Она должна быть бинарной или числовой, собираемой для каждого вызова. Примеры:
- “Пользователь поставил лайк” (1/0).
- “Время до первого ответа пользователя после генерации” (число).
- “Оценка ответа от 1 до 5” (число, собираемая через симуляцию).
-
Выбрать тип статистического теста в зависимости от метрики:
- Для бинарной — z-тест пропорций.
- Для числовой (нормальное распределение) — t-тест Стьюдента.
- Для числовой (нeнормальное) — U-тест Манна-Уитни.
from scipy.stats import ttest_ind, mannwhitneyu # Пример для t-теста stat, p_val = ttest_ind(group_a, group_b, equal_var=False) -
Разработать схему хранения логов
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 ); -
Инициализировать проект создать структуру папок, requirements.txt (pydantic, scipy, numpy, sqlite3, fastapi/uvicorn для сервера), настроить виртуальное окружение.
Ожидаемый результат этапа Чёткая гипотеза, описание метрики, статистического метода, база данных готова к записи.
Этап 2: Разработка агента — распределение трафика и генерация ответов (4–6 часов)
Действия
-
Создать класс
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 с соответствующими параметрами.
-
Реализовать выборку варианта без дисбаланса Использовать фиксированный 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' -
Интеграция с LLM Создать функцию, которая принимает промпт (или конфигурацию) и возвращает ответ. Для симуляции (если нет реального API) можно использовать задержку и возврат фиктивного ответа.
-
Написать эндпоинт (например, FastAPI
/chat), который принимает user_query, вызывает агента, получает вариант, генерирует ответ, логирует метрику (в симуляции — генерирует случайную оценку с заданным сдвигом). -
Протестировать работу агента в ручном режиме: отправить 10–20 запросов, убедиться, что запись в БД корректна, варианты распределены примерно поровну.
Ожидаемый результат этапа Работающий API endpoint, который возвращает ответ LLM (реальный или симулированный) и записывает событие в лог.
Этап 3: Сбор данных — запуск симуляции на неделю (2–4 часа, в основном ожидание)
Действия
-
Написать скрипт симуляции трафика (если используются симулированные данные). Параметры:
- Количество запросов в день: 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() -
Запустить симуляцию в фоне (можно на ускоренном времени, пропуская паузы). Убедиться, что данные записываются без ошибок.
-
Если трафик реальный — оставить агента работать 7 дней в продакшене (или на staging). В пет-проекте часто используется симуляция, поэтому этот этап можно выполнить за час, сгенерировав все данные сразу.
-
Мониторинг процесса каждые 1000 записей выводить распределение вариантов и среднее метрики.
Ожидаемый результат этапа База данных (или CSV) с ~7000 событий, где варианты v1 и v2 сбалансированы.
Этап 4: Статистический анализ и формирование отчёта (3–4 часа)
Действия
-
Загрузить данные из БД в pandas DataFrame.
import pandas as pd, sqlite3 conn = sqlite3.connect('experiment.db') df = pd.read_sql_query("SELECT * FROM experiment_events", conn) conn.close() -
Проверить баланс вариантов
df['variant'].value_counts() -
Рассчитать описательные статистики для каждой группы:
summary = df.groupby('variant')['metric_value'].agg(['count','mean','std','median']) print(summary) -
Выполнить статистический тест Для числовой метрики (нормальное распределение) — 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) -
Интерпретировать результат
- Если p_value < 0.05 — отвергаем нулевую гипотезу, есть значимое различие.
- Иначе — различия не обнаружены на данном уровне значимости.
-
Построить визуализации boxplot, гистограммы распределений, доверительные интервалы средних.
import matplotlib.pyplot as plt df.boxplot(column='metric_value', by='variant') plt.title('Распределение метрики по вариантам') plt.show() -
Сформировать итоговый отчёт в Markdown с разделами:
- Цель эксперимента
- Описание вариантов
- Объём выборки
- Результаты статистического теста (p-value, эффект)
- Вывод (какой вариант победил или нет)
- Рекомендации (например, перейти на v2, если результат значим)
Ожидаемый результат этапа Отчёт с p-value, визуализациями и выводом.
Этап 5: Интеграция агента с отчётом и логирование результатов (1–2 часа)
Действия
- Создать в агенте метод
run_experiment(), который автоматически запускает сбор данных (если ещё не собраны), а затем запускает анализ и генерирует отчёт. - Добавить возможность сохранения отчёта в файл (report.md) и отправки уведомления (например, в Telegram-бота).
- Написать тесты для ключевых компонентов
- Проверка распределения вариантов (хи-квадрат для 50/50).
- Проверка, что p-value для данных с заведомым эффектом < 0.05.
- Проверка, что при отсутствии эффекта p-value > 0.05 (с допустимой ошибкой).
- Документировать весь код (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) |
| 42 | A/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, сбой БД).
- Отчёт содержит визуализацию распределения метрики по вариантам.