Реализовать A/B тест для RAG
ТЕХНИЧЕСКОЕ ЗАДАНИЕ: Реализовать A/B тест для RAG
1. Цель задачи
Разработать и провести A/B эксперимент для оценки влияния модификации RAG пайплайна на качество ответов. В эксперименте 50% пользовательских запросов направляется на контрольную версию (baseline), а 50% — на экспериментальную версию (treatment). Эксперимент длится 2 недели, после чего проводится статистический анализ для выявления значимых различий по заданным метрикам. Ключевой результат: получить статистически значимый вывод о превосходстве или эквивалентности treatment версии по сравнению с control.
2. Исходные данные
| Что нужно | Откуда взять |
|---|---|
| Реализация RAG пайплайна (control) | Готовый компонент проекта (например, на основе LangChain + FAISS/Chroma) |
| Модифицированная версия RAG (treatment) | Разработать: изменить retriever (например, перейти от BM25 к Dense), re-ranker или prompt шаблон |
| Логи запросов пользователей реального приложения | Подготовить датасет из 5000+ запросов (или сгенерировать синтетические) |
| Метрики качества ответов (ROUGE, BLEU, Faithfulness и т.д.) | Выбрать и реализовать функции оценки; для онлайн-метрик — время ответа, CTR, удовлетворённость (имитация) |
| Инфраструктура для логирования | База данных (PostgreSQL/MongoDB) или простые CSV-логи; платформа W&B/MLflow |
Если нет реального инструмента — симулируем:
- Создаём синтетический датасет запросов (например, 5000 вопросов по документации продукта) с известными ground truth ответами.
- Разворачиваем control версию (использовать готовый open-source RAG, например,
langchain_chatbot). - Модифицируем treatment: заменяем
FAISSнаMilvusс иным алгоритмом, добавляемCohereRerank. - Записываем ответы обеих версий в
.csvс колонками:query_id,version,response,latency,ground_truth,rouge-l,faithfulness. - Эмулируем временные метки на 2 недели (равномерно распределённые).
3. Технологический стек
| Компонент | Инструменты | Назначение |
|---|---|---|
| Язык программирования | Python 3.10+ | Основной язык |
| Фреймворк RAG | LangChain / LlamaIndex | Построение пайплайнов |
| Векторная БД | FAISS (control), Milvus (treatment) | Хранение и поиск эмбеддингов |
| Логирование | MLflow / SQLite | Фиксация запросов, метаданных, метрик |
| Статистический анализ | scipy.stats, statsmodels | T-test, bootstrap, проверка гипотез |
| Оценка качества | rouge-score, bert-score, nltk | Вычисление текстовых метрик |
| Версионирование | Git + DVC | Управление кодом и данными |
| Оркестрация экспериментов | W&B / MLflow Tracking | Организация A/B теста |
4. Этапы выполнения
Этап 1: Подготовка данных и определение метрик (2 дня)
Действия
- Собрать/сгенерировать датасет из не менее 5000 пользовательских запросов (каждый с ground truth ответом).
- Если нет реальных данных: использовать датасет
RAG-QA(например,wikiQA), сгенерировать запросы черезtext-davinci-003.
- Если нет реальных данных: использовать датасет
- Определить две метрики для сравнения:
- Primary ROUGE-L (точность совпадения ответов).
- Secondary: средняя латентность ответа (сек).
- Дополнительно: Faithfulness (есть оценка галлюцинаций).
- Реализовать функции вычисления метрик:
def compute_rouge_l(reference, hypothesis) -> float: from rouge_score import rouge_scorer scorer = rouge_scorer.RougeScorer(['rougeL']) return scorer.score(reference, hypothesis)['rougeL'].fmeasure - Создать таблицу
experiment_logдля записи результатов:
Ожидаемый результат этапа Датасет запросов, функции метрик, схема логирования.
Этап 2: Реализация A/B инфраструктуры (2 дня)
Действия
- Разработать модуль
routerдля направления каждого запроса случайным образом (без смещения):import random def assign_version(): return "control" if random.random() < 0.5 else "treatment" - Реализовать обработчик запроса:
- Получает запрос → фиксирует
query_id→ определяет версию → вызывает соответствующий RAG pipeline → логируетresponse,latency,version.
- Получает запрос → фиксирует
- Интегрировать логирование в MLflow:
- Запуск эксперимента
rag_ab_test_01. - Логировать параметры версий (retriever, reranker, prompt).
- Для каждого запроса:
mlflow.log_metricтолько по окончании всего эксперимента (чтобы не замедлять).
- Запуск эксперимента
- Написать юнит-тесты для router (проверка 50/50, отсутствие детерминизма, корректность вызова пайплайнов).
Ожидаемый результат этапа Код A/B системы, готовый к развёртыванию, с доказанной корректностью распределения.
Этап 3: Проведение эксперимента (2 недели в симуляции — 0.5 дня)
Действия
- Запустить скрипт
run_experiment.py, который последовательно подаёт все запросы из датасета с «задержкой» (например,time.sleep(0.01)для имитации времени обработки). - Для каждого запроса записывать в CSV/MLflow метрики.
- По окончании собрать полный лог.
- Проверить визуально распределение запросов между версиями (должно быть ~50/50).
Ожидаемый результат этапа Лог эксперимента с 5000+ записей, каждая содержит version, rouge_l, latency.
Этап 4: Статистический анализ (1.5 дня)
Действия
- Загрузить данные эксперимента в DataFrame.
- Проверить нормальность распределения метрик (Shapiro-Wilk). Если не нормальное — использовать непараметрический тест Манна-Уитни.
- Выполнить двухвыборочный t-test (или U-test) для первичной метрики
rouge_l:from scipy import stats control = df[df['version']=='control']['rouge_l'] treatment = df[df['version']=='treatment']['rouge_l'] t_stat, p_value = stats.ttest_ind(control, treatment) - Вычислить effect size (Cohen's d).
- Применить коррекцию Бонферрони, если анализируем несколько метрик (например, 2 метрики → α = 0.025).
- Построить bootstrap-распределение разности средних (1000 итераций) для доверительного интервала 95%.
- Визуализировать: boxplot, гистограммы, плотность.
Ожидаемый результат этапа Отчёт с p-value, effect size, доверительным интервалом, выводом о значимости различий.
Этап 5: Интерпретация и формирование вывода (1 день)
Действия
- Если p-value < α (с учётом коррекции) → различие статистически значимо. Определить, какая версия лучше.
- Если p-value ≥ α → нельзя отвергнуть нулевую гипотезу. Дополнительно проверить мощность теста (post-hoc power analysis).
- Задокументировать возможные причины (размер выборки, дисперсия, смещение). Принять решение: оставить control, заменить на treatment, или продлить тест.
- Подготовить итоговый отчёт (Markdown/PDF) с таблицами, графиками, выводами и рекомендациями.
Ожидаемый результат этапа Заключение о статистической значимости изменений, приложенный код, артефакты (p-value, доверительный интервал, графики).
5. Критерии приемки (Definition of Done)
- Разработан и задокументирован A/B тест с чётким разделением control/treatment (50/50).
- Эксперимент выполнен на наборе из не менее 5000 запросов (реальных или синтетических).
- Получен лог с полями:
query_id,version,response,rouge_l,latency,timestamp. - Проведён статистический тест (t-test или непараметрический) с коррекцией на множественность.
- Вычислены и представлены: p-value, effect size, 95% доверительный интервал разницы средних.
- Построены визуализации (boxplot, bootstrap distribution).
- Сделан вывод о значимости различий (или их отсутствии) и дана рекомендация.
- Код выложен в репозиторий с инструкцией по воспроизведению.
- Время выполнения эксперимента (симуляция) не превышает 1 час.
- Отчёт включает обсуждение возможных искажений (confounding factors).
6. Ожидаемый результат
- Файл
ab_test_report.pdfс описанием дизайна, результатов статистических тестов и выводами. - Репозиторий с кодом:
router.py,run_experiment.py,analyse.py,config.yaml. - Артефакты MLflow (если использовались) с логами метрик.
- Дополнительно:
bootstrap_plot.png,boxplot_versions.png.
7. Возможные сложности и их решение
| Сложность | Решение |
|---|---|
| Недостаточный размер выборки для обнаружения эффекта | Выполнить power analysis до эксперимента; если эффект мал — увеличить выборку до 10–20 тыс. запросов или продлить тест |
| Смещение из-за времени (например, treatment тестируется в пиковые часы) | Использовать стратифицированную рандомизацию по временным слотам; логировать timestamp |
| Множественное сравнение (несколько метрик) | Применить коррекцию Бонферрони или FDR; зафиксировать первичную метрику заранее |
| Неравномерное распределение между версиями | Проверить случайный генератор; использовать детерминированную salt для стабильного расщепления по ID пользователя (если применимо) |
| Отсутствие реальных пользователей | Симуляция с синтетическими запросами и эмулированными метриками (добавить искусственный шум для реализма) |
8. Бюджет времени (оценка)
| Этап | Время |
|---|---|
| 1. Подготовка данных и метрик | 2 дня |
| 2. Реализация A/B инфраструктуры | 2 дня |
| 3. Проведение эксперимента | 0.5 дня (симуляция) / 2 недели (реальные) |
| 4. Статистический анализ | 1.5 дня |
| 5. Интерпретация и отчёт | 1 день |
| Итого | 7 дней (при симуляции) / ~17 дней (реальный тест) |
Примечание: в реальных условиях A/B тест длится 2 недели, но кодовая подготовка занимает ~5-6 дней. Для первого раза рекомендуется симуляция для отработки методологии.
9. Связанные вопросы из базы знаний
| Вопрос | Тема |
|---|---|
| 21 | Какие методы проверки статистической значимости используются в A/B тестах? |
| 22 | Что такое power analysis и как его проводить? |
| 45 | Как бороться с effect size в A/B экспериментах? |
| 73 | Чем отличается онлайн A/B тест от офлайн оценки RAG? |
| 112 | Как оценить faithfulness в RAG? |
| 145 | Какие метрики подходят для оценки качества генерации в RAG? |
| 189 | Как реализовать bootstrap для разности средних? |
| 234 | Что такое multiple testing problem и как её корректировать? |
| 250 | Как выбрать primary метрику для A/B теста? |
| 278 | Какие фреймворки использовать для логирования экспериментов? |
10. Чек-лист самопроверки
- Я корректно настроил рандомизацию 50/50 и проверил её на тестовых данных.
- Я выбрал primary метрику до анализа, чтобы избежать p-value hacking.
- Я проверил предположения статистического теста (нормальность, равенство дисперсий).
- Я применил коррекцию на множественное сравнение, если используется вторичная метрика.
- Я убедился, что лог содержит достаточно информации для воспроизведения анализа (версии, метки времени, метрики).
- Я задокументировал все гиперпараметры treatment версии (модель, chunk size, prompt).
- Я не полагаюсь только на p-value, но и оценил effect size и доверительный интервал.
- Я протестировал воспроизводимость эксперимента на изолированном окружении (docker/conda).
- Я добавил обработку возможных аномалий (отсутствующие значения, выбросы).