AI Anti-Money Laundering Detection System
We develop AI anti-money laundering (AML) detection systems that combine rule-based transaction screening with machine learning models. Our hybrid approach reduces false positive rates by 20–40% compared to traditional rule engines. Every false negative — a missed suspicious transaction — results in regulator fines. Every false positive blocks a legitimate client account and generates compliance complaints.
ML-powered AML goes beyond static threshold rules. The system captures evolving laundering patterns: transaction velocity changes, network topology anomalies, and cross-jurisdiction transfer chains. We use LightGBM for transaction risk scoring and Graph Neural Networks for network-level laundering scheme detection. Each flagged transaction receives a SHAP-based explanation for compliance officers and regulators.
Our AML system is delivered as a turnkey, full-cycle product. The scope includes data pipeline, trained models, KYC integration, real-time scoring API, and SAR reporting. Write to us to get a project scope assessment and phased delivery timeline.
Money Laundering Typologies
Structuring (Smurfing)
Smurfing splits one large transaction into many smaller ones, each staying below the reporting threshold. In Russian jurisdiction, that threshold is RUB 600,000. Automated systems rarely flag individual sub-threshold transactions. The pattern becomes visible only through time-series aggregation across a rolling window.
Layering
Layering routes funds through a chain of accounts and jurisdictions to break the audit trail. Each transfer adds a new entity between the source and destination. Detection requires full transaction graph analysis across multiple hops.
Integration
Integration reinvests laundered funds into legitimate businesses — payments to affiliated service companies, real estate purchases, or investments in related entities. The money re-enters the economy appearing clean.
Red Flags
- Transactions in equal amounts (RUB 999,000 stays below the threshold)
- Atypical activity: dormant account followed by 50 transactions in one day
- Geographical discrepancies: client based in one city, transactions in foreign jurisdictions
- New account, high turnover, full withdrawal, closure (one-day account pattern)
Feature Engineering
Transactional characteristics:
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
Network features (graph-based):
import networkx as nx
def compute_network_features(account_id, transaction_graph):
"""
Транзакции как граф: узлы = счета, рёбра = переводы
Центральные узлы в подозрительных сетях = высокий риск
"""
G = transaction_graph
# PageRank: насколько центральный узел в транзакционной сети
pagerank = nx.pagerank(G, weight='amount')
# Betweenness: является ли счёт промежуточным в длинных цепочках
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)
}
ML models for AML
LightGBM with AML settings:
import lightgbm as lgb
from sklearn.metrics import roc_auc_score, average_precision_score
# Class imbalance: SAR (Suspicious Activity Report) < 1% транзакций
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, # предотвращение overfitting на редких паттернах
feature_fraction=0.8
)
# Threshold настройка: в AML recall важнее precision
# Регулятор ожидает низкий FNR (не пропускать реальное отмывание)
from sklearn.metrics import precision_recall_curve
precision, recall, thresholds = precision_recall_curve(y_val, y_scores)
# Выбираем threshold с recall >= 0.85
optimal_threshold = thresholds[np.argmax(recall >= 0.85)]
GNN for network analysis:
import torch
from torch_geometric.nn import GCNConv, SAGEConv
class AMLGraphNN(torch.nn.Module):
"""
Graph Neural Network для анализа транзакционных сетей
Более эффективен для layering-схем (цепочки переводов)
"""
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-level prediction: подозрительный ли перевод
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))
Rules and ML Hybrid
Transaction Monitoring System (TMS):
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):
# Уровень 1: правиловые сценарии (детерминистические)
rule_alerts = self.rules.evaluate(transaction)
# Уровень 2: ML-скор риска
features = extract_transaction_features(customer_history)
ml_score = self.model.predict_proba([features])[0][1]
# Комбинация: любое правило ИЛИ высокий ML-скор
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)
)
Regulatory Compliance
FZ-115 (Russia)
- Mandatory control for transactions above 600,000 rubles
- Transfer of SAR to Rosfinmonitoring (FinCERT)
- Delivery time: 3 working days from the transaction date
FATF / EU AMLD
- KYC (Know Your Customer) performed during client onboarding
- Continuous transaction monitoring throughout the client relationship
- Risk-based approach: enhanced due diligence (EDD) for high-risk clients
Explainability for the regulator:
import shap
def explain_sar_decision(model, features, feature_names):
"""
Регулятор требует обоснования каждого SAR
SHAP значения → текстовое описание причин
"""
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
Timeframe: The base system — rule engine, transactional features, LightGBM model, and SAR reporting — is ready in 6–8 weeks. The full production system with GNN network analysis, graph community detection, explainability module, EDD workflow, and real-time scoring API takes 4–5 months.
What We Deliver
The AML system we build includes the following components:
- Hybrid scoring engine combining deterministic rules with ML risk scores
- Transaction feature extraction pipeline covering 30+ behavioral signals
- Graph analysis module for detecting network-level laundering schemes
- Real-time scoring API with sub-200ms p99 latency
- SAR report generation compliant with local and international regulatory requirements
- Monitoring dashboard for compliance officers with alert queue management
- Model validation documentation for regulatory submission
We configure alert thresholds to match your risk appetite and investigator capacity. Conservative settings prioritize recall — no suspicious transaction is missed. Balanced settings reduce investigator workload by cutting false alert volume. The system architecture supports hot-swap model updates without service downtime.
Integration and Support
The system connects to your core banking platform or payment processor via REST API. We support both batch processing for retrospective analysis and real-time scoring for live transactions. Post-deployment services include model performance monitoring, quarterly threshold review, and model retraining as labeled case data accumulates.







