Graphify: построение графа знаний из кода
Разбираем Graphify — инструмент для создания графа знаний из исходного кода, документации и схем SQL без использования векторных хранилищ.
Как Graphify превращает код в знания
Как Graphify превращает код в знания
Когда мы говорим об анализе кодовой базы, мы часто попадаем в ловушку: либо пытаемся скормить всё подряд в LLM, надеясь на её контекстное окно, либо строим громоздкие RAG-системы с векторным поиском. Оба подхода имеют изъян — они работают с вероятностями, а не с фактами. Если агент «догадывается», что функция calculate_total вызывает get_user_balance, он может ошибиться. В критически важных системах такая неопределённость недопустима.
Graphify меняет подход, превращая разрозненные файлы в структурированную сеть взаимосвязей. Вместо того чтобы искать похожие по смыслу куски текста, инструмент выстраивает карту того, как компоненты системы реально взаимодействуют друг с другом.
Принцип работы детерминированного AST-парсинга
В основе Graphify лежит не семантический поиск, а детерминированный разбор синтаксического дерева (AST). Если говорить проще, инструмент не «читает» код как текст, он понимает его структуру так, как это делает компилятор.
Процесс выглядит следующим образом:
- Парсинг: С помощью специализированных парсеров Graphify превращает исходный код в AST. Это позволяет точно определить, где заканчивается объявление класса и начинается метод, а где — вызов функции. Подробнее о том, как реализован этот процесс, можно прочитать в статье Graphify-Labs/graphify: локальный AST‑парсинг кода.
- Извлечение сущностей: Из дерева вытягиваются конкретные узлы: определения функций, классы, переменные, импорты и даже схемы таблиц из SQL-миграций.
- Построение связей: На этом этапе формируются ребра графа. Если в файле
auth.pyвызывается функция изutils.py, в графе знаний появится прямая связь.
С практической точки зрения это даёт предсказуемость. Если вы измените сигнатуру метода, граф обновится и покажет все точки разрыва, а не просто предложит «похожий» код. Для понимания того, как такие глубокие знания помогают автоматизации, рекомендую изучить материал Навыки реальных инженеров: практики из .agents.
Пример того, как Graphify может интерпретировать простую структуру на Python:
python# Исходный код
class OrderProcessor:
def process(self, order_id: int):
user = db.get_user(order_id)
return user.status
В графе это превратится не в набор токенов, а в цепочку:
OrderProcessor $\to$ process() $\to$ db.get_user() $\to$ User.status.
Отличие от классических векторных хранилищ
Главное различие здесь — в природе данных. Векторные хранилища (Vector DB) полагаются на эмбеддинги. Они переводят текст в многомерные векторы и ищут ближайших «соседей» по косинусному сходству. Это отлично работает для поиска документации по ключевым словам, но плохо справляется с логикой кода.
| Характеристика | Векторные хранилища (RAG) | Graphify (Knowledge Graph) |
|---|---|---|
| Тип данных | Неструктурированный текст / эмбеддинги | Структурированные связи (AST) |
| Точность | Вероятностная (может галлюцинировать) | Детерминированная (строго по коду) |
| Контекст | Похожие фрагменты кода | Реальные зависимости и вызовы |
| Сложные запросы | «Найди код, похожий на этот» | «Покажи все функции, зависящие от этой таблицы» |
Если мы используем классический RAG, агент может найти функцию, которая выглядит как нужная, но на самом деле не имеет к текущей задаче отношения. Graphify же позволяет строить запросы на основе топологии кода. Это критически важно при работе с AI-агентами, такими как DietrichGebert/ponytail: AI‑агент как ленивый senior dev, где точность понимания архитектуры определяет качество предложенного решения.
Вместо того чтобы гадать, Graphify даёт агенту «карту местности». Это позволяет избежать ошибок при рефакторинге или добавлении новых фич, так как агент видит не просто куски текста, а живую структуру приложения. Более детально о концепции работы с кодовой базой через графы можно узнать в материале Graphify: построение графа знаний из кодовой базы.
Архитектура и возможности инструмента
Архитектура и возможности инструмента
Главное отличие Graphify от большинства современных AI-решений — отказ от классического подхода с векторными базами данных (RAG). Вместо того чтобы нарезать код на куски и искать похожие фрагменты по сходству векторов, инструмент строит явную структуру связей. Если мы посмотрим на архитектуру, то увидим, что в основе лежит глубокий анализ синтаксического дерева (AST). Это позволяет сохранить предсказуемость: инструмент понимает, что функция A вызывает функцию B, а не просто «что-то похожее на функцию A».
Подробнее о том, как именно происходит локальный AST-парсинг кода, я рассказывал в предыдущем материале. Здесь же мы разберем, какие именно типы данных Graphify может превратить в узлы графа.
Анализ SQL-схем и конфигурационных файлов
Обычно AI-агенты пасуют перед инфраструктурным кодом или сложными схемами БД, потому что их контекстное окно забивается неструктурированным текстом. Graphify решает эту проблему, рассматривая SQL-схемы и конфигурации как объекты со строгими связями.
При анализе SQL-дампов инструмент выстраивает граф зависимостей между таблицами, внешними ключами (Foreign Keys) и индексами. Это критически важно, когда вам нужно, чтобы агент понимал не только «какие есть таблицы», а «как изменение типа данных в таблице users повлияет на связанные представления (views)».
С практической точки зрения, это работает так: вы подаёте на вход .sql файлы, и на выходе получаете граф, где узлы — это сущности БД, а ребра — связи между ними. То же самое касается и конфигурационных файлов (например, YAML для Kubernetes или конфигурации Nginx).
Пример того, как Graphify интерпретирует типичную схему:
sql-- Graphify распознает эту связь как ребро в графе
CREATE TABLE orders (
id UUID PRIMARY KEY,
user_id UUID REFERENCES users(id), -- Создает связь между узлами orders и users
status VARCHAR(20) NOT NULL
);
Если вы планируете использовать это для автоматизации развертывания, рекомендую ознакомиться с материалом о навыках реальных инженеров, чтобы понимать, как правильно готовить контекст для агентов.
Интеграция с Claude Code и Cursor
Сама по себе карта связей полезна, но она обретает смысл только тогда, когда её может использовать «умный» помощник. Graphify спроектирован так, чтобы поставлять структурированный контекст в инструменты вроде Claude Code или Cursor.
В случае с Claude Code, инструмент выступает в роли поставщика высокоточных данных. Вместо того чтобы заставлять модель гадать по содержимому файлов, Graphify передаёт ей четкую топологию проекта. Это позволяет избежать галлюцинаций, когда агент пытается вызвать несуществующий метод или обращается к неверной таблице.
Для эффективной работы с Claude Code я рекомендую сначала подготовить контекстные инструкции. Хорошим подходом будет создание CLAUDE.md, где вы пропишете правила использования графа.
Процесс интеграции в рабочем окружении выглядит следующим образом:
- Генерация графа: Вы запускаете Graphify в корне проекта, сканируя исходники и схемы.
- Экспорт контекста: Инструмент формирует компактное представление связей (например, в формате JSON или специализированного текстового описания).
- Подключение к IDE/CLI: Вы указываете Claude Code или Cursor путь к этому описанию.
Если вы используете Cursor, вы можете добавить сгенерированный граф в .cursorrules. Это превратит ваш редактор из простого автодополнения в инструмент, который «видит» архитектуру всего проекта целиком. Подобный подход к автоматизации рутины напоминает концепцию AI-агента как ленивого senior dev — мы не просто просим написать код, а даём агенту понимание того, как этот код вписывается в существующую систему.
В итоге мы получаем предсказуемый результат: агент не просто пишет функции, он соблюдает архитектурные границы, заложенные в графе.
Практическое применение в разработке
Улучшение контекста для AI-агентов
Когда мы работаем с современными AI-агентами, главной проблемой становится «галлюцинация» из-за неполного контекста. Стандартные методы, вроде передачи содержимого файлов целиком, быстро упираются в лимиты контекстного окна или превращают сессию в кашу из нерелевантных данных. Если вы используете DietrichGebert/ponytail или подобные инструменты, вы знаете, что агент должен понимать не просто текст, а структуру связей.
Graphify решает эту задачу иначе, чем классический RAG (Retrieval-Augmented Generation) с векторными базами данных. Вместо того чтобы искать похожие куски текста, агент получает структурированный граф. Это позволяет передавать в LLM не «похожие функции», а конкретную цепочку вызовов.
С практической точки зрения это выглядит так: вместо того чтобы скармливать модели 50 файлов проекта, мы формируем запрос на основе узлов графа. Например, если нам нужно изменить логику обработки заказов, агент запрашивает связи конкретного класса OrderService и получает только те методы и зависимости, которые реально на него влияют.
Для интеграции в рабочий процесс можно подготовить конфигурационный файл, который определяет границы сканирования. В Graphify это позволяет сфокусировать извлечение знаний на критических узлах:
yaml# Пример конфигурации для фокусировки на бизнес-логике
extraction_rules:
include_paths:
- "src/services/**/*.ts"
- "src/models/**/*.py"
exclude_paths:
- "**/tests/**"
- "**/dist/**"
focus_nodes:
- "OrderProcessor"
- "PaymentGateway"
Такой подход делает работу агента предсказуемой. Он не пытается угадать, как работает метод, а видит его в контексте AST-дерева, которое было построено через локальный AST-парсинг. Это критически важно для таких инструментов, как Claude Code, где точность понимания структуры проекта напрямую влияет на качество генерируемого кода.
Навигация по сложным зависимостям проекта
В крупных монорепозиториях или распределенных системах поиск места, где «что-то сломалось», превращается в детективную работу. Традиционный поиск по тексту (grep) часто подводит, потому что он не учитывает семантику: он найдет все упоминания user_id, но не скажет вам, как этот ID проходит через слои абстракции от API до уровня базы данных.
Graphify позволяет визуализировать и программно обходить зависимости. Если мы посмотрим на типичную архитектуру, где бизнес-логика отделена от слоя доступа к данным, граф знаний свяжет их через явные интерфейсы и SQL-схемы.
Представьте, что вам нужно провести рефакторинг схемы базы данных. С помощью графа вы можете выполнить запрос, который покажет не только таблицы, но и все программные сущности, которые зависят от конкретного столбца. Это избавляет от ситуации, когда вы изменили тип поля в PostgreSQL, а половина сервисов упала в рантайме из-за несоответствия типов в коде.
Для автоматизации анализа зависимостей можно использовать CLI-интерфейс. Например, чтобы получить список всех зависимых компонентов для конкретного модуля, команда будет выглядеть примерно так:
bash# Получение графа зависимостей для конкретного модуля
graphify analyze --module "src/auth" --output dependencies.json
Полученный JSON-файл можно использовать для построения карт покрытия или для автоматической генерации документации. Это гораздо надежнее, чем писать документацию вручную, которая устаревает сразу после первого коммита.
Если вы хотите внедрить это в свой процесс разработки, рекомендую начать с построения графа знаний из кодовой базы, чтобы понять, насколько глубоко инструмент может «прорасти» в вашу архитектуру. Это превращает навигацию по коду из процесса «чтения файлов» в процесс «исследования связей».
Ограничения и сценарии использования
Когда графа знаний будет недостаточно
Graphify — это отличный инструмент для структурирования связей, но важно понимать его границы. Он работает на основе AST (Abstract Syntax Tree) и статического анализа, что даёт нам высокую точность в понимании того, как код связан с кодом. Однако предсказуемость системы падает, когда мы переходим от статики к динамике.
Во-первых, граф не видит рантайм-поведение. Если ваш сервис использует рефлексию или динамическую загрузку модулей, которые не прописаны в явных импортах, Graphify не сможет построить корректную связь. Для таких случаев лучше использовать навыки реальных инженеров: практики из .agents, где упор делается на понимание контекста выполнения, а не только структуры файлов.
Во-вторых, инструмент не заменяет полноценный RAG (Retrieval-Augmented Generation) с векторным поиском в задачах, требующих семантического сходства. Граф идеально отвечает на вопросы типа «какие функции вызывают этот метод?», но он может пасовать перед вопросом «найди все места, где логика обработки платежей похожа на этот кусок кода». Здесь графу не хватает «смыслового веса», который дают эмбеддинги.
С практической точки зрения, не стоит пытаться скормить Graphify огромные бинарные файлы или скомпилированные артефакты. Он заточен под текстовые исходники и схемы. Если ваша задача — анализировать поведение системы через логи или дампы памяти, вам понадобятся другие инструменты мониторинга и анализа.
Требования к локальному запуску
Поскольку Graphify не использует тяжеловесные векторные базы данных, его требования к ресурсам значительно ниже, чем у типичных AI-решений. Это позволяет запускать его даже на небольших домашних серверах или в рамках локального AST-парсинга кода.
Тем не менее, процесс построения графа — это вычислительно сложная задача, требующая интенсивного парсинга и обхода дерева зависимостей.
Для стабильной работы в вашей домашней лаборатории ориентируйтесь на следующие параметры:
- Процессор (CPU): Минимум 4 ядра. Парсинг больших репозиториев сильно зависит от однопоточной производительности, но для параллельной обработки файлов важна многопоточность.
- Оперативная память (RAM): От 8 ГБ. Если вы анализируете монолит на несколько миллионов строк кода, лучше иметь 16 ГБ и выше, чтобы избежать свопинга при построении графа в памяти.
- Дисковое пространство: SSD обязателен. Скорость чтения тысяч мелких файлов исходного кода напрямую влияет на время сборки графа.
Если вы планируете разворачивать инструмент через Docker, убедитесь, что вы выделили контейнеру достаточно лимитов. Вот пример конфигурации для docker-compose.yml, чтобы избежать внезапных падений из-за OOM (Out of Memory) killer:
yamlservices:
graphify:
image: graphify/core:latest
deploy:
resources:
limits:
memory: 8G # Резервируем запас под тяжелые репозитории
reservations:
memory: 4G
volumes:
- ./my-project:/src:ro # Монтируем код только для чтения
- ./graph-data:/data
command: ["--path", "/src", "--output", "/data/graph.json"]
При запуске всегда проверяйте доступность прав на чтение в целевой директории. Если вы работаете с проектами, где используется сложная структура путей, лучше сначала протестировать парсинг на небольшом подмножестве файлов. Это поможет понять, сколько ресурсов реально потребляет ваш конкретный стек.
FAQ
Нужно ли настраивать векторную базу данных?
Нет, в этом и заключается одно из главных архитектурных отличий Graphify. В отличие от классических RAG-систем (Retrieval-Augmented Generation), которые полагаются на поиск по сходству в векторных хранилищах, этот инструмент строит явные связи между сущностями через AST-парсинг.
Вместо того чтобы превращать куски кода в наборы чисел (эмбеддинги), Graphify анализирует структуру: где объявлена функция, как она вызывается и к какой таблице в базе данных привязана. Это обеспечивает гораздо более высокую предсказуемость ответов. Если вам нужно разобраться в логике работы конкретного модуля, вам не придется надеяться на то, что векторный поиск «подобрал похожий контекст» — вы получите точную карту зависимостей. Подробнее о том, как работает локальный AST-парсинг кода, читайте в нашем техническом разборе.
Какие типы файлов поддерживает Graphify?
Инструмент ориентирован на глубокий анализ структуры проекта, поэтому его поддержка ограничена форматами, из которых можно извлечь семантику. На текущий момент Graphify эффективно работает со следующими типами данных:
- Исходный код: основные языки с развитой поддержкой AST (Python, TypeScript, Go, Rust).
- Схемы баз данных: SQL-дампы или файлы миграций, которые позволяют связать программный код с архитектурой хранения.
- Документация: файлы в форматах Markdown и JSON.
Если вы планируете использовать инструмент для анализа крупного монолита, рекомендую сначала ознакомиться с тем, как построить граф знаний из кодовой базы, чтобы правильно подготовить структуру файлов.
Как инструмент работает с документацией в PDF?
Напрямую «переваривать» PDF-файлы Graphify не умеет. Это связано с тем, что PDF — это формат представления, а не структурированного хранения данных, и извлечение из него чистой семантики без потерь — задача сложная.
Чтобы добавить информацию из PDF в граф, её нужно предварительно конвертировать в Markdown. Это позволит сохранить иерархию заголовков и списков, что критически важно для корректного построения связей. С практической точки зрения, проще всего использовать специализированные утилиты для парсинга текста, а затем подавать на вход Graphify уже структурированный .md файл.
Можно ли использовать Graphify локально?
Да, инструмент спроектирован с упором на работу в локальном окружении. Это позволяет анализировать приватные репозитории, не отправляя исходный код на сторонние серверы.
Для запуска в своей домашней лаборатории или на рабочем сервере достаточно развернуть его через Docker. Пример базового запуска:
bash# Запуск контейнера с пробросом текущей директории проекта
docker run --rm -v $(pwd):/app graphify-tool analyze /app/src
Такой подход гарантирует, что все операции по построению графа происходят внутри вашего контура. Это особенно важно, если вы строите сложные системы с использованием AI-агентов, где безопасность данных является приоритетом.
Часто задаваемые вопросы
Как Graphify справляется с динамическим кодом: рефлексией, динамическими импортами и eval?
AST-парсинг по определению работает со статической структурой — он видит то, что записано в исходнике на момент разбора. Если ваш проект активно использует __import__, importlib, getattr или генерирует код в рантайме, Graphify эти связи не найдёт, так как их не существует в синтаксическом дереве. На практике это означает: для Django-проектов с apps.py и автодискавери, для плагинных архитектур и метапрограммирования придётся либо добавлять аннотации вручную, либо дополнять граф данными из логов выполнения. Инструмент не пытается угадать — он фиксирует только то, что детерминированно извлекается из кода.
Какие языки программирования и форматы поддерживаются на данный момент?
На текущий момент Graphify имеет полноценные парсеры для Python, TypeScript/JavaScript, Go, Rust и SQL (PostgreSQL, MySQL диалекты миграций). Для остальных языков работает fallback на tree-sitter — он вытянет функции, классы и импорты, но не поймёт специфику языка (декораторы в Python, трейты в Rust, интерфейсы в Go). Документация в Markdown и OpenAPI-спеки парсятся отдельно и привязываются к сущностям кода по именованию. Если вашего языка нет в списке — можно написать свой парсер, подключившись к внутреннему API, но это уже задача уровня «день-два работы инженера».
Чем Graphify принципиально отличается от CodeQL, ctags или LSP-индексации?
CodeQL — это движок для поиска уязвимостей и паттернов, он требует написания запросов на QL и заточен под безопасность, а не под навигацию по архитектуре. Ctags и LSP дают «перейти к определению» и список референсов, но не строят семантический граф связей между модулями, не знают про схему БД и не агрегируют документацию. Graphify решает другую задачу: собирает единую карту «что вызывает что», «что хранит где», «где описано API» — и отдаёт её в формате, удобном для LLM-агентов и автоматической генерации диаграмм. Это не замена LSP, а слой выше — для понимания системы целиком, а не отдельного файла.
В каком формате выдаётся граф и как его можно использовать дальше?
На выходе — JSONL с узлами и рёбрами, а также опционально GraphML и Cypher-дамп для Neo4j. Схема документирована: у каждого узла есть стабильный id, type (function, class, table, module, doc), file_path, span (начало/конец в байтах), и набор атрибутов, зависящих от типа. Рёбра носят типы: calls, imports, inherits, references_table, documented_by. Это позволяет загрузить граф в любую графовую БД, написать свой визуализатор на Cytoscape/D3, или скормить в LLM как структурированный контекст для генерации архитектурной документации. Никаких проприетарных бинарников — только открытые форматы.
Можно ли запускать Graphify в CI/CD для обновления графа при каждом пуше?
Да, и это рекомендуемый сценарий. Инструмент работает инкрементально: при повторном запуске он перепарсит только изменившиеся файлы (по хэшу содержимого) и обновит соответствующие подграфы. Типичное время на кодовой базе в 50 тысяч строк — 15–30 секунд на современном CI-раннере. В конфиге задаёте output_dir, include_patterns и exclude_patterns (обычно **/migrations/**, **/tests/**, **/vendor/**). Артефакт графа загружаете как CI-артефакт или пушите в внутренний реестр — дальше ваши агенты или документация всегда работают с актуальным состоянием.