Разработка AI-системы для детекции отмывания денег

Anti-Money Laundering (AML) — антиотмывочная система, область где цена ошибки критична. Пропуск подозрительного перевода (false negative) грозит штрафами до 5% оборота по ФЗ-115. Ложная блокировка добросовестного клиента (false positive) — репутационные потери и иски. Традиционные правиловые системы

Направления AI-разработки

Часто задаваемые вопросы

Последние работы

  • image_website-b2b-advance_0.webp
    Разработка сайта компании B2B ADVANCE
    1459
  • image_web-applications_feedme_466_0.webp
    Разработка веб-приложения для компании FEEDME
    1314
  • image_websites_belfingroup_462_0.webp
    Разработка веб-сайта для компании БЕЛФИНГРУПП
    1012
  • image_ecommerce_furnoro_435_0.webp
    Разработка интернет магазина для компании FURNORO
    1275
  • image_logo-advance_0.webp
    Разработка логотипа компании B2B Advance
    727
  • image_crm_enviok_479_0.webp
    Разработка веб-приложения для компании Enviok
    1018

Anti-Money Laundering (AML) — антиотмывочная система, область где цена ошибки критична. Пропуск подозрительного перевода (false negative) грозит штрафами до 5% оборота по ФЗ-115. Ложная блокировка добросовестного клиента (false positive) — репутационные потери и иски. Традиционные правиловые системы детектируют только известные паттерны, генерируя до 95% ложных срабатываний. Мы разрабатываем гибридные AI-системы, которые снижают FPR на 20–40% без потери полноты обнаружения. Наш опыт — 10+ лет в финансовом ML для банков и финтехов.

В основе — комбинация детерминированных правил (для типовых сценариев) и ML-моделей (для выявления скрытых нелинейных паттернов). Ниже — архитектура, модели и этапы внедрения.

В этой статье мы разберём ключевые компоненты системы: транзакционный мониторинг, графовый анализ и интеграцию с KYC. Рассмотрим, как гибридный подход снижает нагрузку на комплаенс-отдел и соответствует требованиям FATF. Правила автоматически обрабатывают 80% операций, оставляя 20% на ML-проверку, что снижает ручной труд на 60%.

Почему ML лучше правиловых систем для AML?

Характеристика Правила ML-модель
Обнаружение новых схем Нет — только известные паттерны Да — выявляет скрытые корреляции
Ложные срабатывания (FPR) 5–10% 2–4% (снижение в 2–5 раз)
Адаптация к изменениям Ручное обновление Автоматическое переобучение
Объяснимость Полная (если правило задано явно) Через SHAP/LIME
Масштабируемость Линейно от числа правил Параллельная обработка

Типология схем отмывания

Структурирование (Smurfing): крупная сумма разбивается на мелкие транзакции ниже порога контроля ($5.4k–7.8k. в РФ).

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

Red flags:

  • Транзакции ровными суммами ($?.) — ниже порога, но подозрительно.
  • Всплеск активности: нет операций → внезапно 50 за день.
  • Географические несоответствия: клиент из Саратова, переводы в Сингапур.
  • Счёт-однодневка: новый счёт, большой оборот, быстрый вывод, закрытие.

Feature Engineering

Ключ к качеству ML — признаки, отражающие поведение клиента. Мы используем два класса: Транзакционные признаки (объём, время, суммы около порогов, концентрация контрагентов):

