📱 Подписаться
IT и цифровая трансформация

Граф кода одной командой: ставим graphlens-mcp в проект и перестаём жечь токены на grep

📰 Habr 👁️ 0 просмотров

Neko13137 часов назад

Граф кода одной командой: ставим graphlens-mcp в проект и перестаём жечь токены на grep

Уровень сложностиСреднийВремя на прочтение9 минОхват и читатели5.7KПрограммирование*Искусственный интеллектPython*ОбзорЭто третья часть серии. В части 1 я разобрал движок graphlens — что он делает и как устроен. В части 2 я прогнал бенчмарк на 936 запусков и честно показал, где граф окупается, а где нет. Эта статья — про то, чего не хватало: готовый продукт, который ставится одной командой.

Коротко

В первых двух статьях я сделал две вещи и обе — честно.

Описал движок graphlens: как он берёт исходники на Python, TypeScript, Go, Rust и PHP и нормализует их в единый типизированный граф — узлы-символы, type-aware рёбра (CALLS, HAS_TYPE, INHERITS_FROM), детерминированные SHA-256 ID, межъязыковые границы.

И померил его: 936 прогонов на apache/superset (~400k строк, Python + TypeScript, граница /api/v1/...). Вывод — на задачах анализа влияния структурный граф бьёт grep по стоимости в 10–23 раза, а на точечных запросах разница почти нулевая.

Но была дыра, о которой я в обеих статьях молчал. Движок — это не продукт. Чтобы реально подключить graphlens к агенту, недостаточно pip install и API. Нужно написать кучу обвязки. Эта статья — про то, как я эту обвязку оформил в отдельный продукт graphlens-mcp, который ставится одной командой и сразу начинает работать. Он в alpha, он бесплатный (MIT), и его можно потестить на своём проекте за пять минут.

Откуда вообще растёт боль

Картина, знакомая всем, кто гоняет кодового агента на большом проекте. Сотни тысяч строк, бэкенд на Python, фронт на TypeScript, легаси, в которое страшно лезть. Вы спрашиваете агента «как у нас устроена авторизация» или «что сломается, если я поменяю сигнатуру этого метода» — и он уходит в цикл: grep → открыть → прочитать → перейти по импорту → снова grep. Читает десятки файлов, забивает контекстное окно и жжёт токены.

Это не теория. Anthropic в своём инженерном блоге прямо пишет, что определения инструментов и промежуточные результаты могут «consume 50,000+ tokens before an agent reads a request» — и это до того, как агент вообще начал думать над задачей. Каждый прочитанный файл оседает в контексте и тарифицируется на каждом следующем ходу.

Структурный граф решает ровно это: вместо «прочитай файл и поищи глазами» агент задаёт точный вопрос — «кто вызывает create_order?» — и получает маленький структурированный ответ.

Стена номер один: движок — это ещё не продукт

Когда я выкладывал graphlens, я сознательно сделал ядро узким. Документация это прямо фиксирует: graphlens производит граф-IR и на этом останавливается. Он не хранит состояние и не владеет базой, не следит за файловой системой и не переиндексируется сам, не считает эмбеддинги, не поднимает долгоживущий сервис. Адаптеры — чистые продюсеры данных. Граф — единственный выход.

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

• хранилище графа и его сериализацию;
• инвалидацию — когда файл изменился, что переиндексировать;
• watcher за файловой системой;
• MCP-сервер с набором инструментов, которые агент реально умеет звать;
• регистрацию сервера в конфиге Claude Code / Cursor / прочих, причём у каждого свой формат;
• и желательно — навигационный скилл, чтобы агент знал, как этими инструментами пользоваться.Вот эта прослойка — и есть та работа, которую в реальности приходится делать самому, чтобы «движок» превратился в «инструмент». Я её написал и оформил отдельным проектом. graphlens-mcp — тонкий рантайм поверх движка: graphlens даёт механизмы (парсинг, стабильные ID узлов, резолверы), а graphlens-mcp владеет хранилищем, моделью свежести и agent-facing поверхностью — всем тем, чем graphlens сам быть отказывается.

