Привет, Хабр! На связи Анастасия Шулакова и Георгий Геймбух, аналитики поддержки Авито. Мы помогаем командам развивать внутренние инструменты для специалистов так, чтобы пользователи получали ответы быстрее, а поддержка оставалась управляемой по качеству и стоимости.

Недавно мы переработали один из самых нагруженных блоков админки — страницы пользователя и объявления, с которыми ежедневно работают поддержка, модерация и другие команды. Это был не косметический редизайн, а замена ключевого операционного контура. И главный вопрос, на который нужно было ответить перед решением о масштабировании: не ухудшает ли новый интерфейс AHT (среднее время обработки обращения)  — нашу ключевую метрику эффективности?

По задумке это выглядит как классическая задача для A/B-теста. Но в реальности дизайн сложнее: единица воздействия здесь — специалист, а не обращение, выборка маленькая, дисперсия большая, и обычный рандомный сплит даёт слишком высокий MDE.
В этой статье расскажем, как мы собирали группы генетическим алгоритмом, балансировали ковариаты, проверяли баланс после старта и считали итоговый эффект через CUPED — этот метод доступен из коробки в нашей внутренней A/B-платформе Trisigma, поэтому нам не пришлось писать расчёт с нуля, и мы сосредоточились на дизайне теста и выборе ковариат.

В этой статье

  • Какую проблему мы решали на уровне продукта и бизнеса

  • Пилот перед масштабированием

  • Как спроектировать проверку гипотезы, чтобы доверять результату

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

  • Условия, при которых случайный сплит достаточен

  • Как мы описали профиль сотрудника

  • Как генетический алгоритм помог собрать группы

  • Проверка баланса после старта

  • Что получили в итоге

Какую проблему мы решали на уровне продукта и бизнеса

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

Цель проекта была не в том, чтобы «перерисовать страницы», а в том, чтобы сделать этот контур более управляемым. Для бизнеса это решало три задачи:

  1. Быстрее развивать продукт. Вместо долгих изменений в монолите команды могут развивать свои виджеты изолированно и управлять конфигурацией интерфейсов.

  2. Снизить операционные риски. Изоляция виджетов, проверки стабильности и алерты владельцам помогают быстрее находить проблемы и ограничивать эффект ошибок.

  3. Усилить безопасность и комплаенс. Ролевая модель и управляемые доступы снижают риск несанкционированного доступа к чувствительным данным. Это бизнес-критичное требование, а не дополнительное улучшением.

Тут еще больше контента

Пилот перед масштабированием

Цена ошибки на проде слишком высокая из-за масштаба операций: если новый интерфейс ломает привычный сценарий, увеличивает время обработки или создает путаницу в массовом процессе, это быстро становится проблемой не только продукта, но и всей поддержки.

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

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

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

Как спроектировать проверку гипотезы, чтобы доверять результату

После пилота стало понятно, что интерфейс можно проверять количественно. Но просто сказать «давайте проведем A/B-тест» было недостаточно: нам нужно было не только посчитать разницу в AHT, но и понять, можно ли доверять этому результату в условиях шумных операционных данных.

Шаг 1 — Гипотеза

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

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

Шаг 2 — Единица сплитования

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

Поэтому эксперимент нужно было строить на уровне сотрудников: один специалист работает либо в тесте, либо в контроле. И здесь большой поток обращений перестаёт быть таким сильным преимуществом: строк в событийной таблице много, но независимых единиц гораздо меньше.

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

Шаг 3 — Особенности метрики

При этом AHT сам по себе остается шумной операционной метрикой. На него влияют вертикали, каналы, типы обращений, сложность кейсов, опыт специалистов, текучка и кадровые движения во время теста. С одной стороны, для надежного измерения нужны большие выборки и длинное наблюдение. С другой — продукту нужен результат, который можно использовать в разумные сроки, а не идеальная статистика спустя месяцы.

Шаг 4 — Чувствительность теста и MDE

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

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

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

