news 2026/9/8 21:22:29

graphify 语义提取子代理规范(extraction-spec)深度解析:如何把文档、论文与图片确定性地结构化为知识图谱 JSON

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
graphify 语义提取子代理规范(extraction-spec)深度解析:如何把文档、论文与图片确定性地结构化为知识图谱 JSON

graphify 语义提取子代理规范(extraction-spec)深度解析:如何把文档、论文与图片确定性地结构化为知识图谱 JSON

【免费下载链接】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 在传统代码库之外,还要把 README、架构文档、论文、PDF 切片乃至截图一并纳入可查询的知识图谱。本文围绕仓库中随 Skill 分发的 语义提取子代理规范(同时在 tools/skillgen/expected/ 下 有 skillgen 生成快照),逐条拆解其中的提取规则、JSON Schema、节点 ID 生成约束与置信度标尺,并结合源码解释这些约束为何存在——读完你将掌握:语义提取通道的触发条件、如何写出不被校验器拒绝的提取 JSON、如何保证节点 ID 与 AST 抽取器完全一致从而避免"幽灵重复节点",以及每条边的来源字段为什么要逐字符复制 FILE_LIST 路径。

规范文件的定位:只在 Part B 且有语义内容时被加载

该 reference 文件的开头明确定义了它的使用边界:

Load this in Step 3 Part B when the corpus has at least one doc, paper, or image chunk. A pure-code corpus skips Part B and never reads this file.

也就是说,graphify 的构建流程分为两大通道:

  • Part A(AST 通道):代码文件由本地确定性 AST 解析器处理,无需 LLM、无需 API Key;
  • Part B(语义通道):只有文档(document)、论文(paper)、图片(image)被送入语义子代理做知识图谱抽取,本规范文件就是这套子代理的提示词正文。

纯代码语料(最常见的/graphify .)直接跳过 Part B,也因此从不加载本文件。主编排脚本 graphify/skill-kilo.md 中同样强调"只在至少一个 chunk 包含 doc/paper/image 时、且仅在此时读取它"。

实际调度流程中的调用点

