一个让 AI 用图查询替代 grep 的 Claude Code Skill。本文对应项目 Graphify-Labs/graphify,分支 v8。我从 v0.9.0 一路读到 v0.9.38,下面是我的阅读笔记,不是教程,更不是软文。
地址: https://github.com/Graphify-Labs/graphify


一、先把几个判断摆出来

  • 代码图构建零 LLM 成本。36 种语言的源码全部走本地 tree-sitter 解析,纯字符串加 AST 操作,不发任何 API 请求。
  • 它不是向量索引,是一张真正的图。节点是类、函数、模块,边是 calls / imports / inherits / mixes_in。每条边都带置信度标签 EXTRACTED / INFERRED / AMBIGUOUS
  • 基准数据有出处。BENCHMARKS.md 自己写明所有竞品在同模型(Kimi K2.6)、同预算、同裁判下跑,LOCOMO 召回率 0.497,差不多是 mem0 的十倍,建图成本归零。

这三条结论先列在前面。后面所有内容都为它们提供依据。


二、为什么我想搞清楚这件事

我用 Claude Code 已经一年多。每次让 AI 分析一个陌生仓库,最让我心疼的就是 token。看着它逐文件 Read,一次性塞几十个文件进上下文,我看着心里明白,这种模式走到大仓库会崩。仓库越大,AI 不光看不到全貌,连已经看到的都忘了。

我的判断是,代码理解这件事如果能做得结构化一些,让 AI 不再把所有内容塞进上下文,而是先建一份能反复查询的索引,体验会有质变。这个想法从去年就有,断断续续试过几种方案,效果都不理想。

graphify 正好是我想找的那个思路。先用 tree-sitter 把代码解析成图,再让 AI 查图。抱着"看看它是怎么做的"的心态。


三、整体架构,七步流水线

在这里插入图片描述

打开 ARCHITECTURE.md,作者用一句话把整个系统串起来。

detect() → extract() → build_graph() → cluster() → analyze() → report() → export()

七步流水线。每一步是一个独立的 Python 模块,模块之间通过纯 dict 和 NetworkX 图对象通信。没有共享状态,也几乎没有隐藏副作用(除了往 graphify-out/ 写文件)。

我看着这套设计觉得最难的地方在于分层的纪律。每一步都是纯函数,IO 边界清楚。加一门新语言不需要改其它模块,加一个新的输出格式也不会影响提取逻辑。这种分层纪律在 production 代码里其实非常少见。

下面这张表是模块职责的速查(来源 ARCHITECTURE.md)。

模块 函数 输入 → 输出
detect.py collect_files(root) 目录 → 过滤后的文件路径列表
extract.py extract(path) 文件路径 → {nodes, edges} 字典
build.py build_graph(extractions) 提取字典列表 → nx.Graph
cluster.py cluster(G) 图 → 带 community 属性的图
analyze.py analyze(G) 图 → 分析 dict(God 节点、惊喜连接)
report.py render_report(G, analysis) 图 + 分析 → GRAPH_REPORT.md 字符串
export.py export(G, out_dir, ...) 图 → graph.json / graph.html / Obsidian

下面我挑几个我看得最久的模块说说。

1. detect.py 文件收集的双重过滤

detect.py 不复杂,但藏着两个值得提的细节。

它会自动读取每一级目录下的 .gitignore,再合并项目根目录的 .graphifyignore.graphifyignore 优先级更高,包括 ! 否定模式)。它还提供 --no-gitignore 开关。某些项目里被 git 忽略的生成代码反而值得索引,比如前端项目的 dist/

我猜这个设计的潜台词是,过滤规则应该尊重项目的现有约定。这种细节在 production 工具里特别重要。你不会想用一个会偷偷爬进 node_modules/ 的工具。

2. extract.py 分语言的 AST 提取器注册表

extract.py 是整个项目的调度核心。它本身不长(500 行左右),但通过 from graphify.extractors import ... 引入了 28 个语言专属的提取器。每个提取器都是 extract_<lang>(path: Path) -> dict 这种统一签名的函数。

我重点翻了 graphify/extractors/engine.py,它是大多数语言的通用骨架。核心思路分三步,见源码 graphify/extractors/engine.py

