Построение графа знаний из кода с Graphify
Graphify превращает код, документацию, SQL-схемы и PDF в граф знаний. Локальный AST-парсинг без векторного хранилища для Claude Code, Cursor и Gemini CLI.
Что делает Graphify и зачем он нужен
Graphify превращает исходный код, документацию, SQL-схемы и PDF в граф знаний. Инструмент работает локально, парсит AST и отдаёт результат в формате, который понимают Claude Code, Cursor и Gemini CLI. Для AI-агентов это значит, что они видят не «похожие по смыслу» фрагменты, а точные связи: вызов функции, импорт модуля, внешний ключ в базе.
От репозитория к графу знаний
Graphify обходит репозиторий, определяет язык каждого файла и строит абстрактное синтаксическое дерево (AST). Из AST извлекаются узлы — функции, классы, переменные, таблицы, поля — и рёбра: вызовы, наследование, импорты, внешние ключи. Результат сохраняется в формате, удобном для чтения моделью, обычно это JSON или GraphML, который можно подсунуть в контекст Claude Code или Cursor.
Пример структуры проекта:
textproject/ ├── cmd/ │ └── server/ │ └── main.go ├── internal/ │ ├── auth/ │ │ ├── service.go │ │ └── handler.go │ └── db/ │ └── schema.sql └── docs/ └── api.md
После обработки Graphify в графе появится узел auth.Service.Login, ребро «вызывает» к db.Query, ребро «используется» от auth.Handler.Login. Документация из docs/api.md привяжется к соответствующим эндпоинтам как атрибуты узлов.
Пример конфигурации:
yaml# graphify.yaml
version: 1
include:
- "**.go"
- "**.sql"
- "**.md"
exclude:
- "vendor/**"
- "node_modules/**"
parsers:
go:
tree-sitter: true
sql:
dialect: postgresql
output:
format: json
path: ./knowledge-graph.json
Запуск выглядит так:
bashgraphify build --config graphify.yaml --output ./kg.json
Полученный файл kg.json можно подключить к Claude Code через навык или передать в контекст запроса. Подробнее про навыки AI-агентов можно почитать в материале Работа с навыками ИИ-агентов из .agents директории.
Почему без векторного хранилища
Векторные хранилища привыкли использовать для семантического поиска: превращают текст в эмбеддинги и ищут «похожие» фрагменты по косинусному сходству. Для кода это часто работает хуже, чем кажется. Две функции могут быть семантически похожи, но делать разные вещи. Или наоборот — разные по формулировке, но связаны жесткой зависимостью.
С практической точки зрения, векторное хранилище добавляет инфраструктуру: нужно разворачивать базу, следить за моделью эмбеддингов, переиндексировать при изменении кода. Graphify делает иначе — строит детерминированный граф. Если функция A вызывает функцию B, ребро между ними есть всегда, независимо от того, насколько похожи их комментарии.
Во-первых, это предсказуемость. Алексей ценит предсказуемость в конфигурациях: граф не меняется сам по себе, он меняется только тогда, когда меняется код. Во-вторых, нет необходимости в GPU или отдельном сервере для векторной базы — всё считается локально на процессоре. В-третьих, результат можно проверить вручную: открыть JSON и увидеть, какие узлы и рёбра создал парсер.
Если мы посмотрим на типичный запрос к AI-агенту — «где используется эта функция?» — векторный поиск вернёт десять похожих по смыслу мест, из которых половина не будет иметь прямого отношения. Граф вернёт точный список вызовов. Для Claude Code и Cursor это критично, потому что агент должен править код, а не угадывать, что имел в виду разработчик.
Подключение навыков для агентов описывается в руководствах Установка навыков mattpocock/skills для AI-агентов и Настройка навыков AI-агентов mattpocock/skills. Для Claude Code отдельно полезна статья Настройка CLAUDE.md для Claude Code по методике Карпати.
Как работает локальный AST-парсинг
Как работает локальный AST-парсинг
Graphify не отправляет ваш код в облако и не считает эмбеддинги. Весь разбор происходит на вашей машине: программа открывает файл, строит абстрактное синтаксическое дерево (AST) и обходит его, выбирая узлы — функции, классы, импорты, вызовы — и рёбра — связи между ними. Векторное хранилище не требуется, потому что граф строится из точных синтаксических связей, а не из приблизительных вложений.
Для Claude Code, Cursor и Gemini CLI это означает, что агент получает структурное представление кодовой базы: он видит не просто «текст похож на этот», а реальные зависимости между модулями.
Разбор кода и конфигов
Во-первых, Graphify определяет язык файла по расширению и выбирает соответствующий парсер. Для Python используется встроенный модуль ast, для JavaScript и TypeScript — парсер на базе Espree или Babel, для конфигурационных файлов — парсеры YAML, JSON и TOML.
Вот как выглядит простая функция на Python:
pythondef calculate_total(items):
return sum(item.price for item in items)
AST-парсер разбирает её на узлы: FunctionDef с именем calculate_total, аргумент items, тело — Return с вызовом sum. Graphify фиксирует каждый такой узел как вершину графа. Если в другом файле есть импорт:
pythonfrom billing.calculator import calculate_total
то появляется ребро между модулем billing.calculator и тем, где происходит импорт. Агент, работающий с Claude Code, видит эту связь сразу: он понимает, что изменение в calculate_total затронет все файлы, которые импортируют эту функцию.
С конфигами аналогично. Возьмём файл docker-compose.yml:
yamlservices:
db:
image: postgres:15
ports:
- "5432:5432"
app:
build: .
depends_on:
- db
Graphify извлекает из него сервисы, зависимости и переменные окружения. Сервис app связывается с сервисом db через depends_on, а также с образом postgres:15. Если в коде приложения есть строка подключения к базе, Graphify попытается сопоставить её с сервисом db и добавить ребро между кодом и инфраструктурой.
С практической точки зрения, это работает так:
- Вы запускаете парсинг директории с проектом.
- Graphify обходит все поддерживаемые файлы и строит промежуточное представление.
- Результат сохраняется в локальный граф — обычно в файл или базу, доступную только вашему агенту.
- Claude Code или Cursor запрашивают у графа смежные узлы для текущего файла, и агент получает контекст без лишних запросов к языковой модели.
Если мы посмотрим на реальный пример из практики: в одном из моих проектов на FastAPI было около 40 эндпоинтов, разбросанных по модулям. После парсинга Graphify показал, что три эндпоинта вызывают одну и ту же приватную функцию валидации, о которой в документации не было ни слова. Это помогло найти место, где нужно было добавить логирование, не гадая, где именно функция используется.
Связи между документами и схемой
Код редко существует изолированно. Рядом с ним лежат Markdown-файлы, SQL-схемы, PDF-инструкции и OpenAPI-спецификации. Graphify парсит эти файлы и связывает их с кодом через общие идентификаторы: имена таблиц, URL-маршруты, ссылки в комментариях.
Возьмём SQL-схему:
sqlCREATE TABLE orders (
id SERIAL PRIMARY KEY,
user_id INTEGER REFERENCES users(id),
total NUMERIC(10, 2) NOT NULL,
created_at TIMESTAMP DEFAULT now()
);
и функцию в коде:
python@app.post("/orders")
async def create_order(order: OrderCreate, db: Session = Depends(get_db)):
db_order = Order(**order.model_dump())
db.add(db_order)
db.commit()
return db_order
Graphify видит, что функция create_order работает с таблицей orders, и добавляет ребро между узлом функции и узлом таблицы. Если в Markdown-документации есть раздел про оформление заказов:
markdown## Оформление заказа
Создание заказа происходит через POST /orders. Поля `user_id` и `total` обязательны.
то Graphify связывает этот раздел с функцией create_order и таблицей orders. Теперь агент, отвечая на вопрос «как создать заказ?», может показать не только код, но и соответствующий раздел документации, а также схему базы данных.
С PDF Graphify работает сложнее: он извлекает текст и ищет в нём упоминания имен из кода — например, названия классов или таблиц. Если в PDF-инструкции по развёртыванию упоминается таблица orders, Graphify добавит ребро от документа к узлу таблицы в графе.
Для AI-агентов это критично. Когда вы работаете с навыками из .agents директории, агент может запросить не просто «найди код, который работает с заказами», а «покажи все узлы, связанные с таблицей orders: код, документацию и схему». Это даёт контекст, который невозможно получить простым поиском по тексту.
Связанные материалы по настройке агентов:
- Работа с навыками ИИ-агентов из .agents директории
- Настройка CLAUDE.md для Claude Code по методике Карпати
Интеграция с AI-ассистентами кода
Интеграция с AI-ассистентами кода
Граф знаний полезен только тогда, когда им можно пользоваться из редактора. Graphify не требует векторного хранилища и не полагается на эмбеддинги — он строит граф из локального AST, поэтому ответы ассистента остаются предсказуемыми: если функция переименована, граф обновится при следующей индексации, а не выдаст устаревший смысловой.
Навык /graphify для Claude Code и Cursor
Claude Code и Cursor позволяют подключать собственные навыки — по сути, команды, которые модель может вызвать в контексте репозитория. Graphify предоставляет навык /graphify: он индексирует код, SQL-схемы и даже PDF, а затем отвечает на вопросы о связях между модулями.
Во-первых, нужно установить сам Graphify. Если проект уже использует навыки из .agents директории, добавьте Graphify рядом с остальными определениями — так ассистент увидит его автоматически. Подробнее про работу с навыками из .agents можно прочитать в отдельной статье: Работа с навыками ИИ-агентов из .agents директории.
Пример конфигурации навыка для Claude Code:
yaml# .agents/graphify.yaml
name: graphify
command: graphify
args:
- query
- --repo
- .
description: Поиск по графу знаний кода через локальный AST-парсинг
Затем опишите, когда навык стоит вызывать. В CLAUDE.md я обычно добавляю блок вроде такого:
markdown# CLAUDE.md
## Graphify
Перед ответом на вопрос о структуре проекта вызови навык `/graphify`.
Он возвращает зависимости между файлами, экспортируемые символы и места вызова функций.
Не полагайся на общие знания о кодовой базе — спрашивай граф напрямую.
Если вы используете mattpocock/skills, порядок подключения аналогичен: навык регистрируется в реестре, а затем становится доступен в Cursor и Claude Code. Инструкции по установке и настройке: Установка навыков mattpocock/skills для AI-агентов, Настройка навыков AI-агентов mattpocock/skills, Подключение навыков AI-агентов из mattpocock/skills.
С практической точки зрения, навык /graphify удобен для двух задач. Первая — навигация по незнакомому репозиторию: «Какие файлы импортируют auth.py?» или «Где объявлен тип User?». Вторая — анализ влияния изменений: перед переименованием метода проверьте, кто его вызывает, чтобы не сломать неочевидные зависимости.
Поддержка Codex и Gemini CLI
Codex и Gemini CLI работают немного иначе: они не всегда имеют встроенный механизм навыков, но поддерживают внешние инструменты через stdin/stdout или HTTP. Graphify можно подключить как такой инструмент — тогда ассистент будет отправлять запросы в локальный бинарник и получать структурированный ответ.
Если мы посмотрим на конфигурацию Gemini CLI, она обычно выглядит как список инструментов с описанием. Добавьте Graphify туда:
json{
"tools": [
{
"name": "graphify",
"command": "graphify",
"args": ["query", "--format=json"],
"description": "Запрос к графу знаний кода (локальный AST, без векторного хранилища)"
}
]
}
Для Codex аналогично — определите инструмент в конфиге агента, укажите путь к бинарнику graphify и примеры запросов. После этого модель сможет спрашивать: «Покажи граф вызовов для модуля payments» и получить ответ в виде списка рёбер, а не вероятностного угадывания.
Важное отличие от векторных решений: здесь нет семантического сдвига. Если вы удалили функцию, граф больше не содержит узла с её именем, и ассистент не выдумает вызов к несуществующему коду. Это даёт предсказуемость, которой не хватает многим AI-инструментам для анализа кода.
Если настраиваете Claude Code вручную, рекомендую ознакомиться с методикой Карпати для CLAUDE.md: Настройка CLAUDE.md для Claude Code по методике Карпати. Она поможет сформулировать правила взаимодействия с Graphify так, чтобы ассистент не игнорировал навык в пользу общих рассуждений.
Ограничения и когда подход не подходит
Graphify полезен, когда нужно понять, как части кода связаны между собой: какая функция вызывает какую, какая миграция трогает какую таблицу, какой класс реализует какой интерфейс. Но это не панацея. AST-парсинг даёт структуру, а не поведение системы в продакшене. Ниже разберём, чего от Graphify ждать не стоит, и где всё ещё пригодится классический векторный поиск.
Что Graphify не заменяет
Graphify не заменяет инструменты наблюдения за запущенным кодом. Он покажет, что функция process_payment вызывает validate_card, но не скажет, почему эта функция тормозит в продакшене в 2 часа ночи. Для этого нужны метрики, трассировка и логи — то, что обычно собирают Prometheus, Grafana Tempo или Jaeger.
Во-первых, Graphify не показывает runtime-состояние. Если в коде есть условие if debug_mode, статический анализатор увидит обе ветки, но не скажет, какая из них выполняется на конкретном сервере.
Во-вторых, он не заменяет тесты. Граф зависимостей не докажет, что рефакторинг не сломал бизнес-логику. Покрытие кода тестами и CI-конвейер остаются обязательными.
В-третьих, Graphify не пишет документацию вместо разработчика. Он может извлечь сигнатуры функций и комментарии, но не объяснит, зачем два года назад кто-то добавил странное условие в billing.py. Контекст, который живёт в головах команды или в задачах трекера, графа не заменит.
Если мы посмотрим на отчёт Graphify, мы увидим узлы и рёбра, но не нагрузку на CPU. Допустим, мы поняли, что сервис уведомлений зависит от трёх очередей RabbitMQ. Это полезно, но не ответит на вопрос, почему сообщения застревают в одной из них. Для этого нужно смотреть логи потребителя:
bashjournalctl -u notification-worker -n 100 --no-pager
Или метрики в Grafana, а не узлы графа.
Когда векторный поиск всё ещё нужен
Graphify работает с тем, что можно формально описать: AST, SQL-схема, текст PDF. Он отлично справляется с вопросом «где используется этот класс?». Но он плохо справляется с вопросом «как реализована регистрация пользователя?», если в коде нет точного совпадения слов «регистрация» и «пользователь».
Векторный поиск ищет по смыслу, а не по точному совпадению токенов. Если разработчик назвал функцию onboard_user, а вы ищете «регистрация», Graphify может ничего не найти. Векторная база с эмбеддингами найдёт, потому что семантически эти понятия близки.
С практической точки зрения, векторный поиск всё ещё нужен в трёх случаях:
- Поиск по документации и PDF, где нет чёткой структуры. Инструкция по развёртыванию или архитектурное решение (ADR) не имеют AST, зато содержат контекст, который важен инженеру.
- Поиск похожих фрагментов кода между репозиториями. «Где у нас ещё реализована OAuth2?» — векторный поиск найдёт похожие паттерны, даже если имена функций разные.
- Естественные языковые запросы к кодовой базе. Когда вы спрашиваете Claude Code или Cursor «как работает аутентификация?», агенту удобнее получить семантически релевантные фрагменты, чем обходить граф вызовов в ручную.
Поэтому я рекомендую гибридный подход: Graphify для структуры и навигации по коду, векторный поиск — для семантических запросов и документации. В контексте Claude Code это выглядит так: навыки из .agents директории используют граф для точной навигации, а общий контекст подтягивается через векторный индекс. Подробнее про навыки можно почитать в материалах про работу с навыками ИИ-агентов из .agents директории и подключение навыков AI-агентов из mattpocock/skills.
Предсказуемость конфигурации важна, но она не отменяет необходимости понимать, что происходит в запущенной системе. Graphify даёт карту, а не показывает погоду на местности.
Часто задаваемые вопросы
Нужен ли Graphify отдельное векторное хранилище?
Нет, Graphify обходится без векторной базы. Он парсит абстрактное синтаксическое дерево локально и сохраняет связи в JSON или GraphML, которые уже можно подать в контекст Claude Code или Cursor. Векторное хранилище не требуется, потому что инструмент строит точные зависимости, а не ищет семантическое сходство.
Безопасно ли обрабатывать приватный код через Graphify?
Весь парсинг происходит локально на вашем оборудовании, исходники не уходят никуда. Graphify не требует доступа к облачным API для построения графа, поэтому код остаётся внутри вашего контура. Это даёт предсказуемость при работе с коммерческой тайной или персональными данными.
Какие языки и форматы поддерживает Graphify?
Из коробки есть парсеры для Go, SQL и Markdown, но инструмент обходит репозиторий и определяет язык каждого файла. Поддерживаются исходный код, документация, SQL-схемы и PDF. Если нужен другой язык, можно добавить свой парсер через tree-sitter.
Как подключить полученный граф к Claude Code или Cursor?
Результат сохраняется в JSON или GraphML, который подключается как навык или передаётся в контекст запроса. В Claude Code это делается через настройку навыка, в Cursor — через подключение файла к контексту чата. После этого агент видит точные вызовы функций и импорты, а не только похожие по смыслу фрагменты.
Что делать, если граф получился слишком большим?
Во-первых, сузьте область сканирования через секции include и exclude в graphify.yaml. Во-вторых, исключите vendor, node_modules и сгенерированный код, они только раздувают граф без практической пользы. С практической точки зрения, лучше собирать граф по отдельным сервисам, а не по всему монорепозиторию сразу.