Как правило, рандомизация — золотой стандарт: в среднем она уравнивает группы и даёт честную оценку эффекта. В реальных операционных экспериментах на малых n и шумных ratio‑метриках этого часто недостаточно.

Случайный сплит не гарантирует баланс: при типичном размере групп в поддержке — от 20 до 150 сотрудников — вероятность перекоса по целевой метрике остаётся заметной. Мы проверили это на исторических данных через серию AA-симуляций: многократно делили выборку 50/50 и считали эффект. В базовом пайплайне (случайный сплит + t-test + дельта-метод) доля ложных срабатываний превышала целевой уровень α и достигала 5,8–6,5%.

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

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

Рандомизация способна выровнять каждую из этих осей по отдельности, но на малых выборках редко выравнивает все оси одновременно. Одной «кривой» оси достаточно, чтобы результат стал неинтерпретируемым.

Условия, при которых случайный сплит достаточен

Можно делить группы случайно, если выполняется большинство условий:

  • Большое n по сущностям — минимум 200 на группу (всего ≈400+). Это не гарантия, но на практике вероятность «фатального» перекоса по нескольким ковариатам заметно падает и рандом начинает быть приемлемым дефолтом;

  • Одна основная метрика, без жёстких требований выровнять «профиль» по нескольким осям;

  • Низкий риск изменения состава/потока в процессе (стабильная команда, мало текучки) — в противном случае баланс будет деградировать после старта;

  • Предэкспериментальная проверка показывает приемлемый баланс по целевой и прокси- метрикам;

  • Ожидаемый эффект достаточно крупный относительно шума (выше MoE в 2,8 и более раз).

Как мы описали профиль сотрудника

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

Выбирайте ковариату, если она удовлетворяет большинству критериев

Доступна до старта теста: измеряется на предпериоде (иначе будет утечка или подглядывание).

Сильно связана с целевой метрикой. Ковариата должна отражать механизм, который «раздувает» дисперсию.
Пример: мы увидели, что AHT плавно снижается с ростом опыта сотрудника в течение первых 9 месяцев, а потом несколько увеличивается. Сначала это выглядит как выгорание, но на практике некоторые из таких сотрудников просто набирают достаточную экспертизу, чтобы решать тяжёлые долгие кейсы, из‑за чего распределение AHT приобретает тяжёлый хвост. В итоге среднее AHT по стажу плохо описывает ситуацию: различия порождаются не сроками работы, а структурой потока. Важно отразить в ковариате именно ключевую причину расхождений — сложность решений.

Стабильна на горизонте эксперимента.
Пример стабильной ковариаты:  опыт сотрудника: на горизонте 2–8 недель сохраняется качественная разница между опытным сотрудником и новичком. 
Пример нестабильной ковариаты:  количество обработанных обращений на предпериоде: зависит от структуры потока в будущем, отпусков и больничных.

Интерпретируема, чтобы можно было объяснить, почему именно эту ковариату балансировали (например, «иначе тест сравнит сложные кейсы с простыми»).

Примеры ковариат, которые мы используем

AHT по каналам, в которых работает сотрудник. Как упоминалось ранее, помимо специфики самого способа взаимодействия (звонок, чат, почта), у сотрудника могут быть индивидуальные особенности обработки в каждом из каналов. Новые выкатки также могут по-разному воздействовать на разные каналы. Например, новая кнопка в интерфейсе может не сказаться значимо на длине телефонного разговора, поскольку мы не имеем возможности прервать пользователя.

Характеристика скорости сотрудника, зависящая от сложности кейсов. Мы предварительно залогировали все признаки, увеличивающие сложность решения вопроса пользователя, вычислили таргетное AHT для каждого уровня сложности. Теперь остаётся только сравнить фактическое AHT сотрудника в каждом обращении с таргетным. Разница между этими значениями объективно характеризует эффективность сотрудника: является ли он просто медленным или занимается сложными вопросами.

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

Дополнительные прокси-метрики, чувствительные к изменениям. Если мы дорабатываем внутреннюю базу знаний, важно понимать, сколько каждый сотрудник тратит времени на изучение инструкций в ней, чтобы равномерно распределить целевое звено AHT. Если мы воздействуем на длительность простоев, важно сбалансировать простои между группами.

