AAYMA
RU
Войти

Граф денег

Python-пайплайн AML-анализа сети из 2248 узлов: строит направленный граф переводов, присваивает узлам роли (coordinator, consolidator, transit и…

Доведённый продукт
Команда «Builoff» 4💬 0 комментариевс 23 сентября 2026 г.

О проекте

Команда: Builoff
Кейс HackAlem.ai: Финансы — Freedom
Стадия: Доведённый продукт

Задача кейса: «Граф денег»: восстановить структуру организованной группы по сети транзакций (AML)

Суть

Python-пайплайн AML-анализа сети из 2248 узлов: строит направленный граф переводов, присваивает узлам роли (coordinator, consolidator, transit и др.), кластеризует и формирует очередь проверки; есть веб-viewer и чат-ассистент по графу.

Как устроено

Три Parquet валидируются и превращаются в направленный граф NetworkX; считаются степени, betweenness, достижимость от 81 seed-клиента, временные сигналы (быстрый выход, синхронные входы, дробление 5–6 тыс. KZT), циклы 2–6 и цепочки. Роли назначаются правилами с порогами, priority_score объединяет признаки, Louvain выделяет кластеры, robustness.csv показывает устойчивость при удалении топ-узлов. Опционально OpenAI пишет проверяемые тексты для кластеров/узлов; ассистент с 6 function tools отвечает по готовому графу, код сверяет каждый gid и число, а guard-вызов проверяет prompt injection.

Ключевые решения

  • NetworkX
  • Louvain
  • betweenness centrality
  • rule-based роли
  • поиск циклов и цепочек
  • temporal signals
  • robustness при удалении топ-N
  • function calling (6 tools)
  • prompt-injection guard
  • Cytoscape.js

Особенности

Жёсткая пост-проверка ответов LLM: каждый gid и число сверяется с результатами tools, иначе помечается [не подтверждено]; отдельный guard/ontology-вызов перед агентом; документ EVIDENCE с фактическими прогонами.

Стек

Python · pandas · pyarrow · NetworkX · SciPy · HTML/JS · Cytoscape.js

Модели

gpt-6-sol (OpenAI Responses API)


Проект создан за 5 часов на финале хакатона HackAlem.ai (23 сентября 2026, Астана). Код — BAITC-Hacks/hack-a716d39d-builoff.

README

README.md

Граф денег

Название проекта

Граф денег — локальный анализ обезличенной сети переводов.

Краткое описание

AML-аналитику известен 81 исходный клиент, а исследовать нужно сеть из 2 248 узлов. Программа строит направленный граф, назначает каждому узлу основную структурную роль и показывает, кого проверить первым и почему. Роли и приоритеты — гипотезы по неполной выгрузке, не вывод о виновности.

Что реализовано

ФункцияДоказательствоКод
Проверка трёх Parquet и согласованности переводовEVIDENCE: I1 и этап 5, живой запуск и тестpipeline.py
Метрики, роли, объяснения, кластеры Louvain и топEVIDENCE: I1–I4, живой запуск и тестpipeline.py
Viewer с направлением связей и поиском gidEVIDENCE: I2–I3, скриншот вкладки «Сеть»viewer/index.html
Временные признакиEVIDENCE: I3, сверка с Parquet и тестtemporal.py
Циклы, цепочки, дробление и устойчивостьEVIDENCE: I4, живой запуск и тестstructural.py
Проверяемые LLM-тексты для 8 кластеров и 5 узловEVIDENCE: этап 5, живой запуск и mock тестcluster_llm.py, node_llm.py
Отдельный read-only CLI-ассистент по готовому графу: шесть function tools, сверка каждого gid и числаEVIDENCE: I5, три live-вопроса и тест без моделиask.py, test_ask.py
Вкладка «Ассистент»: input check (guard и ontology), история ответов и переход по gid во вкладку «Сеть»EVIDENCE: I6–I7, пять live-вопросов, policy-тесты и скриншот вкладки «Ассистент»serve.py, input_check.py, viewer/index.html

Обязательные файлы: out/nodes_roles.csv, out/clusters.csv, out/top_nodes.csv. Дополнительные: out/graph.json, out/robustness.csv, out/completeness.md.

Как работает решение

Аналитик запускает расчёт и открывает viewer на вкладке «Ассистент». История идёт сверху вниз, большое поле вопроса находится внизу. Ответ содержит переходы по полным gid на вкладку «Сеть», где доступны прежние поиск и граф. Первый в топе — gid 100000003684369100, роль coordinator, приоритет 0.779. Экспортированное для его карточки объяснение:

На координацию указывают 24 плательщика, 62 получателя и путь от 9 исходных клиентов. Связан с 9 другими кластерами. Вход неполон. Участвует в 1 возвратной цепочке и 63 повторяющихся маршрутах.

Поиск 100000000850297100 показывает транзит с равными наблюдаемыми входом и выходом 17 520 KZT. Поиск 100000004265639100 показывает обрыв четвёртого колена и оговорку «конечность не доказана». Дословные значения и результаты viewer приведены в EVIDENCE.

Критерии ролей

Выбирается первое подходящее правило сверху вниз. Степень — число разных контрагентов; pass_through = out_kzt / in_kzt при положительном входе.

РольПорог
coordinatorin_deg ≥ 5, out_deg ≥ 10, путь от ≥ 2 seed и связь с ≥ 2 другими кластерами либо betweenness в топ-5% своей слабосвязной компоненты
consolidatorin_deg ≥ 5
distributorout_deg ≥ 10
transitне seed, положительные вход и выход, 0.8 ≤ pass_through ≤ 1.2
terminaldepth < 4, положительный вход, out_deg = 0
peripheralостальные узлы, в том числе обрывы глубины 4

role_score оценивает силу признака. priority_score объединяет входящую степень и сумму, betweenness, достижимые seed и вес роли. Обрыв четвёртого колена снижает оба скора. Точные формулы: PLAN §4 и ONTOLOGY §7.

Дополнительные сигналы: быстрый выход через 1–2 дня, синхронные входы, всплески, циклы длины 2–6, цепочки A→B→C с минимум двумя переводами на каждом ребре и минимум три перевода по 5 000–6 000 KZT одному получателю за день. robustness.csv показывает компоненты и seed, потерявшие направленный путь к оставшимся consolidator/coordinator после удаления топ-5/10/20 узлов; роли при этом не пересчитываются.

Технологии

Python 3.9+ (проверено на 3.9.6); pandas, pyarrow, NetworkX, NumPy, SciPy, openai, python-dotenv (границы версий). Viewer — HTML/JS и локальная копия Cytoscape.js 3.34.3. Необязательные тексты используют OpenAI Responses API и OPENAI_MODEL=gpt-6-sol в проверенном live-прогоне. Роли, скоры и топ модель не вычисляет.

Архитектура проекта

flowchart LR
    A[Три Parquet] --> B[Валидация и направленный граф]
    B --> C[Метрики и временные сигналы]
    C --> D[Роли, кластеры и приоритет]
    D --> E[CSV и graph.json]
    E --> F[Viewer с поиском gid]
    D -. необязательные проверяемые тексты .-> G[OpenAI Responses API]
    G -.-> E

pipeline.py валидирует вход, считает и проверяет выходы; temporal.py и structural.py считают детерминированные сигналы. Viewer читает out/graph.json через локальный HTTP-сервер. Неверный вход завершает CLI с сообщением V-01–V-03. Для панели serve.py отдаёт тот же viewer и out/, принимает вопрос, вызывает input_check.py и затем существующий ask.py. Проверка и ответ используют OPENAI_MODEL; API-ключ остаётся на сервере.

Масштабирование до 1 млн узлов

На таком размере точный betweenness и объекты NetworkX станут узким местом. Нужны потоковое чтение Parquet, компактное хранение рёбер, обработка по компонентам и приближённый betweenness с оценкой ошибки. Эта версия проверена на 2 248 узлах; 1 млн узлов — NOT_VERIFIED.

Установка и запуск

Нужны Python 3.9+, git и доступ к PyPI при установке. Проверено на Python 3.9.6. Все три Parquet находятся в data/ репозитория. Команды на macOS/Linux:

git clone https://github.com/BAITC-Hacks/hack-a716d39d-builoff.git
cd hack-a716d39d-builoff
python3 -m venv .venv
.venv/bin/python -m pip install -r requirements.txt
.venv/bin/python pipeline.py --data data --out out

На Windows используйте .venv\Scripts\python вместо .venv/bin/python. Файл .env для обязательного расчёта не нужен: без него программа сообщает LLM skipped и сохраняет результаты. Для необязательных гипотез скопируйте .env.example в .env, внесите ключ, предоставленный для проверки, и задайте OPENAI_MODEL. Флаг --no-llm пропускает оба LLM-вызова при любом содержимом .env.

ИмяНазначениеОбязательно
OPENAI_API_KEYключ для дополнительных текстов; не хранить в gitнет
OPENAI_MODELмодель Responses APIтолько с ключом

Успешная команда заканчивается wrote: ... и elapsed_seconds=.... Основной запуск из корня репозитория в другом терминале (для ассистента заранее задайте ключ и модель в .env):

source .venv/bin/activate
python serve.py

Откройте http://127.0.0.1:8765/viewer/. Порт 8765 открывает граф, поиск и вкладку «Ассистент». Без ключа граф работает, а ассистент сообщает об отсутствии настроек.

Запасной запуск, если нужен только граф без API ассистента:

python -m http.server 8000 --bind 127.0.0.1

Откройте http://127.0.0.1:8000/viewer/. Порт 8000 даёт граф и поиск; при вопросе вкладка «Ассистент» предложит запустить python serve.py. Введите полный 18-значный gid; клик по соседу открывает его карточку. Стрелки показывают направление перевода. Отдельного production-сервера и Docker нет.

Как проверить решение

Доступ для проверки

Три Parquet включены в репозиторий; личный аккаунт участника не нужен. Обязательные расчёт и viewer работают без ключа. Ключ OpenAI для необязательных текстов эксперт получает по договорённости с организаторами. Без ключа программа сообщает LLM skipped и сохраняет обязательные файлы.

Ассистент

После расчёта можно задать отдельный вопрос ассистенту:

.venv/bin/python ask.py 'что известно о 100000005382566100?'

CLI читает готовые out/nodes_roles.csv, out/clusters.csv и out/graph.json, использует OPENAI_API_KEY и OPENAI_MODEL из .env. Та же логика доступна во вкладке «Ассистент» viewer при запуске serve.py: локальный POST /api/ask принимает JSON {"question":"..."} и возвращает answer, terminal, checks. Перед агентом один структурированный вызов модели проверяет prompt injection и границы онтологии (§1, 2, 9). guard reject или высокий риск и ontology reject завершают запрос отказом; clarify передаёт агенту подсказку. При техническом сбое проверки checks содержит skipped с причиной, а агент продолжает работу. Стадии validate, check, agent и бейджи проверок видны в истории под каждым вопросом. В ответе ** отображаются жирным; рядом с каждым полным gid есть переход «показать в сети», который открывает вкладку «Сеть» с графом и карточкой. Его tools: find_node, neighbors, top_by_role, paths_from_seeds, cluster_members, search_by_metric. После ответа код сверяет все gid и числа с фактически возвращёнными результатами tools; при расхождении добавляет [не подтверждено]. Без ключа сообщает об этом и выходит с кодом 0. Ответы являются гипотезами по наблюдаемому графу.

.venv/bin/python -m unittest discover -s tests -v
.venv/bin/python pipeline.py --data data --out out --no-llm
.venv/bin/python ask.py 'кто собирает деньги с seed-клиентов?'
.venv/bin/python ask.py 'что известно о 100000005382566100?'
.venv/bin/python ask.py 'какие узлы связывают кластеры 3 и 16?'

Фактический вывод, edge cases и AC — в EVIDENCE. Пятиминутный сценарий: выполнить расчёт, открыть viewer и найти 100000003684369100 (coordinator), 100000000850297100 (transit), 100000004265639100 (обрыв, peripheral), затем несуществующий gid 999.

ПроверкаФактическое поведение
Пустая папка --dataкод 1, ERROR: V-01: missing .../nodes.parquet
Битый edges.parquetкод 1, ERROR: V-01: cannot read ... Parquet magic bytes not found
Несогласованный агрегаттест: V-03, выгрузки не создаются
Неизвестный gidviewer: «Узел ... не найден в предоставленной сети.»
Нет OPENAI_API_KEYрасчёт успешен, дополнительные тексты пропущены
Обрыв четвёртого коленани один из 444 обрывов не назван terminal

Данные и интеграции

Источник — предоставленные организаторами данные: 2 248 узлов, 3 119 направленных рёбер, 4 840 отдельных переводов за 2026-07-01…2026-07-31. Выгрузка охватывает только исходящие внутрибанковские переводы от 5 000 KZT на глубину четырёх колен. Дополнительная интеграция с OpenAI получает агрегаты выбранных кластеров и узлов при настроенном ключе. Роли и топ считаются локально. out/completeness.md описывает недостающие данные и следующий запрос.

Ограничения

Нет переводов ниже 5 000 KZT, за пределами периода и вне банка. Вход seed неполон; 444 узла обрываются на четвёртом колене. Поэтому роль terminal, признаки дробления и приоритет требуют проверки на более полных данных. Нет AML-вердикта, авторизации и онлайн-обновления.

Предоставленные данные и starter/ использованы как исходный материал. Процессные AGENTS.md, docs/PROCESS.md и docs/ONTOLOGY_GUIDE.md подготовлены до соревновательной части; код решения, онтология, план и доменные тексты созданы во время неё. Библиотеки и модель перечислены в «Технологиях», иных датасетов нет. GitHub Actions отключён по ограничению репозитория организатора; локальная команда тестов указана выше. Непроверенное отмечено в EVIDENCE.

Ссылка на deployed-версию

Не развёрнуто. Используйте локальный viewer из «Установка и запуск».

Звёзды
⭐ 0
Форки
0
Язык
Python
Последний push
в прошлом месяце
Коммиты
24
Авторы
1
Файлы
35
Ветки
1

Авторы коммитов

Anton Builov 24

История коммитов

  • 2026-09-23 17:14Link final assistant and network screenshotsAnton Builov
  • 2026-09-23 17:11docs: final screenshotsAnton Builov
  • 2026-09-23 17:00Link viewer evidence and document assistant checksAnton Builov
  • 2026-09-23 16:57Make assistant server the primary viewer commandAnton Builov
  • 2026-09-23 16:55Add assistant and network tabs with chat historyAnton Builov
  • 2026-09-23 16:38Add local analyst assistant panel with input checksAnton Builov
  • 2026-09-23 16:08Add read-only graph analyst CLI with grounded responsesAnton Builov
  • 2026-09-23 15:58Remove unrelated baseline architecture documentAnton Builov
Все коммиты (24)
  • 2026-09-23 15:58Document reproducible Python setup without env fileAnton Builov
  • 2026-09-23 15:48Record user viewer verification for AC-05Anton Builov
  • 2026-09-23 15:39Record live and clean-clone acceptance evidenceAnton Builov
  • 2026-09-23 15:36Fix full Russian explanations and prepare feature freeze evidenceAnton Builov
  • 2026-09-23 15:05set which model should be usedAnton Builov
  • 2026-09-23 15:04Add deterministic structural diagnostics and robustness exportAnton Builov
  • 2026-09-23 14:44Record clean clone verification for iteration 3Anton Builov
  • 2026-09-23 14:43Add optional verified node cardsAnton Builov
  • 2026-09-23 14:38Add verified optional cluster hypothesesAnton Builov
  • 2026-09-23 14:34Add temporal signals and remove blocked CIAnton Builov
  • 2026-09-23 14:19Complete iteration 2 local graph viewerAnton Builov
  • 2026-09-23 14:10Polish graph explanations for T2.0Anton Builov
  • 2026-09-23 14:03Complete iteration 1 graph analysis pipelineAnton Builov
  • 2026-09-23 14:03first commitAnton Builov
  • 2026-09-23 13:53Plan Python graph pipeline and viewerAnton Builov
  • 2026-09-23 13:39Document graph money ontologyAnton Builov
Структура репозитория (35 файлов)
.env.example
.gitignore
AGENTS.md
README.md
ask.py
cluster_llm.py
data/README.md
data/edges.parquet
data/nodes.parquet
data/transactions.parquet
docs/EVIDENCE.md
docs/ONTOLOGY.md
docs/ONTOLOGY_GUIDE.md
docs/PLAN.md
docs/PROCESS.md
docs/TZ.md
docs/screenshots/assistant-tab.png
docs/screenshots/network-tab.png
input_check.py
node_llm.py
pipeline.py
requirements.txt
serve.py
starter/README.md
starter/requirements.txt
starter/starter.py
structural.py
temporal.py
tests/check_viewer.js
tests/test_ask.py
tests/test_cluster_llm.py
tests/test_input_check.py
tests/test_node_llm.py
tests/test_pipeline.py
viewer/index.html

Обсуждение 0 комментариев

Войдите, чтобы комментировать

Пока нет комментариев — будьте первым.