首页
/ graphify 语料扩展与增量重建实战:`/graphify add` 拉取外部资料与 `--watch` 目录监控自动刷新知识图谱

graphify 语料扩展与增量重建实战:`/graphify add` 拉取外部资料与 `--watch` 目录监控自动刷新知识图谱

2026-09-07 13:58:09作者:何将鹤

本指南面向使用 graphify 将代码库、文档与外部资料沉淀为可查询知识图谱的开发者,围绕 Codex 平台的 graphify skill 参考文档 add-watch.md 展开。你将掌握两条把“新内容”接入既有图谱的官方路径:用 /graphify add <url> 抓取并落盘一篇外部网页/推文/论文/PDF/视频,再触发语义重建;或用 --watch 让目录监控在代码变更时无需 LLM 即可自动重建图谱。读完即可在 Claude Code、Codex 等 agent 工作流中组合使用两者,实现“边写代码、边抓资料、图谱始终新鲜”。

说明:文中讨论的两条能力都不是默认构建的一部分,需要显式触发。本文同时给出 graphify/skill-codex.md 中的调用约定(见其 For /graphify add and --watch 小节)与底层 Python 实现 graphify/ingest.pygraphify/watch.py,方便按需查证。


一、能力定位:为什么 add 与 watch 不属于默认构建

graphify 的主流程是“把目录变成可查询知识图谱”的一次性(或增量)构建:detect 扫描语料 → extract 解析 → build/cluster 建图 → 产出 graphify-out/graph.jsonGRAPH_REPORT.md 与可选的 graph.html。而本文要讲的两条路径是它的“内容入口”和“时效保障”:

  • /graphify add <url>:把语料库之外的 URL 抓取成本地文件并纳入 ./raw,随后执行更新管线把它合并进既有图谱
  • --watch:守护某个目录,当其中的代码文件变化时立即自动重建(无需 LLM),当文档/论文/图片变化时提示需要一次 LLM 语义更新。

两者都“不是默认构建的一部分”,因此文档要求 agent 只有在用户显式运行了 /graphify add 或传入了 --watch 时才加载对应的参考。Codex skill 的总览把它们的调用方式列为:

  • /graphify <path> --watch —— 监听目录,代码变更自动重建(不需要 LLM);
  • /graphify add <url> —— 抓取 URL、存入 ./raw 并更新图谱;
  • /graphify add <url> --author "Name" / --contributor "Name" —— 记录写入者与语料贡献者。

当用户真正执行这些子命令时,agent 应查阅 add-watch.md,也就是本文展开的核心文档(同名参考在 agentsclaude 等多个平台目录下各有一份,内容一致,平台包体积靠 tools/skillgen 生成)。


二、/graphify add <url>:把 URL 变成图谱里的一个文件

2.1 执行模型与参考命令

文档给出的“抓取 URL → 加入语料 → 更新图谱”动作,本质上是一次对 Python 函数 graphify.ingest.ingest 的调用。参考命令如下(原样继承自文档):

$(cat graphify-out/.graphify_python) -c "
import sys
from graphify.ingest import ingest
from pathlib import Path

try:
    out = ingest('URL', Path('./raw'), author='AUTHOR', contributor='CONTRIBUTOR')
    print(f'Saved to {out}')
except ValueError as e:
    print(f'error: {e}', file=sys.stderr)
    sys.exit(1)
except RuntimeError as e:
    print(f'error: {e}', file=sys.stderr)
    sys.exit(1)
"

其中三个占位符的替换约定:

占位符 含义 替换规则
URL 待抓取链接 替换为真实 URL
AUTHOR 写入者 用户提供了姓名才填,否则按源码回退逻辑处理(见下)
CONTRIBUTOR 语料贡献者 同上

2.2 $(cat graphify-out/.graphify_python) 是什么

命令中没有硬编码 python3,而是读取 graphify-out/.graphify_python 文件得到“正确解释器”路径。该文件的写入发生在 skill 初始化时(参考 hooks.py 的探测顺序:先看固定环境、再看 .graphify_python 文件、再按绑定目录推导、最后回退到 python3),其作用是让同一段 shell 代码在 venv、uv、系统 Python 等不同环境下都能命中“装着 graphify 的那个解释器”。因此后续所有 bash 块都应以 $(cat graphify-out/.graphify_python) 取代裸的 python3

2.3 错误处理契约