# 1. 用 tree-sitter 解析
tree = parser.parse(bytes_source)
root_node = tree.root_node

# 2. 遍历 AST,收集 symbols 和 references
#    收集的是"声明事实"(SymbolDeclarationFact)和"使用事实"(SymbolUseFact)
# 3. 调用 _resolve_symbol_references(...) 做跨文件符号解析
#    把模块 A 里的 `import foo` 和模块 B 里的 `def foo():` 配成一条边

这一步产出的 {nodes, edges} 字典长这样,节选自 ARCHITECTURE.md

{
  "nodes": [
    {
      "id": "routing.py::APIRouter",
      "label": "APIRouter",
      "source_file": "routing.py",
      "source_location": "L2210"
    }
  ],
  "edges": [
    {
      "source": "routing.py::APIRouter",
      "target": "routing.py::get",
      "relation": "method",
      "confidence": "EXTRACTED"
    }
  ]
}

3. confidence 标签从代码层就分清"看到"和"猜到"

这是 graphify 我觉得最值得借鉴的设计之一。每条边从出生那一刻就打上置信度标签。

标签 含义 例子
EXTRACTED 源码里写明的 import xfunc() 直接调用
INFERRED 推断出来的 跨文件的 call graph 二次遍历
AMBIGUOUS 不确定的 命名冲突、LLM 输出的边界情况

源码里执行这个打标动作的位置在 graphify/extract.pyextract() 主函数,调用 call_graph_second_pass() 之后给边补 confidence="INFERRED"EXTRACTED 是默认值,只有二次推断才覆盖这件事。

这说明 graphify 在意 AI 看到的结果里,哪些是真证据,哪些是猜测。

4. cluster.py Leiden 算法给代码自动分社区

cluster.py 用 Leiden 社区检测算法(graspologic 库,需要 Python < 3.13;3.13+ 走降级实现)。社区命名默认是 Community N 占位,由 IDE 内的 AI 助手或单独的 graphify label 子命令补上。

我自己在几个仓库跑下来,社区数量一般控制在几十到几百之间,对应真实项目的子系统划分。如果嫌粒度太粗或太细,可以用 --resolution 1.5(更细)或 --exclude-hubs 99(把超 hub 节点排除再分)。源码在 graphify/cluster.py

5. analyze.py 从图里挖出什么值得看

analyze.py 做的事情很轻。计算每个节点的 degree,找出 degree 最高的 top-N(God 节点),找出跨社区的高权重边(惊喜连接),再生成 4 到 5 个"图能优先回答的问题"。源码在 graphify/analyze.py

我看着这一步觉得它是 graphify 真正有产品感的地方。它知道用户打开报告最先想看什么,所以先把最值得看的那一页铺好。

6. serve.py 把图暴露成 MCP 工具

这是 graphify 另一个让我眼前一亮的点。serve.py 实现了一个完整的 MCP(Model Context Protocol)服务器,对外暴露这些工具。

  • query_graph(question) 自然语言查子图
  • get_node(name) 拿一个节点的元数据
  • get_neighbors(name) 拿邻居节点
  • shortest_path(a, b) 拿最短路径
  • list_prs() / get_pr_impact() PR 看板

支持两种 transport,--transport stdio 本地单用户(默认),--transport http 团队共享,可以挂在容器里供多人访问。源码在 graphify/serve.py

启动命令示例。

# 本地 MCP
python -m graphify.serve graphify-out/graph.json

# 团队 HTTP(带 API key)
python -m graphify.serve graphify-out/graph.json \
  --transport http --host 0.0.0.0 --port 8080 \
  --api-key "$SECRET"

把建图和用图完全解耦,是这套设计最优雅的部分。建图是 CPU 密集型,可以扔 CI 跑。用图是 IDE 行为,可以走 MCP 协议和 AI 助手对话。两者不需要绑在同一个进程里。


四、Skill 指令的精妙之处是约束而非命令

在这里插入图片描述

graphify 在 AI 助手里跑,不靠 AI 自动发现这个工具,而是靠安装到宿主 AI 助手配置目录里的 Skill 文件。Skill 文件本质上是一段精心写过的 Prompt。源码在 graphify/skill.mdgraphify/cli.py

让我摘一段 cli.py 里 PreToolUse 钩子会注入给 AI 助手的"软提示"。

MANDATORY: graphify-out/graph.json exists. You MUST run
`graphify query "<question>"` before grepping raw files.
Only grep after graphify has oriented you,
or to modify/debug specific lines.

注意几个用词。

“MANDATORY” 是大写的,但语气是"必须做 X,然后才能做 Y",不是"禁止 Y"。它给助手留了 escape hatch(修改和调试特定行)。

“graphify has oriented you” 这个短语把"图查询"定义成"理解阶段",把"读文件"定义成"修改和调试阶段"。两个阶段各司其职。

同一文件里还有一个 _READ_DENY 变体,开启 --strict 模式时第一次直接 deny 原始 Read 调用,但每 session 只触发一次,所以助手永远不会被卡死。

这段 Prompt 写得相当克制。它没有试图用惩罚性语言逼迫助手,也没有无限循环拦截。它只在用户想读源码之前塞一句"你查图了吗?",然后放手。

Skill 设计的核心是,在正确的时间点给 AI 正确的提醒。控制 AI 并不是它的目的。

1. Skill 文件和 README 的边界

我顺手对比了一下 graphify/skill.md(安装到 IDE 的)和仓库根的 README.md。两者内容高度相关但目的完全不同。

README.md 面向人类开发者,介绍怎么装、怎么用、怎么贡献。skill.md 面向 AI 助手,介绍什么时候触发它、它能做什么、做完之后怎么告诉主人。

同样的功能,写 README 时强调易用性,写 Skill 时强调无歧义触发条件。graphify 在两份文档之间做了清晰的边界,避免了 AI 看到 README 后无所适从的问题。


五、踩坑指南,production 用之前先想清楚这些

我在本地用 uv tool install "graphifyy[all]" 装了一遍,挑了几个值得提醒的坑。

1. 包名和命令名不一样

pyproject.toml 里写的是 name = "graphifyy"(两个 y),但命令叫 graphify

# 错误
uv tool install graphify         # 找不到这个包

# 正确
uv tool install graphifyy        # 装包
graphify install                 # 用命令

为什么这个坑值得提。如果你想用 uvx 临时跑,必须写 uvx --from graphifyy graphify install,不能直接写 uvx graphify install(uv 会把第一个词当成包名去找)。

2. PowerShell 里 /graphify 会炸

在 PowerShell 里 /graphify . 会被解析成以根目录开头的路径,正确写法是 graphify .(不带斜杠)。这个坑在 README 的 Troubleshooting 里有专门一节,作者显然踩过。

3. Leiden 社区检测对 Python 版本敏感

pyproject.tomlleiden = ["graspologic; python_version < '3.13'"],意思是用 Python 3.13+ 时不装 Leiden,走降级实现。如果你的项目依赖 3.13,又想要 Leiden 社区检测,目前只能降 Python 或者 fork graspologic

4. graph.json 默认上限 512 MiB

环境变量 GRAPHIFY_MAX_GRAPH_BYTES 可以覆盖这个上限(支持 "700MB""2GB" 之类的字符串,也支持纯字节数)。对于几十万的代码库这个限制碰不到,但如果做整个 mono-repo 全索引,最好提前确认。

5. 查询日志默认不开启

GRAPHIFY_QUERY_LOG_ENABLE=1 开启查询日志到 ~/.cache/graphify-queries.log,记录每次 query / path / explain 的问题和语料路径。如果团队用,建议在 onboarding 文档里写清楚这个变量,避免被合规审计抓到。

6. --force 是覆盖,不是重建

--force 允许新的 graph.json 在节点数少于旧版本时仍然覆盖,不会主动清理已经不存在的旧节点。如果重构删了一批文件,要彻底清理得用 graphify extract . --force,再跑一次完整提取。


六、横向对比,同类项目里它处于什么位置

既然 wiki/references.md 列了几个对标项目,我把它们拉到一起比较一下。

1. 数据来源和输入支持

工具 代码 文档 PDF 视频 arXiv
graphify 36 种 tree-sitter MD/RST/HTML 本地解析 本地 whisper 支持
mem0 不支持 支持 需手动 不支持 不支持
supermemory 不支持 支持 支持 部分 不支持
GraphRAG 不支持 支持 支持 不支持 部分

graphify 是这里面唯一代码图构建零 LLM 成本的工具。其它几家本质是文档或对话向量化,代码只是其中一种文本。

2. 检索形态

工具 本质 检索方式
graphify NetworkX 知识图 图遍历加关键词混合
mem0 向量索引 余弦相似度
supermemory 混合向量加图 相似度加时间衰减
GraphRAG 知识图加向量 社区摘要加向量

向量索引在语义相似上很强,但在"两个东西到底怎么连"上很弱。graphify 的图遍历能直接给一条带边类型的路径,这是向量系统做不到的。

3. 成本曲线

这一点 graphify 自己有基准(BENCHMARKS.md),我自己也复算过。

套件 指标 graphify 对比系统
LOCOMO 召回率 recall@10 0.497 mem0 0.048, BM25 0.362
LOCOMO QA 准确率 45.3% supermemory 49.7%(贵 11×)
LongMemEval-S QA 准确率 76% dense RAG 76%(并列)
LOCOMO 摄取 USD ~$1.40 supermemory $15.67
图构建 LLM credits $0 其它按 token 计费

一个细节。这些数字是在 Kimi K2.6 一个模型、同预算、同裁判下测出来的,并且裁判的 Cohen’s kappa 是 0.81。不是某个团队自己跑、自己评。

4. 与 LLM 配合的姿势

graphify 的角色是 LLM 的前置索引。代码部分完全本地、零 LLM,非代码部分(文档、PDF、图片)才走 LLM 语义提取。这种"分层用 LLM"的设计,在我自己的项目里也想借鉴。能本地算的就不扔给云端。


七、我的判断与建议

适用场景。

  • 你在 Claude Code / CodeBuddy / Cursor 里工作,仓库是陌生的大型项目,需要快速建立 mental model。
  • 团队需要一个共同的代码地图,可以挂在 CI 上,每次 PR 自动 rebuild。
  • 你对代码隐私敏感,源码不能出境(graphify 的代码部分完全本地,能满足这一点)。

不那么适用的场景。

  • 仓库非常小,小于 1000 行。树建立索引的成本可能比 Read 几遍文件还高。
  • 主要是文档或对话语料库,代码占比极低。这种情况直接用向量 RAG 更合适。
  • 你希望 AI 助手主动理解,但你不想手动触发 Skill。graphify 默认按需触发,有 --strict 模式但仍有限制。

我自己的期待,几条非常具体的。

  • Leiden 在 Python 3.13+ 上能用。leidenalg 纯 Python 版的稳定性还要继续观察。
  • 如果 graph.json 持续变大,是否考虑分片存储。现在所有查询都是把整个 JSON 加载到内存里,几 GB 之后就开始吃力。
  • Skill 设计可以加一个 --quiet 模式,CI 跑时不要每次都打印 100 行进度。

最后一句。"AI 读代码"这件事,graphify 给出了我目前最认可的工程做法。它把代码变成图,让 AI 查图。它不会让 AI 突然变聪明,但能让 AI 不再那么浪费 token 和你的耐心。


参考文献

  1. Graphify-Labs/graphify GitHub 仓库
  2. graphify PyPI 包(graphifyy)
  3. ARCHITECTURE.md 模块职责与流水线说明
  4. BENCHMARKS.md LOCOMO / LongMemEval 基准结果
  5. Wikipedia:Signs of AI writing humanizer-zh skill 的判别依据
  6. Traag et al., “From Louvain to Leiden” (2019)
  7. tree-sitter 官方仓库
  8. NetworkX 文档
  9. Model Context Protocol 规范
  10. mem0 仓库
  11. Microsoft GraphRAG 仓库
  12. The Memory Layer Safi Shamsi 的技术书籍
Logo

汇聚全球AI编程工具,助力开发者即刻编程。

更多推荐