Как я разрабатывал ИИ‑сервис для проверки кошельков и транзакций (AML). Код проекта.

Как я разрабатывал ИИ‑сервис для проверки кошельков и транзакций (AML). Код проекта.

MistTrack — это ИИ‑сервис для предварительного скрининга кошельков и транзакций на предмет признаков повышенного AML‑риска. Сервис полностью бесплатный и не требует регистрации — в моем примере всё работает локально и использует синтетические/публичные данные.

Далее — архитектурное описание, подходы к моделированию и полный минималистичный код‑прототип (Flask + sklearn), который вы можете запустить локально для демонстрации интерфейса и логики.

Архитектура (высокоуровнево)

  1. Веб‑интерфейс (Flask) — поле ввода адреса/хэша, выдача отчёта.
  2. Модуль получения транзакций — в реальной системе это клиент к публичному блок‑индексу/ноде; в демо — мок/симулятор.
  3. Feature engineering — набор агрегированных метрик по адресу (количество tx, средний объём, процент входящих/исходящих и т.д.).
  4. Лёгкая модель риска (объяснимая) — логистическая регрессия/градиентный бустинг на синтетических данных.
  5. Отчёт с объяснением вкладов признаков (коэффициенты модели) и перечнем факторов, повлиявших на оценку.
  6. Политика приватности/этические предупреждения в интерфейсе.

Подходы и ограничения (этично и безопасно)

  • Никаких обвинений. MistTrack даёт лишь предварительную оценку и пояснения. Рекомендуется привлекать профильные службы при серьёзных подозрениях.
  • Минимум данных. В демонстрации мы не сохраняем личные данные; логирование — опционально и анонимизировано.
  • Не раскрываем способы обхода детекции. Статья и код не содержат деталей, которые могли бы помочь в уклонении от мер комплаенса.

Что в коде

Ниже — полный набор файлов для минимального рабочего прототипа, который:

  • принимает адрес в веб‑форме;
  • запрашивает (симулирует) транзакции;
  • рассчитывает фичи;
  • прогоняет через предобученную модель риска (в примере модель тренируется на синтетике при первом запуске);
  • возвращает отчёт с оценкой и объяснением по признакам.

Файл: model.py — подготовка и сохранение модели

# model.py import numpy as np import pandas as pd from sklearn.linear_model import LogisticRegression from sklearn.model_selection import train_test_split from joblib import dump, load import os MODEL_PATH = "misttrack_model.joblib" FEATURE_COLUMNS = ["tx_count", "incoming_ratio", "avg_amount", "unique_counterparties", "recent_activity_days"] def generate_synthetic_dataset(n=5000, random_state=42): rng = np.random.RandomState(random_state) tx_count = rng.poisson(10, size=n) + 1 incoming_ratio = rng.beta(2, 5, size=n) # доля входящих avg_amount = np.exp(rng.normal(2, 1, size=n)) # лог-норм распределение unique_counterparties = np.clip((tx_count * rng.uniform(0.2, 1.0, size=n)).astype(int), 1, None) recent_activity_days = rng.exponential(30, size=n) # дни с последней активности # Простая, синтетическая «целевая» метка риска для обучения: # чем больше tx_count и avg_amount и чем ближе recent_activity - тем выше риск risk_score = ( 0.3 * (tx_count / (tx_count.max()+1)) + 0.4 * (np.log1p(avg_amount) / np.log1p(avg_amount).max()) + 0.2 * (1 - incoming_ratio) + # например: больше исходящих — показатель (в синтетике) 0.1 * (1 - np.tanh(recent_activity_days / 30)) ) # преобразуем в бинарную метку через порог y = (risk_score + 0.05 * rng.normal(size=n)) > 0.6 df = pd.DataFrame({ "tx_count": tx_count, "incoming_ratio": incoming_ratio, "avg_amount": avg_amount, "unique_counterparties": unique_counterparties, "recent_activity_days": recent_activity_days, "label": y.astype(int) }) return df def train_and_save(model_path=MODEL_PATH): df = generate_synthetic_dataset() X = df[FEATURE_COLUMNS] y = df["label"] X_train, X_test, y_train, y_test = train_test_split(X, y, stratify=y, test_size=0.2, random_state=1) model = LogisticRegression(max_iter=1000) model.fit(X_train, y_train) print("Train score:", model.score(X_train, y_train)) print("Test score:", model.score(X_test, y_test)) dump({"model": model, "features": FEATURE_COLUMNS}, model_path) print(f"Model saved to {model_path}") if __name__ == "__main__": if not os.path.exists(MODEL_PATH): train_and_save() else: print("Model already exists.")

