首页
/ graphify 导出与基准测试指南:从 graph.json 到 Wiki、图数据库与 MCP 实时查询

graphify 导出与基准测试指南:从 graph.json 到 Wiki、图数据库与 MCP 实时查询

2026-09-06 17:05:00作者:申梦珏Efrain

本篇基于 graphify 的 opencode 技能参考文档 exports.md 展开,完整覆盖 /graphify 流程中的全部可选导出步骤(--wiki--neo4j/--neo4j-push--falkordb/--falkordb-push--svg--graphml--mcp)以及大语料场景下的 token 压缩基准测试。读完本文,你将掌握每种导出标志对应的命令、产物与幂等性保证,并能结合 export.pygraphdb.pyserve.pybenchmark.py 等源码,理解 Cypher 生成、MERGE 幂等推送与 MCP 工具暴露的底层实现。

参考文档的加载时机与执行原则

原文档开头明确了这份参考的触发条件:当用户在 /graphify 命令中传入了任意导出标志(--wiki--neo4j--neo4j-push--falkordb--falkordb-push--svg--graphml--mcp),或者语料规模大到值得跑 token 压缩基准时,才加载并执行对应步骤。原文档强调一条关键原则:每一步只为自己的标志执行(Each step runs only for its own flag),即不传标志就不产出对应产物,导出是严格按需的。

cli.py 的实现可以印证这一设计:graphify export 子命令支持 htmlcallflow-htmlobsidianwikisvggraphmlneo4jfalkordb 八种格式,每种格式各自解析 --graph--labels--push--user--password 等参数,互不耦合。

Wiki 导出(仅当传入 --wiki)

只有当原始命令显式带有 --wiki 时才执行此步骤。 原文档额外指出:这一步要放在整个流程的第 9 步(清理)之前运行,因为 wiki 生成依赖 .graphify_labels.json(社区标签文件)仍然存在。

graphify export wiki

wiki.pyto_wiki() 实现可以看到产物的完整结构,它会在 graphify-out/wiki/ 下写出三类文件:

  • index.md:面向 Agent 的入口页,包含全部社区的目录(按规模降序排列)、god node(连接度最高的核心抽象)列表,以及节点/边/社区总数统计;
  • <CommunityName>.md:每个社区一篇维基风格文章,含 Key Concepts(社区内度数最高的节点及来源文件)、跨社区 Relationship 统计、Source Files 列表,以及一段 EXTRACTED/INFERRED/AMBIGUOUS 三级置信度占比的 Audit Trail;
  • <GodNodeLabel>.md:每个 god node 一篇文章,按关系类型分组列出其邻居及置信度。

两个值得注意的实现细节:to_wiki() 会先过滤掉社区列表中已不存在于图里的陈旧节点 ID(去重/增量重建后可能出现漂移),并拒绝在 communities 为空时清空 wiki/ 目录以防数据丢失;另外每次调用会先删除旧 .md 文章再整体重写,因为 to_wiki() 完全拥有 wiki/ 目录。cli.py 中的调用路径也会先检查 .graphify_analysis.json 是否存在,缺失时直接报错拒绝导出。

Neo4j 导出(仅当传入 --neo4j 或 --neo4j-push)

若传入 --neo4j —— 生成一份可手动导入的 Cypher 文件:

graphify export neo4j

若传入 --neo4j-push <uri> —— 直接推送到运行中的 Neo4j 实例。若用户未提供凭据,应先询问:

graphify export neo4j --push bolt://localhost:7687 --user neo4j --password PASSWORD

默认 URI 为 bolt://localhost:7687,默认用户为 neo4j。整个过程使用 MERGE 语句,重复执行是幂等的,不会产生重复节点或边

源码层面这两条路径分别对应:

  • 文件生成路径export.pyto_cypher() 为每个节点输出 MERGE (n:<FileType> {id: ..., label: ...});,为每条边输出 MATCH (a), (b) MERGE (a)-[:<RELATION> {confidence: ...}]->(b);。这里有两道安全防线:_cypher_escape() 会转义单引号、反斜杠和换行符(防止标签内容破坏 cypher-shell 以分号分隔语句的边界,见 F-008 注释),而 _cypher_label() 会把节点标签和关系类型中的非法字符剥离(Cypher 的 :Foo 标识符位置无法转义,只能白名单过滤,非法时回退到 Entity/RELATES_TO)。
  • 直推路径graphdb.pypush_to_neo4j() 通过 neo4j Python 驱动连接,逐节点执行 MERGE (n:{ftype} {id: $id}) SET n += $props,节点属性会附带所属社区编号 community,边则带完整关系属性。驱动未安装时会抛出明确的 pip install neo4j 提示。

另外,cli.py 支持用环境变量 NEO4J_PASSWORD 替代 --password 参数,避免密码出现在 ps 输出或 shell 历史中(F-031);--password 显式传入时优先级更高。

FalkorDB 导出(仅当传入 --falkordb 或 --falkordb-push)

若传入 --falkordb —— 生成 Cypher 文件。原文档特别提示:这些语句虽然是 OpenCypher,但 FalkorDB 的 GRAPH.QUERY 每次只能执行一条语句(没有 Neo4j cypher-shell 那种批量脚本导入),所以优先使用 --falkordb-push 装载图,只有想要可移植的 cypher.txt 产物时才用文件方式:

graphify export falkordb

若传入 --falkordb-push <uri> —— 直接推送到运行中的 FalkorDB 实例。凭据是可选的,仅在实例要求认证时才向用户询问:

graphify export falkordb --push falkordb://localhost:6379

