LLM API и интеграция

A/B-тест двух моделей: как сравнить на живом трафике

A/B-тест двух моделей: как сравнить на живом трафике

A/B-тест двух моделей ставят после офлайн-проверки: выборка показывает, что модель умеет отвечать, а живой трафик — решает ли она задачи реальных людей. Трафик делят по пользователю, а не по запросу, сравнивают правки, повторные обращения, передачи человеку и стоимость решённой задачи и держат тест не меньше 14 дней, даже если разница видна в первый день. Остановка на первом удачном дне превращает случайность в решение: в нашей симуляции одинаковых веток ложный «победитель» находился в 23 % тестов вместо 5 %. Расход честно сравнивается только при отдельном ключе или метке ветки на каждую половину трафика.

Это следующий шаг после тестирования на выборке: кандидат уже прошёл офлайн-проверку, и вопрос теперь в том, выдержит ли он живой поток лучше текущей модели.

Зачем онлайн-тест, если выборка уже показала результат

Затем, что выборка измеряет ответ, а живой трафик — исход. В проде эталона нет, зато есть поведение человека: переписал ли он ответ, вернулся ли с тем же вопросом, позвал ли оператора.

Три вещи выборка не видит в принципе:

  • Реальных людей. Живые пользователи переформулируют, бросают диалог на середине, пишут три слова вместо абзаца. Выборку размечали вы, и ваше «правильно» не обязано совпадать с их «помогло».
  • Новые типы обращений. Выборка заморожена в момент сбора, а в потоке за месяц появляются вопросы, которых в наборе не было.
  • Связку с остальной системой. Интерфейс, операторы и время ответа влияют на исход, а в офлайн-прогоне их нет.

Выборка остаётся фильтром: модель, провалившая её, до живого трафика не доходит. Как отбирать кандидатов на своих данных, разобрано в статье как сравнивать модели.

Как делить трафик: почему по пользователю, а не по запросу

Ветку назначают человеку один раз и держат до конца теста. Если делить случайно каждый запрос, ломаются три вещи сразу:

  • один человек видит то одну модель, то другую и реагирует на смену стиля, а не на качество;
  • диалог, начатый одной моделью, продолжает другая, и исход нельзя приписать ни одной;
  • повторное обращение становится ничьим: первый ответ дала ветка A, повтор обслужила B.

Технически это хэш от идентификатора пользователя вместе с названием эксперимента: остаток от деления даёт номер ветки. Название нужно, чтобы одни и те же люди не попадали в новую ветку в каждом тесте. Если пользователя нет, делят по диалогу, но тогда повторы между диалогами теряются.

Ветку записывают в ваш журнал в момент назначения, а не вычисляют задним числом. Сотрудников и тестовые аккаунты из теста исключают: они ведут себя иначе и знают, что проверяется.

Какую долю отдавать новой модели и зачем сначала A/A

Сначала 5–10 % на два-три дня. Это техническая проверка — ошибки, задержка, формат ответа, — и эти дни в сравнение не идут. Дальше 50 на 50: при равных половинах нужное число задач набирается быстрее всего.

Долю не меняют посреди теста. Если пришлось поменять, счёт начинают заново: периоды с разным делением не смешивают.

Ещё раньше стоит прогнать A/A-тест: обе ветки несколько дней работают на одной и той же модели. Если метрики разошлись сильнее шума, сломан не кандидат, а деление или подсчёт, и A/B-тест на такой основе покажет что угодно.

Что сравнивать между ветками

Исход задачи, а не свойства ответа. Одну метрику назначают главной до старта, остальные служат ограничителями: по ним новая ветка не должна стать хуже. Если смотреть на пять равноправных метрик, одна почти наверняка «выиграет» случайно.

МетрикаКак считать по веткеЧто показывает
Доля передач человекуобращения к оператору / задачи веткигде модель не справилась
Доля повторных обращенийвернувшиеся с тем же вопросом / задачиответ дан, задача не решена
Доля правок перед отправкойисправленные ответы / отправленныекачество до жалоб
Стоимость решённой задачивесь расход ветки / решённые задачицену результата
Время до ответа95-й перцентиль по запросам веткитерпение пользователя

Определения и пороги тревоги разобраны в статье какие метрики отслеживать после запуска. Для теста важно одно: знаменатель — задачи ветки, а не запросы.

Средней длины ответа в таблице нет намеренно. Длинный ответ выглядит основательнее и нравится на глаз, но о решённой задаче не говорит ничего, а счёт за выход увеличивает. Модель, выигравшая по длине, нередко проигрывает по правкам.

Сколько задач нужно в каждой ветке