Тезис, который я хочу донести прямо: «движок предоставляет контракты и API, но на практике продукт так не применяют — чтобы что-то заработало, надо написать много glue-кода самому. Так вот готовый продукт, в alpha, который вы ставите одной командой и начинаете тестировать».

Установка: буквально одна команда плюс init

uv tool install graphlens-mcp # или: pipx install graphlens-mcp
cd your-project && graphlens-mcp initЧто делает init: определяет языки проекта, прогоняет «доктор» по тулчейнам, индексирует код в локальный граф, прописывает MCP-сервер в конфиг ваших агентов (он знает форматы Claude Code, Cursor, Windsurf, VS Code/Copilot, Codex CLI и пишет идемпотентно, не ломая другие ваши серверы) и ставит навигационный скилл. Дальше агент сам запускает сервер из конфига — serve руками вы не зовёте. Перезапускаете агента и спрашиваете что-нибудь вроде «что сломается, если я поменяю сигнатуру create_order?».

Требования: Python ≥ 3.13 (ограничение унаследовано от graphlens). Лицензия MIT. Текущая версия — 0.1.2.

Полезные флаги init: --root <dir>, --agent claude_code --agent cursor (повторяемый), --no-agent, --no-skills, --db <path>, --yes (принять найденных агентов без вопросов).

Инструменты, которые получает агент

Сервер выставляет восемь инструментов. Их немного и они нарезаны под конкретные вопросы, которые агент задаёт о коде:

ИнструментНазначениеsearch_symbolsПолнотекстовый поиск по именам символов — начинать отсюдаget_node_infoСниппет исходника + сигнатура + докстринг + позиция узлаget_file_structureКарта символов файла (outline)get_calleesЧто вызывает функция (исходящие, до max_depth)get_callersКто вызывает функцию — основной инструмент анализа влиянияget_neighborsУзлы в пределах N переходов в любом направленииfind_referencesНе-вызовы: аннотации типов, присваиванияget_cross_language_callsСвязи через границы сервисов (HTTP/gRPC/очереди)Важная деталь честности: каждый ответ несёт статус качества графа (ok | degraded, агрегированный по всем возвращённым узлам), так что агент никогда не примет частичный ответ за полный. Списки ограничены MAX_RESULTS (200) и несут флаг truncated — без тихого обрезания.

CLI: пять команд

КомандаЧто делаетgraphlens-mcp initОпределить языки → доктор тулчейнов → полная индексация → настроить агентов → поставить скиллgraphlens-mcp serveЗапустить MCP-сервер по stdio. Запускается агентом, не вами (--no-watch отключает watcher)graphlens-mcp statusЯзыки, статус тулчейнов, размер и свежесть графаgraphlens-mcp reindexПолная пересборка (например, после установки нового тулчейна)graphlens-mcp removeСнять регистрацию у агентов; с --purge-db — удалить локальный граф

Сценарий из реальной работы: анализ влияния

Вот ради чего всё затевалось. Возьмём типичную задачу рефакторинга: «что сломается, если я поменяю сигнатуру create_order?».

Без графа агент грепает имя по всему репозиторию, получает каждое вхождение create_order (включая тёзок в тестах и комментариях), читает каждый файл-совпадение целиком, идёт по импортам, перечитывает уже прочитанное — и на сложной кодовой базе делает 27 обращений к инструментам, прежде чем собрать картину (а иногда и упирается в лимит ходов, так и не дойдя до ответа).

С graphlens-mcp цепочка короткая и точная:

