AAYMA
RU
Войти

Mirai — Граф денег

Локальное рабочее место AML-аналитика: расчёт ролей, кластеров и приоритетов по сети переводов, интерактивная карта графа и ассистент с ответами по…

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

О проекте

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

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

Суть

Локальное рабочее место AML-аналитика: расчёт ролей, кластеров и приоритетов по сети переводов, интерактивная карта графа и ассистент с ответами по графу.

Как устроено

Проверка консистентности parquet → направленный граф → метрики (степени, суммы, PageRank от seed, betweenness, сквозной транзит) → шесть ролей по правилам с порогами и evidence, второй проход для координаторов, priority_score из пяти компонент, Louvain-кластеры с гипотезами. Дополнительные признаки: быстрый транзит, синхронные поступления, повторяющиеся маршруты, циклы, устойчивость сети при удалении узлов. FastAPI + фронтенд на Cytoscape.js; ассистент с tool calling работает офлайн или через NVIDIA/OpenAI/Anthropic.

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

  • NetworkX
  • personalized PageRank
  • betweenness
  • Louvain
  • rule-based roles
  • cycle detection
  • resilience analysis
  • tool calling

Особенности

Анализ чувствительности места в рейтинге к весам, оценка изменения сети при удалении приоритетных узлов, передача 18-значных gid строками во избежание округления в JS; мультипровайдерный ассистент с локальным fallback.

Стек

Python · FastAPI · Uvicorn · pandas · NumPy · PyArrow · NetworkX · Cytoscape.js · pytest

Модели

meta/llama-3.3-70b-instruct (NVIDIA) · gpt-4o-mini · claude-haiku-4-5


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

README

README.md

Mirai — Граф денег

Команда Mirai · HackAlem AI · кейс «Граф денег: восстановление финансовой структуры организованной группы по транзакционной сети»

О проекте

Mirai — локальное рабочее место AML-аналитика банка для исследования транзакционной сети. Помогает ответить на вопрос «кого проверить первым и почему»: превращает таблицы переводов в карту связей, гипотезы о ролях клиентов и приоритетный список с числовыми объяснениями.

Решение предназначено для аналитика, которому нужно разобраться в потоках вокруг известных исходных клиентов (seed), найти точки сбора, транзита и распределения и определить следующий шаг проверки. Используются только предоставленные транзакции и структура сети.

Все выводы — гипотезы для проверки, а не утверждения о виновности. Приоритет — порядок проверки; role_score — сила соответствия правилу, не вероятность нарушения.

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

  • Полный расчёт из Parquet одной командой: проверка согласованности данных, метрики, шесть ролей с объяснениями, кластеры, приоритеты и обязательные CSV.
  • Объяснимый анализ: правила с порогами, вклады пяти компонент приоритета, проверяемые связи и чувствительность места в рейтинге к изменению весов.
  • Дополнительные признаки: временной транзит, синхронные поступления, повторяющиеся маршруты, структурные циклы и оценка изменения сети при удалении приоритетных узлов.
  • Интерактивная карта: обзор, окружение выбранного клиента, весь граф, фильтры по ролям и кластерам, поиск по полному или частичному gid, направление и суммы переводов.
  • Инструменты исследования: карточка клиента, сравнение двух клиентов, направленный путь, общие получатели, история просмотра, локальные закладки и векторный экспорт текущей сцены в SVG.
  • Ассистент аналитика: ответы по графу со ссылками на клиентов и проверяемыми действиями на карте. Локальный режим работает без ключей; подключение LLM необязательно.

Начальный обзор показывает 12 приоритетных клиентов. Окружение выбранного клиента начинается с 12 крупнейших по сумме соседей; остальных можно раскрыть кнопкой. Данные при этом не удаляются.

Основной пользовательский сценарий

  1. Аналитик предоставляет три согласованных файла: клиенты, агрегированные связи и транзакции.
  2. python run.py проверяет данные, рассчитывает результаты и открывает локальный HTTP-сервер.
  3. В браузере аналитик выбирает клиента из списка приоритетов или находит его по gid.
  4. Карточка объясняет роль и приоритет; карта показывает плательщиков, получателей и связи.
  5. Аналитик проверяет путь или общих получателей, задаёт вопрос ассистенту и сопоставляет ответ с конкретными узлами и переводами.
  6. Результат исследования — гипотеза с числовыми основаниями и оговорками о полноте данных; таблицы доступны в outputs/, выбранную сцену можно скачать как SVG.

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

Понадобятся Git, Python и современный браузер. Рекомендуется Python 3.12 — на этой версии проводились проверки. Доступ к приватному репозиторию должен быть выдан организатором. Интернет нужен для клонирования и установки зависимостей. После установки расчёт, интерфейс и локальный ассистент работают без облака, GPU и API-ключей.

macOS / Linux

git clone https://github.com/BAITC-Hacks/hack-e29d46be-mirai.git
cd hack-e29d46be-mirai
python3 -m venv .venv
source .venv/bin/activate
python -m pip install -r requirements.txt
LLM_PROVIDER=none python run.py

Windows — PowerShell

Команды используют Python виртуального окружения напрямую: менять политику выполнения PowerShell и активировать окружение не требуется.

git clone https://github.com/BAITC-Hacks/hack-e29d46be-mirai.git
cd hack-e29d46be-mirai
py -3.12 -m venv .venv
.\.venv\Scripts\python.exe -m pip install -r requirements.txt
$env:LLM_PROVIDER = "none"
.\.venv\Scripts\python.exe run.py

