AI-evals · LLM A/B Test Simulator
← Симуляторы

Замена LLM-модели в чат-боте маркетплейса: как спланировать A/B

Маркетплейс хочет заменить LLM-модель в чат-боте поддержки покупателей. Текущая модель — топовая (типа GPT-4), дорогая. Новая — в 3 раза дешевле, по бенчмаркам чуть слабее на общих задачах, но возможно достаточная для support-сценариев маркетплейса. Решение нужно принимать на данных, не на бенчмарках.

Простой план: A/B-тест 50/50, метрика CSAT (1-5 stars после диалога). Если новая модель не статистически хуже текущей — мигрируем, экономим деньги. Если хуже — оставляем текущую.

Аналитик должен ответить на три вопроса:

  • Сколько диалогов нужно для статистически достоверного решения?
  • Какие метрики кроме CSAT нужны, чтобы решение было правильным?
  • Что специфично для A/B на LLM-моделях, чего нет в обычном A/B-тесте на UX-фиче?

Эта страница даёт ответы на все три. Симулятор посередине позволяет покрутить параметры и увидеть, как меняется требуемый sample size при разных предположениях.

Что отличает A/B на LLM от обычного A/B

Главное содержание этого кейса. Три специфические угрозы, которых нет в обычном A/B-тесте на UX или продуктовой фиче.

Угроза 1. Stochastic treatment

В обычном A/B treatment детерминирован: пользователь видит фичу A или фичу B. Один и тот же пользователь, тот же контекст, тот же запрос — увидит то же самое. Variance в outcome берётся из вариативности пользователей и контекстов, не из самой treatment.

В A/B на LLM треатмент сам стохастичен. При temperature больше нуля модель даёт разные ответы на тот же запрос. Это не баг, это feature — модель так устроена. Но это добавляет variance, которой не было в стандартной формуле sample size.

Что это значит на практике: тот же пользователь с тем же вопросом получает разный ответ при повторном обращении. CSAT по диалогу зависит не только от того, какая модель ответила, но и от того, как именно она ответила в этот раз. Это дополнительный шум, который маскирует разницу между моделями.

Численно: если variance модели добавляет 30% к общей дисперсии, требуемый N вырастает примерно в 2 раза. При 50% — в 4 раза. Это в формуле напрямую: N пропорционально σ². Игнорировать stochasticity — значит планировать в 2-4 раза меньше выборки чем нужно.

Угроза 2. Survivorship через handoff

Стандартная метрика — CSAT измеряется в конце диалога. Но не все диалоги доходят до конца — часть переключается на живого оператора (handoff). Эти диалоги либо вообще не получают CSAT, либо получают CSAT уже от человека, а не от бота.

Что это меняет в анализе: если новая модель чаще переключает на человека (она хуже справляется и быстрее сдаётся), то на CSAT мы видим только «успешные» диалоги новой модели — те где она дошла до конца. Эти диалоги в среднем легче, и CSAT по ним может быть даже лучше чем у старой модели. А общее качество новой модели хуже — её просто меньше «допускали» до конца.

Это classical survivorship bias. Если измерять только CSAT — можно прийти к выводу, что новая модель лучше, и переключиться на неё, при этом увеличив нагрузку на живых операторов в несколько раз.

Что нужно: мониторить handoff rate как параллельную метрику. Если handoff в новой модели сильно вырос, выигрыш по CSAT — иллюзия selection bias.

Угроза 3. Multi-metric trade-offs

CSAT — одна метрика. Но решение про модель — это multi-objective задача:

Новая модель может выигрывать в CSAT, проигрывать в handoff и tokens. Чистый эффект на бизнес — сумма этих изменений в денежных терминах. Решение принимается не по одной звёздочке CSAT, а по общему ROI.

Это не уникально для LLM (любое решение про продукт — multi-objective), но для LLM особенно опасно: разница в стоимости моделей в 3-10 раз делает второстепенные метрики первостепенными. Замена дорогой модели на дешёвую при равном CSAT — может всё равно быть провалом, если handoff вырос вдвое.

Что нужно: считать total cost per resolved ticket как итоговую метрику решения. CSAT — один из компонентов, не вердикт.

Симулятор: sample size для A/B на LLM-моделях

Покрути параметры и посмотри, как меняется минимальное число диалогов на группу. Главное отличие от обычного power calculator — поправка на stochasticity модели.

Минимальный sample size на группу:
диалогов
Без поправки на stochasticity:
Поправка:

Power curve

Синяя линия — с учётом stochasticity модели. Серая — стандартный расчёт. Горизонтальная линия — целевая power.

Распределения CSAT

Две модели с разницей в среднем = effect size. Variance включает stochasticity. Чем больше σ — тем сильнее перекрываются распределения, тем труднее различить.

