graphify:把代码库变成可查询知识图谱的 Agent Skill
问 AI 编程助手"这个项目的鉴权是怎么接到数据库的",多数宿主的做法是重新 grep 一轮、逐个文件读进去,把一整轮上下文预算花在重建一份本来就固定的认识上。graphify 把这轮认识一次性沉淀成图:跑一次 /graphify .,得到 graphify-out/graph.json、可点击的 graph.html 和一份 GRAPH_REPORT.md,之后的问题改成在图上做遍历回答。
仓库形态是一条复杂 Skill 加一个 Python CLI。Skill 正文 graphify/skill.md 把流程写成按顺序执行的步骤,算得准的部分交给 graphify 命令和包内 Python 模块;每个步骤要看的补充材料随宿主安装在各自的 references/ 目录里,用到才读。CLI 负责把这条 Skill 注册到二十多个宿主。代码这一路走 tree-sitter,按各语言的语法规则在本机解析出类、函数、import 和调用关系,不经过模型,默认就带上 25 套语言语法;文档、PDF、图片,以及视频在本地转写出的文字稿,才走语义抽取。
GitHub 仓库信息
| 信息 | 内容 |
|---|---|
| 项目标题 | graphify |
| 项目描述 | 把任意代码库连同库内的文档、SQL schema、配置文件和 PDF 变成可查询的知识图谱;这是一条面向 Claude Code、Cursor、Codex、Gemini CLI 等助手的 /graphify 技能,用本地确定性 AST 解析,每条边都标注来源,不依赖向量库。 |
| GitHub 仓库 | Graphify-Labs/graphify(safishamsi/graphify 现在 301 重定向到这里) |
| 官网地址 | https://www.graphify.com |
| 主要开发语言 | Python 99.99%、Dockerfile 0.01% |
| 开源许可证 | Apache-2.0,早期以 MIT 贡献的部分保留在 LICENSE-MIT |
| 最近代码更新 | 2026-09-20(GitHub pushed_at;核对日期:2026-09-22) |
版本信息有三层,混写会得出错误结论:GitHub 最近一次 Release 是 v0.9.65(2026-09-20 发布),PyPI 上 graphifyy 的最新版本同样是 0.9.65;活跃开发分支是 v8,固定提交 20a20d30 就是 v8 的分支头;仓库里还有一个 v1.0.0 标签,指向 2026-04-05 的一次早期提交,属于遗留标签而不是新版本。NOTICE 说明当前产品按 Apache-2.0 授权,早期以 MIT 提交的片段仍按原条款可用,因此把 graphify 一概写成 MIT 项目并不准确。
一条 Skill,二十三个安装目标
逻辑上的公开 Skill 只有一个 graphify,但包内带着 16 份 Skill 正文。安装器 graphify/install.py 的 _PLATFORM_CONFIG 注册 21 个具名键,antigravity-windows 已经是其中一个;gemini、cursor、vscode 三个目标走这张表之外的分支,antigravity-windows 在 README 的平台表里不单列一行,所以合起来正好是表中的 23 行。这 23 行并不对应 23 条不同 Skill:claude、codebuddy、antigravity、kimi、gemini 共用 skill.md,trae 与 trae-cn 共用 skill-trae.md,claw 与 hermes 共用 skill-claw.md,windows 与 antigravity-windows 共用 skill-windows.md。
差异集中在两件事上:宿主把 Skill 扫哪个目录,以及宿主有没有 PreToolUse 这类钩子。14 个宿主目录下各带一份 references/ 侧车(query.md、update.md、extraction-spec.md 等 8 份),正文与侧车都由 tools/skillgen/platforms.toml 从同一批 fragment 生成,CI 用 python -m tools.skillgen --check 防止手写漂移。910 个路径里找不到 Skill 常见的 assets/ 或 templates/ 目录,一切可下载产物都由 CLI 现算现写进 graphify-out/。选平台实际是在选宿主能拿到哪一层触发保障:
| 保障层级 | 代表宿主 | 生效机制 |
|---|---|---|
| 钩子主动拦截 | Claude Code、CodeBuddy、Gemini CLI、OpenCode、Kilo Code | PreToolUse / BeforeTool / tool.execute.before 在搜索式和逐文件读取类工具调用前提示走图谱 |
| 指令文件常驻 | Codex、Cursor、Aider、OpenClaw、Factory Droid、Trae、Kiro、Devin、Antigravity、VS Code Copilot Chat、Amp、Agent Skills 跨框架目标 | AGENTS.md、.cursor/rules/graphify.mdc、.kiro/steering/graphify.md、.windsurf/rules/graphify.md、.github/copilot-instructions.md 等指令文件承载同样的查询优先指引 |
| 只放 Skill 文件 | GitHub Copilot CLI、Pi coding agent、Kimi Code | 没有常驻入口,只有用户显式输入 /graphify 时才走流水线 |
回到表格里的 Codex 一行:graphify codex install 会在 .codex/hooks.json 注册 graphify hook-check,而 CLI 里这个分支只有一行 sys.exit(0)。原因是 Codex Desktop 会拒绝 PreToolUse 上的 hookSpecificOutput.additionalContext,硬塞提示会打断 Bash 调用,于是钩子装了也不说话。真正的常驻机制在 AGENTS.md。Trae 落在指令文件这一档:安装器不为 Trae 注册 PreToolUse 钩子,常驻机制同样是 AGENTS.md。
安装范围与支持平台
包名和命令名不一致,是这里最容易踩的第一处坑:PyPI 包叫 graphifyy(两个 y),提供的命令叫 graphify。
uv tool install graphifyy # 推荐:隔离环境
pipx install graphifyy # 等价选择
graphify --version # 期望:打印 0.9.65 或更高前置条件是 Python 3.10 以上。装完找不到命令,通常是工具 bin 目录(~/.local/bin)还没进 PATH:uv tool update-shell 或 pipx ensurepath 之后重开终端。想临时运行而不安装,得写 uvx --from graphifyy graphify …,直接 uvx graphify 会去解析一个并不存在的 graphify 包。
第二条 Skill 注册命令与"常驻"命令长得极像,做的是两件不同的事:
graphify install # 注册 Skill 本体到 ~/.claude/skills/graphify/SKILL.md
graphify claude install # 写 CLAUDE.md 段落 + PreToolUse 钩子,让助手主动查图
graphify install --project --platform codex # 项目级注册,写 .codex/skills/graphify/SKILL.mdgraphify install 争取的是入口:装完后宿主里出现 /graphify。graphify claude install 争取的是主动性:没有 /graphify 的普通对话里也优先查图谱,README 的"Make your assistant always use the graph"表格列的全是这类命令。安装范围上,不带 --project 写入用户主目录,带 --project 写入当前目录并提示可以 git add 的文件。卸载对应两条路径:graphify uninstall 一次清掉所有平台,加 --purge 连 graphify-out/ 一起删;单平台用 graphify <platform> uninstall。
升级要连着做两步,因为 Skill 正文和包版本各自带版本标记,只升包会在 IDE 里看到版本不匹配告警:
uv tool upgrade graphifyy
graphify install # 覆盖 Skill 文件;钩式安装还要重跑 graphify hook install 刷新内嵌解释器路径功能扩展全部走 optional extra,默认安装只有 AST 抽取所需依赖:[pdf]、[office]、[video](faster-whisper + yt-dlp)、[mcp]、[neo4j]、[leiden]、[sql]、[postgres]、[terraform]、[chinese](jieba 中文分词)等,[all] 一次装齐。只读代码不需要任何 extra,也不需要 API key。
支持语言的数量在三份文档里并不一致:README 的扩展名表头写 37 套 tree-sitter 语法,docs/how-it-works.md 写 25 种语言,worked/rsl-siege-manager/review.md 写 29 种。可核对的口径是固定提交的依赖表——25 个 tree-sitter-<语言> 包随默认安装进来,SQL、Terraform、Pascal、OCaml、Common Lisp、DreamMaker 各由对应 extra 追加,Apex 和 Robot Framework 走的是正则与官方解析器而非 tree-sitter。按语言数量做兼容性判断时以依赖表和 extra 清单为准。
最短有效体验
下面的产物、信号和数字都取自仓库自带的文档与运行样本,本次研究没有复现其中的操作流程。
cd /path/to/your-project
graphify install # 一次性
# 然后在助手里输入:
/graphify .成功的可观察信号是目录里出现 graphify-out/,其中 graph.json 非空、GRAPH_REPORT.md 至少列出一节 God Nodes、graph.html 能在浏览器打开并渲染出 README 所称的力导向(force-directed)图,节点可点击、可过滤、可搜索。纯代码仓库这一步不产生 API 费用:Skill 的 Part B 会直接写入空的语义文件并跳到合并步骤。终端里等价的确定性命令是 graphify extract . --code-only。
Windows 上要用 graphify . 而不是 /graphify .,PowerShell 会把开头的斜杠当路径分隔符。
建完之后,三条查询命令都只读 graph.json:
graphify query "鉴权请求是怎么走到连接池的"
graphify path "UserService" "DatabasePool"
graphify explain "RateLimiter"worked/rsl-siege-manager/ 是一份可以直接对照的完整结果:一个真实全栈仓库跑出 1886 节点、3876 边、141 个社区,90% 的边标为 EXTRACTED、10% 标为 INFERRED(INFERRED 平均置信度 0.62),文档记录的成本是 $0、端到端约十分钟 CLI 时间。worked/karpathy-repos/ 则是那组 token 比值数据的原始现场:52 个文件、约 92,616 词的混合语料上,朴素全量塞入约 123,488 token,单次 BFS 子图查询平均约 1,726 token,比值 71.5x;同一批语料只算代码部分是 8.8x。docs/how-it-works.md 的缩放表另给两行:graphify 源码加一篇 Transformer 论文的 4 文件语料是 5.4x,6 个文件的 httpx 合成语料约 1x。压缩收益随语料规模增长;文件本来就塞得进上下文窗口时,节省可以忽略,留下的好处是结构一目了然。
/graphify 内部的九步执行链
skill.md 里的原话是 "Follow these steps in order. Do not skip steps."。顶层编号到 Step 9,中间还插着 2.5、4.5 和合并写的 6b-8,部分步骤自带跳过条件:detect 没返回视频文件时 Step 2.5 整段不做,Step 0 只在参数是 GitHub URL 或需要合并的多个本地子目录时才走,单个本地路径直接跳过。进入这条流水线之前还有两个早退分支——--help 打印 Usage 就返回,不跑任何命令;图已建好、提问又是自然语言时跳过 Step 1–5,直接进入查询章节。模型承担的是 Step 3 的语义抽取和 Step 5 的社区命名两处,其余环节都有对应的命令或包内模块;--dedup-llm 这类显式开关另算,README 写明该开关复用已配置模型后端的那份 key。
正在准备渲染...
查看源码
flowchart TD
U[用户输入 /graphify path] --> G{graphify-out/graph.json 已存在?}
G -- 是,且是自然语言提问 --> Q[跳到查询:词表扩展 → BFS/DFS]
G -- 否,或显式重建 --> S1[Step 1 解析并落盘 Python 解释器]
S1 --> S2[Step 2 detect:文件分类与语料规模告警]
S2 --> S3[Step 3 抽取:Part A tree-sitter AST ∥ Part B 语义子代理]
S3 --> S4[Step 4 build → cluster → analyze → 导出 graph.json]
S4 --> S45[Step 4.5 图健康检查:悬挂/坍缩/自环边]
S45 --> S5[Step 5 用真实社区名重生成报告]
S5 --> S6[Step 6 graph.html(可选 Obsidian/wiki/Neo4j/SVG)]
S6 --> S9[Step 9 写 manifest、累计 cost.json、清理侧车]Step 2 在语料超过约 200 万词或 500 个文件时会先按一级子目录排出文件数前五名,然后停下来问用户跑哪个子目录,不擅自继续。这是 Skill 里的确认门之一。
Step 3 的 Part B 对子代理类型有硬性要求:必须用 general-purpose,不能用只读的 Explore,因为后者写不回 chunk 文件,抽取结果会静默丢失。收集阶段以 .graphify_chunk_NN.json 是否落盘作为成功判据,缺文件就打印警告,不记为成功;超过一半 chunk 失败则整轮中止。图片各自占一个 chunk(视觉需要独立上下文),分块时按同目录聚拢,以提高跨文件关系被抽到的概率。
Step 4 的写入受一个收缩保护约束:新图节点数少于已有 graph.json 时 to_json() 返回 False 并拒绝覆盖,报告和缓存旁文件也跟着不写,避免一次崩溃的抽取把好图换掉。重构删文件后想真正收缩,得显式 --force。Step 4.5 的健康检查只诊断不中止,但发现的问题必须以 GRAPH HEALTH WARNING 出现在最终摘要里。
社区命名在两种运行环境下走不同路径:宿主是 Claude Code、Gemini CLI 这类智能体时由智能体自己命名;裸 CLI 跑 cluster-only 时用配置的模型后端自动命名,--no-label 保留 Community N 占位,事后可用 graphify label 重命名。
没有向量检索,查询为什么还要扩展词表
graphify 明确不做 embedding,社区划分靠 Leiden 按边密度分组,语义相似关系(semantically_similar_to)作为普通边进图参与拓扑计算。这是 graphify 区别于向量 RAG 的卖点,代价在查询侧暴露出来:graphify query 的节点匹配是大小写折叠后的子串加 IDF 加权(一个词在整张图里越稀有,命中这个词的权重越高),没有词干还原、没有同义词、不跨语言。用户问"登录流程"而图上标的是 Guardian、session.py,字面匹配就是零命中,答案直接塌成噪声。
references/query.md 给出的补救办法是把扩展限定在图自己的词表内:先从全部节点标签里切出 3 到 30 字符的 token 集合写入 graphify-out/.vocab.txt,再要求模型只从这份清单里选不超过 12 个 token,跨语言和白话到术语的映射也只有在目标词确实存在于词表时才允许,选不出来就打印空集合并停下——不许凭训练记忆造一个近义词去搜。扩展结果会打印给用户,让这次改写可审计。对中文仓库,[chinese] extra 用 jieba 补查询分词,实现挂在 MCP 服务的查询路径上。
回答之后 Skill 还要求把问答写回去:
graphify save-result --question "Q" --answer "A" --nodes Foo Bar --outcome useful
graphify reflect --if-stale # 汇总成 reflections/LESSONS.md,输入更新过才干活--outcome 取 useful、dead_end、corrected,reflect 把这些记录聚合成经验文档并按社区标注节点为 preferred / tentative / contested;被源码变更追上的条目会显示 [code changed since — re-verify]。这条回路记录的内容,是"哪些问题问过、答案还可不可信"。
图谱报告的可靠性边界
worked/rsl-siege-manager/review.md 是仓库自己提交的评测,标准只有一条:报告头条里点名的东西,熟悉这个代码库的开发者会不会自己也提名。这份评测的结论对准备把 graphify 放进评审流程的人直接有用。
| 现象 | 具体表现 | 可用对策 |
|---|---|---|
| 测试工厂抢占核心抽象 | god nodes 前十名里 6 个是 _make_siege()、_make_member() 这类工厂,被报告标为"你的核心抽象" | .graphifyignore 排除 tests/、__tests__/ 只是部分缓解:同一仓库去测试后前十名里剩 SiegeMember(第 1)、BuildingType(第 7)、MemberRole(第 9)三个真实领域模型,cn() 和页面组件仍按度数留在榜上 |
| 度数高不等于语义重要 | 一行 Tailwind 合并工具 cn() 因被大量组件 import 排到第 5;React 顶层页面组件 BoardPage、PostsPage、MembersPage 因是入口而排到第 2、6、8 位 | 把 god nodes 当候选清单,不当结论 |
跨语言 INFERRED 假阳性 | 后端 Python 类型与前端 TypeScript 类型之间出现按名称相似度连出的 --uses--> 边,例子里的 AuthError → Member 两端运行时毫无关系;"Surprising Connections"一节的标题却把这类边当作现成的洞察呈现 | 读报告的"意外连接"一节时先看 0.62 左右的平均置信度;该次运行里唯一对应真实设计契约的那条,是后端 Pydantic schema 对前端类型的 API 契约 |
| 社区内聚度普遍偏低 | 141 个社区内聚度多在 0.05–0.17,报告把 0.05 写作"弱互联";仓库实际上是 backend/frontend/bot 三服务结构 | 低内聚在这里的价值是提示拓扑与心智模型不符,报告生成的"要不要拆分这个社区"不足以直接当架构建议 |
| 孤立节点噪声 | Alembic 迁移的 docstring 与 pytest docstring 被解析成独立节点,计入 752 个孤立节点,报告标注为"可能的文档缺口" | **/alembic/versions/*.py 之类的忽略规则能显著压低计数 |
| 建议问题偏图指标 | Suggested Questions 多是介数中心性与"SiegeMember 那 17 条推断边对不对"的自审问句,少有"鉴权流程怎么走"这类领域问题 | 领域问题仍要靠提问者自己想、自己问 |
上面这张表全部出自 rsl 那一份评测。图谱做对的部分在另一份评测里:worked/karpathy-repos/review.md 的语料是三个仓库加 5 篇论文、4 张图片,其中 micrograd 的 engine 与 nn 被正确分成两个社区,nanoGPT 与 minGPT 的 Block 之间生成了一条真实的跨仓库推断边,FlashAttention 论文连到了两边的 CausalSelfAttention,图片节点认出了 val_loss=2.905 at step 399。漏掉的是论文结论到具体实现的直连,评测里写明要 --mode deep 才补得上。
副作用、确认门与隐私
graphify 不是只读工具,写进工作区的文件本身就是交付物,这也是采用 graphify 的主要成本。
| 侧面 | 行为 | 证据 |
|---|---|---|
| 文件写入 | 在扫描根下创建 graphify-out/(graph.json、graph.html、GRAPH_REPORT.md、cost.json、cache/、若干 .graphify_* 侧车) | 静态读 skill.md Step 1–9 |
| Git 改动 | graphify hook install 写 post-commit 与 post-checkout 钩子并注册 graph.json 的 merge driver;已有 post-commit 时追加而非替换 | 文档声明 + references/hooks.md |
| 后台执行 | 钩子的重建在后台运行,大仓库上刚提交完的几秒内图谱可能滞后 | README 团队工作流一节 |
| 网络 | /graphify add <url> 与 GitHub URL 克隆会外呼;graphify prs 走 GitHub;文档/PDF/图片的语义抽取按配置发到所选模型后端 | 静态读 Skill 与 README |
| 凭据与付费 | Skill 侧只按 GEMINI_API_KEY/GOOGLE_API_KEY 决定语义抽取走不走 Gemini,并明确写着不读 ANTHROPIC_API_KEY、OPENAI_API_KEY;headless 的 graphify extract 才需要按 --backend 配对应 key | skill.md Step 3 的原文约束 + README 环境变量表 |
| 本地日志 | query/path/explain 与 MCP query_graph 可记入 ~/.cache/graphify-queries.log(JSON Lines),完整子图响应另需 GRAPHIFY_QUERY_LOG_RESPONSES | README 环境变量表 + graphify/querylog.py |
| 团队共享 | 建议把 graphify-out/ 提交进 Git,cost.json 加入 .gitignore,manifest.json 已按相对路径存储可移植 | README Team setup |
四件事会咬到现有工具链。
查询日志的默认值在 README 内部就有分歧:环境变量表说"默认关闭、需 GRAPHIFY_QUERY_LOG_ENABLE=1 才开启",Privacy 一节写成每次调用都会记录;graphify/querylog.py 只在 GRAPHIFY_QUERY_LOG 或 _ENABLE 存在时返回日志路径,否则返回 None,所以以关闭为默认。
缓存费用藏在 Claude Code 一侧:graphify extract 写工作区文件会作废 prompt cache,下一轮变成全额 cache-write 费用,README 的处置是把 graph.json 与 graphify-out/ 加进 .claudeignore。
MCP 的 HTTP 传输默认绑 127.0.0.1,对外暴露要 --host 0.0.0.0 和 --api-key 同时给;换来的是 --transport http 让全团队共用一个进程,不必各装一份本地 graphify。
拦截强度分两档,且严格档只属于 Claude Code:默认安装只是"提示"助手先查图,graphify install --project --strict 会拦下本次会话第一次直接读源码并转向图谱,之后退回提示,因此每会话最多触发一次而不会卡死;README 的标题和安装器的注释都把这档拦截限定在 Claude Code。
另需分开看的是隐私:代码确实留在本地(tree-sitter 路径),但"完全本地"这个说法只覆盖代码;文档、PDF、图片和视频是否外发取决于配置,视频走本地 faster-whisper。[video]、[office]、[pdf] 这类 extra 会引入较大的第三方依赖面,近期发布说明里有两条处理记录:v0.9.65 因 matplotlib 传递引入的 Pillow 出现 CVE 而给 svg/all 组的 Pillow 加上版本下限;v0.9.64 把 Terraform 里以 password、*secret*、*token*、*_key 命名以及连接串类的属性值在写入 graph.json 或送进模型之前脱敏。
适合谁,不值得为谁
值得采用的信号很具体:仓库大到逐文件读取代价明显、团队希望有一份能进 Git 的共享结构地图、要把论文和文档与代码放进同一张图并让助手持续用下去。同一套 CLI 还能以 MCP 形式把图暴露给助手,工具面包括 query_graph、get_node、get_neighbors、shortest_path、list_prs、get_pr_impact、triage_prs。
只有六个文件时 docs/how-it-works.md 的缩放表就给出约 1x 的比值,此时收益主要是可视化,成本却是提交一个额外的输出目录。测试密集、前后端同名类型很多的 monorepo,会同时命中上面几条误报模式,需要先调 .graphifyignore 才能得到可用的 god nodes。要"语义检索任意自然语言提问"的场景,graphify 的字面匹配加词表扩展并不等价于向量检索,仓库自报的 LOCOMO 结果也承认 QA 准确率 45.3% 低于 supermemory 的 49.7%,赢的一面是 recall@10 的 0.497,以及 LOCOMO 摄入一次约 $1.40、supermemory 为 $15.67 的成本差;LongMemEval-S 只有 50 个样本,且这些数字都出自项目方自己维护的 BENCHMARKS.md(同一套开放 harness、统一模型与判分器,最后更新 2026-07-05),固定提交里没有第三方复现记录。已有向量 RAG 或代码搜索平台的团队,替换成本要按这些指标自己复测。
值得学习与不应照搬的做法
把可确定的工作从模型手里拿走,是这条 Skill 最值钱的部分。AST 抽取、图构建、聚类、健康检查、收缩保护全是本地 Python,模型只做文档语义抽取和社区命名,因此代码语料建库成本为零、结果可复现。安装器把两个写入都做成暂存加原子重命名:references/ 先复制到 references.tmp 再 os.replace 就位,SKILL.md 最后一步用同名 .tmp 文件原子替换,因此中断的安装不会留下指向空侧车的半份技能;Skill 正文、16 张平台渲染配置(一张表渲染一份正文,gemini 连平台表都不在)和 6 段 always-on 文本都由 tools/skillgen 从 fragment 生成并带 --check 门禁,避免了多平台文档常见的复制漂移。
查询侧那条"只准用图自己的词表,选不出来就停"的约束,比多数 RAG 实现里放任模型改写查询要诚实。
有些做法不适合照搬。AGENTS.md/CLAUDE.md 里常驻一段"先查图"的指令,会持续占用宿主上下文,纯 Skill 与 strict 两档之间的差别在实际会话里需要自己验证。save-result 与 reflect 把问答写进工作区形成反馈环,这个环的输入是模型自己生成的答案,把这类自引用记录当事实来源前,需要确认团队能接受。另外,把 graphify-out/ 提交进 Git 让团队共享地图很省事,但 graph.json 的体积上限是 512 MiB(GRAPHIFY_MAX_GRAPH_BYTES 可调),大图进版本库会拖慢克隆,得连 .gitignore 策略一起决定,README 的默认建议未必适配。
继续探索
docs/how-it-works.md 按抽取的三遍流程讲清置信度分级和 Leiden 聚类;ARCHITECTURE.md 讲模块划分和怎样新增语言;BENCHMARKS.md 给出完整对比表与复现命令。想先确认 graphify 在自己的仓库上会得到什么,直接打开 worked/rsl-siege-manager/GRAPH_REPORT.md 对着 review.md 读,比读任何宣传都有效。仓库自身的 AGENTS.md 是一段真实可用的 always-on 配置样本,只有三条规则,其中包括改完代码跑 graphify update .。