Разбор кейса: Dodo: ML System Design
Системный дизайн pricing-policy для доставки с guardrails по конверсии и операционной нагрузке.
Этапы
7
Вопросы
15
Практика
10
Кейс простыми словами
Кейс не про то, чтобы “предсказать стоимость доставки”. Dodo хочет управлять предложением в корзине: когда дать бесплатную доставку от порога, когда показать платную доставку ниже порога и как не потерять пользователя из-за неожиданной цены.
Разложение такое: бизнес выбирает действие, а модель оценивает последствия этого действия. Действие - порог бесплатной доставки или размер платы. Последствия - заказал ли пользователь, какая маржа заказа, не сорвали ли сроки кухни и курьеров, не вырос ли негатив.
Дальше собирается цепочка: цель бизнеса, путь пользователя, доступные данные на момент показа цены, модель реакции, выбор действия из допустимой сетки, эксперимент, затем запуск в продукте с контролем свежести данных и запасными сценариями.
7
этапов с вопросами, просадками и сильной структурой ответа.
4
повторяющихся слабых мест вынесены наверх перед деталями.
15
связанных вопросов открываются прямо из этапов разбора.
Главные просадки
- Слишком рано начался разговор про модель. Не хватило первой фразы: “какую бизнес-метрику оптимизируем и что запрещено ухудшать”.
- Ограничительные метрики были названы позже и местами абстрактно. Нужно сразу сказать, что прибыль нельзя поднимать ценой резкого падения заказов, жалоб или срыва доставки.
- Не хватило жесткого продуктового инварианта: цена на оплате не должна стать хуже, чем цена, которую пользователь уже видел в корзине.
- Было мало конкретики про события пересчета: изменение адреса, ресторана, состава корзины, промокода или слота доставки.
Цель бизнеса и границы решения
Что спрашивали
- Интервьюер просил не просто назвать алгоритм, а спроектировать систему: данные, проверку, обучение, запуск и обратную связь после запуска.
- Кейс звучал как персонализация минимальной суммы заказа и платной доставки ниже порога. Значит, продукт управляет ценой или порогом, а не расписанием курьеров.
Что было хорошо
- Кандидат быстро понял, что это ML System Design, а не отдельная задачка на классификацию.
- В ответе появились нужные блоки: данные, валидация, эксперимент и производственный контур.
Где просело
- Слишком рано начался разговор про модель. Не хватило первой фразы: “какую бизнес-метрику оптимизируем и что запрещено ухудшать”.
- Ограничительные метрики были названы позже и местами абстрактно. Нужно сразу сказать, что прибыль нельзя поднимать ценой резкого падения заказов, жалоб или срыва доставки.
Сильная структура ответа
- 1Сильнее было бы начать с цели: увеличиваем прибыль или маржу на пользователя, но держим нижние границы по конверсии в заказ, повторным заказам, жалобам, отменам и времени доставки.
- 2Затем зафиксировать действие: система выбирает порог бесплатной доставки или плату за доставку из заранее разрешенного диапазона. Она не управляет сменами курьеров и не обещает решить всю логистику.
Путь пользователя и момент обещания цены
Что спрашивали
- Интервьюер подвел к разбору пути заказа: пользователь открывает приложение, выбирает адрес или ресторан, собирает корзину, видит условия доставки и идет на оплату.
- Главный вопрос: где именно система принимает решение и что пользователь уже видит как обещание.
Что было хорошо
- Кандидат начал раскладывать процесс заказа, а не пытался сразу выбрать CatBoost или нейросеть.
- Были упомянуты корзина, оформление заказа, кухня, курьеры и доступность доставки.
Где просело
- Не хватило жесткого продуктового инварианта: цена на оплате не должна стать хуже, чем цена, которую пользователь уже видел в корзине.
- Было мало конкретики про события пересчета: изменение адреса, ресторана, состава корзины, промокода или слота доставки.
Сильная структура ответа
- 1Сильнее было бы описать путь словами: на входе в корзину считаем предложение, при изменении корзины или адреса пересчитываем, на оплате валидируем, но не ухудшаем уже показанное обещание без явного объяснения.
- 2Отдельно проговорить срок жизни обещания цены: например, оно фиксируется на короткое время, а при существенном изменении корзины создается новое обещание.
Данные: что известно до показа цены
Что спрашивали
- Интервьюер просил конкретизировать признаки нагрузки курьеров и кухни: из каких событий они считаются и насколько свежими должны быть.
- Проверялось, отделяет ли кандидат стабильные признаки пользователя и ресторана от быстрых операционных сигналов.
Что было хорошо
- В ответе появились правильные источники: состояние кухни, курьеры, текущие заказы, ресторан, зона, корзина и пользовательская история.
- Кандидат не ограничился “возьмем фичи из базы”, а начал думать про реальный операционный процесс.
Где просело
- Часть признаков звучала как названия без формулы. Например, “нагрузка курьеров” нужно разложить на активные заказы, свободные минуты курьеров, ожидаемое освобождение и риск опоздания.
- Не хватило проверки доступности признаков: если сигнал обновляется раз в 10 минут, он не подходит как точная картина для решения прямо сейчас.
Сильная структура ответа
- 1Сильнее было бы назвать единицу расчета: ресторан или зона доставки на ближайшие 15-30 минут. Нагрузка = ожидаемые минуты работы по активным и новым заказам / доступные курьерские минуты.
- 2Для каждого быстрого признака сразу задать срок годности: когда считаем устаревшим, чем заменяем и сколько таких замен допустимо до ухода в запасной сценарий.
Модель: предсказывать реакцию, а не цену
Что спрашивали
- Ключевой поворот был в том, что цена или минимальная сумма заказа - это действие, а не целевая переменная модели.
- Интервьюер уточнял, как собрать датасет: что является строкой, какие признаки известны до решения и какой результат наблюдаем после показа цены.
Что было хорошо
- Кандидат дошел до идеи реакции пользователя: вероятность заказа, средний чек, маржа или другой результат при заданном предложении.
- Была видна попытка отделить обучение модели от выбора финальной цены.
Где просело
- Сначала прозвучало слишком близко к “предсказываем цену”. Это опасно: модель просто повторит старые решения менеджеров или старого правила.
- Не хватило явной строки датасета: показ конкретного предложения конкретному пользователю в конкретном контексте в конкретное время.
Сильная структура ответа
- 1Сильнее было бы сказать: строка обучения - момент показа предложения. В строке есть пользователь, корзина, ресторан, зона, время, состояние кухни и курьеров, а также само действие: плата или порог.
- 2Метка - что случилось после показа: заказ, сумма заказа, маржа, отмена, жалоба, повторный заказ. Признаки после оплаты и фактическую задержку доставки в обучение на момент показа не подмешиваем.
Выбор действия и запасной сценарий
Что спрашивали
- Интервьюер проверял, что делать, если историческая цена почти не менялась и честного сигнала о реакции на разные цены мало.
- Затем вопрос перешел к выбору финальной цены по сетке допустимых вариантов и к риску учиться на данных, которые создала сама текущая политика.
Что было хорошо
- Кандидат обсуждал перебор вариантов цены и понимал, что решение нужно ограничивать бизнес-правилами.
- Был назван риск обучаться только на собственной истории новой модели.
Где просело
- Не хватило фразы “нет разнообразия действий - нет надежного сигнала об эластичности”. Если всем почти всегда показывали одну цену, обычное обучение не скажет, что было бы при другой.
- Запасной сценарий нужно описывать конкретно: старое правило, популярный для зоны порог, ручной лимит или скрытие динамики при плохих данных.
Сильная структура ответа
- 1Сильнее было бы предложить малую управляемую разведку: несколько безопасных вариантов цены на маленьком трафике, заранее заданные ограничения по конверсии и жалобам, отдельные срезы по городам и ресторанам.
- 2После модели перебираем сетку действий, считаем ожидаемую прибыль и отбрасываем варианты, которые нарушают ограничения. Если уверенность низкая, признаки устарели или пользователь в редком сегменте, включаем запасной сценарий.
Эксперимент: что доказывает A/B-тест
Что спрашивали
- Финальный блок был про метрики, статистику, разбиение пользователей и проверку алгоритма до запуска.
- В доставке есть зависимость между пользователями: общая кухня и курьеры могут сделать простое разбиение по пользователям недостаточным.
Что было хорошо
- Кандидат не забыл A/B-тест и начал обсуждать разные статистические тесты.
- Были затронуты разбиение по пользователям, минимальный заметный эффект и предварительная проверка.
Где просело
- Метрики нужно связывать с бизнесом: прибыль на пользователя или маржа не заменяют контроль конверсии, жалоб, отмен и времени доставки.
- Статистический тест нельзя выбирать отдельно от единицы разбиения. Если курьеры и кухня общие, пользователи в разных группах могут мешать друг другу.
Сильная структура ответа
- 1Сильнее было бы задать основную метрику: например, маржа на подходящего пользователя. Рядом поставить ограничения: конверсия в заказ, средний чек, отмены, жалобы, время доставки, повторные заказы и доля ухудшенных цен.
- 2Перед запуском сделать A/A или сухой прогон без изменения цены: проверить логи, долю запасных сценариев, задержку ответа сервиса, пропуски признаков и перекос разбиения.
Запуск в продукте: как модель отвечает и где риски
Что спрашивали
- Интервьюер возвращался к вопросу, можно ли использовать новые данные от текущей модели для следующего обучения.
- Это проверка на понимание замкнутого круга: модель меняет поведение пользователей, а потом учится на измененном распределении данных.
Что было хорошо
- Кандидат видел, что свежие данные не всегда лучше старых и что новая политика может сузить наблюдаемые варианты.
Где просело
- Не хватило конкретного контракта эксплуатации: что логируем на каждом показе, какие алерты ставим и когда откатываемся к старому правилу.
- Слова про изменение распределения данных нужно приземлять: например, модель перестала показывать дешевые варианты части зон, и мы больше не знаем реакцию этих пользователей на дешевую доставку.
Сильная структура ответа
- 1Сильнее было бы логировать версию политики, действие, вероятность выбора действия, входные признаки, свежесть каждого быстрого признака, итоговую цену, причину запасного сценария и последующие события пользователя.
- 2Отдельно держать контрольный или разведочный трафик, чтобы не потерять информацию о других вариантах цены. Откат включать при росте жалоб, просадке конверсии, высокой доле устаревших признаков или задержке ответа сервиса выше допустимого порога.
Термины
- Quote
- Зафиксированное обещание цены или условия доставки, которое пользователь уже увидел. Его нельзя тихо ухудшить на оплате.
- Fallback
- Запасной сценарий: старое правило, ручной лимит или простая эвристика, которая включается при плохих данных, низкой уверенности или сбое сервиса.
- Guardrails
- Ограничительные метрики: показатели, которые нельзя ухудшить ради роста основной метрики. Здесь это конверсия, жалобы, отмены, сроки доставки и доля неприятных изменений цены.
- Serving
- То, как модель отвечает в продукте: какие данные получает сервис, сколько миллисекунд он может думать и что возвращает пользователю.
- Drift
- Изменение распределения данных. Например, поменялся спрос по районам или новая политика стала показывать совсем другие цены, и обучающая история больше не похожа на текущие запросы.
- Latency
- Задержка ответа сервиса. В корзине это время между изменением корзины и показом новой цены; если оно велико, пользователь видит тормоза или устаревшее предложение.