用 AI 编程助手读大仓库,最疼的不是不会读,是读不起:每开一个新会话,它都得把文件翻一遍,token 像流水一样走。向量检索(RAG)是主流答案,但它本质是「找几块长得像的文本碰运气」,返回的是相似度排名,不是代码的真实关系。
上周刷 GitHub 撞见了另一个思路:graphify,把代码库拆成一张图——类、函数、导入、调用都是节点和边,回答问题时沿真实的边遍历,每条边带 文件:行号 引用。GitHub API 实查 144,006 star(2026-11-08),Apache-2.0,我写稿这天凌晨它还在推送提交。我拿它把 Flask 和自己堆了三年的工作区各拆了一遍,这篇文章是全部实测结果。
先说清楚它是什么
graphify 的本体是一个 Python CLI(PyPI 包名是 graphifyy,五个 y,官方说正名在回收中)加一个 AI 助手技能。装好后你在 Claude Code、Codex、OpenCode 这些助手里输入 /graphify .,它就接管整个流程,产出四样东西:可交互的 graph.html、可持久查询的 graph.json、一份人话审计报告 GRAPH_REPORT.md,还有 SHA256 缓存目录。
架构上是两段式:代码文件走 tree-sitter 确定性 AST 抽取,完全不调模型、不要 API key;文档、PDF、图片才走模型语义抽取,而且后端可以指到本地 Ollama。官方反复强调「无 embedding、无向量库」,社区检测用 Leiden 算法按边的密度聚类,不靠相似度。
我的实测环境:macOS 26.5.2,M4 / 16GB,Python 3.13.12,opencode v2.1.4 配免费模型 nemotron-3.5-lightning:free(opencode 官方免费额度当天已耗尽,这也是个坑,后面细说)。
十分钟跑通全流程
安装两步,先装 CLI 再把技能注册进你的助手:
# 环境:macOS + Python 3.13,Windows/Linux 同理
pip install graphifyy # 注意是五个 y
graphify install # 默认注册到 Claude Code
graphify install --platform opencode # 我用的 opencode,也支持 codex/cursor/gemini 等 17 个平台然后找一个仓库试。我选了 Flask(读者都能复现):
graphify clone https://github.com/pallets/flask
cd ~/.graphify/repos/pallets/flask
opencode run -m openrouter/nvidia/nemotron-3.5-lightning:free "/graphify ."第一次直接跑会报错——flask 有 115 个文档文件和 8 张图片需要语义抽取,没有 API key 就走不下去。报错信息本身很友好,给了两条出路:设一个 key,或者加 --code-only 只索引代码。opencode 里的免费模型自己读懂了报错,主动切到 --code-only 把流程跑完了。
最终数字:100 个代码文件,产出 2325 个节点、3745 条边、213 个社区,整个 agent 会话 35 秒,token 花费 0。我后来用 Python 统计了 graph.json 里的边长这样:
| 边类型 | 数量 | 说明 |
|---|---|---|
| contains | 1316 | 文件包含符号 |
| references | 632 | 引用 |
| calls | 373 | 显式调用 |
| method | 313 | 方法边 |
| rationale_for | 304 | 注释里的设计理由挂到代码上 |
| imports / imports_from | 269 / 253 | 导入关系 |
| indirect_call | 126 | 间接调用 |
| inherits | 41 | 继承 |
最关键的一列其实不在表里,是置信度:3454 条 EXTRACTED(92.2%)对 291 条 INFERRED(7.8%),每条边都标了是「源码里直接找到的」还是「模型推测的」。这个设计我给好评——后面有个环节全靠它救场。
查询三件套:query、path、explain
图建好了,查询是纯本地 CLI,不用模型:
graphify query "AppContext 在哪定义、被哪些模块使用" --budget 1000
graphify path "Flask" "RequestContext" --undirected
graphify explain "Scaffold" --allquery 走 BFS 二度遍历。我问 AppContext,它找到 181 个关联节点,然后诚实地告诉我:预算 1000 token 只够显示 40 个,砍了 141 个,想全看就把预算提到 4852。截断不装死,明示你怎么拿全量,这种交互比很多工具的静默截断强太多。
path 给了我一个重要教训。我在自己工作区的图上查 GGUFWriter(llama.cpp 的 Python 写出器)到 ggml_add(C 层张量加法)的路径:有向图查无路径,加 --undirected 后给了 4 跳结果——中间经过了 math 这个节点,因为 gguf_writer.py 导入了 math,ggml.c 也导入了 math。两个共享一个标准库模块的文件,图上就是连通的。图的边是「语法事实」不是「业务调用链」,跨大社区的路径查询要自己长个心眼,别把连通当因果。
explain 我拿 451 度的 GGUFWriter 试的:5 秒出结果,451 条连接全部带方向(--> 出边 / <-- 入边)、类型、置信度和 文件:行号。
增量更新:改一行,1.9 秒
官方说改代码只重解析改动文件。我在 flask 的教程示例里加了个探针函数,然后:
graphify update .总耗时 1.9 秒,节点 2325 变成 2327,探针函数在 graph.json 里查得到了。缓存机制是 SHA256 对文件哈希,没改的文件直接跳过 AST。日常开发挂个 git hook,图就永远跟代码同步。
这里有个我踩的坑:一开始我随手敲了 graphify update examples/tutorial,它给我在子目录下新建了一张独立的 93 节点小图,而不是更新根图。update 的路径参数就是图的根,传子目录就建子图——想清楚再敲。
顺手做的压力测试:103,106 个节点
写这篇的时候出了个事故,反而成了全文最有说服力的数据:agent 在错误的工作目录执行了 /graphify .,把我的整个工作区——三年攒下的文章产出、脚本、克隆的 llama.cpp 源码——全扫了。5381 个代码文件,产出 103,106 节点、254,080 条边、2271 个社区,3 分 28 秒,0 token。我的 M4 风扇都没转起来。
两个意外收获:
- 敏感文件自动规避。它检测出 9 个「潜在敏感文件」并跳过——包括我目录里的
.npmrc和几个.pem密钥文件;flask 仓库里则跳过了.env。跑在本地不外传是一回事,工具主动不碰密钥文件是另一回事,后者更难得。 - 混语料会失真。我的工作区里 Python 脚本、C 源码、Svelte 组件、中文 markdown 混在一起,
query的 BFS 起点混进了旧文章标题和中文注释片段,社区标签也出现torch、os这种泛化巨社区。图工具假设语料是一个有机项目,喂它一锅粥,它就只能给你一锅粥状的图。建议给每个项目单独建图,配.graphifyignore(语法同 .gitignore)排掉杂物。
我核验了它的两个声称,一个属实一个注水
循环导入检测:属实,而且解释了 Flask 源码的一个为什么。 报告声称 __init__.py → app.py → ctx.py 存在导入环。我回源码核验:__init__.py 第 5-8 行确实从 .ctx 导入,app.py 第 32 行导入 .ctx;更有意思的是 app.py 第 124 行有个躲在函数体内的 from flask import Flask——这正是为了绕开包级循环才用的延迟导入。图检测到的环路方向是对的,具体逐跳路径带了推断成分(INFERRED 标签没有骗人),但「这里存在循环依赖」这个结论经得起查。
「71.5× fewer tokens」:实测没有这么神。 官网引用的用户证词说比读原文件省 71.5 倍 token。我做了个对照:grep -rn "AppContext" src/ 全量命中 4788 字节裸文本;graphify query --budget 1000 输出 3512 字节结构化结果。单次查询的字节数差距连一倍都不到。graphify 真正省 token 的场景是多轮、跨会话的架构级问题——图是持久化的,第 N 次提问不用再碰源文件;而且它给的是「谁调用谁、属于哪个社区」的关系数据,不是「恰好包含关键词的行」。单看一次 grep 式查询你甚至不需要它,skill 文档自己也承认:一次性单问题,直接 grep 更快。
踩坑清单
- PyPI 包名是
graphifyy(五个 y),CLI 才叫graphify。装错了会摸半天。 - opencode 免费额度是账号级日限额,换模型没用,官方几个免费模型撞的是同一堵墙——我在用免费模型跑安全审计技能那次也撞过。绕法是走 openrouter 的免费模型:nemotron-3.5-lightning:free 顶着 799 行的 skill 文档完成了全部编排,没掉链子——这已经是本站免费模型跑第三方技能系列的第三单,前两单是改 AI 味界面和上面的安全审计。
- 语义抽取必须有 key。没有 API key 时文档、PDF、图片完全不进图,
--code-only是唯一出路。想让文档也进图,可以把后端指到本地 Ollama,做到全离线;本地大模型的内存账可以参考我之前测的不装内存改「摆放」的推理方案。 - 社区命名会悄悄回退。没 key 时它先试
claude -p,我机器上没登录,三个批次全失败,最后用 Community N 占位——好在警告打得明明白白,没装没问题。 - tree-sitter_sql 是可选依赖。flask 仓库里 2 个 SQL 文件没进图,警告提示
pip install "graphifyy[sql]"。要索引带 SQL schema 的项目记得装 extras。
什么时候不建议用
- 一次性单问题:想知道「X 在哪定义」,grep 一下就完事,建图纯属杀鸡用牛刀(skill 自己都这么劝)。
- 想拿它当事实核查器:92% 的边是源码抽取的,剩下 8% INFERRED 是模型推测——上文的环路核验就是例子,方向对、细节可能是拼出来的。别把 INFERRED 边直接当架构文档抄。
- 混杂语料一锅建图:多项目目录、笔记、代码混在一起,社区检测会失真,查询结果噪声大。
- 代码之外的重语义场景无 key 硬跑:PDF、图片、音视频进图全依赖模型后端,没 key 就是空转。
写在最后
graphify 解决的是一个很具体的问题:让 AI 助手「记住」你的代码结构,并且每次回答都给出可验证的出处。它没有把 RAG 打死——单次查询省不了多少 token——但它把「第二问开始」的成本压到了接近零,同时用 EXTRACTED/INFERRED 标签守住了诚实的底线。
对每天在大仓库里跟 AI 结对的人,值得一装。花 35 秒建一张图,之后每次会话都少烧一截 token,这买卖在我这里是划算的。