Антифрод в реальном времени

Real-time fraud scoring

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

Senior 5 шагов разбора · 3 развилки · 4 поломки из прода

Вводная

3000 транзакций в секунду в пике, ответ нужен до отправки в платёжную систему.

Доля мошеннических операций — около 0,1 %, и она меняется волнами.

Цена пропуска — прямые потери; цена ложной блокировки — ушедший клиент.

Схемы мошенничества меняются за недели: то, что ловилось месяц назад, уже не ловится.

Требования и ограничения
ЧтоЗначениеОткуда
Нагрузка3000 TPS в пикесуточный профиль с шестикратным перепадом
Бюджет ответа80 мс по p99включая расчёт признаков
Доступность99,99 %отказ = остановка платежей
Доля ручной проверки≤ 0,3 % операцийограничена штатом
Свежесть признаковсекундыагрегаты по карте за последний час

Прежде чем читать разбор, попробуйте спроектировать систему сами — по этим требованиям. Дальше будет видно, что вы учли, а что нет.

Разбор по шагам

Начать с матрицы стоимостей, а не с метрики

Пока ошибки не оценены в деньгах, любой порог — вкусовщина.

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

Обозначения
  • ложные срабатывания: модель сказала «да», а это неправда
  • пропуски: модель сказала «нет», а объект был положительным
  • параметр SVM: цена нарушения зазора
  • число объектов в выборке
Третье слагаемое — ручная проверка: она не бесплатна и ограничена по объёму.

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

На практике

Отсюда жёсткое требование к : ожидаемые потери считаются через вероятности, и если модель выдаёт «0,8» там, где на деле 0,4, вся арифметика порогов неверна.

Признаки, которых ещё нет в хранилище

«Сколько операций по этой карте за последние десять минут» нельзя посчитать запросом в аналитическое хранилище.

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

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

Где считается чтения
Число операций по карте1 мин / 1 ч / 24 чпотоковая агрегация~2 мс
Сумма по карте1 ч / 24 чпотоковая агрегация~2 мс
Число устройств24 чпотоковая агрегация~2 мс
Профиль мерчанта30 днейпакетный пересчёт ночью~1 мс, кеш
Возраст карты, тип продуктастатическиесправочник в памяти< 1 мс

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

Модель и почему не нейросеть

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

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

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

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

Противник, который учится

Распределение меняется в ответ на саму модель — это не дрейф, это обратная связь.

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

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

Последний пункт неприятен и обязателен. Если блокировать всё подозрительное, разметка приходит только по заблокированному, и модель перестаёт узнавать, где проходит настоящая граница.

Что делать, когда модель недоступна

Требование 99,99 % относится к платежам, а не к скорингу.

Сервис скоринга может упасть или начать отвечать медленно. Останавливать платежи из-за этого нельзя, пропускать всё подряд — тоже. Решение — деградация по ступеням, прописанная заранее.

  1. Таймаут на скоринг 60 мс: не ответил — переходим к запасному пути.
  2. Запасной путь: упрощённая модель на статических , живущая в памяти вызывающего сервиса.
  3. Не сработал и он — правила по сумме, стране и типу операции.
  4. Все деградации логируются и попадают в отдельный дашборд: тихая работа на запасном пути неделю — это инцидент.

Развилки и выбор

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

Как бороться с дисбалансом 1:1000?

Веса классов и метрики на PR-кривой

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

Что отклонено и почему
  • Синтетическая генерация положительных примеровНа таких пропорциях порождает правдоподобные, но несуществующие схемы; модель учится на них и хуже ловит настоящие.
  • Урезание отрицательного классаВыбрасывает основную массу информации о нормальном поведении — именно она и нужна, чтобы отличать от него аномальное.

Где считать скоростные признаки?

Потоковая агрегация с записью в быстрое хранилище ключ-значение

Даёт свежесть в секунды и чтение за миллисекунды — единственный вариант, укладывающийся в бюджет.

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

Нужны ли правила рядом с моделью?

Да, как быстрый контур реакции

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

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

Что ломается в проде

Утечка через скоростные признаки

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

Смещение выборки после внедрения

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

Порог не пересматривали после переобучения

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

Очередь ручной проверки переполнилась

Средняя зона рассчитана на 0,3 % операций. Всплеск трафика или сдвиг распределения — и в очередь падает 2 %, проверка не справляется, операции висят. Нужен предохранитель: при переполнении очереди сужать среднюю зону, а не копить.

По чему видно, что система здорова

МетрикаЗначениеЗачем
Precision при recall 0,3рабочая точкаименно она, а не F1
PR-AUCотслеживается по неделямROC-AUC на таком дисбалансе вводит в заблуждение
Ожидаемые потери на 1000 операцийглавная метрикасчитается из матрицы стоимостей
Задержка p99≤ 80 мсвключая чтение признаков
Доля ручной проверки≤ 0,3 %
Доля работы на запасном пути< 0,1 %рост — инцидент

Что спрашивают по этому кейсу

  1. Где вы поставите порог и как его обоснуете?
  2. Почему не ROC-AUC?
  3. Как вы считаете признак «число операций за последний час» и на обучении, и в проде?
  4. Что произойдёт с обучающей выборкой через год после внедрения?
  5. Модель недоступна. Что отвечает сервис?
  6. Появилась новая схема мошенничества. Ваши действия сегодня, завтра и через месяц?

Проверить себя: тест «Классический ML», тест «Временные ряды», тест «Рекомендательные системы». Открытые задачи там же — под тестом.