参考主 Skill 文档 Part B 的完整编排 可以看到本规范被使用的具体方式:

  1. Step B0:先通过graphify.cache.check_semantic_cache(all_files, root=..., prompt_file='SPEC_PATH')查询缓存。注意prompt_file参数传入的正是本规范文件的绝对路径——缓存条目按提示词归属,graphify 升级导致提示词变化后旧条目会被重新抽取而非原样回放(对应 issue #1939);
  2. Step B1:把未命中缓存的文件按 20–25 个一组切 chunk,每张图片独占一个 chunk(视觉需要独立上下文),同目录文件尽量分到同一 chunk 以提高跨文件关系命中率;
  3. Step B2:在同一条消息中并行派发所有 Agent 子代理,每个子代理收到本规范文件的提示词(替换FILE_LISTCHUNK_NUMTOTAL_CHUNKSDEEP_MODECHUNK_PATH五个占位符),并把结果写到绝对路径graphify-out/.graphify_chunk_NN.json
  4. Step B3:等待全部子代理落盘,把真实 token 数回填后合并且写缓存。

因此,本文件实质上是语义抽取通道的"接口契约":子代理是执行者,规范是唯一权威 prompt。下面的规则全部来自规范正文,并与仓库源码相互印证。

证据分级三原色:EXTRACTED / INFERRED / AMBIGUOUS

规范在文件开头定义了三种证据等级,用于在 JSON 的confidence字段标注每条边"为什么可信":

confidence含义判据
EXTRACTED源文本中显式存在的关系import、call、引用、"see §3.2"这类显式指涉
INFERRED合理推断出的关系共享数据结构、隐含依赖、功能对齐
AMBIGUOUS不确定的关系标记出来供人工复核,绝不静默省略

这条分级的工程价值在于"宁可标记,不可吞没":对 LLM 而言,把可疑的边降级为AMBIGUOUS比把它扔掉更安全,因为图谱查询阶段的缺失不可恢复,而AMBIGUOUS边可以被诊断与人工审查过滤。源码侧 graphify/validate.py 将其固化为一组白名单常量VALID_CONFIDENCES = {"EXTRACTED", "INFERRED", "AMBIGUOUS"},任何其它取值都会在校验阶段被拒绝。

按文件类型分类的提取细则

代码文件:只补 AST 看不见的语义

规范明确要求:代码文件的语义抽取聚焦 AST 无法发现的边(调用关系、共享数据、架构模式),不要重复抽取 import——AST 已经覆盖了它们。这与"纯代码语料完全不需要 LLM"的整体设计自洽:代码结构交给确定性解析器,LLM 只负责"读代码之间的人味关系"。

文档与论文:把 rationale 存成属性而不是节点

这是规范里最容易犯错的规则之一,值得单独强调:

  • 对文档/论文提取命名的概念、实体、引用
  • 对于决策理由(WHY)——为什么这么做、取舍、设计意图——把它作为rationale属性挂在相关的概念节点上绝不单独创建 "rationale 节点"或"片段节点";
  • 只有"本身就是一个命名实体或概念"的对象才配创建节点;
  • 概念类节点(想法、原则、机制、设计模式)使用file_type: "rationale"

file_type必须且只能是以下六个值之一:codedocumentpaperimagerationaleconcept。任何其它值都是非法取值并会被拒绝。源码 graphify/validate.py 用VALID_FILE_TYPES = {"code", "document", "paper", "image", "rationale", "concept"}一一对应地校验。

图片:用视觉理解"图是什么",而不是只做 OCR

规范为六类图片分别定义了提取目标,核心原则是"不要只 OCR,要看懂这张图":

  • UI 截图→ 布局模式、设计决策、关键元素与用途;
  • 图表(chart)→ 指标、趋势/洞见、数据来源;
  • 推文/帖子→ 以"观点"为节点,附带作者与涉及的概念;
  • 示意图(diagram)→ 组件及其连接关系;
  • 研究图(research figure)→ 它演示了什么、方法、结论;
  • 手写笔记/白板→ 想法与箭头连线,不确定的解读一律标AMBIGUOUS

跨语言边与方向约束

关于calls边,规范给出两条硬性规则:

  1. 方向不可逆source必须是调用方(发起调用的函数/类),target必须是被调用方
  2. 语言边界不可逾越calls边必须保持在同一种语言内——Python 函数不能callsJS/TS/Go/Rust/Java 符号,反之亦然。跨语言调用边被视为幻影伪影(phantom artifacts),严禁产出。

源码中 graphify/analyze.py 等在分析阶段对跨语言幽灵调用有对应的防护逻辑,可见这条约束贯穿从抽取到装配的全链路。implements/references/cites等边的语义在 graphify/llm.py 的内置抽取系统提示词中被同样明确:source 永远是动作发出方,target 是被作用方

confidence_score:禁用 0.5 默认值的离散置信度标尺

规范用一整段强调:每条边都必须携带confidence_score,绝不能省略,也绝不能把 0.5 当默认值。其背后的理由非常工程化:

Models follow discrete rubrics better than continuous ranges; the bimodal distribution observed in production (>50% at 0.5, >40% at 0.85+) shows the range guidance is being collapsed to a binary.

即生产数据观察到明显的双峰分布(超过 50% 落在 0.5、超过 40% 落在 0.85+),说明给连续区间反而诱导模型退化成二值选择。因此对INFERRED边只能从下面这组离散值中恰好选一个

confidence_score语义判据示例
0.95直接结构证据共享数据结构、具名的跨文件引用
0.85强推断明确的功能对齐,但没有直接符号连接
0.75合理推断共享问题域 + 形态相似,需要解读
0.65弱推断主题相关,无形态证据
0.55猜测但合理仅表面共现

配套规则:

  • EXTRACTED边的confidence_score恒为 1.0
  • AMBIGUOUS边落在0.1–0.3区间;
  • 若上述没有一个值适用,宁可把边标为AMBIGUOUS,也不要选 0.4 或更低;
  • 语义相似边(见下文)的置信度区间为0.6–0.95

Node ID:确定性格式与"幽灵重复节点"的根源

规范中篇幅最长、最容易踩坑的规则是节点 ID 的生成,因为ID 必须与 AST 抽取器生成的 ID 完全一致,否则会产生没有任何边能连接到的"孤儿幽灵节点(orphan ghost-duplicate nodes)"。

规则精要:

  • 只允许小写[a-z0-9_],不允许点号与斜杠;
  • 格式为{stem}_{entity}
    • stem=完整仓库相对路径去掉扩展名,每个目录段都保留、转成小写并用_连接,非字母数字字符替换为_
    • entity= 符号名,同样归一化;
    • 必须使用每一级目录,不能只取文件名或仅用最近一级父目录——这样才能区分不同目录下的同名文件。

规范给出的官方示例:

符号结果 ID
src/auth/session.pyValidateTokensrc_auth_session_validatetoken
lib/utils/helpers.pyparse_urllib_utils_helpers_parse_url
tests/test_foo.py_helpertests_test_foo_helper
docs/v1/api/README.mdgetUserdocs_v1_api_readme_getuser
setup.py(顶层文件)my_funcsetup_my_func

错误示范:只写session_validatetoken(丢目录)或auth_session_validatetoken(丢深层目录),都会与 AST 生成的真实 ID 失配。如果项目是旧的"仅最近父目录"格式构建的,用户应运行graphify extract --force干净重建

最关键的一条铁律:

CRITICAL: never append chunk numbers, sequence numbers, or any suffix to an ID (no_c1,_c2,_chunk2, etc.). IDs must be deterministic from the label alone — the same entity must always produce the same ID regardless of which chunk processes it.

ID 必须仅由实体本身决定——同一实体无论被哪个 chunk 处理都必须得到相同 ID。这也是并行分片抽取能够合并不冲突的前提。该格式在 graphify/llm.py 的引擎内置系统提示词中与规范一字不差地保持一致。

semantically_similar_to:只在"真正跨界的非显然相似"时才添加

规范允许在没有任何结构连接(无 import、无 call、无引用)的情况下,为"解决同一问题 / 表达同一思想"的两个概念添加semantically_similar_to边,标记为INFERREDconfidence_score按相似度取 0.6–0.95。官方示例包括:

  • 两个都校验用户输入、但从不互相调用的函数;
  • 代码里的一个类与论文中描述同一算法的概念;
  • 两个以不同方式处理同一失败模式的错误类型。

同时给出限制:只有相似性真正非显然且跨边界时才加,琐碎相似不要加。这也与 graphify/analyze.py 的注释一致——分析时会将semantically_similar_to视为"真正的跨边界洞见"而做特殊处理;报告输出在 graphify/report.py 中也会对其标注[semantically similar]

Hyperedges:3 个以上节点才值得用,每 chunk 上限 3 条

当 3 个及以上节点明确共同参与一个共享概念、流程或模式,而这种群体关系无法仅靠两两边表达时,写入顶层hyperedges数组。官方示例:

  • 实现同一协议/接口的全部类;
  • 认证流程中的所有函数(即使它们并不互相调用);
  • 论文某一节中构成统一思想的全部概念。

relation只能取participate_inimplementform三者之一,且每个 chunk 最多 3 条,务必克制。这条规则防止图谱被成堆的二元边淹没,同时让"群体语义"(协议实现集、流程参与者)有第一等的表达位置。

YAML frontmatter 元数据透传

对于带 YAML frontmatter(--- ... ---)的文件,规范要求把source_urlcaptured_atauthorcontributor四个字段复制到该文件的每一个节点上。这让来自网页归档、博客、PDF 的文章在知识图谱中保留出处与溯源信息,便于回答"这段知识来自哪里、什么时候被抓取"。

JSON Schema 逐字段精读

规范要求子代理输出恰好匹配下面结构的纯 JSON——无解释、无 markdown 代码围栏、无开场白(源码侧 graphify/llm.py 的内置 prompt 也执行同样的纪律)。下面是整理后的逐字段注解(示例路径沿用了规范原文):

{ "nodes": [ { "id": "auth_session_validatetoken", // 确定性 ID,见上文规则 "label": "Human Readable Name", // 人类可读展示名 "file_type": "code|document|paper|image|rationale|concept", "source_file": "<FILE_LIST path verbatim>", "source_location": null, // 如 "L1" / "§3.1",无则 null "source_url": null, // frontmatter 透传,无则 null "captured_at": null, "author": null, "contributor": null } ], "edges": [ { "source": "node_id", "target": "node_id", "relation": "calls|implements|references|cites|conceptually_related_to|shares_data_with|semantically_similar_to|rationale_for", "confidence": "EXTRACTED|INFERRED|AMBIGUOUS", "confidence_score": 1.0, // 按离散标尺取值 "source_file": "<FILE_LIST path verbatim>", "source_location": null, "weight": 1.0 } ], "hyperedges": [ { "id": "snake_case_id", "label": "Human Readable Label", "nodes": ["node_id1", "node_id2", "node_id3"], "relation": "participate_in|implement|form", "confidence": "EXTRACTED|INFERRED", "confidence_score": 0.75, "source_file": "<FILE_LIST path verbatim>" } ], "input_tokens": 0, // 占位,Part B Step B3 会用真实 usage 回填 "output_tokens": 0 }

注意两点细节差异:

  • 规范正文的边relation枚举比引擎内置 prompt 多了rationale_for,可用于表达概念节点对另一节点的"理由说明"关系;对应 graphify/callflow_html.py 等下游渲染中对rationale_for有专门的关系文案与配色处理;
  • input_tokens/output_tokens由子代理写 0 占位,合并阶段由编排者从真实调用用量回填。

校验器视角:哪些字段是硬性的

graphify/validate.py 定义了装配图之前的 schema 校验:

  • 节点必填:idlabelfile_typesource_file
  • 边必填:sourcetargetrelationconfidencesource_file
  • file_typeconfidence均为白名单枚举,越界即报错。

这解释了规范里"只输出合法 JSON"的强语气——任何偏离都会被validate_extraction拦下并返回错误列表。

source_file 规则:逐字符复制,别自作聪明

规范用单独一段强调source_file是最容易"好心办坏事"的字段:

set source_file to the path of the originating file EXACTLY as it appears in FILE_LIST — verbatim and absolute. Do NOT shorten to a basename, do NOT re-relativize, do NOT strip any directory prefix, and do NOT change separators.

即:逐字符复制 FILE_LIST 中的条目,不改 basename、不改相对化、不删目录前缀、不改分隔符。原因写得非常清楚:

  • 下游引擎会负责分隔符规范化与相对化(canonicalize separators and relativize against the build root downstream);
  • 全量构建与增量--update必须站在同一基线上;
  • 只有路径逐字符一致,build_merge的"重抽取即替换(replace-on-re-extract)"才能命中已存在的节点,而不是累积出重复节点

从工程视角看,这是"LLM 输出的脏数据由引擎统一清洗"的典型设计:模型不需要理解引擎的路径规范,只需当一个忠实的复制机器。这点与 graphify/llm.py 中对rel使用as_posix()的注释形成闭环——文件内容被包装进带path=sha256=<untrusted_source>块(llm.py 的 _wrap_untrusted),供模型照抄,同时哈希可用于把可疑节点追溯到原始字节。

落盘位置:CHUNK_PATH 必须是绝对路径

规范最后一条指令是:用 Write 工具把 JSON 写到提示词末尾给出的精确绝对路径CHUNK_PATH。它特别警告:不要用相对路径——Write 会以未定义的 cwd 解析相对路径,文件会被静默丢失。结合主 Skill 的 Step B3,"chunk 文件是否存在于磁盘"本身就是子代理成功的判定信号,所以落盘位置错了等于整个 chunk 白跑。

DEEP_MODE 与 --mode deep:更深、更激进的推断

规范提示词中含有一段条件指令:当用户以--mode deep调用时,子代理要更激进地补充INFERRED——间接依赖、共享假设、潜在耦合都要尝试挖掘,拿不准的标AMBIGUOUS而不是省略。

命令层面,graphify extract --mode deep是真实的 CLI 选项(参见 graphify/cli.py 的--mode解析与校验,以及 graphify/main.py 帮助文本 "--mode deepaggressive INFERRED-edge semantic extraction")。在 Skill 文档的快速上手里对应:/graphify <path> --mode deep # thorough extraction, richer INFERRED edges(见 graphify/skill-agents.md)。

编排层面,主 Skill 要求编排者在调用开始时记录是否传入--mode deep,若传入则把DEEP_MODE=true传给每个 Part B 子代理。缓存层面,graphify/cache.py 为 deep 模式维护独立的semantic-deep/缓存命名空间(普通模式用semantic/),graphify cache-check --mode deep也据此检查——避免深浅两种抽取结果互相污染。

规范背后的设计哲学小结

  • 分层确定性:代码交给 AST(确定性、免费、无幻觉),LLM 只处理代码解析器覆盖不到的语义层(文档/论文/图片),两者通过同一套确定性 ID 规则缝合;
  • 约束即接口file_typerelationconfidence、ID 字符集、source_file复制规则,全部在 validate.py 与装配逻辑中有对应的硬校验,规范文本只是把校验器翻译成了人话;
  • 防幻觉与防伪影AMBIGUOUS宁可多标不可省略、跨语言calls一律禁止、非显然才允许semantically_similar_to、每 chunk 超边上限 3 条——这些规则的共同目标都是控制图的质量边界,而不是追求"抽得越多越好";
  • 为增量与缓存而生:确定性 ID 让 replace-on-re-extract 不会叠重复节点;逐字符source_file让全量与增量构建对齐同一基线;提示词文件路径被作为缓存 key 的一部分,规范一变,旧缓存自动作废重抽。

因此,对任何想在 Claude Code、Cursor、Codex、Gemini CLI 等宿主上为 graphify 贡献语义抽取实现、或排查"图里出现幽灵节点/重复节点/跨语言假调用"的开发者来说,这份 reference 文件 + graphify/llm.py 的内置系统提示词 + graphify/validate.py 的白名单三处对照阅读,就是理解整个语义抽取契约的最短路径。

【免费下载链接】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 21:22:17

Qt6迁移实战指南:C++17、CMake重构与QML引擎升级

1. 这不是一份普通日志&#xff1a;Qt6-2020更新日志背后的真实战场你搜“Qt6-2020更新日志”&#xff0c;大概率是刚在官网下载完Qt 6.0.0 Beta&#xff0c;点开那个叫qt6-2020-changelog.md的文件&#xff0c;结果发现里面全是commit hash、Jira编号和一行行冷冰冰的“Fixed …

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

Flask仓库管理系统源码解析:从数据库设计到出入库实战

简介&#xff1a;这是一份基于Flask框架开发的Python仓库管理系统源码&#xff0c;面向库存管理初学者、课程设计或毕业设计开发者。系统已实现库存管理三大核心功能&#xff1a;出库、入库、低库存预警与物品搜索&#xff0c;并附带预算统计与出入库记录导出&#xff0c;覆盖了…

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

STM32F103驱动ADS1220高精度电压采集实战

简介&#xff1a;此工程包面向STM32开发者与高精度模拟量采集项目&#xff0c;演示STM32F103通过SPI接口读取ADS1220高精度24位Σ-Δ型ADC芯片&#xff0c;实现多路电压数据的采集、换算与输出。整个压缩包共308个文件&#xff0c;大小约5.12MB&#xff0c;文件类型覆盖87个C源…

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

宠物AI摄像头低功耗设计:芯片、算法与系统协同优化实战

1. 项目概述&#xff1a;为什么宠物AI摄像头的低功耗不是“省电”而是“生存逻辑” 你有没有拆开过市面上卖两三百块的宠物智能摄像头&#xff1f;我去年帮朋友调试三款不同品牌的设备&#xff0c;发现一个反直觉的事实&#xff1a;它们的主控芯片标称功耗都不到100mW&#xff…

作者头像 李华
网站建设 2026/9/8 21:19:21

Firecrawl:将网页秒变干净Markdown,为LLM与RAG高效供给数据

先说结论&#xff1a;如果你想用 LLM 批量处理网页内容&#xff0c;但又不希望整天被 HTML 标签、动态渲染、反爬策略这些东西折磨&#xff0c;Firecrawl 是目前难得让我觉得“终于有个工具是把我想做的事直接做好”的抓取 API。它做的事情一句话就能讲清楚&#xff1a;把任意 …

作者头像 李华