def extract_transaction_features(transaction_history, lookback_days=90): """Признаки на основе истории транзакций клиента.""" df = transaction_history.copy() features = { # Объём транзакций 'total_amount_30d': df[df['days_ago'] <= 30]['amount'].sum(), 'transaction_count_30d': len(df[df['days_ago'] <= 30]), 'avg_transaction_amount': df['amount'].mean(), 'amount_std': df['amount'].std(), # Временные паттерны 'transactions_per_active_day': len(df) / df['date'].nunique(), 'max_transactions_single_day': df.groupby('date').size().max(), 'night_transaction_ratio': (df['hour'] < 6).mean(), 'weekend_activity_change': calculate_weekend_ratio(df), # Суммы около порогов 'near_threshold_pct': (df['amount'].between(550000, 610000)).mean(), 'round_amount_pct': (df['amount'] % 1000 == 0).mean(), # Контрагенты 'unique_counterparties': df['counterparty_id'].nunique(), 'counterparty_concentration': df.groupby('counterparty_id')['amount'].sum().max() / df['amount'].sum(), 'new_counterparty_ratio': (df['is_new_counterparty'] == True).mean(), # Географические 'foreign_transaction_ratio': (df['country'] != 'RU').mean(), 'high_risk_jurisdiction_pct': df['country'].isin(HIGH_RISK_COUNTRIES).mean() } return features def compute_network_features(account_id, transaction_graph): """Транзакции как граф: узлы = счета, рёбра = переводы.""" G = transaction_graph pagerank = nx.pagerank(G, weight='amount') betweenness = nx.betweenness_centrality(G, weight='amount') communities = nx.community.greedy_modularity_communities(G.to_undirected()) community_risk = assess_community_risk(account_id, communities, G) return { 'pagerank_score': pagerank.get(account_id, 0), 'betweenness_score': betweenness.get(account_id, 0), 'community_risk': community_risk, 'in_degree': G.in_degree(account_id), 'out_degree': G.out_degree(account_id) } 

Сетевые признаки (PageRank, betweenness, кластеризация) — помогают обнаруживать сложные layering-схемы, где счёт выступает транзитным узлом.

Модели машинного обучения

LightGBM с настройкой под AML

import lightgbm as lgb from sklearn.metrics import roc_auc_score, average_precision_score n_normal = (y_train == 0).sum() n_sar = (y_train == 1).sum() scale_pos_weight = n_normal / n_sar model = lgb.LGBMClassifier( n_estimators=500, scale_pos_weight=scale_pos_weight, learning_rate=0.05, num_leaves=31, min_child_samples=20, feature_fraction=0.8 ) # Threshold подбирается так, чтобы recall >= 0.85 from sklearn.metrics import precision_recall_curve precision, recall, thresholds = precision_recall_curve(y_val, y_scores) optimal_threshold = thresholds[np.argmax(recall >= 0.85)] 

Графовая нейронная сеть (GNN) для сетевого анализа

import torch from torch_geometric.nn import SAGEConv class AMLGraphNN(torch.nn.Module): """GNN для анализа транзакционных сетей.""" def __init__(self, node_features, edge_features, hidden_dim=64): super().__init__() self.conv1 = SAGEConv(node_features, hidden_dim) self.conv2 = SAGEConv(hidden_dim, hidden_dim) self.edge_mlp = torch.nn.Linear(edge_features, hidden_dim) self.classifier = torch.nn.Linear(hidden_dim * 2, 1) def forward(self, node_features, edge_index, edge_features): x = torch.relu(self.conv1(node_features, edge_index)) x = torch.relu(self.conv2(x, edge_index)) edge_emb = self.edge_mlp(edge_features) source_emb = x[edge_index[0]] target_emb = x[edge_index[1]] edge_repr = torch.cat([source_emb, target_emb], dim=1) return torch.sigmoid(self.classifier(edge_repr)) 

Как устроена гибридная архитектура AML?

Гибридная система объединяет правила и ML в единый пайплайн. Правила быстро отсеивают очевидные легитимные операции и сигнализируют о явных нарушениях (превышение лимитов, запрещённые юрисдикции). ML-модели анализируют признаки, которые невозможно закодировать правилами: аномальное поведение, скрытые связи, нелинейные зависимости. Результат: каждый перевод получает единый риск-скор, который учитывает и правила, и ML.

class HybridAMLSystem: def __init__(self, rule_engine, ml_model, threshold=0.5): self.rules = rule_engine self.model = ml_model self.threshold = threshold def evaluate_transaction(self, transaction, customer_history): rule_alerts = self.rules.evaluate(transaction) features = extract_transaction_features(customer_history) ml_score = self.model.predict_proba([features])[0][1] final_risk = max(rule_alerts.max_risk_score if rule_alerts else 0, ml_score) if final_risk > self.threshold: return SARCandidate( transaction=transaction, risk_score=final_risk, triggered_rules=rule_alerts, ml_explanation=shap_explain(self.model, features) ) 

Что входит в работу

  • Документация: архитектурная схема, model card, руководство администратора.
  • ML-пайплайн: извлечение признаков, обучение, валидация, A/B-тестирование.
  • Интеграция: с KYC-системой, core banking, CRM.
  • Real-time API: HTTP/gRPC эндпоинт для оценки риска каждой транзакции.
  • Дашборды: мониторинг метрик, отчётность SAR, SHAP-объяснения.
  • Развёртывание: в контуре заказчика (on-prem) или в облаке.
  • Поддержка: 1 месяц пост-продакшн, обучение команды.

Процесс разработки

  1. Аналитика — сбор требований, аудит текущих логов, нормативных актов (ФЗ-115, FATF).
  2. Проектирование — выбор архитектуры, определение признаков, конфигурация пилота.
  3. Разработка — написание кода, обучение моделей, настройка пайплайна.
  4. Тестирование — кросс-валидация на исторических данных, сценарное тестирование.
  5. Деплой — развёртывание, интеграция, нагрузочное тестирование.

Сроки: от 6–8 недель на базовую версию (правила + LightGBM + SAR) до 4–5 месяцев на полную (с GNN, real-time, графическим анализом).

Сравнение моделей: LightGBM vs GNN

Характеристика LightGBM GNN (SAGEConv)
Тип данных Табличные признаки (транзакции) Графовые данные (сеть счетов)
Выявляет Аномалии в поведении клиента Сложные цепочки переводов (layering)
Обучаемость Быстрое обучение, мало данных Требует много данных и GPU
Интерпретация SHAP, важность признаков Визуализация графа, attention

Регуляторное соответствие

ФЗ-115 (Россия): обязательный контроль операций >$5.4k–7.8k., передача SAR в Росфинмониторинг в течение 3 рабочих дней.

FATF/EU AMLD: KYC на онбординге, continuous monitoring, усиленная проверка (EDD) для high-risk клиентов. Регуляторные требования описаны в Рекомендациях FATF.

Как мы обеспечиваем объяснимость?

Каждое подозрительное решение сопровождается SHAP-объяснением. Рассмотрим пример: перевод $8.6k–12k. из Саратова в Сингапур. SHAP-значения показывают, что foreign_transaction_ratio повысил риск на 0.34, near_threshold_pct — на 0.28, new_counterparty_ratio — на 0.21, transaction_count_30d — на 0.15, avg_transaction_amount — на 0.10. Итоговый риск 0.87 превышает порог 0.5, что генерирует SAR-отчёт.

import shap def explain_sar_decision(model, features, feature_names): """Регулятор требует обоснования каждого SAR.""" explainer = shap.TreeExplainer(model) shap_values = explainer.shap_values(features) top_factors = sorted( zip(feature_names, shap_values[0]), key=lambda x: abs(x[1]), reverse=True )[:5] explanation = "\n".join([ f"- {name}: {'повысил' if val > 0 else 'снизил'} риск на {abs(val):.2f}" for name, val in top_factors ]) return explanation 

Такой подход позволяет не только пройти аудит, но и дать операторам понятные причины блокировок.

Готовы оценить ваш проект? Закажите разработку AML-системы под ваши данные — получите консультацию по архитектуре и срокам. Свяжитесь с нами для обсуждения.