О проекте
Команда: TRIO
Кейс HackAlem.ai: Финансы — Freedom
Стадия: Доведённый продукт
Задача кейса: «Граф денег»: восстановить структуру организованной группы по сети транзакций (AML)
Суть
Локальный MVP для AML-анализа на FastAPI и React. Он присваивает клиентам роли и приоритет проверки, кластеризует сеть переводов и показывает направленные подграфы и ego-сети. AML Copilot отвечает на вопросы аналитика через безопасные инструменты без внешней LLM.
Как устроено
Pipeline проверяет Parquet, считает метрики узлов, кластеризует (компоненты, для крупных Louvain с весом log1p(sum)+0.25×log1p(n_tx), resolution 1.15, seed 42) и выставляет score по шести ролям. Transit определяется через FIFO-сопоставление: не меньше 15% входа уходит за 1–2 дня. role_score = (0.6×лучший + 0.4×отрыв от второго)×Q. priority = Q×Σ(вес×нормализованный фактор) по 9 факторам. Copilot по намерению вопроса вызывает разрешённые инструменты: trace_money_flow, find_common_recipients, explain_priority и другие.
Ключевые решения
- Louvain
- FIFO-сопоставление транзита
- ролевые scores с отрывом от второго
- фактор полноты наблюдения Q
- ранговая нормализация факторов
- ego-сети
- intent-based copilot с whitelisted tools
Особенности
Copilot работает офлайн без LLM: распознаёт намерение и вызывает только разрешённые инструменты, произвольные Python, SQL и команды не выполняются. Ограничения данных описаны подробно (depth=4 как обрыв обхода, нет межбанка). В metadata.json сохраняются SHA256 входных данных. Синтетика подставляется только тогда, когда нет всех трёх файлов.
Стек
Python 3.12 · FastAPI · Uvicorn · React · TypeScript · Vite · Docker Compose · Parquet
Проект создан за 5 часов на финале хакатона HackAlem.ai (23 сентября 2026, Астана). Код — BAITC-Hacks/hack-0601d926-trio.
README
README.mdГраф денег
Локальный MVP исследования AML-графа: объяснимые роли, кластеры, очередь проверки клиентов, направленные подграфы и AML Copilot без ключей и внешних сервисов. Все выводы — признаки и гипотезы для проверки.
Реальный набор уже распакован: 2 248 клиентов, 3 119 связей, 4 840 операций, 81 seed, 365 890 012,01 KZT за июль 2026. Исходные parquet включены в репозиторий; дублирующие ZIP-архивы остаются только локально. Описание организаторов — data/README.md, аудит — docs/data-audit.md.
Для жюри
Репозиторий команды: BAITC-Hacks/hack-0601d926-trio. Исходный код, данные, готовые CSV-результаты, тесты и документация доступны в одном месте.
git clone https://github.com/BAITC-Hacks/hack-0601d926-trio.git
cd hack-0601d926-trio
Далее выполните команду запуска для своей ОС ниже. Для быстрой оценки: сценарий демонстрации, результаты проверок, методология, приоритетные клиенты, роли всех клиентов, кластеры.
Запуск одной командой
Требования: Python 3.12+, Node.js 22 LTS+ с npm. Версии зависимостей закреплены в lock-файлах. При первом запуске нужен интернет для установки пакетов. После установки приложение и Copilot работают без сети и GPU. На этой машине Windows-скрипт также обнаруживает уже установленный runtime Codex.
Windows PowerShell из корня проекта:
powershell -ExecutionPolicy Bypass -File .\scripts\start.ps1
Unix/macOS:
bash scripts/start.sh
Открыть http://127.0.0.1:8000. OpenAPI — http://127.0.0.1:8000/docs. Скрипт создаёт .venv, устанавливает зависимости, собирает frontend и запускает FastAPI. Pipeline выполняется автоматически при старте. Остановка — Ctrl+C. Windows: -Port 8001 меняет порт; -SkipInstall пропускает установку имеющихся зависимостей, но выполняет сборку.
Если установлен Docker:
docker compose up --build
Адрес тот же; данные монтируются read-only, CSV сохраняются в outputs/. На текущей Windows-машине Docker отсутствует: контейнерный запуск не проверялся. Dockerfile и Compose подготовлены. Unix-скрипт в этой среде также не исполнялся.
Отдельный pipeline и данные
Windows, с установкой зависимостей при необходимости:
powershell -ExecutionPolicy Bypass -File .\scripts\start.ps1 -PipelineOnly
После установки окружения:
.\.venv\Scripts\python.exe -X utf8 -m backend.app.analytics --data data --out outputs
Unix: bash scripts/start.sh --pipeline-only либо .venv/bin/python -m backend.app.analytics --data data --out outputs.
Все три файла nodes.parquet, edges.parquet, transactions.parquet должны находиться в data/. Они обнаруживаются автоматически при запуске и пересчёте. Отсутствующие колонки, отрицательные/нечисловые суммы, неизвестные nodes и несогласованность операций с агрегатами дают понятную ошибку. Частичный набор никогда не подменяется синтетикой.
Отсутствие всех трёх файлов включает явно обозначенный небольшой синтетический набор. Отдельный генератор для разработки:
.\.venv\Scripts\python.exe -m backend.app.analytics --generate-demo demo-data
.\.venv\Scripts\python.exe -m backend.app.analytics --data demo-data --out demo-outputs
Генератор не перезаписывает parquet; принадлежность к синтетике хранится внутри файлов, в API, UI и выгрузках. Эти результаты не являются выводами по реальной сети.
Выгрузки
outputs/nodes_roles.csv: все клиенты, роль, role_score, cluster_id, priority_score, evidence, суммы, глубина и source.outputs/clusters.csv: все кластеры, размер, seed, внутренний/внешний оборот, top_gids, роли и гипотеза.outputs/top_nodes.csv: 100 приоритетных клиентов с рангом и объяснением.outputs/metadata.json: источник, время, статистика, ограничения, параметры, версии библиотек, SHA256 исходных parquet и конфигурации.
CSV: UTF-8 BOM, стабильная сортировка и восемь десятичных знаков. В UI есть меню экспорта. gid содержит 18 цифр: при импорте CSV в Excel выбирайте текстовый тип, иначе ID округлится. JSON API передаёт клиентские ID строками; Python сохраняет точные целые.
Интерфейс и Copilot
Обзор показывает статистику, временной оборот, роли, качество и очередь проверки. Граф предлагает top-N, агрегированные кластеры и ego-сеть. Стрелки показывают перевод, цвет — роль, обводка — seed, размер — приоритет. Есть фильтры ролей, кластеров, глубины, seed и суммы; поиск, zoom/pan/fit, соседи, входящее/исходящее направление и глубина ego.
Приоритеты используют сортировку и серверную пагинацию. Карточка показывает потоки, все role scores, вклады факторов, временные признаки, ограничения и следующий шаг. Кластеры имеют мини-граф и ключевые gid. Методология доступна непосредственно в продукте.
Copilot распознаёт типовые вопросы и вызывает разрешённые инструменты: get_node_profile, get_neighbors, trace_money_flow, find_common_recipients, find_shared_senders, get_cluster_profile, compare_nodes, get_top_nodes, explain_priority, suggest_next_data_request. Ответы содержат наблюдения, гипотезы, ограничения, ссылки и журнал инструментов. Произвольный Python, SQL и команды ОС не исполняются. Необязательная внешняя LLM не подключена.
Примеры: «Почему gid 100000004400305100 находится в топе?», «Какие узлы похожи на транзитные?», «Куда дальше уходят деньги от gid 100000008730846100?», «Каких данных не хватает для проверки этой гипотезы?».
Роли, приоритет и воспроизводимость
Все параметры — в config.json; полные формулы, пороги и словарь — docs/methodology.md. Правила не содержат конкретных gid.
| Роль | Основной признак и ограничение |
|---|---|
| consolidator | ≥3 отправителя; fan-in, входящий объём, агрегация |
| transit | двусторонний поток; FIFO-сопоставление ≥15% входа через 1–2 дня; исключены seed |
| distributor | ≥3 получателя; fan-out, исходящий объём, распределение контрагентов |
| terminal | наблюдаемый out/in ≤10%; исключены seed и depth=4 |
| coordinator | ≥4 ветки, ≥2 связанных seed, центральность ≥0,60 и межкластерные связи; кандидат |
| peripheral | недостаточно выраженных признаков остальных ролей |
Основная роль — максимум шести scores; ничья разрешается фиксированным порядком из config. role_score = (0,60 × лучший score + 0,40 × отрыв от второго) × Q, где Q — полнота наблюдения. Scores не являются вероятностями.
priority = Q × Σ(weight × normalized_factor):
| Фактор | Вес |
|---|---|
| Выраженность и значимость роли | 0,20 |
| Связанные seed | 0,16 |
| Центральность | 0,14 |
| Оборот | 0,12 |
| Ветвление | 0,10 |
| Межкластерные связи | 0,10 |
| Циклы / повторные пары | 0,06 |
| Быстрый транзит | 0,06 |
| Полнота наблюдения | 0,06 |
Q: 1 по умолчанию, 0,65 при менее трёх участий в операциях, 0,35 для изолированных; дополнительно ×0,90 для seed и ×0,70 для depth=4. Вклады UI включают Q. Положительные значения нормализуются по рангам; нули остаются нулём. Кластеризация: компоненты отдельно, Louvain для больших компонент, вес log1p(sum_kzt)+0,25×log1p(n_tx), resolution 1,15, seed 42. Порядок входа и алгоритмы детерминированы при закреплённых версиях.
Ограничения данных
- Depth=4 без выхода может быть обрывом обхода: terminal там запрещён.
- Видны исходящие переводы исходной выборки, полный баланс неизвестен.
- Входящие seed занижены: out/in и удержание равны null и не используются как балансовое доказательство.
- Выход может превышать вход; это допустимо и само по себе не является подозрительным признаком.
- Отсутствуют операции менее 5 000 KZT и межбанковские переводы.
- Seed без рёбер или только с входящими сохраняются; в данных 19 полностью изолированных узлов.
- Кластеры не смешивают несвязанные компоненты.
- Нет ФИО, ИИН, возраста, доходов, остатков и назначения платежа; они не придумываются.
- Правильные роли не размечены: эвристики дают гипотезы, а не установленную структуру преступной группы.
- FIFO и циклы отражают совместимость наблюдений, не трассируют одни и те же деньги. Внутридневной порядок неизвестен; конец месяца скрывает последующее движение.
Архитектура и API
frontend/ React / TypeScript / Vite
backend/app/analytics/ валидация → метрики → кластеры → роли → приоритет → CSV
backend/app/api/ строгие модели, кэш снимка, ограниченные выборки
backend/app/agent/ локальные намерения и безопасные инструменты
data/ исходные parquet
outputs/ результаты и метаданные
tests/ аналитика, API, реальный набор
scripts/ запуск и живой smoke test
docs/ архитектура, методология, демонстрация
Первоначальный расчёт выполняется один раз. Пересчёт — в фоновом потоке; только валидный снимок заменяет кэш. При ошибке предыдущие результаты доступны. Используйте один Uvicorn worker; БД не требуется.
| Метод | URL | Назначение |
|---|---|---|
| GET | /api/health | готовность, источник, ошибка |
| GET | /api/overview | статистика, предупреждения, top, временной ряд |
| POST / GET | /api/recalculate / /api/recalculate/status | пересчёт и статус |
| GET | /api/top-nodes?limit=20 | очередь проверки |
| GET | /api/nodes?q=...&page=1&page_size=25 | поиск, фильтры, сортировка |
| GET | /api/nodes/{gid} | профиль |
| GET | /api/nodes/{gid}/ego?depth=2&direction=out | ограниченная ego-сеть |
| GET | /api/graph?limit=60 | ограниченная выборка графа |
| GET | /api/clusters, /api/clusters/{id}, /api/clusters/graph | сообщества |
| GET | /api/methodology | актуальные правила |
| POST | /api/copilot | { "message": "...", "context_gid": "..." } |
| GET | /api/exports/{filename} | одна из трёх CSV |
Фильтры nodes/graph: role, cluster_id, depth, is_seed; для graph также min_amount/max_amount. Response schemas — в /docs. Ошибочные параметры дают 422, неизвестный gid — 404, неготовые данные — 503. CORS разрешает только локальные адреса Vite. Приложение слушает loopback; данные не отправляются наружу. Это локальный инструмент без многопользовательской авторизации.
Проверки и разработка
.\.venv\Scripts\python.exe -m pip install -r backend/requirements-dev.txt
.\.venv\Scripts\python.exe -m pytest -q
.\.venv\Scripts\python.exe -m ruff check backend scripts tests
.\.venv\Scripts\python.exe -m pip check
cd frontend
npm run lint
npm run typecheck
npm run build
cd ..
.\.venv\Scripts\python.exe scripts/smoke.py
Smoke требует работающий сервер: пересчёт → top20 → профиль → ego → объяснение Copilot. Тесты проверяют контролируемые роли, цензуру, seed, FIFO, валидацию, детерминированность, CSV, изолированных, компоненты, API и точные 18-значные ID. Фактические итоги и измерения — в STATUS.md.
Development: backend python -m uvicorn backend.app.main:app --reload, отдельно npm run dev в frontend. Аудит известных уязвимостей: python -m pip_audit -r backend/requirements.txt --no-deps --disable-pip и npm audit. Передаются только названия/версии пакетов.
Типичные проблемы
- Нет python/npm: установите Python 3.12+ и Node.js 22 LTS+ и откройте новую консоль.
- Windows запрещает ps1: используйте приведённую команду с
-ExecutionPolicy Bypassбез изменения системной политики. - Порт 8000 занят: завершите предыдущий запуск либо передайте
-Port 8001. - Ошибка parquet: прочитайте диагностику; все три файла должны относиться к одной выборке. После исправления нажмите «Пересчитать».
- Синтетический режим: проверьте каталог data и наличие всех трёх parquet.
- gid округлился в Excel: повторно импортируйте CSV как текст; не копируйте округлённый номер в поиск.
- Ошибка установки: проверьте доступ к PyPI/npm registry. Клиентские данные для установки не передаются.
- API-сообщение вместо UI: соберите frontend или запустите общий скрипт.
Масштабирование до миллиона узлов
NetworkX заменить на igraph/Graph-tool/Spark GraphFrames либо графовую БД по профилю запросов. Использовать колоночное хранение и lazy execution Polars/DuckDB, предварительные агрегации и индексы, фоновые задания с версионированными снимками, приближённые centrality-алгоритмы, серверную выборку подграфов и многоуровневую визуализацию. Полный граф не передавать браузеру. Этот масштаб в MVP не реализован.
Демонстрация: docs/demo-script.md. Дополнительно: SPEC.md, PLAN.md, архитектура, Mermaid.
Авторы коммитов
История коммитов
- 2026-09-23 17:28Add complete Money Graph AML MVP, dataset, results and documentationDanial
Структура репозитория (69 файлов)
.dockerignore .env.example .gitignore Dockerfile PLAN.md README.md SPEC.md STATUS.md backend/__init__.py backend/app/__init__.py backend/app/agent/__init__.py backend/app/agent/copilot.py backend/app/agent/tools.py backend/app/analytics/__init__.py backend/app/analytics/__main__.py backend/app/analytics/config.json backend/app/analytics/demo.py backend/app/analytics/pipeline.py backend/app/analytics/validation.py backend/app/api/__init__.py backend/app/api/models.py backend/app/api/routes.py backend/app/api/store.py backend/app/main.py backend/requirements-dev.txt backend/requirements.txt compose.yaml data/README.md data/edges.parquet data/nodes.parquet data/transactions.parquet docs/architecture-diagram.md docs/architecture.md docs/data-audit.md docs/demo-script.md docs/methodology.md frontend/eslint.config.js frontend/index.html frontend/package-lock.json frontend/package.json frontend/pnpm-lock.yaml frontend/pnpm-workspace.yaml frontend/src/App.tsx frontend/src/CopilotPage.tsx frontend/src/DataPages.tsx frontend/src/GraphPages.tsx frontend/src/api.ts frontend/src/components.tsx frontend/src/main.tsx frontend/src/styles.css frontend/tsconfig.json frontend/vite.config.ts outputs/clusters.csv outputs/dependency-audit-frontend.json outputs/dependency-audit.json outputs/metadata.json outputs/nodes_roles.csv outputs/top_nodes.csv pyproject.toml scripts/lock_python.py scripts/smoke.py scripts/start.ps1 scripts/start.sh starter/README.md starter/requirements.txt starter/starter.py tests/test_analytics.py tests/test_api.py tests/test_real_dataset.py
Обсуждение 0 комментариев
Войдите, чтобы комментироватьПока нет комментариев — будьте первым.