文档对失败路径有严格要求:

  • ingest 抛出 ValueError(典型的如 URL 未通过校验)或 RuntimeError(网络抓取失败等),一律打印 error: <原因>stderr 并以退出码 1 结束;
  • 不得静默跳过——命令出错必须如实告知用户,避免 agent “假装成功”导致图谱缺失该内容;
  • 成功落盘(输出 Saved to <路径>)之后,自动对 ./raw 跑一遍 --update 管线,把新文件合并进既有图谱。

2.4 URL 类型自动识别:六类来源

文档列出了 ingest 自动识别的 URL 类型,均可由 ingest.py 中的 _detect_url_typeL64-L81)印证:

类型 判定依据(源码中的匹配逻辑) 落地行为 后续处理
Twitter / X URL 含 twitter.comx.com publish.twitter.com/oembed 拉取,存为带推文正文与作者的 .md 下一次 update 由语义层抽取
arXiv URL 含 arxiv.org 且能提取 \d{4}\.\d{4,5} 编号 抓摘要页,把标题/作者/摘要连同元数据存为 .md 同上
PDF 路径以 .pdf 结尾 直接以二进制形式下载到 ./raw PDF 切片/语义抽取
图片 .png/.jpg/.jpeg/.webp/.gif 二进制下载 依赖视觉模型在下一轮抽取内容
YouTube / 视频 URL 含 youtube.comyoutu.be 通过 yt-dlp 下载音频 下一轮转写为 .txt,需要 video 可选依赖
普通网页 以上都不命中 拉 HTML,抽取 <title>,转成 Markdown 存盘 作为文档抽取

几个值得注意的实现细节(均可在源码中核对):

  1. 安全前置校验ingest 在分支处理前先调用 validate_url(url)(来自 graphify/security.py),校验失败抛 ValueError,对应上面 try/except 的第一个分支;
  2. 网页正文清洗:先正则剔除 <script>/<style> 再转换,优先用 markdownify(ATX 标题、- 列表、丢弃 <img>),没有该库时才退回朴素的标签剥离(并截断到 8000 字符),详见 _html_to_markdownL88-L100);
  3. YAML 前端元数据:每个 .md 都会带上 source_urltypecaptured_at(UTC ISO 时间)、contributor 等字段,作者/论文作者分别存入 author/paper_authors。所有可被远程页面污染的值(如标题)都经 _yaml_str 转义,防止注入出兄弟 YAML 键(L13-L52);
  4. 防覆盖命名:文件名由 URL 主机的 netloc+path 清洗而成,最长 80 字符;若同名文件已存在,则自动追加 _1_2…… 计数器(上限 1000),避免抓取重复推文/文章时互相覆盖(L259-L268)。

2.5 命令行直用

除 skill 的 python -c 包装外,ingest.py 自带 __main__ 入口(L344-L353),可直接运行以便人工调试:

$(cat graphify-out/.graphify_python) graphify/ingest.py <url> ./raw --author "Name" --contributor "Team"

其参数与 skill 路径一致:位置参数 url、可选目标目录(默认 ./raw)、--author--contributor


三、--watch:目录守护与免 LLM 自动重建

3.1 启动方式

$(cat graphify-out/.graphify_python) -m graphify.watch INPUT_PATH --debounce 3

INPUT_PATH 替换为要监听的目录;--debounce 3 表示“停止收到文件事件 3 秒后才触发一次重建”。模块入口等价实现见 watch.py 末尾的 argparse,默认监听 .、默认 --debounce 3.0

3.2 触发后的行为分支

文档把变更分成两类,watch.py 中对应的判定逻辑分别位于 _batch_triggers_rebuildL2107-L2118)与 _notify_onlyL2092-L2100):

