Скоринг транзакций на лету: решение «пропустить, запросить подтверждение или заблокировать» принимается до ответа платёжной системе. Кейс о трёх вещах, которые здесь ломают обычный ML-подход: экстремальный дисбаланс, признаки, которые нужно считать за миллисекунды по свежей истории, и нестационарность из-за адаптации мошенников.
Схемы мошенничества меняются за недели: то, что ловилось месяц назад, уже не ловится.
Требования и ограничения
Что
Значение
Откуда
Нагрузка
3000 TPS в пике
суточный профиль с шестикратным перепадом
Бюджет ответа
80 мс по p99
включая расчёт признаков
Доступность
99,99 %
отказ = остановка платежей
Доля ручной проверки
≤ 0,3 % операций
ограничена штатом
Свежесть признаков
секунды
агрегаты по карте за последний час
Прежде чем читать разбор, попробуйте спроектировать систему сами — по этим требованиям. Дальше будет видно, что вы учли, а что нет.
Разбор по шагам
1Начать с матрицы стоимостей, а не с метрики
Пока ошибки не оценены в деньгах, любой порог — вкусовщина.
и не отвечают на вопрос, где ставить порог. Ответ даёт стоимость ошибок: пропущенное мошенничество стоит средний чек плюс расходы на возврат, ложная блокировка — вероятность ухода клиента, умноженная на его пожизненную ценность.
потери=CFN⋅FN+CFP⋅FP+Creview⋅Nreview
Обозначения
FPложные срабатывания: модель сказала «да», а это неправда
FNпропуски: модель сказала «нет», а объект был положительным
Cпараметр SVM: цена нарушения зазора
nчисло объектов в выборке
Третье слагаемое — ручная проверка: она не бесплатна и ограничена по объёму.
Порогов получается два, а не один: до нижнего пропускаем, выше верхнего блокируем, между ними отправляем на подтверждение или в ручную . Верхний порог задаётся ценой ложной блокировки, ширина средней зоны — пропускной способностью проверки.
На практике
Отсюда жёсткое требование к : ожидаемые потери считаются через вероятности, и если модель выдаёт «0,8» там, где на деле 0,4, вся арифметика порогов неверна.
2Признаки, которых ещё нет в хранилище
«Сколько операций по этой карте за последние десять минут» нельзя посчитать запросом в аналитическое хранилище.
Самые сильные антифрода — скоростные: число операций по карте за минуту, час и сутки, сумма за час, число разных устройств, география подряд идущих операций. Все они зависят от событий, произошедших секунды назад.
Аналитическое хранилище отвечает секундами и отстаёт на минуты — оно не годится. Агрегаты считаются потоково и лежат в быстром хранилище , откуда сервис читает их за единицы миллисекунд по ключу карты.
Где считается
чтения
Число операций по карте
1 мин / 1 ч / 24 ч
потоковая агрегация
~2 мс
Сумма по карте
1 ч / 24 ч
потоковая агрегация
~2 мс
Число устройств
24 ч
потоковая агрегация
~2 мс
Профиль мерчанта
30 дней
пакетный пересчёт ночью
~1 мс, кеш
Возраст карты, тип продукта
статические
справочник в памяти
< 1 мс
обязана собираться так же: значение берётся на транзакции, а не на момент выгрузки. Иначе модель обучится на будущем — в антифроде это особенно коварно, потому что мошенническая операция часто идёт в серии, и «число операций за час», посчитанное задним числом, содержит ответ.
3Модель и почему не нейросеть
На табличных признаках с бюджетом 80 мс выбор довольно предсказуем.
: лучшее качество на табличных данных, за единицы миллисекунд, понятная — а объяснять решение придётся и службе поддержки, и проверяющему.
Дисбаланс лечится не переливанием данных, а весами классов и правильной метрикой. Синтетическая генерация положительных примеров на таких пропорциях чаще вредит: она порождает правдоподобные, но несуществующие схемы, и модель учится ловить их вместо настоящих.
Рядом с моделью живёт слой правил. Не как костыль: правила закрывают то, чего у модели нет, — мгновенную реакцию на новую схему. Заметили паттерн вечером, выкатили правило ночью, добавили в обучающую выборку и убрали правило через две недели, когда модель научилась.
4Противник, который учится
Распределение меняется в ответ на саму модель — это не дрейф, это обратная связь.
Обычный происходит сам по себе. Здесь он целенаправленный: мошенник пробует, натыкается на блокировку и меняет поведение. Модель, обученная год назад, ловит только тех, кто не адаптировался.
— еженедельно, с обязательными воротами качества перед выкаткой.
доли срабатываний по типам схем, а не только общей метрики: новая схема видна как провал в одном срезе.
Контур без разметки — он ловит то, чего в обучающей выборке ещё нет.
Часть трафика с ослабленным порогом как источник обучающих примеров: без пропущенных операций неизвестно, что модель пропускает.
На практике
Последний пункт неприятен и обязателен. Если блокировать всё подозрительное, разметка приходит только по заблокированному, и модель перестаёт узнавать, где проходит настоящая граница.
5Что делать, когда модель недоступна
Требование 99,99 % относится к платежам, а не к скорингу.
Сервис скоринга может упасть или начать отвечать медленно. Останавливать платежи из-за этого нельзя, пропускать всё подряд — тоже. Решение — деградация по ступеням, прописанная заранее.
Таймаут на скоринг 60 мс: не ответил — переходим к запасному пути.
Запасной путь: упрощённая модель на статических , живущая в памяти вызывающего сервиса.
Не сработал и он — правила по сумме, стране и типу операции.
Все деградации логируются и попадают в отдельный дашборд: тихая работа на запасном пути неделю — это инцидент.
Развилки и выбор
На собеседовании ценится не сам выбор, а объяснение, почему отклонены остальные варианты.
Как бороться с дисбалансом 1:1000?
✓Веса классов и метрики на PR-кривой
Сохраняет исходное распределение, а значит и калибровку, которая нужна для расчёта ожидаемых потерь.
Что отклонено и почему
Синтетическая генерация положительных примеров — На таких пропорциях порождает правдоподобные, но несуществующие схемы; модель учится на них и хуже ловит настоящие.
Урезание отрицательного класса — Выбрасывает основную массу информации о нормальном поведении — именно она и нужна, чтобы отличать от него аномальное.
Где считать скоростные признаки?
✓Потоковая агрегация с записью в быстрое хранилище ключ-значение
Даёт свежесть в секунды и чтение за миллисекунды — единственный вариант, укладывающийся в бюджет.
Что отклонено и почему
Запрос в аналитическое хранилище на лету — Отвечает секундами и отстаёт на минуты: и по задержке, и по свежести мимо требований.
Пересчёт всех агрегатов ночью — Серия мошеннических операций укладывается в минуты — ночной агрегат её не видит вовсе.
Нужны ли правила рядом с моделью?
✓Да, как быстрый контур реакции
Новая схема появляется за ночь, а цикл переобучения занимает неделю. Правило закрывает разрыв и снимается, когда модель научилась.
Что отклонено и почему
Только модель — Между появлением схемы и выкаткой переобученной модели проходят дни прямых потерь.
Только правила — Не масштабируются: сотни правил начинают противоречить друг другу, и никто не знает, какое из них ещё работает.
Что ломается в проде
Утечка через скоростные признаки
Агрегат «число операций по карте за час», посчитанный по всей истории, включает операции после текущей. На обучении это даёт фантастическое качество, в проде — обычное. Единственная защита — расчёт признаков на момент события и регулярная сверка обучающих признаков с продовыми.
Смещение выборки после внедрения
Модель блокирует то, что считает мошенничеством, и разметка перестаёт приходить по заблокированному. Через полгода обучающая выборка описывает только тех мошенников, которых модель пропускала. Лечится долей операций с ослабленным порогом — платой за возможность учиться.
Порог не пересматривали после переобучения
Новая модель выдаёт вероятности в другом масштабе, а порог остался прежним — доля блокировок скачет в разы. Пороги должны пересчитываться из матрицы стоимостей при каждой выкатке, автоматически.
Очередь ручной проверки переполнилась
Средняя зона рассчитана на 0,3 % операций. Всплеск трафика или сдвиг распределения — и в очередь падает 2 %, проверка не справляется, операции висят. Нужен предохранитель: при переполнении очереди сужать среднюю зону, а не копить.
По чему видно, что система здорова
Метрика
Значение
Зачем
Precision при recall 0,3
рабочая точка
именно она, а не F1
PR-AUC
отслеживается по неделям
ROC-AUC на таком дисбалансе вводит в заблуждение
Ожидаемые потери на 1000 операций
главная метрика
считается из матрицы стоимостей
Задержка p99
≤ 80 мс
включая чтение признаков
Доля ручной проверки
≤ 0,3 %
Доля работы на запасном пути
< 0,1 %
рост — инцидент
Что спрашивают по этому кейсу
Где вы поставите порог и как его обоснуете?
Почему не ROC-AUC?
Как вы считаете признак «число операций за последний час» и на обучении, и в проде?
Что произойдёт с обучающей выборкой через год после внедрения?
Модель недоступна. Что отвечает сервис?
Появилась новая схема мошенничества. Ваши действия сегодня, завтра и через месяц?