news 2026/9/8 22:04:23

graphify 外部内容接入实战:`/graphify add <url>` 语料抓取与 `--watch` 目录增量建图完全指南

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
graphify 外部内容接入实战:`/graphify add <url>` 语料抓取与 `--watch` 目录增量建图完全指南

graphify 外部内容接入实战:/graphify add <url>语料抓取与--watch目录增量建图完全指南

【免费下载链接】graphifyTurn any codebase, with its docs, SQL schemas, configs, and PDFs, into a queryable knowledge graph. A /graphify skill for Claude Code, Cursor, Codex, and Gemini CLI: local deterministic AST parsing, every edge explained, no vector store.项目地址: https://gitcode.com/GitHub_Trending/graph/graphify

graphify 默认构建链路把「某个本地目录」解析成可查询的知识图谱,但真实开发中语料来源往往是动态的:你随时可能丢进来一篇 arXiv 论文、一段推文、一个网页或一段演讲视频,也会在 Agent 并行写代码的过程中持续新增与修改文件。本篇技术指南聚焦 graphify 在默认构建之外的两个增量扩展入口——/graphify add <url>(抓取一个 URL 进入语料库并合并进图谱)与--watch(后台监听文件夹、随文件变化自动重建图谱),完整讲解它们的命令用法、URL 类型自动识别、目录监听的分流策略,并结合 ingest.py、watch.py、transcribe.py、security.py 的源码实现,说明底层是如何保证安全、防重、去抖与原子更新的。读完你既能手工把这些命令接进自己的工作流,也能理解一个"持续保鲜"的图谱背后的工程机制。

本文依据仓库内已发布到各平台的参考文档整理,源文件为片段库中的 tools/skillgen/fragments/references/shared/add-watch.md,其在各技能目录下均有同名副本(如 graphify/skills/agents/references/add-watch.md)。各平台的完整技能文件(graphify/skill.md 等)在文档末尾统一跳转到该参考:当用户运行/graphify add <url>或传入--watch时加载——这两者都不是默认构建(default build)的一部分,是显式选用的扩展流程。

一句话背景:为什么需要 add 与 watch

  • 默认的/graphify <path>是一次性的:给定目录 → 检测文件 → AST + 语义抽取 → 聚类 → 产出graphify-out/graph.jsonGRAPH_REPORT.md
  • add解决"语料之外的内容进来":把网页/论文/推文/PDF/图片/视频抓进./raw,再增量合并进已有图谱。
  • watch解决"语料之内持续变化":后台盯着目录,代码一变就免 LLM 重建,文档一变就提示你去跑一次带 LLM 的/graphify --update

两条路径共享一个前置约定——通过graphify-out/.graphify_python记住"装了 graphify 的那个 Python 解释器",所有后续命令都用它执行,从而保证跨会话、跨平台命令可用。

前置约定:$(cat graphify-out/.graphify_python)是什么

文中的命令都形如$(cat graphify-out/.graphify_python) -c "..."$(cat graphify-out/.graphify_python) -m graphify.watch ...。这个写法不是魔法,而是 graphify 技能在初始化阶段做的一次"解释器固化":在首次运行/graphify时,技能会把当前可用的 Python 可执行文件路径写入graphify-out/.graphify_python(见各 skill 文件的 Step 1,例如 graphify/skill.md 中"$PYTHON" -c "import sys; open('graphify-out/.graphify_python','w',encoding='utf-8').write(sys.executable)")。随后任何一步都可以cat出该路径直接执行,保证使用的是确实安装了 graphify 依赖的那个解释器,而不是可能与pip环境不一致的裸python3。该机制同样被钩子系统复用:在 graphify/hooks.py 中,解释器探测的优先级之一是读取graphify-out/.graphify_python

两点实用说明:

  • 输出目录名graphify-out并非写死常量,其单一事实来源在 graphify/paths.py:GRAPHIFY_OUT = os.environ.get("GRAPHIFY_OUT", "graphify-out"),可通过GRAPHIFY_OUT环境变量覆盖(如 worktree / 共享输出场景),全仓库统一遵守。
  • 如果graphify-out/被删过导致.graphify_python丢失,技能中有"解释器守卫"逻辑会先重新解析并回填该文件,再继续执行子命令。

一、/graphify add <url>:把任意 URL 变成图谱语料

1.1 核心调用骨架