Файл: fetcher.py — модуль получения транзакций (мок)

# fetcher.py import random import datetime from typing import List, Dict # В реальной системе здесь был бы клиент к public node / block explorer API. # В демо мы возвращаем синтетические транзакции. def simulate_transactions_for_address(address: str, seed: int = None): rng = random.Random(seed or hash(address) & 0xffffffff) tx_count = rng.randint(1, 50) now = datetime.datetime.utcnow() txs = [] for i in range(tx_count): direction = rng.choice(["in", "out"]) amount = round(rng.uniform(0.0001, 50.0) * (1 if rng.random() < 0.8 else 10), 8) days_ago = rng.expovariate(1/30) timestamp = now - datetime.timedelta(days=days_ago) counterparty = "0x" + "".join(rng.choice("0123456789abcdef") for _ in range(40)) txs.append({ "txid": f"tx{i}_{address[:6]}", "direction": direction, "amount": amount, "timestamp": timestamp, "counterparty": counterparty }) # сортируем по времени txs = sorted(txs, key=lambda x: x["timestamp"], reverse=True) return txs

Файл: app.py — минимальный Flask‑сервис

# app.py from flask import Flask, render_template, request from joblib import load from fetcher import simulate_transactions_for_address from features import extract_features_from_txs, FEATURE_COLUMNS import os import model as model_module MODEL_PATH = "misttrack_model.joblib" app = Flask(__name__) def ensure_model(): if not os.path.exists(MODEL_PATH): print("Training model (synthetic data)...") model_module.train_and_save(MODEL_PATH) data = load(MODEL_PATH) return data["model"], data["features"] model, feature_cols = ensure_model() @app.route("/", methods=["GET", "POST"]) def index(): if request.method == "POST": address = request.form.get("address", "").strip() if not address: return render_template("index.html", error="Введите адрес.") # В ДЕМO — получаем синтетические транзакции txs = simulate_transactions_for_address(address) feats = extract_features_from_txs(txs) X = [[feats[c] for c in feature_cols]] prob = float(model.predict_proba(X)[0][1]) pred = int(prob > 0.5) # объяснение — коэффициенты логистической регрессии coef = model.coef_[0] explanations = [] for name, c, val in zip(feature_cols, coef, X[0]): impact = c * val explanations.append({"feature": name, "coef": float(c), "value": float(val), "impact": float(impact)}) explanations = sorted(explanations, key=lambda x: abs(x["impact"]), reverse=True) report = { "address": address, "probability": prob, "flag": "Повышенный риск" if pred else "Низкий/средний риск", "features": feats, "explanations": explanations, "sample_txs": txs[:10] # показываем несколько транзакций } return render_template("report.html", report=report) return render_template("index.html") if __name__ == "__main__": app.run(debug=True, port=5000)

Технические замечания и улучшения (если захотите развивать)

  • Реальные данные: подключение к публичному блок‑индексу/ноде или провайдеру (Blockstream, Etherscan, публичные RPC) — с учётом rate‑limit и API‑ключей. В учебном коде мы заменили это моками.
  • Более сложные модели: градиентный бустинг, графовые нейросети для анализа связей; при этом нужно повышенное внимание к объяснимости.
  • Explainability: SHAP/LIME для локальных объяснений; в нашем прототипе использованы коэффициенты линейной модели как простая интерпретация.
  • Data governance: чёткая политика хранения логов, anonymization, и удаление PII.
  • Инфраструктура: очередь для асинхронной индексации адресов, кэширование результатов, rate limiting, мониторинг и alerting (для реального сервиса).

Этическое и юридическое напоминание

  • MistTrack — демонстрация. Ни при каких обстоятельствах результаты не должны использоваться как единственный источник для принятия юридических или операционных решений.
  • Не используйте код для попыток обойти AML/санкционные фильтры — это незаконно и выходит за рамки данной статьи.
  • При создании реального продукта необходимо консультироваться с юристами и специалистами по комплаенсу.

Заключение

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

11
Начать дискуссию