Перейти к содержимому
RAGRAF

Open Source · MIT · v0.1.0

Факты о коде вместо слепого grep

RAGRAF индексирует репозиторий и отвечает LLM-агенту фиксированными операциями: где определено, кто вызывает, что сломается при правке. Каждый факт — с проверяемой ссылкой файл:строка.

Python 3.13+SQLiteMCP · 23 инструментаtree-sitter · 16 языковMIT

92%

попадание в файл-цель с первого запроса

12 из 13, замер

100%

фактов со ссылкой файл:строка

замер M6

1,0

вызов инструмента на задачу

было 2,0–3,1

0

файлов, прочитанных целиком

было 14

Замеры на реальном PHP-портале (14 навигационных задач): bench/results/ и README проекта. Числа вызовов и попаданий — измерения; «реалистично 43» — модельная поправка, записанная в артефакте.

Проблема

Агент работает по памяти о коде, которого не видел

Три симптома, которые знает каждый, кто поручал LLM правку в существующем проекте. Все три — измерены, а не придуманы.

Не находит место

grep по имени даёт десятки кандидатов, и нужный — не первый. VulnGym: в цепочках длиннее 9 шагов в 56,5% провалов агент не нашёл файл (26,8%) или нашёл файл, но не строку (29,7%). Больше половины отказов — про навигацию, не про анализ.

источник: измерение

Не знает схему БД

Колонку назвали «как переменную в соседнем модуле» — и узнали об этом только в рантайме: SQLSTATE[42S22] Unknown column при первом же сохранении. Схема из миграций должна проверяться до запуска кода.

источник: реальный дефект

Не знает, что устарел

Индекс построили, код отредактировали — агент получает факты о состоянии, которого уже нет. Отличить «такой функции нет» от «она появилась после индексации» по ответу невозможно. Решение принято по неверному факту.

источник: ключевой риск

Язык запросов не спасает

Дать агенту Cypher/CPGQL? LLMxCPG (USENIX Security \u{27}25): базовые модели генерируют валидный запрос к графу кода в 19–132 случаях из 1278. Свободный язык запросов превращается в генератор ошибок.

источник: литература

Вывод, из которого вырос RAGRAF: больше половины отказов агента — не про анализ, а про навигацию. Её и нужно вынести из модели во внешний индекс, который отвечает фактами и знает границы своих знаний.

Возможности

Что делает RAGRAF

Фиксированный контракт вместо свободного поиска: 22 операции фасада, 23 инструмента MCP, три хранилища SQLite. Ничего лишнего — и ничего молча сломанного.

22 фиксированные операции

symbol, callers, impact, slice, schema, write_check, policy_trace… Агент выбирает «что спросить», а не «как спросить»: языка запросов к графу нет — по измерению, а не по вкусовщине.

facade: 22 op_* · MCP: 23 инструмента

Каждый факт — с доказательством

path:line, provenance (stated — доказано анализатором, derived — эвристика), confidence, index_rev. Ребро без доказательства не живёт в графе как факт.

проверяемость ссылок: 100% (замер M6)

Индекс знает, что устарел

Ревизия иммутабельна; правки копятся в append-only журнале расхождений; затронутые факты помечаются stale в каждом ответе; сторож контрольных сумм переиндексирует автоматически.

drift ledger · guard · auto-reindex

Гибридный поиск, полностью локальный

BM25 (FTS5) + векторы 384 измерения (paraphrase-multilingual-MiniLM-L12-v2 через fastembed/ONNX). Без torch, без облака, без подписок. Модель скачивается один раз (~240 МБ).

SQLite: граф + FTS5 + vec0 в трёх файлах

Схема БД из миграций + write_check