默认 URI 为 falkordb://localhost:6379。这里有一个细节:协议头仅起说明作用,redis:// 或裸的 host:port 写法同样有效;认证可选;目标命名图默认为 graphify。同样使用 MERGE,重跑不产生重复。

graphdb.pypush_to_falkordb() 用注释完整列出了与 Neo4j 路径的差异,与原文档一一对应:

  • 连接方式改为 FalkorDB(host, port, username, password),只从 URI 中解析 host/port,因此协议头随意;
  • 通过 db.select_graph("graphify") 选择命名图,同一实例内按图名隔离;
  • 查询走 graph.query(cypher, params),没有 session 对象;
  • 认证可选:FalkorDB 默认无凭据运行,此时代码会忽略 bolt 风格的默认用户名(如 Neo4j 的 neo4j),因为 FalkorDB 会将其当作未知 ACL 用户拒绝;
  • MERGE/SET 语句与 Neo4j 路径完全相同,依赖 OpenCypher 兼容性实现幂等 upsert。

SVG 导出(仅当传入 --svg)

graphify export svg

cli.py 中该子命令调用 to_svg() 写出 graphify-out/graph.svg,控制台提示该图可嵌入 Obsidian、Notion 或 GitHub README。SVG 与 HTML、Obsidian 导出共用 base.py 中定义的 COMMUNITY_COLORS 十色调色板,保证社区着色在各格式间一致。

GraphML 导出(仅当传入 --graphml)

graphify export graphml

产物为 graphify-out/graph.graphml,可供 Gephi、yEd 等任意 GraphML 工具打开做进一步分析。export.py 中专门实现了 _strip_xml_illegal(),在写出前剔除 XML 1.0 无法承载的 C0 控制字符——标签直接来自语料,一个终端粘贴进来的 ANSI 转义序列就足以让 nx.write_graphml 抛异常中断整个导出,这个防护将其降级为单个标签的问题而非整次导出的失败。

MCP 服务(仅当传入 --mcp)

$(cat graphify-out/.graphify_python) -m graphify.serve graphify-out/graph.json

这会启动一个 stdio MCP 服务器,暴露以下工具:query_graphget_nodeget_neighborsget_communitygod_nodesgraph_statsshortest_path。把它接入 Claude Desktop 或任何 MCP 兼容的 Agent 编排器,其他 Agent 就能对图谱做实时查询。

serve.py 中的工具定义与原文档列出的清单一致,关键参数包括:query_graph 支持 mode=bfs/dfsdepth(1-6)与 token_budget(默认 2000 token);shortest_path 默认遵循存储的边方向,undirected=true 可忽略方向;graph_stats 返回节点数、边数、社区数与置信度分布。源码中还可以看到服务器实现了带 LRU 缓存的图上下文管理(默认 8 个项目上下文,可用 GRAPHIFY_MAX_CONTEXTS 覆盖),以及加载前对 graph.json 的文件大小上限检查。

Claude Desktop 配置要点(原文档给出的完整示例):Claude Desktop 无法执行 $(...) 命令替换,且 uv tool install 安装方式下系统 python3 无法 import graphify,因此 command 必须写成 cat graphify-out/.graphify_python 打印出的绝对解释器路径

{
  "mcpServers": {
    "graphify": {
      "command": "<absolute path from: cat graphify-out/.graphify_python>",
      "args": ["-m", "graphify.serve", "/absolute/path/to/graphify-out/graph.json"]
    }
  }
}

其中 <absolute path from: ...> 占位处填第一步 cat 命令的实际输出,args 第三个元素填 graphify-out/graph.json 的绝对路径。

Token 压缩基准测试(仅当 total_words > 5000)

graphify-out/.graphify_detect.json 中的 total_words 大于 5,000,则运行:

graphify benchmark

并把输出直接打印到聊天中。若 total_words <= 5000静默跳过——原文档的理由是:对小语料而言,图谱的价值在于结构清晰度,而不是 token 压缩。

cli.py 中的命令实现与这一描述完全对应:它从 .graphify_detect.json 读取 total_words 后调用 run_benchmark()benchmark.py 的度量方法值得了解:

  • 朴素基线corpus_tokens = corpus_words * 100 // 75(即按 100 词约 133 token 折算整份语料直接塞进上下文的成本);
  • 图查询成本:对 5 个内置样本问题(如 "how does authentication work"),用 serve.py_query_terms 做节点标签匹配,取得分最高的 3 个节点为起点做 3 层 BFS,把访问到的节点(label + 来源文件 + 位置)与边(关系)渲染成文本,按每 4 字符约 1 个 token 估算;
  • 输出print_benchmark() 打印语料 token 数、图谱节点/边数、平均单次查询 token 数,以及 reduction_ratio(每次查询节省的 token 倍数)和每个问题的明细。若样本问题在图中找不到任何匹配节点,会返回 "Build the graph first" 的错误提示。

小结

这份参考文档把 graphify 的"图谱出图"能力归纳为一条按标志触发的流水线:wiki 服务于 Agent 可读的静态维基,Neo4j/FalkorDB 服务于图数据库里的交互式 Cypher 查询(文件生成与直推两种模式,均靠 MERGE 保证幂等),SVG/GraphML 服务于可视化生态,MCP 服务则让任意 Agent 对图谱做活的查询,最后由 token 压缩基准在语料足够大时量化图谱带来的上下文节省。所有步骤共享同一份 graphify-out/graph.json 产物,命令、默认值与幂等性语义均可在上述源码路径中逐条核对。

登录后查看全文
热门项目推荐
相关项目推荐