Чем меньше разница, которую хотите увидеть, тем больше задач. Расчёт для доли передач человеку, которая сейчас 20 %, при стандартных 95 % достоверности и 80 % мощности:

Хотите увидеть снижениеЗадач в каждой ветке
с 20 до 10 %около 200
с 20 до 15 %около 900
с 20 до 17 %около 2 600
с 20 до 18 %около 6 000

При 300 задачах в сутки и делении пополам ветка набирает 900 задач за шесть дней, а 6 000 — за сорок.

Практическое следствие: если ожидаемая разница — пара процентных пунктов, а поток — сотни задач в сутки, тест растянется на месяцы. Иногда честнее признать это до старта, чем получить ничью через три недели.

Почему нельзя остановить тест в первый хороший день

Потому что «значимая» разница в один из дней чаще всего случайна. Мы смоделировали две одинаковые ветки по 100 задач в сутки с ежедневной проверкой в течение двух недель и остановкой при первом значимом результате. «Победитель» нашёлся в 23 % тестов, хотя разницы не было; без подглядывания таких ложных побед 5 %.

Отсюда правило: тест длится не меньше двух полных недель и не меньше расчётного числа задач, что наступит позже. Две недели нужны из-за недельного цикла: в понедельник и в субботу пишут разные люди о разном.

Есть и эффект новизны: первые дни люди реагируют на то, что стало иначе, а не на то, что стало лучше.

Задачи последнего дня досчитывают, когда закроется окно повторного обращения. Иначе у ветки занижены возвраты.

Досрочно тест останавливают только в одну сторону — из-за вреда. Условия записывают до старта: всплеск ошибок, рост передач человеку сверх порога, жалобы. Выигрыш поводом для остановки не бывает.

Почему одного ключа на две модели недостаточно

Потому что журнал общего ключа знает модель запроса, но не ветку задачи. Мешают четыре вещи:

  • Ветка — не то же самое, что модель. Запасной вариант или эскалация на сильную позицию уводят часть запросов ветки B под модель ветки A. А если ветки отличаются только промптом, модель в обеих одна.
  • В том же ключе живёт чужой трафик. Классификация перед ответом, прогоны выборки и ручные проверки разработчика попадают в те же строки.
  • Задача — это несколько запросов. Повторы и уточнения надо сложить в задачу и отнести к ветке, а журнал ключа не знает, что они связаны.
  • Лимит общий. Если ветка B расходует больше, она выбирает лимит ключа, и обе ветки получают отказ key_limit_exceeded: один сбой портит обе половины.

Решение из двух частей. Ключ на ветку с одинаковыми настройками, кроме разрешённой модели. И в вашем собственном журнале у каждого запроса — идентификатор задачи, пользователь, ветка и версия промпта; что ещё туда писать, разобрано в статье логирование запросов к моделям.

В KeyDealer ключей можно завести несколько, и у каждого есть своё название, дневной и месячный лимит в рублях и список разрешённых моделей, а журнал показывает по каждому запросу ключ, модель, входные и выходные токены и стоимость. Ключ на ветку делает её расход отдельной строкой, а откат — отзывом одного ключа.

Настройки ключей должны совпадать во всём, кроме модели: например, KD Trim для длинных агентских сессий включают или выключают в обоих одинаково, иначе сравниваются настройки, а не модели.

Во что обходится решённая задача в каждой ветке

Не в то, что показывает ставка. Условный пример на 10 000 задач в месяц в каждой ветке:

ПоказательВетка AВетка B
Модельqwen-3-7-maxgpt-5-6-luna
Ставка, ₽ за 1 млн токенов38
Запросов на задачу1,81,2
Токенов на задачу5 4003 600
Решено без человека70 %85 %
Токенов на решённую задачу7 7004 200
Передано человеку3 0001 500

Ветка B дороже за токен, но тратит на решённую задачу на 45 % меньше токенов: у неё меньше повторов и уточнений. В рублях по ставкам на 24 сентября 2026 года ветки обходятся в 162 и 288 ₽ в месяц. Разница в 126 ₽ против 1 500 обращений, которые не дошли до оператора, — решает здесь вторая цифра. Как разбирать счёт по составляющим, описано в статье как читать биллинг.

Как откатиться, если новая модель хуже

Откат описывают до старта одной строкой: условие, кто решает, какая команда. Сама команда — доля ветки B в конфигурации становится нулём, и функция назначения возвращает A всем.

  1. Новые задачи сразу идут в ветку A.
  2. Открытые диалоги ветки B доживают на своей модели, если вред не в самих ответах. Если в ответах — переключаются сразу: шов в диалоге дешевле вреда.
  3. Ключ ветки B отзывают. Забытый вызов в коде упадёт с явной ошибкой, а не продолжит тихо тратить деньги.
  4. Журнал ветки B сохраняют и записывают итог: гипотеза, даты, деление, метрики, решение.