search_symbols("create_order") # 1. найти узел
get_callers(id, max_depth=5) # 2. кто вызывает — радиус поражения
find_references(id) # 3. где ещё упоминается (аннотации, присваивания)
get_cross_language_calls(id) # 4. бьёт ли фронт в этот эндпоинт через /api/v1/...Дальше агент зовёт get_node_info только для тех мест, которым реально нужна детализация, — вместо того чтобы читать каждый файл-вызывающий целиком. Вместо «вывалить кодовую базу в контекст» — «навигировать по структуре»: кто вызывает, от чего зависит, что сломается.

Рекомендованный паттерн прямо зашит в навигационный скилл, который ставит init: search_symbols → get_callers/find_references → суммировать, и get_node_info точечно.

Модель свежести: почему граф не протухает на лету

Главное отличие готового продукта от «движка + скрипт» — граф остаётся актуальным сам, пока вы редактируете код.

graphlens-mcp держит свежесть через filesystem watcher (стартует вместе с serve, отключается флагом --no-watch). Когда файл меняется на диске, сервер переиндексирует connected set — изменённый файл плюс файлы, которые его импортируют, и файлы, которые импортирует он сам — одним полным analyze, чтобы межфайловые рёбра пересобрались корректно, а не остались наполовину битыми. Удаление файла вычищает его символы и обновляет импортёров. Никакого поллинга и никакой «скелетной» фазы: каждая (пере)индексация выдаёт полный граф, который резолвер способен дать.

Отдельно решена проблема правок «пока сервер был выключен»: при старте serve делает one-shot reconcile — сканирует проект, индексирует новые файлы, вычищает исчезнувшие, обновляет изменённые, и только потом передаёт управление watcher'у.

Граф лежит в <project>/.graphlens/graph.db (SQLite). Это регенерируемый кэш — его безопасно удалить, reindex пересоберёт. Добавьте .graphlens/ в ignore вашей VCS.

Сколько это экономит токенов

Теперь то, ради чего вы дочитали до сюда — цифры. И я даю их с той же честностью, что и в части 2: это замеры на конкретном кейсе, а не универсальный рейтинг.

В части 2 я мерил graphlens против файлового поиска на apache/superset, меняя у одного и того же агента ровно одну вещь — какой MCP-сервер отдаёт контекст. На сложных задачах (анализ влияния, разрешение неоднозначных имён, полный набор переопределений):

ИнструментТокеныВызовы$/задачаfilesystem (grep+read)1259627$0.424graphlens (граф)7481$0.018Это сокращение токенов примерно на 94% и стоимости в 10–23 раза, при одном вызове инструмента вместо двадцати семи. На простых точечных запросах («где определён класс») выигрыш скромнее — 690 токенов против 1780, около 61%, и я честно повторю вывод части 2: на точечных справках граф особо не нужен, grep справляется. Граф окупается на структурной работе — рефакторинг, оценка радиуса поражения, трассировка.

Это согласуется с независимыми замерами по соседним инструментам. По актуальному README CodeGraph (перевалидирован на Claude Opus 4.8, 2026-06-02, медиана 4 прогонов на 7 репозиториях) — 47% меньше токенов, 58% меньше вызовов инструментов, 35% дешевле, 46% быстрее (более ранняя сборка README давала 57%/71%). А независимый недельный обзор Ry Walker Research на четырёх репозиториях намерил «70% median tool-call reduction, 59% fewer tokens, and 49% faster responses». Порядок величины везде один: на структурных вопросах граф режет и токены, и round-trips в разы.

Оговорка, без которой цифры нельзя переносить на ваш проект: мой замер — это один репозиторий (apache/superset) и 26 задач; cost_usd — API-эквивалент, а не счёт по подписке; провал засчитан как точность 0. Хотите проверить на своём коде — стенд открыт (github.com/Neko1313/agent-context-bench).

Чем graphlens-mcp сознательно не является

Чтобы не выглядело рекламно — статус честный: early. Ядро навигации работает, остальное в развитии. Известные ограничения зафиксированы прямо в документации:

• Watcher переиндексирует connected set изменения, а не весь проект. Рефакторинг, который рябью идёт через много слоёв косвенности — или создание файла, который уже импортирует неизменённый файл, — может потребовать полного reindex для точного графа.
• Межъязыковые рёбраCOMMUNICATES_WITH пересобираются на полном reindex и могут эродировать на инкрементальных правках (запрос по границам всё ещё резолвит связи, но для точной кросс-языковой картины зовите reindex).
• Деградация без тулчейна. Python работает из коробки (ty в комплекте). Для TypeScript нужен Node, для Go/Rust/PHP — их тулчейны; без них язык репортится как degraded (структура распарсена, вызовы/типы не полностью разрешены) — но init это никогда не блокирует, а status показывает реальный статус по каждому языку с подсказкой, что доставить.И принципиально: graphlens-mcp не считает эмбеддинги и не делает семантический поиск «по смыслу» — граф структурный и type-aware, а не векторный индекс. Если нужно «найди код, концептуально похожий на rate limiting, как бы он ни назывался» — это к векторным инструментам, не сюда. graphlens-mcp отвечает на структурные вопросы: кто вызывает, от чего зависит, что сломается.

Зачем это вам и как начать

Ставьте, если вы регулярно гоняете Claude Code, Cursor или совместимый клиент на большом полиглотном проекте и устали смотреть, как агент жжёт токены на рекурсивный grep по репозиторию. Особенно если часто делаете анализ влияния перед рефакторингом — это ровно тот режим, где граф окупается.

Не заморачивайтесь, если проект маленький (десятки файлов — grep отработает мгновенно) или вам нужен в основном семантический поиск по смыслу.

Порог входа — нулевой: всё локально, ничего не уезжает наружу, MIT, удаляется одной командой (graphlens-mcp remove --purge-db). Поставьте на свой главный проект, убедитесь, что MCP активен в агенте, и сравните число вызовов инструментов на одном и том же архитектурном вопросе — с графом и без.

uv tool install graphlens-mcp
cd your-project && graphlens-mcp init
graphlens-mcp status # проверить языки и свежесть графа

Заключение

Часть 1 описала движок. Часть 2 его померила и честно показала, где он выигрывает, а где проседает. Эта часть закрывает разрыв между «есть API» и «есть продукт».

Движок graphlens сознательно отдаёт контракты и останавливается — это правильно для движка. Но в реальности продукт так не применяют: чтобы что-то заработало в связке с агентом, поверх надо написать хранилище, watcher, MCP-слой и регистрацию у агентов. Я эту обвязку написал и оформил в graphlens-mcp — тонкий рантайм поверх движка, который ставится одной командой, сам держит граф свежим и режет токены на структурных вопросах в разы.

Он в alpha, и я говорю это прямо: ядро навигации работает, межъязыковые рёбра и whole-project re-link ещё допиливаю. Но потестить уже можно за пять минут на своём репозитории — и именно обратная связь с реальных проектов мне сейчас нужнее всего. Issue, замеры на ваших кодовых базах, претензии к гранулярности инструментов — всё в репозиторий. Чем больше независимых прогонов на разных проектах, тем ближе мы к ответу, который можно переносить, а не «работает на superset».

Репозиторий: github.com/Neko1313/graphlens-mcpДвижок: github.com/Neko1313/graphlensБенчмарк: github.com/Neko1313/agent-context-benchТеги:• graphlens
• MCP
• граф кода
• кодовые агенты
• Claude Code
• LLM
• статический анализ кода
• оптимизация токенов
• Python
• tree-sitterХабы:• Программирование
• Искусственный интеллект
• Python

Получайте больше инсайтов о систематизации бизнеса

Подписывайтесь на Telegram-канал Business Operations — ежедневные материалы о бизнес-процессах, операционном управлении и повышении эффективности

💬 Подписаться на канал