Дообучение LLM: как провести A/B-тест и не ошибиться

Сравнение дообученных LLM: практика A/B эксперимента

Направления AI-разработки

Часто задаваемые вопросы

Последние работы

  • image_website-b2b-advance_0.webp
    Разработка сайта компании B2B ADVANCE
    1440
  • image_web-applications_feedme_466_0.webp
    Разработка веб-приложения для компании FEEDME
    1301
  • image_websites_belfingroup_462_0.webp
    Разработка веб-сайта для компании БЕЛФИНГРУПП
    997
  • image_ecommerce_furnoro_435_0.webp
    Разработка интернет магазина для компании FURNORO
    1264
  • image_logo-advance_0.webp
    Разработка логотипа компании B2B Advance
    712
  • image_crm_enviok_479_0.webp
    Разработка веб-приложения для компании Enviok
    1002

Сравнение дообученных LLM: практика A/B эксперимента

Допустим, вы дообучили Llama 3.1 на 5000 демонстраций саппорта. ROUGE вырос на 7%, perplexity упала. Запускаете в прод — и escalation rate подскакивает на 15%. Знакомая ситуация. Лабораторные метрики не гарантируют улучшения в реальных условиях. Единственный достоверный способ — провести A/B-тест: разделить трафик, показывать часть запросов baseline, часть — candidate, и сравнить бизнес-метрики.

Наш опыт подтверждает: без корректного A/B-эксперимента дообучение часто оборачивается потерей времени и бюджета. Правильная методология позволяет за 2–5 недель получить статистически значимый ответ и принять решение о rollout или откате. Если вы хотите внедрить A/B-тестирование в свой MLOps-пайплайн, получите консультацию — мы поможем настроить эксперимент под ваш стек.

Например, в одном из проектов мы сравнили две версии fine-tuned Mistral 7B: контрольная (v1) и экспериментальная (v2). Результаты показали улучшение task completion rate на 7.6% при p-value < 0.01. Это позволило обосновать rollout и сэкономить бюджет на дальнейшее дообучение.

Как организовать эксперимент?

Сравниваются две версии: baseline (например, исходная GPT-4o) и candidate (fine-tuned на новых данных). Типичные сценарии:

  • базовая модель против fine-tuned на том же архитектурном ядре;
  • fine-tuned v1 против v2 (итерация датасета);
  • две разные модели (Llama 3.1 8B vs Mistral 7B), обе дообучены;
  • один и тот же inference с разными промптами.

Ключ — детерминированное разделение трафика. Реализуем через хэш от user_id:

import hashlib import random from typing import Literal class ABRouter: """Детерминированная маршрутизация A/B по user_id""" def __init__(self, experiment_name: str, split: float = 0.5): self.experiment_name = experiment_name self.split = split # Доля трафика для варианта B def assign(self, user_id: str) -> Literal["control", "treatment"]: """Один пользователь всегда попадает в одну группу""" hash_input = f"{self.experiment_name}:{user_id}" hash_value = int(hashlib.md5(hash_input.encode()).hexdigest(), 16) normalized = (hash_value % 10000) / 10000 return "treatment" if normalized < self.split else "control" router = ABRouter("fine-tuned-v2-test", split=0.2) # 20% трафика на новую модель # В обработчике запроса def handle_request(user_id: str, prompt: str) -> str: variant = router.assign(user_id) if variant == "control": response = baseline_model.generate(prompt) model_version = "baseline" else: response = finetuned_model.generate(prompt) model_version = "v2-finetuned" log_event(user_id, variant, prompt, response, model_version) return response 

Какие метрики выбрать?

  • Task completion rate — доля диалогов, где пользователь получил ответ без escalation. Первичная метрика, напрямую отражает бизнес-ценность.
  • CSAT — оценка пользователем качества ответа (звёзды, лайк/дизлайк).
  • Escalation rate — процент обращений, переданных оператору.
  • Time-to-value — количество сообщений до решения задачи.
  • Latency (P50, P95, P99) — чтобы не потерять в скорости.

Измеряйте их на одинаковом срезе запросов, исключая сезонность. Если модель показывает улучшение по первичной метрике, а latency выросла в пределах допуска — решение о rollout принимается.

Как определить статистическую значимость?

Недостаточно просто сравнить средние — нужен t-тест. Реализация на Python:

from scipy import stats import numpy as np def ab_significance_test( control_outcomes: list[float], treatment_outcomes: list[float], alpha: float = 0.05 ) -> dict: """ Двусторонний t-тест для проверки значимости разницы в метриках control_outcomes: метрики группы A (например, task_completion = [1,0,1,1,...]) """ t_stat, p_value = stats.ttest_ind(control_outcomes, treatment_outcomes) control_mean = np.mean(control_outcomes) treatment_mean = np.mean(treatment_outcomes) relative_lift = (treatment_mean - control_mean) / control_mean * 100 return { "control_mean": control_mean, "treatment_mean": treatment_mean, "relative_lift_pct": relative_lift, "p_value": p_value, "significant": p_value < alpha, "sample_sizes": {"control": len(control_outcomes), "treatment": len(treatment_outcomes)} } # Расчёт необходимого размера выборки def required_sample_size( baseline_rate: float, # Текущая метрика (например, 0.75) min_detectable_effect: float, # Минимальное значимое улучшение (например, 0.05) alpha: float = 0.05, power: float = 0.80 ) -> int: from statsmodels.stats.power import TTestIndPower analysis = TTestIndPower() effect_size = min_detectable_effect / (baseline_rate * (1 - baseline_rate)) ** 0.5 n = analysis.solve_power(effect_size=effect_size, alpha=alpha, power=power) return int(np.ceil(n)) # Пример: baseline task_completion = 75%, хотим зафиксировать улучшение на 5% n = required_sample_size(0.75, 0.05) print(f"Нужно {n} запросов на каждую группу") # ~500–1000 

Почему t-тест, а не только доверительные интервалы?

Традиционный подход с доверительными интервалами (check overlap) может вводить в заблуждение при малых выборках. t-тест даёт точный p-value, а при нормально распределённых метриках (task completion — бинарная, но для больших n t-тест робастен) он статистически корректен. В случае бинарных метрик можно дополнительно использовать z-тест для пропорций — мы в работе используем оба метода для перекрёстной проверки.

Кейс: A/B-тест саппорт-бота (из нашей практики)

Контекст: customer support бот на базе Llama 3.1 8B fine-tuned v1. Подготовлена версия v2 с улучшенным датасетом (+800 примеров, исправлены failure cases v1).

Эксперимент:

  • Контроль (80% трафика): v1
  • Тест (20% трафика): v2
  • Длительность: 14 дней
  • Размер выборки: 6200 диалогов на контрольную группу, 1550 на тестовую

Первичная метрика: task_completion_rate (пользователь решил вопрос без escalation). Вторичные: CSAT, escalation_rate, avg_turns_to_resolution.

Результаты:

Метрика v1 (control) v2 (treatment) p-value Значимо?
Task completion 71.3% 78.9% 0.0012 Да
CSAT 3.8 4.1 0.034 Да
Escalation rate 28.7% 21.1% 0.0008 Да
Avg turns 3.2 2.9 0.18 Нет
Latency P95 2.1с 2.3с +10%

v2 статистически значимо лучше по трём из четырёх метрик. Рост латентности P95 (+10%) приемлем. Принято решение о полном rollout.

Пошаговый план внедрения A/B-тестирования

Чтобы вы не упустили детали, вот чеклист этапов:

  1. Определите бизнес-метрику (например, task completion). Выберите одну первичную.
  2. Рассчитайте размер выборки с помощью power analysis (как в коде выше).
  3. Реализуйте маршрутизацию с детерминированным хэшем по user_id.
  4. Запустите эксперимент — не менее 1-2 недель, чтобы покрыть недельные циклы.
  5. Соберите данные — логируйте метрики в единую систему (MLflow, Weights & Biases).
  6. Проведите t-тест — проверьте p-value < 0.05.
  7. Примите решение: rollout, доработка или откат.

Что входит в нашу работу по A/B-тестированию?

  • Разработка схемы эксперимента и выбор метрик.
  • Реализация модуля маршрутизации с логированием.
  • Интеграция с вашим MLOps-стеком (MLflow, LangSmith, Weights & Biases).
  • Расчёт необходимого размера выборки и длительности теста.
  • Анализ результатов и подготовка отчёта с рекомендациями.
  • Пост-rollout мониторинг и, при необходимости, корректировка.

Мы также обучаем вашу команду самостоятельно запускать A/B-тесты в будущем.

Сравнение популярных инструментов

Инструмент Назначение Интеграция Открытый исходный код
LangSmith Трекинг экспериментов LangChain LangChain, Python Да
Phoenix (Arize) Observability LLM OpenTelemetry Да
MLflow Универсальный трекинг Python, REST API Да
Weights & Biases Таблицы, гистограммы Python Да

Выбор зависит от текущего стека. Мы помогаем настроить оптимальную связку.

Сроки и экономия бюджета

  • Настройка A/B инфраструктуры: 3–7 дней
  • Эксперимент (достижение необходимого n): 1–4 недели
  • Анализ результатов и принятие решения: 2–3 дня
  • Итого: 2–5 недель

Сократите затраты на дообучение: закажите внедрение A/B-тестирования под ключ — мы настроим эксперимент, интегрируем с вашим MLOps-стеком и поможем интерпретировать результаты.