Как вы делаете A/B тестирование двух моделей в production?
Краткий тезис
A/B тестирование в production ML позволяет объективно сравнить две модели (обычно текущую стабильную и новую кандидата) на реальном трафике. Ключевые принципы: стабильная рандомизация трафика (один пользователь всегда видит одну и ту же модель), изоляция инфраструктуры (отдельные поды) и сбор как количественных (latency, cost, токены), так и качественных (LLM-as-a-judge, пользовательская обратная связь) метрик. Решение принимается на основе статистической значимости различий, после чего трафик полностью переводится на победителя с возможностью быстрого роллбэка.
1. Термин: A/B тестирование в ML
A/B тестирование (сплит-тестирование) — метод сравнения двух версий системы (здесь — моделей) путём разделения пользовательского трафика. В контексте ML это онлайн-эксперимент, который проверяет гипотезу о том, что новая модель лучше текущей по бизнес-метрикам. В отличие от офлайн-оценки (на статическом датасете), A/B тест учитывает реальное поведение пользователей, динамику контекста и обратную связь.
2. Дизайн эксперимента: стабильная рандомизация
Рандомизация должна быть стабильной: один и тот же пользователь всегда попадает в одну и ту же группу (control или treatment) на протяжении всего эксперимента. Иначе — смещение оценок из-за переключения между моделями.
Практическая реализация — хэширование user_id по модулю 100 и направление в группу:
- 0–49 → контроль (старая модель)
- 50–99 → тест (новая модель)
import hashlib
def get_experiment_group(user_id: str) -> str:
hash_value = int(hashlib.sha256(user_id.encode()).hexdigest(), 16) % 100
return "control" if hash_value < 50 else "treatment"
Важно: стратификация по значимым признакам (регион, тип устройства) может повысить чувствительность, но требует предварительного анализа и увеличивает сложность.
3. Инфраструктура: изоляция и роутинг
Каждая модель разворачивается в собственном поде (Kubernetes) с отдельным endpoint. Роутинг трафика реализуется на уровне API-шлюза (например, Kong, Envoy) или через Service Mesh (Istio). Feature-флаги (например, LaunchDarkly, OpenFeature) позволяют динамически менять распределение без передеплоя.
| Компонент | Роль |
|---|---|
| Ingress/Gateway | Принимает запрос, вычисляет группу по user_id, направляет к нужному service |
| Service A (control) | Старая модель (репликация 1+ для надёжности) |
| Service B (treatment) | Новая модель (такая же репликация) |
| Feature Flag SDK | Централизованное управление экспериментом (например, % трафика) |
| Monitoring stack | Prometheus + Grafana для сбора метрик |
4. Метрики: количественные и качественные
4.1 Количественные (легко измерить)
- Latency (p50, p95, p99) — время ответа модели
- Cost — затраты на инференс (GPU/CPU, токены)
- Token usage — количество входных/выходных токенов (особенно для LLM)
- Throughput — запросов в секунду
- Error rate — 5xx ошибки
4.2 Качественные (требуют оценки)
- LLM-as-a-judge — использование сильной LLM (GPT-4, Claude) для оценки ответов по критериям (полезность, безопасность, точность). Дёшево, но может быть bias.
- Human evaluation — краудсорсинг или внутренние эксперты (дорого, медленно, но надёжно).
- User feedback — лайки/дизлайки, thumbs up/down, доля «решения задачи» (conversion rate).
| Метрика | Тип | Плюсы | Минусы |
|---|---|---|---|
| Latency | Количественная | Объективно, непрерывно | Не отражает качество |
| LLM-as-a-judge | Качественная | Масштабируется | Дорого, bias |
| Human evaluation | Качественная | Золотой стандарт | Медленно, дорого |
| User conversion | Бизнесовая | Реальный эффект | Шум, требуется много данных |
5. Длительность эксперимента
Минимальная длительность определяется power analysis (расчёт необходимого размера выборки). Для LLM-приложений типичный период — 1–2 недели, чтобы:
- собрать достаточное количество событий для значимости;
- учесть недельные циклы (понедельник vs суббота);
- снизить эффект novelty effect (временное повышение интереса к новинке).
Условие остановки: достижение статистической значимости (p < 0.05) по ключевым метрикам при power >= 0.8.
6. Статистическая значимость и принятие решений
Для сравнения двух групп применяют t-тест Стьюдента (для нормально распределённых метрик) или Mann-Whitney U (для ненормальных). Для долей (conversion rate) — Z-тест для пропорций.
from scipy.stats import ttest_ind
import numpy as np
control_latencies = np.array([...])
treatment_latencies = np.array([...])
stat, p_value = ttest_ind(control_latencies, treatment_latencies)
print(f"p-value: {p_value:.4f}")
if p_value < 0.05:
print("Различие статистически значимо")
Множественные сравнения: если метрик много, применяют поправку Bonferroni или Benjamini-Hochberg.
Решение:
- Если treatment значимо лучше по всем ключевым метрикам → победитель.
- Если значимо хуже хотя бы по одной (например, latency) → отказ.
- Если нет значимых различий → принимается бизнес-решение (например, оставляют старую или выпускают новую, если она дешевле).
7. Роллбэк и rollout победителя
После принятия решения трафик переключается постепенно (canary rollout) или полностью (big bang). В любом случае должна быть возможность быстрого отката в течение минут:
- Сохранить оба deployment'а;
- Переключить feature flag на 100% одной группы;
- Мониторить метрики первые часы (возможны отложенные проблемы).
8. Подводные камни и их решения
| Проблема | Описание | Решение |
|---|---|---|
| Novelty effect | Новая модель кажется лучше из-за новизны | Увеличить длительность, или сделать holdout после эксперимента |
| Network effects | Взаимодействие пользователей (в соцсетях) | Проводить эксперимент в изолированном сегменте (например, по региону) |
| Data drift | Изменение распределения запросов во времени | Скользящее окно при анализе, мониторинг drift |
| Неравномерное разделение | Баг в хэшировании | Юнит-тесты на функцию рандомизации, логирование группы в ответе |
| Инфраструктурные сбои | Падение пода новой модели | Автоматический failover на control, алерт |
9. Пет-проект для закрепления
Задача: сравнить две LLM (например, Mistral-7B и Llama-2-7B) как чат-бота для поддержки на синтетическом трафике.
Инструменты: Kubernetes (minikube), Python (FastAPI для моделей), Argo Rollouts (canary), Prometheus + Grafana (метрики), MLflow (логирование).
Шаги:
- Развернуть оба инференс-сервиса в отдельных подах с метками model: control и model: treatment.
- Написать API-шлюз с хэшированием user_id (использовать заголовок
X-User-Id). - Настроить сбор метрик: latency (p50,p95), error rate, количество токенов.
- Подключить LLM-as-a-judge (GPT-4) для оценки качества ответов — отправлять 10% ответов на оценку, сохранять скоры.
- Запустить эксперимент на 7 дней с 50/50 трафика.
- Построить дашборд в Grafana: разница средних latency, p-value, распределение скоров.
- По окончании — выполнить t-тест. Если новая модель значимо лучше по качеству и не хуже по latency — переключить 100% трафика через feature flag.
Ожидаемый результат: навык проведения полного цикла A/B теста в production-среде, понимание инфраструктурных нюансов и статистики.
10. Связь с другими вопросами
| Вопрос | Тема |
|---|---|
| 5 | Оценка качества генерации (offline и LLM-as-a-judge) |
| 7 | Уменьшение latency RAG-системы |
| 74 | Оптимизация стоимости инференса |
| 77 | Мониторинг модели в production |
| 78 | CI/CD для ML-моделей |
| 90 | Feature flags и управление экспериментами |
Навигация
- Предыдущий: 75
- Следующий: 77
- Индекс: 00. Индекс разборов