О проекте
Команда: GosKZ
Кейс HackAlem.ai: Финансы — Freedom
Стадия: Рабочий MVP
Задача кейса: «Граф денег»: восстановить структуру организованной группы по сети транзакций (AML)
Суть
Streamlit-пространство для исследования графа денежных потоков: роли, Louvain-кластеры, рейтинг приоритетов, интерактивный граф и опциональный AI-ассистент аналитика с инструментами над графом.
Как устроено
starter.py проверяет согласованность трёх parquet и строит направленный граф в NetworkX с взвешенным PageRank. Роли назначаются правилами сверху вниз (distributor → transit → consolidator → terminal → coordinator → peripheral). Priority = 0.5·role_score + 0.3·норм. log-оборот + 0.2·норм. PageRank. Louvain работает на неориентированной проекции. AMLAnalystAgent ведёт цикл OpenAI Responses API с function calling по allowlist детерминированных инструментов (карточка узла, обход вверх и вниз, общие получатели, пути, кластер), найденные узлы подсвечиваются на графе Plotly.
Ключевые решения
- NetworkX
- PageRank
- Louvain
- rule-based roles
- function calling
- tool registry allowlist
Особенности
LLM-ассистент аналитика получает факты только через зарегистрированные детерминированные инструменты графа; вызовы инструментов можно раскрыть в интерфейсе, а найденные узлы подсвечиваются на графе.
Стек
Python · NetworkX · pandas · PyArrow · Streamlit · Plotly · D3.js · OpenAI SDK
Модели
gpt-4.1-mini
Проект создан за 5 часов на финале хакатона HackAlem.ai (23 сентября 2026, Астана). Код — BAITC-Hacks/hack-bbfda7b2-goskz.
README
README.mdFlow Atlas — исследование графа денежных потоков
Flow Atlas — аналитическое рабочее пространство для изучения переводов между клиентами. Проект создан для кейса «Граф денег» HackAlem AI и помогает аналитику исследовать структуру финансовой сети, находить примечательные узлы и проверять гипотезы по наблюдаемым данным.
Все назначенные роли и приоритеты — объяснимые эвристики по загруженной выборке. Они не устанавливают факт нарушения и не заменяют расследование.
Что реализовано
- Загрузка и проверка согласованности
nodes.parquet,edges.parquetиtransactions.parquet; Streamlit также принимает полный набор этих трёх Parquet-файлов для отдельного анализа в памяти. - Построение направленного графа переводов с суммами и числом транзакций на ребре.
- Расчёт входящих и исходящих связей, оборотов, числа транзакций и взвешенного PageRank.
- Назначение каждой записи одной поведенческой роли:
distributor,transit,consolidator,terminal,coordinatorилиperipheral. Для роли сохраняются краткое объяснение длиной до 200 символов и эвристическая оценка поддержки. - Поиск сообществ алгоритмом Louvain на неориентированной проекции графа и формирование рейтинга приоритетных клиентов.
- Экспорт результатов в
out/nodes_roles.csv,out/clusters.csv,out/top_nodes.csvи интерактивныйout/network.html. - Streamlit-интерфейс с обзором сети, графом переводов, фильтрами по роли и кластеру, рейтингом и карточкой клиента.
- Необязательный AI-ассистент, который отвечает на вопросы о данных через ограниченный набор детерминированных инструментов графа. Вызовы инструментов можно раскрыть в интерфейсе.
Как работает решение
- Пайплайн читает данные о клиентах, агрегированных направленных рёбрах и отдельных транзакциях. Перед расчётом он проверяет, что агрегаты переводов согласуются с
edges.parquetпо парам отправитель–получатель. - По графу рассчитываются метрики узлов и распределяются эвристические роли. Для сообществ направленный граф временно проецируется в неориентированный; суммы взаимных потоков используются как веса.
- На основе роли, логарифма наблюдаемого оборота и PageRank вычисляется приоритетный рейтинг. Результаты сохраняются в
out/. - Веб-приложение загружает граф и выгрузки. Пользователь выбирает узел на графе, в рейтинге или по GID, изучает его контрагентов и показатели, а при настроенном OpenAI API задаёт вопрос ассистенту. Ответ ассистента строится на результатах зарегистрированных инструментов, а найденные узлы и потоки могут подсвечиваться на графе.
Правила ролей и рейтинга
Роли назначаются по наблюдаемым рёбрам и суммам в этой выборке. Правила применяются сверху вниз; если узел подходит нескольким правилам, выбирается первое:
- distributor — не менее 5 разных исходящих получателей.
- transit — узел не является seed-клиентом, имеет входящие и исходящие связи, получил не менее 50 000 KZT и отправил дальше не менее 80% наблюдаемой входящей суммы.
- consolidator — не менее 2 входящих контрагентов, положительная наблюдаемая входящая сумма, не более 1 исходящего и отношение исходящей суммы к входящей не выше 0,5. Узлы глубины 4 без исходящих связей сюда не относятся.
- terminal — есть входящие связи, нет исходящих связей, а минимальная глубина узла меньше 4. Это наблюдаемый конец в выгрузке, а не подтверждение фактического конечного получателя.
- coordinator — есть не менее 2 входящих и 2 исходящих контрагентов. Это гипотеза о многостороннем связующем узле, а не вывод об организаторе.
- peripheral — ни одно из предыдущих правил не подошло.
role_score — эвристическая поддержка роли, рассчитанная из её признаков; это не вероятность. Приоритет равен 0.5 × role_score + 0.3 × нормированный log(1 + входящий и исходящий оборот) + 0.2 × нормированный PageRank. Поэтому рейтинг помогает расставить очередь ручной проверки, но не устанавливает нарушение. Для transit отношение сумм считается только по наблюдаемым рёбрам; полнота входящих seed-клиентов ограничена способом построения графа.
Технологии
- Python — расчёт графа, аналитические инструменты и запуск приложения.
- Pandas, NumPy, PyArrow — обработка таблиц и чтение Parquet.
- NetworkX — направленный граф, взвешенный PageRank и сообщества Louvain.
- Streamlit — интерактивный интерфейс; Plotly — граф сети.
- OpenAI Python SDK и Responses API с function calling — опциональный диалоговый аналитический ассистент. По умолчанию задана модель
gpt-4.1-mini; её можно переопределить черезAML_AGENT_MODEL. Модель не рассчитывает метрики напрямую: факты о графе получает через инструменты проекта. - python-dotenv — загрузка переменных из
.env. - В автономной HTML-визуализации используется D3.js 7.9 с jsDelivr CDN; интерфейс запрашивает шрифты DM Sans и Manrope из Google Fonts.
Архитектура
parquet/*.parquet
│
▼
starter.py ──► NetworkX-граф ──► метрики, роли, кластеры, рейтинг
│ │
└──────────────► out/*.csv, out/network.html
│
▼
interface/network_app.py (Streamlit)
│ │
│ └──► AMLAnalystAgent
│ │
└──► GraphToolService ◄── ToolRegistry
▲ │
└──── OpenAI Responses API
starter.pyсодержит загрузку и проверку данных, построение графа, расчёт признаков, назначение ролей и экспорт. Обычный запускpython starter.pyсначала проверяет окружение и запускает интерфейс;--analyze-onlyпересчитывает выгрузки.agent_tools.pyреализует детерминированные операции: получить карточку узла и его связи, пройти граф вверх или вниз, найти общих получателей, сравнить клиентов, посмотреть кластер, отфильтровать узлы и найти ограниченные по длине пути.tool_registry.pyописывает доступные AI-ассистенту инструменты и выполняет вызовы из allowlist.aml_agent.pyуправляет циклом вызовов OpenAI Responses API и возвращает ответ, список вызванных инструментов и данные для подсветки на графе.prompts.pyзадаёт инструкции модели.interface/network_app.pyобъединяет обзор, визуализацию и чат. Сервис графа кэшируется и используется интерфейсом и ассистентом.
Установка и запуск
Требуются Python и доступ к терминалу. Данные кейса уже находятся в parquet/.
Windows PowerShell
Из корневой папки репозитория выполните:
py -m venv .venv
.\.venv\Scripts\Activate.ps1
python -m pip install --upgrade pip
pip install -r requirements.txt
Если команда py недоступна, используйте python -m venv .venv.
Запустить проверки путей и зависимостей:
python starter.py --check
Запустить приложение одной командой после установки зависимостей:
python starter.py
Откройте адрес, который Streamlit напечатает в терминале. При первом запуске или после изменения Parquet-файлов приложение создаст либо обновит выгрузки в out/.
Чтобы исследовать другой набор данных, в боковой панели загрузите вместе edges.parquet, nodes.parquet и transactions.parquet с той же схемой, что в поставке. Приложение проверит идентификаторы, пары переводов, суммы и количество транзакций, пересчитает анализ в памяти и предложит скачать три CSV-выгрузки. Загруженные файлы не перезаписывают данные проекта.
Пересчитать выгрузки без запуска интерфейса:
python starter.py --analyze-only
AI-ассистент (необязательно)
Для работы чата нужен ключ OpenAI API. Его можно задать в текущем PowerShell-сеансе перед запуском:
$env:OPENAI_API_KEY = "ваш-ключ"
# Необязательно: выбрать модель, отличную от gpt-4.1-mini
$env:AML_AGENT_MODEL = "gpt-4.1-mini"
python starter.py
Либо создайте .env в корне проекта (он исключён из Git):
OPENAI_API_KEY=ваш-ключ
AML_AGENT_MODEL=gpt-4.1-mini
Без OPENAI_API_KEY интерфейс аналитики доступен, но чат-ассистент отключён.
Как проверить решение
- Установите зависимости и запустите
python starter.py. - В боковой панели откройте Top Customers и выберите строку рейтинга либо вставьте GID
100000002224132100в поле поиска клиента. - На карточке клиента изучите роль, приоритет, входящие и исходящие связи и основания назначения роли. Этот GID присутствует в текущей выгрузке
out/top_nodes.csv. - Откройте вкладку Network: выбранный клиент и прямые контрагенты должны быть видны на графе. Используйте фильтры по роли или кластеру и переключатель фокуса на окружение выбранного клиента.
- Если задан
OPENAI_API_KEY, спросите в чате: «Объясни роль и приоритет клиента 100000002224132100». В раскрывшемся разделе вызовов можно посмотреть, какие данные инструментов использованы для ответа.
Сценарий демо на 5 минут
Запустите python starter.py и используйте поставленный набор данных:
- 0:00–0:45 — обзор. Покажите размер сети, оборот, число seed-клиентов и ограничения наблюдаемой выборки.
- 0:45–1:30 — карта. Покажите направление переводов, окраску по ролям и кластерам, затем найдите клиента по GID и откройте его окружение.
- 1:30–3:45 — три клиента из рейтинга. Сравните транзитный узел
100000002224132100(ранг 1), распределителя100000007747786100(ранг 2) и консолидатора100000004892144100(ранг 27). Для каждого прочитайтеwhy, покажите роль и контрагентов в карточке клиента. - 3:45–4:30 — проверка границ вывода. Покажите оговорку о неполных входящих потоках seed-клиентов и о глубине 4; роли являются гипотезами для проверки.
- 4:30–5:00 — результат для аналитика. Покажите скачивание трёх CSV. Если настроен API-ключ, задайте вопрос ассистенту и раскройте использованные инструментальные данные.
GID в сценарии взяты из текущего рейтинга поставленного набора; после изменения данных используйте GID из его нового top_nodes.csv.
Данные и интеграции
parquet/nodes.parquet— записи о клиентах, включая GID, глубину обхода и seed-признак.parquet/edges.parquet— агрегированные направленные пары переводов с суммой (sum_kzt) и количеством транзакций (n_tx).parquet/transactions.parquet— транзакции с отправителем, получателем, суммой и датой; используется для проверки агрегатов и временных сведений в графовых инструментах.- OpenAI Responses API используется только при включённом AI-чате. Проект не указывает другие внешние источники финансовых данных.
- Для D3.js и веб-шрифтов браузеру нужен доступ к указанным CDN. Основные расчёты графа выполняются локально по файлам Parquet.
Ограничения текущей версии
- Анализ относится только к предоставленной выгрузке. Seed-клиенты могут иметь неполную историю входящих переводов.
- Узел без исходящих рёбер на глубине 4 может быть концом обхода, а не реальным конечным получателем. Роль
terminalозначает только наблюдаемый конец потока внутри выборки. - Роли,
role_scoreи рейтинг приоритета эвристические.role_scoreне является вероятностью, а кластерные гипотезы — подтверждением нарушения. - Louvain работает на неориентированной проекции, поэтому при выделении кластеров направление потоков теряется.
- Трассировка графа ограничена пятью переходами и 500 узлами; списки результатов инструментов ограничены 200 записями. AI-ассистент ограничен шестью раундами и двенадцатью вызовами инструментов на запрос.
- Чат требует отдельного ключа и доступного OpenAI API. Без них доступны остальные функции приложения.
- Данные, выдаваемые OpenAI, зависят от ответа внешней модели; фактические сведения о графе должны поступать через инструменты, но формулировки ответа создаёт модель.
Масштабирование примерно до 1 млн узлов
Текущая реализация хранит граф как объекты NetworkX в памяти, что удобно для набора из 2 248 узлов, но создаёт большой накладной расход памяти на миллионных графах. Для такого объёма следует перейти на компактное CSR-представление рёбер и векторизованные разреженные операции для степеней, оборотов и PageRank; Louvain считать библиотекой, рассчитанной на крупные графы, либо по связным компонентам, если их независимость подтверждена. CSV-выгрузки нужно формировать пакетно, а для просмотра показывать выбранный узел, его окрестность и агрегаты вместо одновременного рендеринга миллиона вершин. Потребление памяти и время пересчёта следует измерить на целевом оборудовании до выбора размера пакета и параметров.
Развернутая версия
Ссылка на deployed-версию в текущем репозитории не указана.
Авторы коммитов
История коммитов
- 2026-09-23 17:59YEsAisul_Alp
- 2026-09-23 17:30Readme file updatedAisul_Alp
- 2026-09-23 17:22deleted app.py and changed the ai assitant locationAisul_Alp
- 2026-09-23 16:53Changes to starter.pyAisul_Alp
- 2026-09-23 16:49Merge branch 'main' of https://github.com/BAITC-Hacks/hack-bbfda7b2-goskzAisul_Alp
- 2026-09-23 16:46Changes to interfaceAisul_Alp
- 2026-09-23 16:02Changes to interfaceAisul_Alp
- 2026-09-23 15:45Some ChangesAisul_Alp
Все коммиты (22)
- 2026-09-23 17:05AI + Interfacetaz
- 2026-09-23 14:41Add loading interface and a folderAisul_Alp
- 2026-09-23 16:36messagetaz
- 2026-09-23 16:31Merge branch 'main' of https://github.com/BAITC-Hacks/hack-bbfda7b2-goskztaz
- 2026-09-23 16:27tools connectionstaz
- 2026-09-23 14:19added some interface and added my env to detected by git ignoreAisul_Alp
- 2026-09-23 13:29From data zipAisul_Alp
- 2026-09-23 13:25From the starter fileAisul_Alp
- 2026-09-23 14:44convcsvtaz
- 2026-09-23 14:43Merge branch 'main' of https://github.com/BAITC-Hacks/hack-bbfda7b2-goskztaz
- 2026-09-23 14:41convcsvtaz
- 2026-09-23 13:43outtaz
- 2026-09-23 13:32reqtaz
- 2026-09-23 13:12requirementstaz
Структура репозитория (18 файлов)
.gitignore README.md agent.py agent_tools.py aml_agent.py docs/agent_tools.md docs/aml_agent.md interface/network_app.py parquet/edges.parquet parquet/nodes.parquet parquet/transactions.parquet prompts.py requirements.txt starter.py tests/test_agent_tools.py tests/test_aml_agent.py tests/test_starter.py tool_registry.py
Обсуждение 0 комментариев
Войдите, чтобы комментироватьПока нет комментариев — будьте первым.