跳到主要内容
RAGRAF

开源 · MIT · v0.1.0

用可验证的代码事实取代盲目 grep

RAGRAF 为代码仓库建立索引,通过固定操作回答 LLM 代理的问题:定义在哪里、谁调用了它、修改会影响什么。每个事实都带有可验证的 file:line 引用。

Python 3.13+SQLiteMCP · 23 个工具tree-sitter · 16 种语言MIT

92%

首次查询命中目标文件

13 中 12,实测

100%

事实带有 file:line 引用

实测 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):基础模型在 1278 次中仅生成 19–132 条有效的代码图查询。自由查询语言会沦为错误生成器。

来源: 文献

RAGRAF 由此得出的结论:代理一半以上的失败不在分析,而在导航。这部分工作应当从模型中剥离,交给一个用事实回答、并且知道自己边界的外部索引。

功能特性

RAGRAF 做什么

用固定契约取代自由检索:22 个门面操作、23 个 MCP 工具、三个 SQLite 存储。没有多余的东西——也没有会悄悄坏掉的东西。

22 个固定操作

symbol、callers、impact、slice、schema、write_check、policy_trace……代理只需选择「问什么」,不必操心「怎么问」:不提供图查询语言——这是基于实测的决定,而非主观偏好。

门面:22 个 op_* · MCP:23 个工具

每个事实都有证据

path:line、来源标记(stated——分析器证明;derived——启发式)、置信度、index_rev。没有证据的边不会作为事实存在于图中。

引用可验证率:100%(M6 实测)

索引知道自己过时了

修订版本不可变;代码改动累积在只追加的差异日志中;受影响的事实在每个回答中标记 stale;校验和守护进程可自动重建索引。

drift 日志 · 守护进程 · 自动重建

混合检索,完全本地

BM25(FTS5)+ 384 维向量(paraphrase-multilingual-MiniLM-L12-v2,经 fastembed/ONNX)。无 torch、无云端、无订阅。模型仅下载一次(约 240 MB)。

SQLite:图 + FTS5 + vec0,共三个文件

从迁移文件解析表结构 + write_check

表和字段直接解析自 migrations/*.sql,无需连接数据库。write_check 在执行前将写入计划与表结构核对,并给出最接近的现有字段名建议。

试点项目:44 张表 / 453 个字段

MCP 服务器与诚实降级

通过 stdio 提供 23 个 ragraf_* 工具(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 证据、来源标记与置信度的结果
  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

修订历史、只追加的差异日志、重建归档、调用遥测。永不删除。

语料配置
# 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}——仅 action 必填config/acl.php:104

此前代理仅凭签名「array $data」构造调用,结果得到 TypeError:array 类型并不能说明键的组成。

模拟界面。数据取自产品文章与调用日志中的真实输出。

快速开始

三步拿到第一个事实

无需管理员权限:一切安装在用户目录中。已验证平台为 Windows + PowerShell 7.6;通用 pip 方式适用于任何装有 Python 3.13+ 的系统。

  1. 安装

    脚本会在 ~/.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 MB)下载到 ~/.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 GB(ONNX Runtime、tree-sitter),索引约为每 1–2 个源文件 1 MB。已验证平台为 Windows + PowerShell 7.6;Linux 与 macOS 的通用 pip 方式未经验证。可选的 Joern 层(跨过程图)另需 JDK 21 与约 5–6 GB 空间。

本地模型 sentence-transformers/paraphrase-multilingual-MiniLM-L12-v2(384 维),经 fastembed 与 ONNX Runtime 运行——无 torch、无云端。模型在首次带向量索引时下载一次(约 240 MB)至 ~/.ragraf/models;缓存目录可通过 RAGRAF_MODEL_CACHE 覆盖。读取操作永不下载模型。使用 --no-vectors 的无向量索引照常提供 BM25 词法检索。

一切留在本机:三个 SQLite 文件位于项目的 .ragraf/ 目录,调用日志也在那里。secrets_exclude 列表中的文件完全不会被打开——不索引、不读取、不写入日志。遥测只存参数的哈希与 60 字符摘要,不存完整查询文本。产品唯一的网络流量是安装时的 PyPI 与一次性的模型下载;不存在 API 密钥,也不存在任何向外发送数据的行为。

16 种语言按语法树解析(生成图的节点与边):PHP、Python、JavaScript、TypeScript、Java、C#、C、C++、Ruby、Lua、Go、Perl、bash、PowerShell、CSS、HTML。另有 10 种按纯文本收录(可被搜索到,但不产生节点):Markdown、SQL、YAML、JSON、TOML、INI、XML、RST、batch、纯文本。验证最充分的是 PHP——试点项目与 CPG 层(Joern php2cpg)都建立在它之上。

三点承诺。其一:索引在修订版本内不可变,与代码的偏差累积在只追加的日志中——过时事实会在每个回答中标记 stale,而不是被悄悄当作最新。其二:每个事实携带证据——path:line、来源标记(stated/derived)与置信度;启发式结果绝不与已证明结果混排。其三:不用自由检索生成答案,而是固定操作,并附明确的限制(limits)与能力状态(capability)。

图查询语言没有、也不会有——这是架构决定 P4,基于实测(LLMxCPG:基础模型在 1278 次中仅产出 19–132 条有效 CPGQL 查询)。22 个操作是固定集合;扩展请在仓库 Issues 中讨论。项目面向具体任务开发,因此相比未经沟通的大型补丁,架构层面的提议更受欢迎。

RAGRAF 本身就是本地工具:索引与应答都不需要服务器。MCP 服务器是由你的代理启动的 stdio 进程。管理面板(可选)仅监听 127.0.0.1:8777,对外不可达。唯一的外部组件是 Joern——CPG 索引期间在 localhost:9500 运行常驻服务,结束后自动停止。

让代理拥有可验证的事实

代码索引不是「更快的搜索」,而是把一部分工作从模型转移到一个知道自己不知道什么的外部结构。RAGRAF 最可贵的特质:在没有把握时,它拒绝给出自信的回答。

签名 array $data 诚实却无用;写明键组成的 docblock 才有用;事实旁边的 stale: true 标记则是必需。