Таблицы и колонки разбираются из migrations/*.sql без доступа к СУБД. write_check сверяет план записи со схемой до запуска и предлагает ближайшие существующие имена колонок.

44 таблицы / 453 колонки на пилоте

MCP-сервер и честная деградация

23 инструмента ragraf_* по stdio (JSON-RPC). Нет слоя Joern — capability=degraded, slice отказывает с причиной; остальные операции работают. Молчаливой деградации не бывает.

опциональный CPG: Joern + JDK 21

16 языков разбираются деревом (PHP, Python, JS, TS, Java, C#, C, C++, Ruby, Lua, Go, Perl, bash, PowerShell, CSS, HTML) и 10 подключаются текстом (Markdown, SQL, YAML, JSON, TOML, INI, XML, RST, batch, текст).

Как работает

Два контура: индексация и ответ

Индексация строит снимок-ревизию. Ответы читают снимок и сверяют его свежесть. Правки кода во время работы идут в журнал, а не в индекс.

Индексация (одна команда)

  1. шаг 1scanобход корпуса, sha256 каждого файла, контрольная сумма входа
  2. шаг 2asttree-sitter: символы, вызовы, SQL-литералы, границы строк
  3. шаг 3resolveразрешение имён: точное совпадение → имя+файл → честный отказ
  4. шаг 4schemaтаблицы и колонки из миграций — без подключения к БД
  5. шаг 5cpgJoern (опционально): межпроцедурные вызовы; нет — degraded
  6. шаг 6lexvecFTS5-токены и векторы; неизменённые чанки переиспользуются по хешу

Ответ агенту (каждый запрос)

  1. шаг 1операцияагент вызывает фиксированную операцию через MCP или CLI
  2. шаг 2свежестьсторож сверяет corpus_hash; расхождение — stale-пометки или авто-реиндекс
  3. шаг 3фактырезультат со ссылками path:line, provenance и confidence
  4. шаг 4конвертindex_rev, capability, drift, limits, stale_warnings — в каждом ответе

Три принципа, выведенных из измеренных дефектов

  • Индекс неизменяем в пределах ревизии — факты разных моментов времени не смешиваются.
  • Устаревание показывается, а не прячется: stale-факт нельзя принять за актуальный.
  • Деградация никогда не молчит: capability и причина — в каждом ответе.

Архитектура

Три файла SQLite и никакой инфраструктуры

Всё состояние индекса живёт в каталоге .ragraf/ внутри проекта. Ни сервисов, ни демонов, ни облака. Удалил каталог — удалил индекс.

graph.sqlite

Узлы (класс, функция, метод), рёбра (вызовы, наследование, импорты) с доказательствами, схема БД, маршруты. Всё помечено rev_id.

lexvec.sqlite

FTS5-лексика (BM25) и векторы vec0 (384) в одном файле; сырой текст чанков — выдача фрагментов без чтения диска.

control.sqlite

Ревизии, append-only журнал расхождений, архивы переиндексаций, телеметрия обращений. Не удаляется никогда.

Конфигурация корпуса
# ragraf init <каталог проекта> — создаст конфиг сам.
# Индекс ляжет в .ragraf/ внутри проекта (добавьте в .gitignore).
project: myproject
root: C:/path/to/your/project
languages: [python, javascript, markdown]
include: ["**/*.py", "**/*.js", "**/*.md"]
exclude: ["**/node_modules/**", "**/build/**"]
secrets_exclude:            # не индексируются и не читаются
  - "**/.env"
  - "**/*.pem"
embedding:
  model: sentence-transformers/paraphrase-multilingual-MiniLM-L12-v2
  dim: 384
index:
  retain_revs: 3
  joern_enabled: true       # нет Joern — capability=degraded

Демо

Как это выглядит в работе

Сценарии собраны на реальных выводах продукта (замеры и статья проекта). Это мокапы интерфейса, а не скриншоты: у CLI и MCP намеренно нет графики — и это часть философии.

запрос агента

ragraf -p config/portal.yaml query symbol --name z_agr_acl_audit

function · config/acl.php:112–148 · сигнатура: function z_agr_acl_audit(array $data): voidconfig/acl.php:112
контракт параметра (из docblock): array{action:string, user_id?:int, field?:string, to:?string, actor_id?:int} — обязателен только actionconfig/acl.php:104

До этого агенты строили вызов по сигнатуре «array $data» и получали TypeError: контракт array не сообщает состав ключей.

Мокап. Данные — реальные выводы продукта из статьи и журнала обращений.

Быстрый старт

Три шага до первого факта

Прав администратора не нужно: всё ставится в пользовательский каталог. Проверенная платформа — Windows + PowerShell 7.6; общий pip-путь работает везде, где есть Python 3.13+.

  1. Установка

    Скрипт создаст venv в ~/.ragraf/venv, поставит зависимости и проверит каждый шаг итоговой таблицей. Лог — в ~/.ragraf/logs/.

    PowerShell
    git clone https://github.com/paulmann/RAGRAF.git
    cd RAGRAF
    pwsh -NoLogo -NoProfile -File scripts/install.ps1
  2. Корпус

    ensure найдёт корпус, создаст его для незнакомого каталога и пересоберёт отставший индекс — одной командой.

    PowerShell
    ragraf ensure C:\work\myproject
  3. Первый запрос

    Глобальные флаги -p и --json ставятся ДО подкоманды. selftest — отчёт по 11 компонентам.

    PowerShell
    ragraf -p <конфиг> query search "порог переиндексации"
    ragraf -p <конфиг> query symbol --name corpus_hash
    ragraf -p <конфиг> selftest

Порядок флагов

Глобальные --project/-p и --json — ДО подкоманды (ragraf -p cfg query search …). Исключение: у ensure свой --json, он ставится после (ragraf ensure <dir> --json).