Жми сюда!

Как генетический алгоритм помог собрать группы

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

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

Упрощённо процесс выглядел так:

  1. Собираем матрицу «сотрудник — ковариаты»: AHT по каналам, скорость с учётом сложности, прокси вовлечённости и другие признаки.

  2. Кластеризуем сотрудников по этому вектору и создаем стартовую популяцию стратифицированно: внутри каждого кластера распределяем людей примерно 50/50 в тест и контроль. В обычном генетическом алгоритме стартовая популяция решений (сплитов) создаётся случайно. На малых n это означает, что первые десятки поколений алгоритм тратит на перебор очевидно плохих сплитов.

  3. Кодируем каждый сплит как хромосому — вектор из 0 и 1, где 0 означает контроль, а 1 — тест.

  4. Считаем fitness-функцию: насколько близки группы по набору метрик и ковариат, и насколько сильно нарушены ограничения.

  5. Добавляем штрафы за плохую мощность, в том числе за перекос размеров групп. При фиксированном общем N равные группы минимизируют выражение 1/n1 + 1/n2, поэтому дают меньшую дисперсию оценки и лучший MDE.

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

  7. Останавливаем поиск по числу поколений или стабилизации функции качества, затем дополнительно проверяем средние, распределения и размеры групп на предпериоде.

Псевдокод, который отражает логику без привязки к конкретной библиотеке:

population = init_stratified_population(employees, clusters)
for generation in range(max_generations):
    scored = [(split, fitness(split)) for split in population]
    parents = select_best(scored)               # tournament / top-k
    children = crossover(parents)
    children = mutate(children, p=mutation_rate)
    population = elite(scored) + children            # elitism
best_split = min(population, key=fitness)

Параметры мы подбирали на исторических A/A: порядка сотен поколений, популяция десятки-сотни кандидатов, скрещивание с вероятностью ~0.7, точечные мутации с низкой вероятностью (~5%). Точные числа менее важны, чем сам принцип: много кандидатов, явная fitness-функция, стратифицированный старт.

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

На исторических A/A-симуляциях такой подход снизил вероятность ошибки первого рода с 5,8–6,5% при случайном семплировании до 1% и ниже. МоЕ значимо не меняется, однако снижается выраженность смещения эффекта на АА-тестах с 6% до 4%.

Это не делает эксперимент идеальным само по себе. Но снижает риск того, что итог теста будет объясняться не продуктовым изменением, а неудачно собранными группами.

Проверка баланса после старта 

Даже хороший сплит до старта не гарантирует идеальный баланс до конца эксперимента. В поддержке на горизонте теста часть группы может выпасть из-за текучки, отпусков, больничных и других операционных причин. В наших тестах потери могли доходить примерно до 10 % группы.

Поэтому после завершения мы отдельно проверяем итоговый баланс по каждому каналу и ковариате через SMD — standardized mean difference, стандартизованную разность средних.

  • |SMD| < 0,1 — отличный баланс;

  • 0,1 <= |SMD| < 0,2 — умеренный дисбаланс;

  • |SMD| >= 0,2 — серьёзный дисбаланс, который требует внимания.

При дисбалансе групп мы корректируем расчётную выборку по предэкспериментальным данным: итеративно пробуем исключить каждого сотрудника из test/control, пересчитываем средний SMD по метрикам и выбираем удаление, которое сильнее всего улучшает баланс. Процесс повторяется до остановки улучшения или лимита итераций.

Важное ограничение: при такой корректировке не смотрим на результаты эксперимента после старта. Чтобы не превратить корректировку в ручной подбор выборки, правило было зафиксировано до анализа эффекта: используем только предпериодные ковариаты, не смотрим на экспериментальный АНТ, ограничиваем число исключений X%, отдельно считаем sensitivity check на полной выборке.

Поэтому это не data snooping и не p-hacking, а способ восстановить сопоставимость групп после операционных изменений состава. 

Финальную оценку мы делаем на сбалансированных группах и после адаптационного окна. 