Откройте http://localhost:8000. Дождитесь завершения расчёта и сообщения Uvicorn о запуске сервера. Терминал должен оставаться открытым; остановка — Ctrl+C. run.py сам пересчитывает и проверяет выгрузки, затем запускает интерфейс.

Следующие команды выполняются из корня репозитория с Python установленного окружения (на Windows замените python на .\.venv\Scripts\python.exe).

КомандаЧто делает
python run.pyпересчёт + интерфейс
python run.py --no-serveтолько расчёт и проверка CSV
python run.py --skip-pipelineинтерфейс на готовых результатах
python run.py --port 8018запуск на другом порту, если 8000 занят
python run.py --no-serve --data "my-data" --out "my-results"расчёт другой совместимой выборки
python run.py --skip-pipeline --out "my-results"просмотр этих результатов

Каталог результатов: явный --out → переменная MIRAI_OUTPUT_DIR → outputs/. Один и тот же каталог используется расчётом и сервером. Пути с пробелами заключайте в кавычки. При ошибке согласованности входных данных исправьте исходные файлы: пропуск расчёта через --skip-pipeline не исправляет данные.

Необязательное подключение LLM

Для локальной проверки оставьте LLM_PROVIDER=none. Чтобы включить внешний API, скопируйте .env.example в .env, задайте провайдера и его ключ, затем перезапустите сервер. Если ранее задана переменная LLM_PROVIDER в терминале, измените её тоже: окружение имеет приоритет над .env.

LLM_PROVIDERИнтеграцияКлючМодель по умолчанию в коде
noneлокальные инструменты и шаблоныне нуженбез модели
nvidiaNVIDIA, OpenAI-совместимый APINVIDIA_API_KEYmeta/llama-3.3-70b-instruct
openaiOpenAI APIOPENAI_API_KEYgpt-4o-mini
anthropicAnthropic Messages APIANTHROPIC_API_KEYclaude-haiku-4-5-20251001

Модель можно переопределить через LLM_MODEL; она должна поддерживать вызов инструментов. Это поддержанные кодом настройки, а не гарантия доступности конкретной модели или аккаунта. При отсутствии ключа или ошибке API предусмотрен локальный ответ. Ключи передаются через переменные окружения или локальный .env, исключённый из Git; в репозиторий их добавлять не нужно. Подробнее: assistant/README.md.

Что на выходе (outputs/)

ФайлСодержимое
nodes_roles.csv2 248 строк: gid, role, role_score, cluster_id, priority_score, evidence + метрики (лишние колонки разрешены ТЗ)
clusters.csv91 кластер: cluster_id, n_nodes, n_seed, sum_kzt_internal, top_gids, hypothesis
top_nodes.csvтоп-50 по приоритету: rank, gid, role, priority_score, why
graph.jsonузлы с координатами, рёбра, кластеры — для интерфейса и ассистента

Числа в таблице относятся к поставленной выборке. После записи пайплайн проверяет выгрузки: число строк совпадает с числом входных узлов (здесь 2 248), все обязательные поля заполнены, роли только из словаря, evidence ≤ 200 символов, топ ≥ 20, каждый cluster_id описан в clusters.csv.


Технологии

КомпонентРеализация в репозитории
Язык расчёта и сервераPython
Таблицы и Parquetpandas, NumPy, PyArrow; SciPy используется графовыми расчётами
Графовые алгоритмыNetworkX: направленный граф, PageRank, betweenness, Louvain, раскладка
HTTP-серверFastAPI, Uvicorn
ИнтерфейсHTML, CSS, JavaScript без сборки; локальная копия Cytoscape.js 3.30.4
Необязательные LLMOpenAI SDK для OpenAI/NVIDIA; HTTP-клиент стандартной библиотеки для Anthropic
Конфигурацияпеременные окружения, python-dotenv
Проверкиpytest, HTTPX, встроенный тестовый запуск Node.js

Зависимости Python перечислены в requirements.txt. Node.js нужен только для тестов JavaScript; для запуска приложения он не требуется. Обученной собственной модели, отдельной базы данных и обязательных внешних сервисов в текущей реализации нет.

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

Источник — три файла организаторов из data/. Период поставленной выборки: 1–31 июля 2026 года, 81 исходный клиент (seed), обход исходящих переводов на четыре колена, только внутрибанковские переводы от 5 000 ₸. Всего 2 248 клиентов, 3 119 направленных агрегированных связей и 4 840 транзакций. Внешнее обогащение данными не используется.

ФайлОбязательные поля
nodes.parquetgid, depth, is_seed
edges.parquetsrc, dst, sum_kzt, n_tx, depth
transactions.parquetsrc, dst, date, sum_kzt

gid, src, dst во входных Parquet должны быть целочисленными и помещаться в int64. Суммы — положительные конечные числа; пары, суммы и количества в edges должны совпадать с агрегацией transactions, а все участники связей — присутствовать в nodes. В JSON/API идентификаторы передаются строками, чтобы JavaScript не округлял 18-значные числа. CSV также следует открывать с текстовым типом столбца gid, если используется электронная таблица.

Другую выборку можно передать через --data, сохранив эти схемы. Число клиентов не зашито в расчёт, но действующий валидатор требует минимум 20 строк в топ-листе. Предположения о четырёх коленах, валюте и устройстве выгрузки необходимо пересмотреть для данных другого происхождения.