Первая индексация с векторами

Скачивает модель эмбеддингов ~240 МБ в ~/.ragraf/models (один раз). Без интернета или с --no-vectors работает лексический поиск BM25.

selftest — не гейт

Команда всегда возвращает код 0: это отчёт, а не проверка. Читать сам отчёт: 9 обязательных компонентов + joern/java (опционально).

Корпоративный TLS-прокси

Если загрузка модели падает на certificate verify failed — поставьте truststore: install.ps1 -WithTruststore или pip install truststore.

Полный список команд — ragraf --help. Документация и протоколы замеров — в репозитории.

FAQ

Частые вопросы

Короткие ответы на вопросы, которые задают чаще всего. Детали — в документации репозитория.

MIT — свободное использование, включая коммерческое. Внешние зависимости сохраняют свои лицензии (tree-sitter — MIT, sqlite-vec — MIT/Apache-2.0, fastembed — Apache-2.0, PyYAML и tiktoken — MIT, ijson — BSD). Java и Joern ставятся отдельно и распространяются под Apache-2.0; в поставку они не входят.

Python 3.13 или новее (проверено на 3.14), права администратора не нужны — всё устанавливается в пользовательский каталог. Диск: ~2,5 ГБ на окружение (ONNX Runtime, tree-sitter), индекс — примерно 1 МБ на 1–2 файла исходников. Проверенная платформа — Windows + PowerShell 7.6; общий путь через pip на Linux и macOS не проверялся. Опциональный слой Joern (межпроцедурный граф) добавляет JDK 21 и ~5–6 ГБ.

Локальная sentence-transformers/paraphrase-multilingual-MiniLM-L12-v2 (384 измерения) через fastembed и ONNX Runtime — без torch и без облака. Модель скачивается один раз (~240 МБ) при первой индексации с векторами в ~/.ragraf/models; каталог кэша переопределяется переменной RAGRAF_MODEL_CACHE. Операции чтения модель не скачивают никогда. Индексация без векторов (--no-vectors) работает на лексическом поиске BM25.

Всё остаётся на вашей машине: три файла SQLite в каталоге .ragraf/ внутри проекта, журнал обращений — там же. Файлы из списка secrets_exclude не открываются вовсе — не индексируются, не читаются, не попадают в логи. Телеметрия хранит хеш аргумента и короткий дайджест вместо полного текста запросов. Единственный сетевой трафик — PyPI при установке и разовая загрузка модели; ни API-ключей, ни отправки данных наружу в продукте нет.

Шестнадцать языков разбираются деревом (граф: узлы и рёбра): PHP, Python, JavaScript, TypeScript, Java, C#, C, C++, Ruby, Lua, Go, Perl, bash, PowerShell, CSS, HTML. Ещё десять подключаются текстом (файлы находятся поиском, но узлов не дают): Markdown, SQL, YAML, JSON, TOML, INI, XML, RST, batch, обычный текст. Глубже всего проверен PHP — на нём строился пилот и слой CPG (Joern php2cpg).

Тремя обязательствами. Первое: индекс иммутабелен в пределах ревизии, а расхождения с кодом копятся в append-only журнале — устаревший факт помечается stale в каждом ответе, а не молча выдаётся за актуальный. Второе: каждый факт несёт доказательство — path:line, provenance (stated/derived) и confidence; эвристика никогда не смешивается с доказанным. Третье: вместо свободного retrieval-ответа — фиксированные операции с явными ограничениями (limits) и состоянием возможностей (capability).

Языка запросов к графу нет и не будет — это архитектурное решение P4, основанное на измерении (LLMxCPG: базовые модели дают 19–132 валидных CPGQL-запроса из 1278). Набор из 22 операций фиксирован; его расширение обсуждается в issues репозитория. Проект разработан под конкретные задачи, поэтому предложения по архитектуре обсуждаются охотнее, чем большие патчи без предварительного разговора.

RAGRAF сам по себе и есть локальный инструмент: сервер не нужен ни для индекса, ни для ответов. MCP-сервер — это процесс stdio, который запускает ваш агент. Панель управления (опционально) слушает только 127.0.0.1:8777 и наружу не доступна. Единственный внешний компонент — Joern с постоянным сервером на localhost:9500 во время индексации CPG; он останавливается автоматически.

Дайте агенту проверяемые факты

Индекс кода — это не «ускорение поиска». Это перенос части работы из модели во внешнюю структуру, которая знает, чего она не знает. Самое ценное свойство RAGRAF: он отказывается отвечать уверенно, когда не имеет права.

Сигнатура array $data честна и бесполезна. Docblock с составом ключей — полезен. Пометка stale: true рядом с фактом — обязательна.