/graphify add的动作是"抓取一个 URL 加入语料库,然后更新图谱"。参考文档给出的标准执行片段如下:

$(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实际抓取地址必填
AUTHOR内容原作者用户提供时填写
CONTRIBUTOR将该内容加入语料库的人用户提供时填写,通常用于团队图谱标注归属

错误处理契约(也是 Agent 行为规范):如果命令以错误退出,必须向用户说明出错原因,不能静默继续;只有保存成功后才自动对./raw执行--update增量管线,把新文件合并进既有图谱。

该调用对应的 CLI 入口在 graphify/cli.py 中同样存在,且支持--dir指定目标目录:

Usage: graphify add <url> [--author Name] [--contributor Name] [--dir ./raw]

从 ingest.py 的ingest()实现可见完整流程:

  1. target_dir.mkdir(parents=True, exist_ok=True)确保./raw存在;
  2. _detect_url_type(url)判定 URL 类型;
  3. validate_url(url)做安全校验(不合法时抛ValueError);
  4. 按类型分派抓取(PDF/图片/YouTube/推文/arXiv/网页);
  5. 网络错误(HTTPError/URLError/OSError)统一包装为RuntimeError
  6. 文件名冲突时自动追加_1_2计数器(上限 1000 次),避免覆盖已有文件。

1.2 支持的 URL 类型(自动识别)与产出物

参考文档定义了 6 类自动识别的来源,产出物与后续处理各不相同:

  • YouTube / 任何视频 URL→ 经 yt-dlp 下载音频,下次运行时转录为.txt(需要pip install 'graphifyy[video]',该 extra 写法与 transcribe.py 中的提示一致);
  • Twitter/X→ 经 oEmbed 获取,存为带推文正文与作者的.md
  • arXiv→ 摘要 + 元数据存为.md
  • PDF→ 直接下载为.pdf
  • 图片(.png/.jpg/.webp)→ 直接下载,下次运行时由 Claude vision 抽取;
  • 任意网页→ 经 html2text(实现中为markdownify,带降级方案)转换为 markdown。

URL 类型判定的先后顺序可从 ingest.py 的_detect_url_type源码中精确还原(含文档未细列的 github 分支):

  1. twitter.comx.comtweet
  2. arxiv.orgarxiv
  3. github.comgithub(直接以普通网页方式抓取)
  4. youtube.comyoutu.beyoutube
  5. 路径以.pdf结尾 →pdf
  6. 路径以.png/.jpg/.jpeg/.webp/.gif结尾 →image
  7. 其余一律 →webpage

各类型的落地细节(对应源码佐证):

  • 推文_fetch_tweet):先把x.com规整为twitter.com,请求publish.twitter.com/oembedomit_script=true),再从返回 HTML 中剥离标签得到纯文本正文与author_name;oEmbed 失败时降级保存 "could not fetch content" 的 URL 占位文件,绝不静默丢弃。产出为带 YAML frontmatter(source_url/type: tweet/author/captured_at/contributor)的.md
  • arXiv_fetch_arxiv):用正则(\d{4}\.\d{4,5})从 URL 提取论文 ID,改走export.arxiv.org/abs/<id>抓摘要、标题、作者;文件名规范为arxiv_<id 中点转下划线>.md(如arxiv_2401_12345.md)。
  • PDF / 图片_download_binary):字节流直写,不经过任何文本转换。
  • 视频(ingest.py 委托 transcribe.py 的download_audio):先经validate_url安全校验再用 yt-dlp 下载bestaudio;下载文件名用 URL 的 SHA-1 前 12 位做稳定名(yt_<hash>.m4a/.opus/...),并做已下载缓存检查避免重复下载。真正的语音转写由 faster-whisper 在后续--update中完成。
  • 网页_fetch_webpage):优先markdownify(ATX 标题、-无序列表、剥除<img>),缺失时降级为正则剥标签并截断;抽取<title>写入 frontmatter,正文默认截断到 12000 字符。

1.3 抓下来的文件长什么样

无论哪种类型,最终写入语料库的文本文件(推文/arXiv/网页)都带统一格式的 YAML frontmatter,供后续抽取器当作节点元数据读取。以网页为例(ingest.py):

--- source_url: "https://example.com/post" type: webpage title: "A great technical post" captured_at: 2026-09-07T03:53:47+00:00 contributor: "someone" --- # A great technical post Source: https://example.com/post --- <转换后的 markdown 正文>