Откат один раз проходят на учениях до теста — зачем, разобрано в статье как перевести пилот в прод. Переезд на победившую модель целиком — отдельная процедура: как перейти на другую модель.

Когда A/B-тест не нужен

Когда он не сможет ответить или ответ известен заранее.

  • Мало трафика. При 50 задачах в сутки 900 задач на ветку набираются больше месяца. Честнее выкатить модель на всех после выборки и сравнить метрики «до» и «после», помня, что такое сравнение путает модель с сезоном.
  • Разница видна без людей. Формат, цену и задержку измеряют офлайн.
  • Кандидат в режиме проверки. На 24 сентября 2026 года это gemini-3-6-flash и fable-5: их доступность может измениться посреди теста.
  • Модели сильны в разном. Тогда победитель не нужен: запросы разводят между моделями, как описано в статье маршрутизация между моделями.

Чего мы не утверждаем

Мы не утверждаем, что цифры в примере с двумя ветками — замер. Это условный расчёт, показывающий механику, и на вашем потоке соотношение будет другим.

Мы не утверждаем, что таблица числа задач универсальна. Она посчитана для доли в 20 % при 95 % достоверности и 80 % мощности; другая исходная доля и другие пороги дают другие числа.

Мы не утверждаем, что A/B-тест отвечает навсегда. Он сравнивает ветки на потоке своего периода; через квартал поток меняется, и вывод стоит перепроверить.

Что нужно, чтобы попробовать

Ключ заводится за минуту на keydealer.ru/login — почта и пароль, без документов и без зарубежной карты. Оплата российской картой в рублях, один ключ на весь каталог из 57 позиций.

Для теста заведите два ключа, по одному на ветку, с лимитом в рублях и одной разрешённой моделью в каждом. Бесплатные позиции тоже годятся в кандидаты: пять текстовых открываются после первого платного пополнения и дальше не тарифицируются, так что их ветка ничего не стоит.

Что держать в голове

Выборка отвечает на вопрос «умеет ли модель», живой трафик — «решает ли она задачи людей». Второй вопрос задают только после того, как закрыт первый.

Честный тест держится на трёх решениях до старта: ветку назначают пользователю, главную метрику и условия остановки фиксируют заранее, а срок — не меньше двух недель и расчётного числа задач. Подглядывание с остановкой на первом успехе делает тест бессмысленным.

Расход ветки — это строка отдельного ключа, а не догадка по столбцу модели. Как мы проверяем факты и почему у каждой цифры стоит дата — на странице о проекте. Завести ключи под обе ветки: keydealer.ru/login.

Частые вопросы

Зачем A/B-тест, если модель уже прошла проверку на выборке?

Выборка проверяет ответы на запросах, которые вы собрали и разметили сами, а живой трафик показывает исход: решил ли человек задачу, вернулся ли с тем же вопросом, позвал ли оператора. Реакцию реальных людей и новые типы обращений выборка не видит в принципе.

Почему трафик делят по пользователю, а не по запросу?

При делении по запросу один человек видит то одну модель, то другую, диалог продолжает не та модель, что его начинала, а повторное обращение нельзя приписать ни одной ветке. Ветку назначают один раз по хэшу идентификатора пользователя и держат до конца теста.

Сколько длится A/B-тест двух моделей?

Не меньше двух полных недель и не меньше расчётного числа задач в каждой ветке, в зависимости от того, что наступит позже. Чтобы увидеть снижение доли передач человеку с 20 до 15 %, нужно около 900 задач на ветку.

Можно ли остановить тест, если новая модель выиграла в первые дни?

Нет. При ежедневной проверке случайная «значимая» разница появляется намного чаще обещанных 5 %: в нашей симуляции двух одинаковых веток — в 23 % тестов. Досрочно тест останавливают только из-за вреда: всплеска ошибок, жалоб или передач человеку.

Что сравнивать между двумя моделями на живом трафике?

Долю передач человеку, долю повторных обращений, долю ответов, которые правили перед отправкой, и стоимость решённой задачи. Средняя длина ответа ничего не говорит о том, решена ли задача, зато увеличивает счёт за выход.

Почему для сравнения расхода нужны два ключа?

В общем ключе журнал видит модель запроса, но не ветку: запасные вызовы, служебные запросы и повторы смешиваются, а общий лимит при перерасходе одной ветки останавливает обе. Отдельный ключ на ветку делает её расход отдельной строкой, а откат — отзывом одного ключа.

Источники