Интерфейс обращается к локальному API FastAPI: /api/graph, /api/node/{gid}, /api/search, /api/top, /api/node/{gid}/card, /api/ask. Ассистент получает рассчитанный граф из сервера. Только при включённом LLM вопросы и результаты вызовов инструментов передаются выбранному внешнему провайдеру; в режиме none API модели не вызывается.

Архитектура и алгоритмы

flowchart LR
    A[data/*.parquet<br/>edges · nodes · transactions] --> B[Проверка консистентности]
    B --> C[Направленный<br/>взвешенный граф]
    C --> D[Метрики узлов<br/>степени, суммы, PageRank от seed,<br/>betweenness, сквозной транзит]
    D --> E[Роли по правилам<br/>с порогами + evidence]
    E --> F[Координаторы<br/>2-й проход]
    F --> G[priority_score<br/>5 компонент]
    G --> H[Кластеры Louvain<br/>+ гипотезы]
    H --> I[outputs/<br/>3 CSV + graph.json]
    I --> J[Интерфейс аналитика<br/>схема · поиск · карточки]
    I --> K[AI-ассистент<br/>вопросы по графу]

Связь компонентов: run.py управляет расчётом и запуском Uvicorn; pipeline/ записывает результаты; app/server.py читает их и обслуживает браузер; assistant/ вызывается сервером как Python-модуль и использует тот же граф. Необязательная LLM выбирает инструменты анализа, но не рассчитывает роли, кластеры или приоритеты.

Код: pipeline/ — load.py → metrics.py → roles.py → priority.py → clusters.py → layout.py → export.py, оркестратор — pipeline/main.py. Пороги ролей — в pipeline/config.py, параметры дополнительных паттернов — в pipeline/extras.py и описании методики.

Метрики узла

МетрикаСмысл
in_deg / out_degсколько разных клиентов перевели узлу / скольким он перевёл
in_kzt / out_kzt, in_tx / out_txсуммы и число переводов внутри графа (сумма и количество — разные сигналы)
pass_throughout_kzt / in_kzt — какую долю полученного узел отдал дальше
fast_forward_shareдоля исходящей суммы в пределах 0–2 дней от любого поступления; близость дат, без сопоставления сумм
seed_exposurePageRank с телепортацией только в 81 seed, взвешенный суммой — структурная близость к seed по направленным связям; не доля их денег и не трассировка происхождения средств
n_seed_up2сколько разных seed достают до узла не более чем за 2 перевода
betweennessпосредничество на направленном невзвешенном графе: как часто узел лежит на кратчайших направленных путях; не трассировка конкретных денег
pagerankвлияние узла, взвешенное суммой
truncated_by_depthузел 4-го колена без исходящих — здесь остановился обход

Дополнительно экспортируются fast_transit_share (FIFO-сопоставление входящей суммы с исходящей через 1–2 дня, без повторного использования суммы), sync_in_days, sync_max_payers, repeated_route_count и признаки неопределённости стока. Флаг fast_transit требует долю ≥80% и исключает seed. Это отдельный показатель: у него другой знаменатель, чем у fast_forward_share. Переводы в один день не имеют известного порядка, поэтому для них сохраняется только верхняя оценка.

Циклы — направленные структурные пути, не доказательство возврата той же суммы денег. Устойчивость в graph.json → extras.resilience показывает удаление топ-5/10/20 именно по итоговому priority_score; перечислены удалённые gid и доля исчезнувшего наблюдаемого оборота.

Роли: правила и пороги

Пороги по степеням = max(абсолютный минимум, перцентиль): на этих данных у 99% узлов ≤ 6 плательщиков, поэтому «много» — это хвост распределения, а не число «с потолка». Правила проверяются по порядку, срабатывает первое.

РольПравило (фактический порог на данных)Пример evidence
consolidator — точка консолидацииfan-in: ≥ 5 разных плательщиков (max(5, p98)). Если одновременно выполнен fan-out, сохраняется при out_deg <= 2 × in_deg, иначе выбирается distributor; флаг gather_scatter«Сбор от 15 разных плательщиков (1.2 млн ₸; порог ≥5), раздаёт 17 получателям»
distributor — распределительfan-out: ≥ 10 разных получателей (max(10, p97))«Веер на 62 получателей (8.6 млн ₸; порог ≥10), входящих от 24»
transit — транзитный счётне seed; есть и вход, и выход; отдаёт дальше 70–130% полученного или ≥ 60% исходящей суммы ушло в течение 2 дней после поступления (флаг rapid_outflow; близость дат без сопоставления сумм)«Отдаёт дальше 81% полученного (1.2 млн ₸ → 1.0 млн ₸); 85% исходящих по датам близки к поступлениям (0–2 дн.; суммы не сопоставлены)»
terminal — гипотеза конечного получателяисходящих нет; ≥ 2 плательщиков или сумма входящих в верхней четверти (≥ 167 тыс ₸); глубина < 4. Включает 7 seed глубины 0 с оговоркой о неполных входящих. На границе глубины 4 — отдельное слабое правило: ≥ 3 плательщика, «сток вероятен, не доказан»«Получил 1.1 млн ₸ от 4 плательщиков и не переводил дальше (колено 1 — обход продолжался бы)»
coordinator — кандидат в организаторы2-й проход по готовым ролям: получает от ≥ 2 точек сбора (второй уровень консолидации), или связка «точка сбора → узел → распределители», или сборщик/распределитель в верхнем 1% по посредничеству, связанный с другими ключевыми узлами«Получает от 2 точек сбора — второй уровень консолидации; вход 8 (2.2 млн ₸), выход 2»
peripheral — периферияостальное: разовые мелкие получатели, узлы на обрыве 4-го колена, seed без переводов«4-е колено: обход остановился здесь (исходящие не выгружались); получил 7 тыс ₸ от 1»

role_score (0–1) — эвристическая сила соответствия правилу: растёт с тем, насколько узел превышает порог (для consolidator/distributor), и с числом выполненных условий (для transit баланс и скорость одновременно дают 1.0). Это не калиброванная вероятность роли или нарушения.

Итог на данных: peripheral 1 619 · terminal 281 · transit 248 (из них 202 — с быстрыми исходящими по датам) · distributor 48 · consolidator 36 · coordinator 16.

Как мы учли особенности данных

Особенность (из ТЗ)Что сделали
Обрыв на 4-м колене: 444 узла без исходящих — артефакт обходаНе считаем их конечными получателями автоматически. По умолчанию peripheral + флаг truncated_by_depth и пометка в evidence. terminal — только при ≥ 3 плательщиках и с формулировкой «сток вероятен, не доказан» (таких 3). Узлы колен 1–3 без исходящих — наоборот, гипотезы стоков в пределах видимости: обход бы продолжился, будь у них переводы ≥ 5 000 ₸
Видны только исходящие переводы, у seed входящие заниженыРоль transit не присваивается seed (у них pass_through бывает > 20 по устройству выгрузки). Для соответствующих ролевых гипотез seed в evidence указана неполнота входящих
Сумма и число переводов — разные сигналыРоли строятся по числу разных контрагентов (устойчиво к одному крупному переводу), суммы — в evidence и в компоненте объёма приоритета
Граф направленныйМетрики ролей и betweenness учитывают направление. Ненаправленная проекция используется для Louvain и раскладки; сценарии устойчивости также оценивают слабую связность без учёта направления
19 seed без рёберВсе 2 248 узлов попадают в выгрузку; изолированные seed — peripheral с флагом isolated_seed. Маленькое сообщество не обязательно изолировано: связи с другими кластерами сохраняются
Нет ground truthКаждое правило — формула с порогом из config.py, каждое решение — evidence с числами. За минуту объясняется любой gid

priority_score — кого смотреть первым

Взвешенная сумма пяти показателей (0–1), веса в config.PRIORITY_WEIGHTS. Близость к seed, объём и посредничество преобразуются в перцентили; сила роли и поведение считаются отдельными правилами:

priority = 0.30 · близость к seed по потоку (seed_exposure)
         + 0.25 · сила роли (вес роли × role_score; coordinator 1.0 … peripheral 0.1)
         + 0.20 · объём денег через узел (max(in_kzt, out_kzt))
         + 0.15 · посредничество (betweenness)
         + 0.10 · поведение (близость дат исходящих и поступлений, флаги паттернов)

Почему так: главное для аналитика — структурная связь узла с seed, затем — предполагаемая функция в сети, и только потом — масштаб. Это порядок проверки, а не оценка виновности. В top_nodes.csv колонка why содержит роль, evidence и два наиболее влияющих показателя с их значениями; выбор учитывает веса. Точные значения, веса и произведения доступны в priority_components:

distributor: Веер на 62 получателей (8.6 млн ₸; порог ≥10), входящих от 24 (seed: входящие занижены выгрузкой) | приоритет: близость к seed по потоку денег — 99%; сила роли — 80%

Кластеры

Встречные суммы A→B и B→A складываются в вес A—B. Порядок узлов/рёбер фиксирован. Исправление прежней потери одного направления меняет состав групп; cluster_id не является постоянным идентификатором группы между версиями расчёта.

Louvain (networkx, seed=42, вес = сумма переводов) на неориентированной проекции графа — в нашем решении сообщества ищутся по суммарным связям; направление денег при этом сохраняется в ролях и свидетельствах отдельных связей. Получилось 91 кластер (61 крупнее 3 узлов, 8 содержат > 1 seed). Гипотеза собирается из состава ролей: например, «в составе: 8 seed; узлов с признаками консолидации: 1». Сосуществование этих узлов в сообществе не означает, что все seed переводили сборщику. Направленный путь проверяется отдельно по рёбрам; маленький кластер не объявляется изолированным.

Раскладка схемы

Для общего графа каждый кластер раскладывается отдельно (spring layout), кластеры стоят по спирали: крупные ближе к центру, мелкие фрагменты по краям. Эти координаты считает пайплайн. Для окружения клиента интерфейс строит локальную схему: плательщики слева, получатели справа, встречные связи снизу. Скорость взаимодействия зависит от компьютера и выбранного режима карты.


Интерфейс и AI-ассистент

  • Интерфейс (app/, FastAPI + Cytoscape.js без сборки): топ-лист приоритетов, схема сети с цветом роли и направлением потоков, подсветка кластера, поиск по gid, карточка узла с evidence и связями.

  • AI-ассистент (assistant/): карточка узла и ответы на вопросы аналитика на естественном языке по данным графа со ссылками на gid. Работает и без LLM (шаблонные ответы из метрик); с LLM — через настроенный API провайдера (LLM_PROVIDER в .env, см. .env.example). LLM не присваивает роли: код формирует фактическую часть ответа из результатов инструментов.

Примеры вопросов: «Кого стоит проверить первым и почему?», «Какие ограничения есть у данных?», «Покажи транзитные узлы кластера <номер из интерфейса>», «Кто переводил деньги узлу <полный gid>?». В режиме без LLM работают локальные запросы по графу. С LLM модель выбирает инструменты и готовые результаты; непроверенный свободный текст не становится фактом ответа. Настройка и ограничения: assistant/README.md.

Для интерфейса экспортируются проверяемые связи evidence_items, пять вкладов priority_components и чувствительность rank_stability. Базовые роли и рейтинг при этом не меняются. Определения и результаты сравнения.

Ограничения

  • Прототип для локального исследования: весь граф обрабатывается в памяти. Миллион узлов, многопользовательская эксплуатация и публичный production deployment не подтверждены.
  • Эвристики, а не обученный классификатор: нет размеченной выборки, оценки accuracy или доказанной вероятности нарушения. Структурный путь и цикл не доказывают движение одной и той же суммы.
  • Интерфейс: интерактивная карта рисуется на Canvas; SVG — формат экспорта. Фильтр по отдельным дням не реализован. При ограниченном показе соседей нужно раскрывать окружение для просмотра остальных.
  • SVG: сохраняет текущие координаты, изгибы и стили всей сцены, включая элементы за краями окна. Скрытые подписи не добавляются автоматически; точные gid остаются в метаданных элементов. Отдельная легенда ролей и таблица подписей всех узлов в экспорт не добавляются.
  • Состояние исследования: закладки сохраняются в браузере, но история чата и ручные координаты узлов не являются постоянным хранилищем. Вопросы отправляются независимо, с явным контекстом клиента.
  • Полнота паттернов: поиск циклов и повторяющихся маршрутов ограничен временем и количеством; признаки полноты доступны в extras. Отсутствие результата не доказывает отсутствия паттерна.
  • Ассистент без LLM: распознаёт поддержанные типы вопросов; произвольные формулировки могут потребовать перефразирования. Работа внешних моделей зависит от ключа, сети и доступности API.
  • Режим демонстрационных данных: при отсутствии outputs/graph.json сервер может использовать shared/sample_graph.json с пометкой DEMO-DATA. Для оценки на данных кейса сначала выполните расчёт.
  • Воспроизводимость: версии Python-зависимостей ограничены снизу, полного lock-файла нет. Проверка на целевом ноутбуке и браузере обязательна для подготовки показа.
  • Видимость: только внутрибанковские исходящие переводы ≥ 5 000 ₸ за июль 2026. Дробление ниже порога, внешние поступления и переводы в другие банки не видны — роли описывают поведение внутри выгрузки.
  • Нет ground truth: пороги подобраны по распределению данных и типовым AML-паттернам (fan-in, fan-out, gather-scatter, сквозной транзит), а не обучены. Их легко пересмотреть в config.py.
  • coordinator — самый гипотетический класс: без данных выше по цепочке (входящие к организатору извне) это «кандидат», а не вывод.
  • Louvain использует фиксированный seed и упорядоченную проекцию. Для воспроизведения используйте те же входные файлы и версии библиотек: другая версия алгоритма может иначе разбить сообщества.

Как проверить решение — сценарий для жюри

Проверка расчёта и интерфейса

  1. Выполните установку выше и запустите python run.py в режиме LLM_PROVIDER=none. Для поставленных файлов ожидаются 2 248 клиентов и 3 119 связей в интерфейсе; в outputs/ — три CSV и graph.json. Пайплайн завершает расчёт проверкой выгрузок.
  2. Выберите любого клиента из списка приоритетов. В карточке найдите роль, объяснение с числами, входящую/исходящую сумму и раздел «Как рассчитан приоритет».
  3. Скопируйте полный gid выбранного клиента в поиск и нажмите Enter или выберите найденного клиента. Он должен открыться без потери цифр. Перейдите к окружению клиента: проверьте направления стрелок и значения выбранной связи.
  4. Спросите ассистента: «Кто переводил деньги узлу <полный gid>?». Сопоставьте ссылки и суммы в ответе с входящими связями. Вопрос «Какие ограничения есть у данных?» должен объяснять неполноту выборки. Эти сценарии не требуют внешней модели.
  5. Для воспроизводимого примера найдите 100000001616816100, затем спросите ассистента: «Покажи путь от 100000004015047100 до 100000001616816100». Нажмите «Показать путь»: должна подсветиться существующая направленная связь. Оставьте путь выделенным до экспорта.
  6. Выберите «Ещё» → «Скачать SVG», откройте файл отдельно и увеличьте масштаб. Сравните сторону дуги, зелёные обводки узлов, стрелки и подписи с картой.
  7. После экспорта нажмите «Назад» для восстановления вида. В ответе ассистента нажмите ссылку gid, откройте карточку и проверьте кнопку «← Вернуться к ответу ассистента».
  8. Откройте CSV: у каждого клиента должны быть роль, role_score, cluster_id, priority_score и текстовое evidence с числами; для исходной выборки в топ-листе 50 строк.

При выборе произвольной пары отсутствие пути или общего получателя — допустимый результат.

Автоматические проверки

В активированном окружении из корня репозитория:

python run.py --no-serve
python -m pip install pytest pytest-subtests httpx
python -m pytest -q tests app/tests assistant/tests
python -m assistant.evaluate --graph outputs/graph.json

На Windows используйте .\.venv\Scripts\python.exe вместо python. Оценщик ассистента выполняет 12 локальных сценариев и два дополнительных вопроса с контекстом/направлением, проверяет ссылки и действия без обращения к API. Это проверка ответов, а не точности выявления нарушений.

Если установлен Node.js, дополнительно проверьте модели интерфейса, HTTP-обработку и SVG:

node --test app/tests/test_graph_model.cjs app/tests/test_http.cjs app/tests/test_svg.cjs

Тесты проверяют расчётные правила, входные данные, выгрузки, сервер, ассистента и логику интерфейса. Их успешное выполнение не заменяет визуальный прогон в браузере на компьютере показа. На коде 3648ed4 (23 сентября 2026, macOS / Python 3.12) повторно прошли 200 Python-тестов, 8 дополнительных проверок и 24 JavaScript-теста. Пересчёт исходных Parquet дал 2 248 клиентов, 3 119 связей, 91 кластер и топ-50. Настоящий сервер с отдельной папкой --out прошёл проверки поиска, карточки, топа и указанного направленного пути. Живые LLM этим прогоном не проверялись. Сценарий демонстрации: docs/DEMO.md. Аудит требований и методологии: docs/FINAL_AUDIT.md.

Развёрнутая версия

Публичный адрес развёрнутого приложения в репозитории не указан. Предусмотрен локальный запуск на http://localhost:8000; этот адрес доступен на компьютере, где запущен сервер, и не является публичным демо. Uvicorn по умолчанию слушает 127.0.0.1.

План масштабирования до ~1 млн узлов — не реализован

Сейчас (2 248 узлов)При ~1 млн узлов
networkx, весь граф в памятиigraph / graph-tool (C/C++) или cuGraph; рёбра в Parquet + DuckDB/Polars
точный betweenness O(V·E)приближённый betweenness по выборке k источников (k ≈ 500–1000)
PageRank от seedразреженные/распределённые вычисления с контролем сходимости и числа итераций
сквозной транзит по всем транзакциям в Pythonоконный join в DuckDB/Spark по (dst = src, date ≤ date + 2)
Louvain на всём граферассмотреть Leiden (leidenalg) и иерархические сообщества, сравнить качество и время на целевом масштабе
раскладка всего графараскладка на сервере по кластерам + показ эго-сети / топ-N по запросу, WebGL-рендер (sigma.js)
батч раз в выгрузкуинкрементальный пересчёт метрик только для затронутых компонент

Это направление дальнейшей разработки, а не результат нагрузочного тестирования. Локальные правила ролей можно сохранить по смыслу, но глобальные метрики, пороги, временные паттерны и качество приближений потребуют отдельной проверки.


Структура репозитория

run.py              одна команда: пайплайн + интерфейс
pipeline/           метрики, роли, приоритет, кластеры, раскладка, выгрузки; config.py — пороги ролей
outputs/            nodes_roles.csv, clusters.csv, top_nodes.csv, graph.json
app/                интерфейс аналитика (FastAPI + Cytoscape.js)
assistant/          AI-ассистент (карточки узлов, вопросы по графу)
shared/             sample_graph.json — синтетический мок для разработки (make_sample.py)
data/, starter/     данные и стартовый код организаторов (не изменялись)
docs/               ТЗ, контракты между частями, план команды

Команда Mirai

Роль
Мирас (@ausmiras-glitch)ведущий агент и пайплайн: метрики, роли, паттерны, приоритет, кластеры, интеграция; README
Нурай (@nqori)интерфейс аналитика
Даниал (@dnurboluly01-cmd)AI-ассистент, вопросы и проверяемые действия на карте
Звёзды
⭐ 0
Форки
0
Язык
Python
Последний push
в прошлом месяце
Коммиты
78
Авторы
6
Файлы
86
Ветки
27

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

Miras Aussabayev 26Nurai Baktur 22ausmiras-glitch 12dnurboluly01-cmd 12dnurboluly01-cmd 5Miras Aussabayev 1

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

  • 2026-09-23 18:01docs: align jury README with full-project audit (#50) (#52)Nurai Baktur
  • 2026-09-23 18:00docs: align jury README with full-project audit (#50)Nurai Baktur
  • 2026-09-23 17:53docs: README для жюри с запуском и проверкой решения (#49) (#51)ausmiras-glitch
  • 2026-09-23 17:51docs: README для жюри с запуском и проверкой решения (#49)Miras Aussabayev
  • 2026-09-23 17:42fix(app): preserve live graph geometry and styles in SVG (#47) (#48)Nurai Baktur
  • 2026-09-23 17:41fix(app): preserve live graph geometry and styles in SVG (#47)Nurai Baktur
  • 2026-09-23 17:28fix(launcher): единая папка выгрузок для расчёта и интерфейса (#44) (#46)ausmiras-glitch
  • 2026-09-23 17:28fix(pipeline): проверяемые гипотезы и точные идентификаторы (#43) (#45)ausmiras-glitch
Все коммиты (78)
  • 2026-09-23 17:14docs: record final integrated audit and accepted UI fixesMiras Aussabayev
  • 2026-09-23 17:11docs(launcher): describe shared output directory precedenceMiras Aussabayev
  • 2026-09-23 17:11Merge remote-tracking branch 'origin/main' into miras-gpt/44-launcher-outputMiras Aussabayev
  • 2026-09-23 17:11Merge remote-tracking branch 'origin/main' into miras-gpt/43-final-correctnessMiras Aussabayev
  • 2026-09-23 17:09feat(app): устойчивый граф, проверяемые подсветки и SVG (#31) (#41)Nurai Baktur
  • 2026-09-23 17:09fix(launcher): единый каталог результатов для пайплайна и UI (#44)Miras Aussabayev
  • 2026-09-23 17:09fix(pipeline): точные гипотезы и защита идентификаторов (#43)Miras Aussabayev
  • 2026-09-23 17:08Merge main after #42; preserve graph versioning and graph-backed topNurai Baktur
  • 2026-09-23 17:07fix(app): apply direction filter to the selected client (#31)Nurai Baktur
  • 2026-09-23 17:07fix(app): derive HTTP top from current graph snapshot (#39) (#42)Nurai Baktur
  • 2026-09-23 17:00fix(app): simplify graph views and recover from network failures (#31)Nurai Baktur
  • 2026-09-23 16:45fix(app): derive HTTP top from current graph snapshot (#39)Nurai Baktur
  • 2026-09-23 16:43feat(app): integrate pipeline explanations with progressive disclosure (#31)Nurai Baktur
  • 2026-09-23 16:37feat(app): stable graph investigation, grounded actions and SVG export (#31)Nurai Baktur
  • 2026-09-23 16:36chore(app): sync team integration before workspace changes (#31)Nurai Baktur
  • 2026-09-23 16:35fix(pipeline): sum reciprocal flows and expose verified explanations (#36) (#40)ausmiras-glitch
  • 2026-09-23 16:28fix(pipeline): sum reciprocal flows and expose verified explanations (#36)Miras Aussabayev
  • 2026-09-23 16:18fix(assistant): understand Russian transfers and validate map actions (#37) (#38)dnurboluly01-cmd
  • 2026-09-23 16:16fix(assistant): understand Russian transfers and validate map actions (#37)dnurboluly01-cmd
  • 2026-09-23 16:06fix(pipeline): устойчивые выгрузки и согласованные признаки без изменения ролей (#30) (#32)ausmiras-glitch
  • 2026-09-23 16:05docs(app): assign follow-up work and team prompts (#31)Nurai Baktur
  • 2026-09-23 16:05docs(app): publish UX and integration audit (#31)Nurai Baktur
  • 2026-09-23 16:04fix(assistant): restore Q&A to main and distinguish pipeline signals (#29) (#34)dnurboluly01-cmd
  • 2026-09-23 16:01fix(integration): bring completed graph Q&A into main (#33)Miras Aussabayev
  • 2026-09-23 16:00fix(assistant): restore Q&A to main and distinguish pipeline signals (#29)dnurboluly01-cmd
  • 2026-09-23 15:58Merge main after squash of network extras PR24Miras Aussabayev
  • 2026-09-23 15:58docs: move demo to September29 and continue development until18Miras Aussabayev
  • 2026-09-23 15:56feat(extras): циклы, повторяющиеся маршруты и устойчивость сети (#6) (#24)ausmiras-glitch
  • 2026-09-23 15:54feat(assistant): add graph grounded Q&A (#12) (#27)dnurboluly01-cmd
  • 2026-09-23 15:53feat(assistant): add graph backed node cards (#11) (#25)dnurboluly01-cmd
  • 2026-09-23 15:53feat(assistant): cached provider client (#10) (#23)dnurboluly01-cmd
  • 2026-09-23 15:52docs: link hardening PR and verified handoff timestampMiras Aussabayev
  • 2026-09-23 15:50fix(pipeline): harden exports and preserve role behavior (#30)Miras Aussabayev
  • 2026-09-23 15:45fix(assistant): ground graph Q&A and cover offline queries (#12)dnurboluly01-cmd
  • 2026-09-23 15:41fix(assistant): ground node cards and preserve boundary warnings (#11)dnurboluly01-cmd
  • 2026-09-23 15:41fix(assistant): validate LLM settings and isolate provider failures (#10)dnurboluly01-cmd
  • 2026-09-23 15:40Merge remote-tracking branch 'origin/miras/24-extras-integration' into miras-gpt/30-pipeline-hardeningMiras Aussabayev
  • 2026-09-23 15:39chore: reconcile merged temporal PR with network branchMiras Aussabayev
  • 2026-09-23 15:26feat(extras): временные признаки и осторожная гипотеза terminal (#5) (#17)ausmiras-glitch
  • 2026-09-23 15:15docs: hand lead role to miras-gpt — HANDOFF.md, zones, lead prompt; Danial owns assistant only (#28)ausmiras-glitch
  • 2026-09-23 15:13docs: hand lead role to miras-gpt — HANDOFF.md, zones, lead prompt; Danial owns assistant onlyMiras Aussabayev
  • 2026-09-23 15:12feat(app): карточка клиента, AI-карточка и чат (#9) (#20)Nurai Baktur
  • 2026-09-23 15:11Merge main into nurai/9-node-cards-chat after #18 and #19Nurai Baktur
  • 2026-09-23 15:10feat(app): offline graph workspace with exact gid search (#8) (#19)Nurai Baktur
  • 2026-09-23 15:09fix(assistant): use active Anthropic Haiku model (#10)dnurboluly01-cmd
  • 2026-09-23 15:07docs(assistant): add analyst evaluation questions (#12)dnurboluly01-cmd
  • 2026-09-23 15:06fix(assistant): preserve Anthropic tool turns (#10)dnurboluly01-cmd
  • 2026-09-23 15:05feat(assistant): add graph tools and grounded Q&A (#12)dnurboluly01-cmd
  • 2026-09-23 15:05feat(pipeline): extras flag whitelist, sync_inflow, Russian metric/flag labels in graph.json metaMiras Aussabayev
  • 2026-09-23 15:04feat(app): HTTP API with exact client IDs and assistant fallbacks (#7) (#18)Nurai Baktur
  • 2026-09-23 15:03feat(assistant): export public functions (#11)dnurboluly01-cmd
  • 2026-09-23 15:03feat(assistant): add graph grounded node cards (#11)dnurboluly01-cmd
  • 2026-09-23 15:01feat(assistant): add optional cached provider client (#10)dnurboluly01-cmd
  • 2026-09-23 15:01feat(extras): bounded cycles, repeated routes and resilience (#6)Miras Aussabayev
  • 2026-09-23 15:00docs: README — run, role criteria and thresholds, data quirks, priority formula, limits, scaling (#4) (#22)ausmiras-glitch
  • 2026-09-23 14:59docs: README — run, role criteria and thresholds, data quirks, priority formula, limits, scaling (#4)Miras Aussabayev
  • 2026-09-23 14:56feat(app): node details and assistant chat with clickable citations (#9)Nurai Baktur
  • 2026-09-23 14:55feat(app): offline graph workspace with exact gid search (#8)Nurai Baktur
  • 2026-09-23 14:55docs(extras): record full pipeline validation (#5)Miras Aussabayev
  • 2026-09-23 14:55Merge remote-tracking branch 'origin/main' into miras-gpt/5-temporal-extrasMiras Aussabayev
  • 2026-09-23 14:54feat(app): HTTP API with exact client IDs and assistant fallbacks (#7)Nurai Baktur
  • 2026-09-23 14:52docs: move miras-gpt tasks (extras) to danial, demo to miras (#14)ausmiras-glitch
  • 2026-09-23 14:52feat(pipeline): фундамент — run.py, пайплайн v0, outputs, мок (#1) (#15)ausmiras-glitch
  • 2026-09-23 14:52feat(pipeline): правила ролей, координаторы, формула приоритета, раскладка по кластерам (#2, #3) (#16)ausmiras-glitch
  • 2026-09-23 14:47feat(extras): temporal signals and conservative terminal hypotheses (#5)Miras Aussabayev
  • 2026-09-23 14:44feat(pipeline): turn boolean extras columns into node flagsMiras Aussabayev
  • 2026-09-23 14:43feat(pipeline): role rules, coordinator detection, priority formula, cluster layout (#2, #3)Miras Aussabayev
  • 2026-09-23 14:35feat(pipeline): foundation — run.py, pipeline v0, outputs, mock graph (#1)Miras Aussabayev
  • 2026-09-23 14:29docs: move miras-gpt tasks (extras) to danial, demo to mirasMiras Aussabayev
  • 2026-09-23 14:10chore: team setup — agent protocol, case brief, contracts, plan, prompts, data and starterMiras Aussabayev
Структура репозитория (86 файлов)
.env.example
.gitignore
AGENTS.md
CLAUDE.md
README.md
app/README.md
app/__init__.py
app/docs/TEAM_FOLLOWUP.md
app/docs/UX_AUDIT.md
app/docs/WORKSPACE_QA.md
app/server.py
app/static/app.js
app/static/graph-model.js
app/static/http.js
app/static/index.html
app/static/panels.css
app/static/panels.js
app/static/style.css
app/static/workspace.css
app/tests/test_graph_model.cjs
app/tests/test_http.cjs
app/tests/test_server.py
app/tests/test_svg.cjs
app/tests/test_top_consistency.py
app/tests/test_workspace.py
assistant/README.md
assistant/__init__.py
assistant/actions.py
assistant/cards.py
assistant/core.py
assistant/eval_questions.md
assistant/evaluate.py
assistant/llm.py
assistant/questions.py
assistant/tests/test_actions_questions.py
assistant/tests/test_ask.py
assistant/tests/test_cards.py
assistant/tests/test_llm.py
data/README.md
data/edges.parquet
data/nodes.parquet
data/transactions.parquet
docs/AUDIT-2026-09-23.md
docs/CASE.md
docs/CONTRACTS.md
docs/DEMO.md
docs/FINAL_AUDIT.md
docs/HANDOFF.md
docs/PLAN.md
docs/PROMPTS.md
docs/methodology/cycles.md
docs/methodology/explanations.md
docs/methodology/extras-integration.md
docs/methodology/fast-transit.md
docs/methodology/repeated-routes.md
docs/methodology/resilience.md
docs/methodology/synchronous-incoming.md
docs/methodology/terminal.md
outputs/clusters.csv
outputs/graph.json
outputs/nodes_roles.csv
outputs/top_nodes.csv
pipeline/__init__.py
pipeline/clusters.py
pipeline/config.py
pipeline/export.py
pipeline/extras.py
pipeline/layout.py
pipeline/load.py
pipeline/main.py
pipeline/metrics.py
pipeline/priority.py
pipeline/roles.py
requirements.txt
run.py
shared/make_sample.py
shared/sample_graph.json
starter/README.md
starter/requirements.txt
starter/starter.py
tests/test_cluster_hypotheses.py
tests/test_explanations.py
tests/test_extras.py
tests/test_input_ids.py
tests/test_pipeline_hardening.py
tests/test_run_output.py
Ветки (27)

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

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

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