Что показывает симулятор

  1. Без stochasticity (slider в 0) — N расчитывается по классической формуле, как для обычного A/B.
  2. Реалистичная stochasticity 30% (default) — N в 1.4× больше. Это типично для GPT-class моделей с temperature 0.7.
  3. Высокая stochasticity 50%+ — N в 2× больше. Это модели с большой вариативностью ответов или с fallback-логикой между несколькими retries.

Главный takeaway: для realistic effect size (0.15 stars) вам нужно ~850 диалогов на группу. Большинство команд закладывают 200-300 — и не видят разницы между моделями, делая вывод что они «эквивалентны». На самом деле — просто не хватает выборки.

Полный eval pipeline

Теперь практическое: что именно собирать в коде и как агрегировать. Это рабочий шаблон для аналитика, который запускает A/B на LLM-модели в продакшене.

Что логировать на уровне диалога

Минимальный набор полей в логе каждого диалога:

dialog_id          — уникальный ID
user_id            — кто пользователь (для дедупликации
                     и кластеризации SE)
arm                — A или B (какая модель)
started_at         — время начала
ended_at           — время окончания
end_reason         — resolved, handoff, abandoned, timeout
csat               — 1-5, если пользователь оценил
num_turns          — сколько раундов диалога
tokens_total       — суммарно токенов на сессию
resolved_flag      — бинарный, успешно ли решена проблема
                     (нужен для cost-per-resolved)
category           — тип запроса (доставка, возврат,
                     и т.д.) — для гетерогенности

Что считать на уровне эксперимента

Базовая SQL-агрегация:

SELECT
  arm,
  COUNT(*) AS n_dialogs,
  AVG(csat) FILTER (WHERE csat IS NOT NULL) AS csat_avg,
  COUNT(csat) * 1.0 / COUNT(*) AS csat_response_rate,
  AVG(end_reason = 'handoff'::TEXT) AS handoff_rate,
  AVG(resolved_flag::INT) AS resolution_rate,
  AVG(tokens_total) AS tokens_avg,
  AVG(EXTRACT(EPOCH FROM ended_at - started_at)) AS duration_avg
FROM dialogs
WHERE experiment_id = 'llm_swap_q2'
  AND started_at >= '2026-04-01'
GROUP BY arm;

Это даёт baseline-таблицу: что показывает каждая модель по всем ключевым метрикам.

Что считать на уровне дашборда

Дашборд показывает:

  1. CSAT mean per arm + 95% CI, с поправкой на stochasticity
  2. Handoff rate per arm + CI
  3. Resolution rate per arm + CI
  4. Cost per resolved ticket per arm (комбинированная)
  5. Heterogeneity: CSAT в разрезе category (топ-5 категорий)

Псевдокод финального вердикта:

def decision(arm_A, arm_B):
    # Главный вопрос: total cost per resolved ticket
    cost_A = (arm_A.tokens_cost +
              arm_A.handoff_rate * COST_PER_HUMAN_HANDOFF)
              / arm_A.resolution_rate
    cost_B = (arm_B.tokens_cost +
              arm_B.handoff_rate * COST_PER_HUMAN_HANDOFF)
              / arm_B.resolution_rate

    # CSAT не должен сильно падать
    csat_acceptable = (arm_B.csat >= arm_A.csat - 0.10)

    # Statistical significance с поправкой на stochasticity
    sig = test_diff(arm_A, arm_B, account_for_stochasticity=True)

    if sig and cost_B < cost_A and csat_acceptable:
        return 'switch_to_B'
    elif sig and cost_A < cost_B:
        return 'keep_A'
    else:
        return 'inconclusive_need_more_data'

Это не «выкатываем по CSAT». Это решение с явным учётом trade-off между качеством и стоимостью, и с честной обработкой «неубедительного» исхода.

Что писать в финальный отчёт

По образцу Module 8 квазиэкспериментов — семь шагов:

  1. Контекст и вопрос
  2. Дизайн (A/B 50/50, primary metric = cost per resolved ticket, secondary = CSAT, handoff, tokens)
  3. Допущения (treatment экзогенен — рандомизация на уровне пользователей; stochasticity модели учтена в sample size)
  4. Проверки (balance check, sample ratio mismatch, handoff sanity)
  5. Оценка (главные цифры с CI)
  6. Ограничения (короткое окно, конкретный сегмент пользователей, эффект на новых vs returning)
  7. Рекомендация (migrate / keep / continue с планом)

Что делать дальше

Минимальные шаги для аналитика который собирается запустить A/B на LLM-моделях:

Связь с курсом

Этот кейс опирается на понятия из курса квазиэкспериментов: