graphify 导出与基准测试参考指南:从知识图谱到 Neo4j、FalkorDB、MCP 与 Token 压缩实测
本文基于 graphify 仓库中 Kiro 等编码 Agent 的 skill reference 文档《graphify reference: extra exports and benchmark》编写。该文档定义的是 graphify 在图构建完成之后的「附加导出与基准测试」环节:当构建命令带有
--wiki、--neo4j、--neo4j-push、--falkordb、--falkordb-push、--svg、--graphml、--mcp任一标志,或语料规模大到值得做 token 压缩评测时,逐个执行相应导出步骤。读完本文,你将掌握每种导出格式的触发条件、命令形态、输出产物与底层实现,能把一个已生成的graph.json自如地转成 Obsidian Wiki、Cypher 文件或直接推送进图数据库、静态 SVG/GraphML,甚至以 MCP 服务的形式开放给其他 Agent 实时查询。
一、导出子命令的触发条件与整体编排
在 graphify 的 skill 编排流程中,导出并不是 graphify build 的默认行为,而是逐标志独立触发的附加步骤。每个 export 步骤只在自己的 flag 出现时运行("Each step runs only for its own flag")。从 CLI 实现看,所有附加导出统一收敛到 graphify export <format> 这一条子命令树,支持的格式为 html、callflow-html、obsidian、wiki、svg、graphml、neo4j、falkordb,见 cli.py 的 export 分支。
export 系列默认从 graphify-out/ 读取构建产物:
- 图本体:
graphify-out/graph.json; - 社区标签(人工或 LLM 策展的可读命名):
graphify-out/.graphify_labels.json; - 社区划分与凝聚度分析:
graphify-out/.graphify_analysis.json; - 语料规模探测:
graphify-out/.graphify_detect.json。
共用参数 --graph PATH 与 --labels PATH 允许改指向其它目录的产物;若显式给出 --graph,标签文件默认跟着图所在目录走(labels_path = graph_out_dir / ".graphify_labels.json")。因此只要 graph.json 存在,以下命令基本都可独立回放,不一定需要重新做一次全量构建。
下面按 reference 文档的 Step 编号依次展开。
二、Step 6b:Wiki 导出(--wiki)
Wiki 导出只在构建命令显式携带 --wiki 时运行,并且必须在 Step 9 清理之前执行——因为它在运行期仍需要 .graphify_labels.json 里的策展社区命名。
graphify export wiki
对应实现位于 export.py 的 wiki 分发逻辑,真正的写入函数为 graphify.wiki.to_wiki。它把图谱渲染成一组面向 Agent 的 Markdown 文章,输出到 <输出目录>/wiki/:
- 每个社区生成一篇概览文章;
- 生成
wiki/index.md作为 Agent 入口页(CLI 会明确打印index.md -> agent entry point)。
两点易踩坑的前提条件:
- 必须有社区分析数据。若
.graphify_analysis.json缺失或为空,CLI 会拒绝导出并提示"refusing to export wiki to prevent data loss",要求先运行graphify extract .或graphify cluster-only .重新生成社区数据。 - 必须在清理前运行。Skill 编排里 wiki 属于 Step 6b(早于 Step 9 cleanup),就是为了保住
.graphify_labels.json;一旦该文件被清掉,社区文章将退化回Community N这种默认编号名,丢失策展语义。
三、Step 7:Neo4j 导出(--neo4j / --neo4j-push)
Neo4j 有两个行为完全不同的分支:生成可移植 Cypher 文件,或直推运行中的实例。
3.1 生成 Cypher 文件(--neo4j)
graphify export neo4j
此命令不连接任何数据库,仅调用 to_cypher 把图谱序列化为 graphify-out/cypher.txt,供你之后用 Neo4j 官方批量导入工具加载:
cypher-shell < graphify-out/cypher.txt
从源码可以看清其生成策略:
- 每个节点产出一条
MERGE (n:FileType {id: '...', label: '...'});——用MERGE而非CREATE,重复执行不会产生重复节点; - 每条边产出
MATCH (a {id}), (b {id}) MERGE (a)-[:REL {confidence: '...'}]->(b);,边上的confidence(EXTRACTED / INFERRED / AMBIGUOUS)会作为关系属性原样保留; - 节点类型取自节点的
file_type,例如Python、Markdown;关系类型由relation大写化而来,兜底为RELATES_TO。
值得强调的是其安全设计(见 _cypher_escape / _cypher_label):节点 label、id 等字面量位置的内容会做引号与换行的转义,而标签名、关系类型这类标识符位置的值无法在 Cypher 中安全转义,因此采用白名单式清洗(仅保留 [A-Za-z0-9_]、必须以字母开头,否则回退到安全常量),从根上避免把语料里不可信内容注入成可执行的 MATCH/DELETE 语句。这一点与 graphify 一贯的"来源内容即潜在攻击面"安全基线是一致的。
3.2 直推运行中的实例(--neo4j-push <uri>)
graphify export neo4j --push bolt://localhost:7687 --user neo4j --password PASSWORD
当同时提供 --push URI 时,走的是 push_to_neo4j,它通过官方 neo4j Python driver 建立会话、逐节点逐边 upsert:
- 默认 URI:
bolt://localhost:7687; - 默认用户名:
neo4j; - 全程使用参数化
MERGE ... SET n += $props,幂等安全; - 返回并打印实际写入的
nodes/edges计数。
关于密码的工程化细节:CLI 解析器为 push 类连接准备了 --push / --user / --password,并优先从环境变量 NEO4J_PASSWORD 读取密码——这是为了不让口令出现在 argv(进而暴露在 ps 输出与 shell history 里);显式的 --password 仍可覆盖环境变量。reference 文档也提醒:凭据未提供时应先向用户询问。
四、Step 7a:FalkorDB 导出(--falkordb / --falkordb-push)
FalkorDB 分支刻意与 Neo4j 区分对待,因为它虽然是 OpenCypher 兼容,执行模型却不同。
4.1 生成 Cypher 文件(--falkordb)
graphify export falkordb
同样产出 cypher.txt。reference 文档明确警告了一个实操误区:FalkorDB 的 GRAPH.QUERY 一次只执行一条语句,没有类似 cypher-shell 的整脚本批量导入;因此当你真正想装载一个图时,cypher.txt 只是"便携产物",优先用 --push 直推。
4.2 直推运行中的实例(--falkordb-push <uri>)
graphify export falkordb --push falkordb://localhost:6379
对应的 push_to_falkordb 与 Neo4j 路径共享同一套 MERGE/SET upsert 语义,但差异明显:
- 连接方式:用
FalkorDB(host, port, ...)SDK 而非 bolt driver;URI 只解析 host/port,scheme 是信息性的——falkordb://localhost:6379、redis://localhost:6379甚至裸的localhost:6379三者等价,默认端口 6379; - 命名图:通过
db.select_graph(graph_name)选择图,目标图默认名为graphify; - 鉴权可选:FalkorDB 默认无凭据即可运行,因此
user/password可缺省;仅在实例确实要求认证时才向用户询问。实现上只有当提供了 password 时才会带上 username,避免把 Neo4j 风格的默认用户误传给 FalkorDB 而被当成未知 ACL 用户拒绝(URI 中内嵌凭据优先级最高); - 无 session 对象:每条查询直接
graph.query(cypher, params)。
密钥同样支持环境变量 FALKORDB_PASSWORD,且与 NEO4J_PASSWORD 按子命令分流,互不串扰。
五、Step 7b:SVG 导出(--svg)
graphify export svg
生成 graphify-out/graph.svg。底层 to_svg 使用 matplotlib(Agg 后端)+ spring layout(seed=42 固定随机性)渲染静态矢量图,主要特征:
- 体积轻、零依赖 JS:可直接嵌入 Obsidian 笔记、Notion、GitHub README 等任意 Markdown 渲染器;
- 节点大小随度(degree)缩放,节点越多关系越多的枢纽符号越大;
- 节点颜色与 HTML 导出一致(复用
COMMUNITY_COLORS),便于两套产物对照阅读; - 边按置信度区分线型:
EXTRACTED画实线,非 EXTRACTED 画虚线且降低透明度,让"确定性事实"与"推断关系"在视觉上一目了然; - 若带社区标签则自动渲染图例(标注每个社区名及其成员数)。
前置条件是本机装有 matplotlib(pip install matplotlib),缺失时会抛出明确的 ImportError 提示。若读者使用 skill 化流程,只需保证生成 graph.svg 的源图存在——CLI 会自动从 graph.json 及随附的社区属性重建社区划分,因此即使 .graphify_analysis.json 被清理,SVG/GraphML 等导出仍能工作(这部分回退逻辑见 cli.py 的社区重建分支)。
六、Step 7c:GraphML 导出(--graphml)
graphify export graphml
生成 graphify-out/graph.graphml,面向 Gephi、yEd 等桌面图分析/可视化工具。实现 to_graphml 的几个关键点:
- 把社区 ID 写成节点属性
community,这样 Gephi 可直接按社区着色; - 把边的 confidence(EXTRACTED/INFERRED/AMBIGUOUS)保留为边属性;
- 会剔除下划线开头的内部标记(如 AST 来源
_origin、方向标记_src/_tgt),不让持久化/运行期细节泄漏进产物; - 对属性值做三层归一化:
None -> ""、dict/list -> JSON 字符串(GraphML 不支持非标量,见 #1831)、字符串再做 XML 1.0 非法字符清洗——否则一个标签里混入的 ANSI 转义序列会让整次导出在nx.write_graphml处崩溃; - 采用临时文件 + 原子替换写入,防止序列化中途出错留下 0 字节的伪完成文件。
七、Step 7d:MCP 服务器(--mcp)
这是把图谱从"静态文件"升级为"可被其它 Agent 实时查询的活服务"的关键一步:
$(cat graphify-out/.graphify_python) -m graphify.serve graphify-out/graph.json
命令里的 $(cat graphify-out/.graphify_python) 会把构建时记录的 Python 解释器绝对路径展开出来,再以 python -m graphify.serve <graph.json> 方式启动一个 stdio MCP 服务器。其工具清单在 serve.py 的 MCP 注册处 可完整看到:
| 工具 | 作用 |
|---|---|
query_graph |
面向自然语言问题检索子图并返回带引用的文本摘要 |
get_node |
按 label 解析单个节点(多义时给出歧义说明) |
get_neighbors |
返回某节点的邻居及关系 |
get_community |
查看节点所属社区 |
god_nodes |
返回跨社区枢纽节点(god node) |
graph_stats |
图规模统计 |
shortest_path |
两节点间最短路径 |
你可以把该服务挂到 Claude Desktop 或任意兼容 MCP 的 Agent 编排器上,让其它 Agent 以工具方式实时查询构建好的代码图谱。
Claude Desktop 配置的坑位说明
在 claude_desktop_config.json 中配置时要注意:Claude Desktop 无法执行 $(...) 命令替换,而且在 uv tool install 方式安装后,系统的 python3 通常无法 import graphify。因此配置里 command 必须填 .graphify_python 输出的绝对解释器路径:
{
"mcpServers": {
"graphify": {
"command": "<absolute path from: cat graphify-out/.graphify_python>",
"args": ["-m", "graphify.serve", "/absolute/path/to/graphify-out/graph.json"]
}
}
}
即:先用 cat graphify-out/.graphify_python 拿到解释器绝对路径填进 command,再把 graph.json 也用绝对路径写进 args,才能避开 Claude Desktop 对相对路径与命令替换的限制。
八、Step 8:Token 削减基准测试(语料 > 5000 词时)
这一步不是导出,而是成本论证:当语料大到值得用图谱结构替代"整库塞进上下文"时,量化 graphify 的查询能省多少 token。
触发条件读取自 graphify-out/.graphify_detect.json 的 total_words 字段:
- 若
total_words > 5000,执行:
graphify benchmark
并把输出原样打印在对话中,向用户呈现量化的压缩收益;
- 若
total_words <= 5000,静默跳过——reference 文档给出的理由很精辟:小语料下图谱的价值在于结构清晰而非 token 压缩,没必要跑基准。
运行 graphify benchmark 时,CLI 会尝试从 .graphify_detect.json 读取 corpus_words 供评测使用(见 benchmark 分发逻辑)。核心实现 run_benchmark 的做法是:
- 语料词数换算 token:
corpus_tokens = words * 100 / 75(约按 100 词 ≈ 133 token); - 用一组预置的示例问题,对每道问题在图上走查询管线,得到实际消耗的
query_tokens; - 汇总输出
corpus_words、语料 token 估算、图的节点/边数、每问题平均查询 token、总削减倍数 reduction_ratio,以及逐问题的削减明细。
最终控制台报告的形态(print_benchmark)大致是:Corpus: N words -> ~M tokens (naive)、Graph: X nodes, Y edges、Avg query cost: ~Z tokens、Reduction: Rx fewer tokens per query,下面再逐行列出每个示例问题对应的削减倍数——这组数字可以直接作为"为什么代码库要先建成图再喂给 LLM"的实证论据。若图尚未构建导致示例问题匹配不到任何节点,则会返回明确错误 No matching nodes found for sample questions. Build the graph first.
九、把导出串起来的几个注意事项
- 产物默认落在
graphify-out/:cypher.txt、graph.svg、graph.graphml、wiki/均与graph.json同目录,除非用--graph指到其它位置; - 图数据库两种形态分工:文件型导出(
neo4j/falkordb不带--push)给出可审查、可版本化的cypher.txt,适合交付或留档;push 型适合直接装载进正在运行的实例。Neo4j 可用cypher-shell批量导入脚本,FalkorDB 没有等价物,故 reference 明确建议其用--push; - 安全性是导出层的一等公民:Cypher 字面量转义 + 标识符白名单、GraphML 的 XML 清洗与原子写、Neo4j/FalkorDB 统一的参数化 upsert、以及密码优先走环境变量,共同保证"语料里不可信的内容"不会通过导出环节变成注入向量或让整次导出静默失败;
- 与 skill 编排的关系:本文所讲解的每一步(Step 6b/7/7a/7b/7c/7d/8)实际是 agent skill 在用户给出对应 flag 时执行的参考动作,同一个 reference 文档被同步复制到各 Agent 平台的 skill 目录中(例如 kiro 版本),保证 Claude、Kiro、Kilo 等不同前端跑出的行为一致;
- 何时评估:真正的建图、聚类、HTML/Obsidian 导出以及最后的清理属于其它 Step,不在本文范围;你只需记住:图一旦建好,
graphify export全家族可以随时重放,MCP 服务可以让图谱在 Agent 生态里"活"起来。
如需深入这些命令背后的完整实现,推荐直接阅读 export.py、exporters/graphdb.py、serve.py 与 benchmark.py,其中每一处导出都带有详实的工程决策注释(从文件系统非法字符、Windows MAX_PATH 到 Cypher/XML 注入防御),是理解"生产级图导出"的上佳样本。
atomcodeClaude Code 的开源替代方案。连接任意大模型,编辑代码,运行命令,自动验证 — 全自动执行。用 Rust 构建,极致性能。 | An open-source alternative to Claude Code. Connect any LLM, edit code, run commands, and verify changes — autonomously. Built in Rust for speed. Get StartedRust0629
MiniCPM5-2BMiniCPM5-2B 是一款面向端侧、本地部署和资源受限场景的 2B 稠密 Transformer,能够达到同尺寸开源模型 SOTA 水平。Markdown00
GLM-5.3GLM-5.3 与 GLM-5.2 使用相同的基座模型——所有提升均来自后训练。与 GLM-5.2 相比,它在复杂编程和长程任务上的表现显著提升。Jinja00
HivisionIDPhotos⚡️HivisionIDPhotos: a lightweight and efficient AI ID photos tools. 一个轻量级的AI证件照制作算法。Python07
DragonOSDragonOS is an operating system developed from scratch using Rust, with Linux compatibility. It is designed for **Serverless** scenarios. 使用Rust从0自研内核,具有Linux兼容性的操作系统,面向云计算Serverless场景而设计。Rust00
Spark-X2.5-1.7BSpark-X2.5-1.7B 旨在让强大的 AI 更加实用、高效且易于获取。这些模型在广泛的日常任务中表现出色,涵盖对话、写作、翻译、推理、编程、工具调用和智能体工作流,并在同等规模的开源模型中取得领先结果。Spark-X2.5 将面向效率的架构与最高 1M tokens 的原生上下文窗口相结合,并支持 200 多种语言。Python00