При выборе метода оценки эффекта не обнаружили значимых различий между bootstrap и delta t-test, однако всегда важно помнить, что для ratio-метрик t-test без дельта-метода не подходит. 

Проверка баланса после старта 

Даже хороший сплит до старта не гарантирует идеальный баланс до конца эксперимента. В поддержке на горизонте теста часть группы может выпасть из-за текучки, отпусков, больничных и других операционных причин. В наших тестах потери могли доходить примерно до 10 % группы.

Поэтому после завершения мы отдельно проверяем итоговый баланс по каждому каналу и ковариате через SMD — standardized mean difference, стандартизованную разность средних.

  • |SMD| < 0,1 — отличный баланс;

  • 0,1 <= |SMD| < 0,2 — умеренный дисбаланс;

  • |SMD| >= 0,2 — серьёзный дисбаланс, который требует внимания.

При дисбалансе групп мы корректируем расчётную выборку по предэкспериментальным данным: итеративно пробуем исключить каждого сотрудника из test/control, пересчитываем средний SMD по метрикам и выбираем удаление, которое сильнее всего улучшает баланс. Процесс повторяется до остановки улучшения или лимита итераций.

Важное ограничение: при такой корректировке не смотрим на результаты эксперимента после старта. Чтобы не превратить корректировку в ручной подбор выборки, правило было зафиксировано до анализа эффекта: используем только предпериодные ковариаты, не смотрим на экспериментальный АНТ, ограничиваем число исключений X%, отдельно считаем sensitivity check на полной выборке.

Поэтому это не data snooping и не p-hacking, а способ восстановить сопоставимость групп после операционных изменений состава. 

Финальную оценку мы делаем на сбалансированных группах и после адаптационного окна. 

При выборе метода оценки эффекта не обнаружили значимых различий между bootstrap и delta t-test, однако всегда важно помнить, что для ratio-метрик t-test без дельта-метода не подходит. 

Для наглядности посмотрите на сравнение метрик по дельта-тесту, bootstrap и naive t-test (Welch t-test по среднему AHT агента):

Welch t-test по сравнению с корректными методами увеличивает MoE с 14,5 % до 18,1 %, смещает эффект с 4 % до 6,5 %
Welch t-test по сравнению с корректными методами увеличивает MoE с 14,5 % до 18,1 %, смещает эффект с 4 % до 6,5 %

Для дальнейшего снижения дисперсии мы используем CUPED. 

Предэкспериментальное AHT коррелирует с экспериментальным — в среднем на 78%, поэтому является сильной ковариатой для снижения шума. CUPED помогает вычесть 

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

В результате стандартная ошибка снижается примерно на 36 % (с 14,5 % до 9,2 %). Для нас это принципиально: чем ниже стандартная ошибка, тем ниже MDE и тем выше шанс отличить реальное влияние продукта от операционного шума.

Ratio-метрики при расчёте CUPED нуждаются в линеаризации, в противном случае мы увеличиваем смещение эффекта, MoE, вероятность ошибки первого рода.

Что получили в итоге

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

На выходе мы получили несколько важных результатов:

  • стандартная ошибка снизилась примерно на 36 % за счёт CUPED;

  • генетический алгоритм и постпроверка баланса убрали риск неудачного сплитования на малой выборке;

  • мы получили статистически обоснованный ответ на вопрос о раскатке на 100 % — а не «выглядит вроде неплохо». 

Главный вывод для нас оказался шире одного запуска. В операционных экспериментах хороший A/B-тест начинается задолго до первого пользователя в тестовой группе. Нужно заранее понять, где возникает дисперсия, какие сотрудники и каналы создают перекосы, какой адаптационный период нельзя смешивать с продуктовым эффектом и какой MDE действительно нужен бизнесу для решения.

Генетический алгоритм здесь был не математическим украшением, а практичным способом защитить чувствительность эксперимента. Он помог сделать вывод не просто статистически аккуратным, а полезным для продуктового решения.

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

Кликни здесь и узнаешь

Комментарии (0)