需要特别指出的是 YAML 转义的安全性设计:抓取到的页面标题、作者名等外部不可信字符串要嵌入双引号标量,若不做转义可能被用于注入同级 YAML 键(源码注释中记作 F-009 / F-019)。因此 ingest.py 的_yaml_str()手工实现了完整的 YAML 双引号转义——覆盖\\\"\n\r\t\0,连 Unicode 行分隔符 U+2028(\L)与段分隔符 U+2029(\P)都不放过,其余控制字符走\xNN转义,且刻意不依赖 PyYAML。

1.4 安全边界:这不是一次"裸"网络请求

URL 抓取天然是 SSRF 重灾区,graphify 在 security.py 中做了完整防护,ingest 全程经由这些原语:

  • validate_url:只放行http/https,拦截file://ftp://data:等 scheme,并解析域名解析出的 IP,禁止私网段(127.x、10.x、169.254.x 等)与云元数据端点,从源头防 SSRF;
  • safe_fetch:重定向会经_NoFileRedirectHandler二次校验,响应体按max_bytes流式限量读取,超时默认 30s;
  • safe_fetch_text:文本抓取的轻量封装,默认 15s 超时,UTF-8 容错解码。

文件名同样做了"落地安全":_safe_filename只保留netloc + path中的\w-字符,压缩连续下划线并截断到 80 字符,杜绝 URL 里夹带的路径穿越或超长文件名问题。

二、--watch:让图谱随文件变化自动保鲜

2.1 启动方式

参考文档给出的监听命令:

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

INPUT_PATH替换为要监听的文件夹。模块入口在 graphify/watch.py:python -m graphify.watch [path] [--debounce SECONDS],路径缺省为当前目录.--debounce缺省为3.0秒(type=float)。启动后会在前台持续运行,打印类似[graphify watch] Watching <path> - press Ctrl+C to stop的信息,按 Ctrl+C 停止

--debounce(默认 3s)的含义:等文件活动完全停止后再触发。这样一拨并行 Agent 写出的几十个文件不会每个都触发一次重建——事件会被聚合到"安静 3 秒"后的单次批处理里。此语义在 watch.py 的watch()主循环中实现:事件处理器只记录last_trigger时间戳与待处理集合,主线程每 0.5s 醒来检查一次time.monotonic() - last_trigger >= debounce,达标才把整批文件送入处理。

2.2 两条处理分支:按文件类型分流

参考文档规定了监听的核心分流策略:

  • 仅代码文件变化(.py、.ts、.go 等):立即重新执行 AST 抽取 + 重建 + 聚类,不需要 LLMgraph.jsonGRAPH_REPORT.md自动更新。
  • 文档 / 论文 / 图片变化:写入graphify-out/needs_update标记并打印提示,让你运行/graphify --update(需要 LLM 语义重抽取)。