变更内容 系统行为 是否需 LLM
仅代码文件(.py/.ts/.go 等所有 AST 可解析扩展名,甚至 .md/.mdx 这类有抽取器的文档) 立即重跑“AST 抽取 + rebuild +(必要时)cluster”,自动更新 graph.jsonGRAPH_REPORT.md(拓扑无变化时保留原产物并顺带自愈缺失的 graph.html
文档、论文、图片等非代码文件 graphify-out/needs_update 写入标志并打印通知,提示运行 /graphify --update 做 LLM 语义重抽取
纯删除(无论何类文件) 视同需要 rebuild——删除的节点逐出无需 LLM,由全量语料 reconcile 完成

3.3 debounce 的意义

默认 3 秒的防抖窗口,是为了让“一波并行写入”合并成一次重建,而不是每个文件各触发一次。这在 agent 场景尤其重要:一批 agent 并发落盘几十个文件时,若没有防抖,守护进程会反复重建、浪费 CPU 并不断重写产物。实现上,观察线程每 0.5 秒巡检一次,只有“距最近一次事件已超过 debounce”才取出批处理(见 watch() 主循环)。

3.4 停止与后台运行

前台按 Ctrl+C 即可停止,观察器会优雅退出(observer.stop()/observer.join())。文档明确建议的 agent 工作流是:

在后台终端里跑 --watch:agent 波浪式写入的代码改动会在各波之间被自动拾取并重建;若 agent 同时也在写文档或笔记,则需要在这些波之后手动执行一次 /graphify --update

也即“代码交给守护进程、语义留给手动更新”的分工,与 3.2 的分支完全对应。

3.5 源码级加固细节(供排查时参考)

  • 忽略规则:启动时一次性加载 .graphifyignore(可选叠加持久化的 gitignore 开关),事件处理器先在扩展名/隐藏目录过滤之前短路掉被忽略路径;graphify-out 自身的写入、以 . 开头的路径段都不会触发自身循环重建(L2171-L2208)。
  • 只读事件过滤:Linux inotify 下的 opened/closed_no_write 只算“被读”不算“被改”,避免守护进程自己读文件引发无限重触发(_READ_ONLY_EVENT_TYPESL2121-L2136)。
  • 重建互斥:rebuild 全程持有基于 fcntl.flock.rebuild.lock,拿不到锁的增量请求会先把变更集写入 graphify-out/.pending_changes,等持锁进程重建后回吸合并——保证并发的 post-commit hook 与 watch 触发不丢变更(L161-L218)。
  • macOS 用轮询观察器PollingObserver 用于规避 FSEvents 对某些编辑器快速保存的漏报(L2212)。
  • 持久化排除项:初次 extract--exclude/gitignore 决策被写入 .graphify_build.json,watch/update 的 rebuild 会重新套用,避免已排除路径被悄悄召回(L80-L137)。
  • 外部队列可读的进程 ID:持锁期间 .rebuild.lock 内容为持有者 PID,发布脚本等外部轮询者可以据此判断重建是否结束(L182-L218)。

四、两套机制串联成的“自更新语料管线”

将以上能力组合,可得到一条不打断开发节奏的知识图谱保鲜链路:

  1. agent 执行 /graphify add <url>ingest 把六类外部资料归一化落盘到 ./raw
  2. 成功后自动对 ./raw--update,把新文件合并进既有图谱,产出刷新 graph.json / GRAPH_REPORT.md
  3. 后台常驻 graphify.watch <项目目录> --debounce 3
  4. 代码变更波(.py/.ts/.go/可解析的 Markdown 等)被守护进程捕获,防抖后走 AST-only 重建:detect → extract(仅变更文件,配合从旧图挑选的 resolution context)→ build → cluster → report,全程不调用 LLM,因此可以放心高频率运行;
  5. 新下载的推文/论文转写稿、新增的 PDF/图片/长文档触发 needs_update 标志,agent 在合适的波次后执行一次 /graphify --update 完成语义重抽取。

值得注意的边界条件(源码注释可印证):已携带语义(LLM)层节点的文档不会被 AST 快扫重复建节点(避免同一文件双重表示造成约 4 倍膨胀,见 watch.py L1420-L1482 附近 semantic_doc_files 的判定);而“节点数骤减但文件仍存在”会被 shrink guard 拦截,只有 --force 或显式删除证据才能放行较小写入(_check_shrinkL1080-L1150)。这些设计让 add + watch 的高频重建不会意外摧毁既有图谱。


五、验证与测试入口

仓库对这两条路径均有专门测试,可作为行为规范的“可执行文档”:

平台分发侧的权威参考位于各 skill 目录的 references/add-watch.md(如 codex 版),codex skill 正文 skill-codex.md 中“For /graphify add and --watch”一节会指引 agent 加载它——本文即为该参考的完整展开。

六、快速结论

  • 想让“外部链接”进入图谱,用 /graphify add:六类 URL 自动识别、安全落盘、成功后自动 --update,失败必须显式报错;
  • 想让“代码变化”即时反映到图谱,用 --watch(后台终端 + 默认 3 秒 debounce):代码变更免 LLM 自动重建 graph.json/GRAPH_REPORT.md;文档/图片变更只写 needs_update 标志,等你手动跑一次 /graphify --update
  • 两者叠加即形成“agent 时代”的语料保鲜闭环:抓取与代码演进交给自动化,语义理解保留给 LLM 驱动的 update,全程不打断开发节奏。
登录后查看全文
热门项目推荐
相关项目推荐