Продвинутый

Построение графа знаний из кода с Graphify

Алексей Кузнецов
Алексей Кузнецов
Системный администратор10 ноября 2026 г.13 мин чтения

Graphify превращает код, документацию, SQL-схемы и PDF в граф знаний. Локальный AST-парсинг без векторного хранилища для Claude Code, Cursor и Gemini CLI.

Построение графа знаний из кода с 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.

Пример структуры проекта:

text
project/
├── 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

Запуск выглядит так:

bash
graphify 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:

python
def calculate_total(items):
    return sum(item.price for item in items)

AST-парсер разбирает её на узлы: FunctionDef с именем calculate_total, аргумент items, тело — Return с вызовом sum. Graphify фиксирует каждый такой узел как вершину графа. Если в другом файле есть импорт:

python
from billing.calculator import calculate_total

то появляется ребро между модулем billing.calculator и тем, где происходит импорт. Агент, работающий с Claude Code, видит эту связь сразу: он понимает, что изменение в calculate_total затронет все файлы, которые импортируют эту функцию.

С конфигами аналогично. Возьмём файл docker-compose.yml:

yaml
services:
  db:
    image: postgres:15
    ports:
      - "5432:5432"
  app:
    build: .
    depends_on:
      - db

Graphify извлекает из него сервисы, зависимости и переменные окружения. Сервис app связывается с сервисом db через depends_on, а также с образом postgres:15. Если в коде приложения есть строка подключения к базе, Graphify попытается сопоставить её с сервисом db и добавить ребро между кодом и инфраструктурой.

С практической точки зрения, это работает так:

  1. Вы запускаете парсинг директории с проектом.
  2. Graphify обходит все поддерживаемые файлы и строит промежуточное представление.
  3. Результат сохраняется в локальный граф — обычно в файл или базу, доступную только вашему агенту.
  4. Claude Code или Cursor запрашивают у графа смежные узлы для текущего файла, и агент получает контекст без лишних запросов к языковой модели.

Если мы посмотрим на реальный пример из практики: в одном из моих проектов на FastAPI было около 40 эндпоинтов, разбросанных по модулям. После парсинга Graphify показал, что три эндпоинта вызывают одну и ту же приватную функцию валидации, о которой в документации не было ни слова. Это помогло найти место, где нужно было добавить логирование, не гадая, где именно функция используется.

Связи между документами и схемой

Код редко существует изолированно. Рядом с ним лежат Markdown-файлы, SQL-схемы, PDF-инструкции и OpenAPI-спецификации. Graphify парсит эти файлы и связывает их с кодом через общие идентификаторы: имена таблиц, URL-маршруты, ссылки в комментариях.

Возьмём SQL-схему:

sql
CREATE 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: код, документацию и схему». Это даёт контекст, который невозможно получить простым поиском по тексту.

Связанные материалы по настройке агентов:

Интеграция с 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. Это полезно, но не ответит на вопрос, почему сообщения застревают в одной из них. Для этого нужно смотреть логи потребителя:

bash
journalctl -u notification-worker -n 100 --no-pager

Или метрики в Grafana, а не узлы графа.

Когда векторный поиск всё ещё нужен

Graphify работает с тем, что можно формально описать: AST, SQL-схема, текст PDF. Он отлично справляется с вопросом «где используется этот класс?». Но он плохо справляется с вопросом «как реализована регистрация пользователя?», если в коде нет точного совпадения слов «регистрация» и «пользователь».

Векторный поиск ищет по смыслу, а не по точному совпадению токенов. Если разработчик назвал функцию onboard_user, а вы ищете «регистрация», Graphify может ничего не найти. Векторная база с эмбеддингами найдёт, потому что семантически эти понятия близки.

С практической точки зрения, векторный поиск всё ещё нужен в трёх случаях:

  1. Поиск по документации и PDF, где нет чёткой структуры. Инструкция по развёртыванию или архитектурное решение (ADR) не имеют AST, зато содержат контекст, который важен инженеру.
  2. Поиск похожих фрагментов кода между репозиториями. «Где у нас ещё реализована OAuth2?» — векторный поиск найдёт похожие паттерны, даже если имена функций разные.
  3. Естественные языковые запросы к кодовой базе. Когда вы спрашиваете 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 и сгенерированный код, они только раздувают граф без практической пользы. С практической точки зрения, лучше собирать граф по отдельным сервисам, а не по всему монорепозиторию сразу.

Поделиться:TelegramX / TwitterVK

Читайте также