从源码看,分流逻辑落在两处判定上(watch.py):

  • _batch_triggers_rebuild(batch):批量内有代码文件,或存在被删除的文件→ 触发即时重建。删除任何受监听文件也会重建,因为"驱逐失效节点"同样不需要 LLM(代码注释记录为 #2580:否则仅删文档的批次会一直挂在needs_update标记后面,直到下一次代码事件或手动 update 才生效)。
  • _batch_needs_llm_flag(batch):批量内存在仍存活的非代码文件 → 写needs_update标记。已删除的非代码文件不写标记(它已被上面的删除重建路径清理干净),纯删除批次不会留下过期标记。

写标记的实现是_notify_only:在graphify-out/needs_update写入"1",并打印三条提示——检测到新文件、非代码文件需要 LLM 语义抽取、请运行/graphify --update

2.3 事件监听的工程细节

底层的watch()(watch.py)使用 watchdog 观察目录,细节决定了它在真实机器上不会误触发、不自循环:

  • 观察者选择:macOS 上使用PollingObserver(FSEvents 会漏掉部分编辑器的快速保存),其余平台用原生Observer;均以recursive=True递归监听子目录。
  • 事件过滤:目录事件与只读事件(openedclosed_no_write)直接丢弃——否则 watcher 自己重建时读文件,会把自身触发的打开事件当成修改,无限自循环烧 CPU(_is_read_only_event)。
  • 忽略规则:启动时一次性加载.graphifyignore(并按需合并.gitignore语义),先于扩展名检查短路;点号开头的路径组件与graphify-out自身目录被排除;只关心_WATCHED_EXTENSIONS(代码 + 文档 + 论文 + 图片扩展名的并集,见 watch.py)。

2.4 代码重建的完整调用链与防错设计

代码批次触发的_rebuild_code(watch.py 起)远比"重跑一次 extract"复杂,它在增量正确性上做了大量防护,值得展开:

  1. re-detect 并沿用持久化排除项:重建会再次调用detect(),但必须重新套用首次 extract 时记录的--exclude与 gitignore 决策(持久化在graphify-out/.graphify_build.json),否则每次重建都会把当初故意排除的路径悄悄捡回来(#1886)。
  2. 增量 re-extract:只对新抽取的 AST 文件重跑extract()_reconcile_existing_graph把既有 graph.json 中未变化文件的节点/边/超边保留下来,并把磁盘上已删除来源对应的旧节点驱逐(eviction),实现"增删改都在一次 update 里正确落地"。
  3. 语义层共存保护:已有 LLM 语义节点(semantic-backed)的文档不会被 AST 快速扫描重复铸点(#1915/#1954),避免文档在图上被表示两遍。
  4. 拓扑比较快速路径:先把候选图与旧图做规范化比较;若拓扑与报告都未变化,直接跳过聚类与文件重写,打印No code-graph changes detected以省去不必要的 I/O(watch.py 等处的same_graph/same_topology判定)。
  5. 原子写与临时文件graph.json先写graphify-out/.graph.tmp.jsonreplace原子替换,崩溃不会留下半截 JSON。
  6. 防"意外缩水"守卫_check_shrink:若新图节点数明显少于旧图且无法用"本次重建的文件集/显式删除"解释,会拒绝覆盖并提示你检查 chunk 文件缺失,必要时用--force强制(例如大重构后节点数合法变少)。
  7. 并发互斥:per-repo 的 flock 重建锁(graphify-out/.rebuild.lock,锁文件内写当前持有者 PID);拿不到锁的增量提交先把变更集追加进graphify-out/.pending_changes队列,持锁方重建前后两轮 drain 并合并(#1059),确保"一波并发提交"不会丢任何一次变更。

重建成功时输出类似:

[graphify watch] Rebuilt: 1420 nodes, 3891 edges, 7 communities [graphify watch] graph.json, graph.html and GRAPH_REPORT.md updated in graphify-out

若之前生成过 callflow HTML(*-callflow.html),重建后也会按需重新生成;缺失或过期的graph.html则由_reconcile_graph_html从 graph.json 中已有的社区与标签独立重建。

2.5 有 LLM 时的配合入口:check-update

对于"只写标记、不即时处理"的非代码变更,仓库还提供 cron 友好的配套命令graphify check-update <path>(watch.py):只检查graphify-out/needs_update是否存在并打印提示,任何情况下都返回成功(True),因此放进定时任务不会产生告警噪音。

三、Agentic 工作流中的组合用法

参考文档对--watch的定位很明确:为 Agent 多轮迭代服务。推荐的编排方式是:

  1. 在后台终端运行--watch,让代码变更在每一波 Agent 写入之间被自动拾取——AST 抽取免 LLM,批量代码改动会在静默 3 秒后自动完成重建与聚类;
  2. 如果 Agent 同时还在写文档或笔记(.md、论文、图片),watch 只会写needs_update标记并提示,你需要在这些波次结束后手动执行一次/graphify --update,用 LLM 语义重抽取把新增内容真正并入图谱;
  3. /graphify add <url>则是把语料库外的内容(论文/推文/网页/PDF/视频/图片)先落到./raw,再走同一条--update增量管线合入。

两者配合的本质是"零成本保鲜"的权衡:代码图可以全自动(确定性 AST,无 LLM),语义层需要人工/LLM 的一下确认(文档语义抽取成本高),watch 用一个标记文件把这个"待办"显式化,避免遗忘。

四、测试与源码佐证

该模块的正确性有完整测试背书,可直接阅读 tests/test_watch.py 加深理解,其中覆盖了文档描述的关键语义:

  • test_watched_extensions_includes_code:确认监听扩展集合包含代码文件;
  • test_batch_doc_only_deletion_triggers_rebuild/test_batch_doc_only_deletion_skips_llm_flag:纯文档删除会触发重建、但不写 LLM 标记(对应第 2.2 节的分流);
  • test_batch_modified_doc_only_does_not_rebuild/test_batch_code_file_still_triggers_rebuild:修改文档不即时重建、修改代码即时重建;
  • test_rebuild_code_evicts_nodes_from_deleted_files:删除文件后其节点被驱逐;
  • test_rebuild_code_is_idempotent_when_cluster_ids_flaptest_rebuild_code_skips_cluster_when_topology_unchanged:无变化时输出不被反复改写;
  • test_rebuild_lock_*系列:并发重建锁行为;
  • test_rebuild_honors_persisted_excludes:重建时沿用持久化的排除项。

另外,若你的项目把语料放在非./raw目录,可用 ingest.py 的独立 CLI(python -m graphify.ingest,支持--author/--contributor)直接抓取,效果与/graphify add等价。

小结

/graphify add <url>--watch是 graphify 知识图谱从"一次性快照"进化为"持续更新的活图"的关键通道:前者靠 URL 类型识别 + 安全抓取 + YAML 消毒 + 自动合并,把外部内容以统一 frontmatter 形态沉淀进语料库;后者靠 watchdog 事件分流、3 秒去抖、AST 免 LLM 即时重建与needs_update标记,让代码与语义内容在"零成本自动"与"LLM 介入确认"之间取得正确平衡。理解这两条路径的源码级行为(防缩水守卫、并发锁、原子写、增量 reconcile),你就既能安全地把它接入 CI 或 Agent 工作流,也能在遇到"图没更新/被拒写/丢变更"时快速定位到对应的保护机制。

【免费下载链接】graphifyTurn any codebase, with its docs, SQL schemas, configs, and PDFs, into a queryable knowledge graph. A /graphify skill for Claude Code, Cursor, Codex, and Gemini CLI: local deterministic AST parsing, every edge explained, no vector store.项目地址: https://gitcode.com/GitHub_Trending/graph/graphify

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/9/8 22:03:56

如何用 PDF 翻译工具把英文论文快速翻成中文且保住公式

如何用 PDF 翻译工具把英文论文快速翻成中文且保住公式 【免费下载链接】PDFMathTranslate [EMNLP 2025 Demo] PDF scientific paper translation with preserved formats - 基于 AI 完整保留排版的 PDF 文档全文双语翻译&#xff0c;支持 Google/DeepL/Ollama/OpenAI 等服务&a…

作者头像 李华
网站建设 2026/9/8 22:03:01

低压配电网拓扑辨识与可视化系统源码解析:SpringMVC+MyBatis+高德GIS实践

简介&#xff1a;低压配电网拓扑辨识与可视化系统源码面向电力信息化开发人员及高校毕业设计者&#xff0c;是一套基于SpringMVC与MyBatis框架&#xff0c;并结合高德GIS与SVG矢量图形技术的完整工程。源码实现低压配电网拓扑结构的自动辨识与图形化展示&#xff0c;打通GIS地理…

作者头像 李华
网站建设 2026/9/8 22:02:48

Steam云存档冲突原理与实战诊断指南

1. 云存档冲突不是错误&#xff0c;而是Steam在替你做关键决策“Steam提示‘云存档冲突’&#xff0c;该怎么选&#xff1f;”——这句话最近在游戏社区高频出现&#xff0c;尤其集中在《空洞骑士》《星露谷物语》《蔚蓝》《哈迪斯》这几款存档敏感型独立游戏中。我连续三周在S…

作者头像 李华
网站建设 2026/9/8 22:01:53

帧率+12%:tiny11精简系统性能优化指南

帧率12%&#xff1a;tiny11精简系统性能优化指南 【免费下载链接】tiny11builder Scripts to build a trimmed-down Windows 11 image. 项目地址: https://gitcode.com/GitHub_Trending/ti/tiny11builder 开游戏掉帧、后台一堆 Xbox 进程吃内存、系统装完空闲就占 3GB 多…

作者头像 李华
网站建设 2026/9/8 22:01:22

STM32F407+LAN8720A+FreeRTOS+LwIP实现TCP转串口网关完整指南

简介&#xff1a;针对STM32F407外接LAN8720A的常用硬件组合&#xff0c;使用STM32CubeIDE整合FreeRTOS与LwIP协议栈&#xff0c;实现TCP Server网络数据与串口数据双向透传的完整开发资料。资源面向需要快速落地MCU联网功能的嵌入式工程师&#xff0c;尤其适合参考典型PHY芯片方…

作者头像 李华