首页
/ graphify extraction-spec 子智能体抽取规范详解:用确定性 Prompt 把文档、论文与图片沉淀为可查询知识图谱

graphify extraction-spec 子智能体抽取规范详解:用确定性 Prompt 把文档、论文与图片沉淀为可查询知识图谱

2026-09-07 19:58:46作者:宣利权Counsellor

这篇技术指南以 graphify 随各 AI 编程助手 Skill 分发的 references/extraction-spec.md(其生成产物对应仓库中的 tools/skillgen/expected/graphify__skills__opencode__references__extraction-spec.md)为讲解对象。全文围绕该规范展开:它在 graphify 语义抽取流水线(Step 3 Part B)中的角色、文件类型六值枚举、三种证据置信度、精确置信度评分刻度、确定性节点 ID 规则、超边与相似边契约,以及写回磁盘的路径纪律。读完你将能复现 graphify 训练语义子智能体的完整 Prompt 设计,并理解每个约束在 extractbuildsemantic_cleanup 等引擎模块中的落地点与防护动机。

一、这份 reference 是什么:语义抽取子智能体的唯一作业指导书

graphify 把一个代码库(连同其文档、SQL Schema、配置与 PDF)变成可查询知识图谱的流程分三步:Part A 由本地确定性 AST 解析器抽取代码结构Part B 由"语义子智能体"(semantic subagent)抽取 AST 看不见的语义层(文档概念、论文观点、图片内容、跨文件设计意图),Part C 合并两个来源

extraction-spec.md 正是 Part B 子智能体收到的逐字 Prompt。规范开门见山地写明它的装载条件:

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.

即:只有当语料中存在文档(doc)、论文(paper)或图片(image)分块时才加载本文件;纯代码语料直接跳过 Part B,根本不读它——代码结构由 AST 负责,无需语义子智能体。每个语义子智能体收到的 Prompt 在原文基础上一字不改,仅替换五个占位符:

占位符 含义
FILE_LIST 本分块负责读取的文件列表
CHUNK_NUM / TOTAL_CHUNKS 当前分块序号 / 总分块数
DEEP_MODE 是否处于 --mode deep 激进推理模式
CHUNK_PATH 抽取结果 JSON 必须写到的绝对路径

这一编排逻辑在各平台 Skill 中保持一致:例如 graphify/skill-opencode.md 的 Part B 明确要求"把该 Prompt 逐字传给每个子智能体,替换 FILE_LIST、CHUNK_NUM、TOTAL_CHUNKS、DEEP_MODE"。仓库中每个平台目录都镜像同一份 reference 文件(如 graphify/skills/opencode/references/extraction-spec.md),而 tools/skillgen/expected/ 下则沉淀了 skillgen 工具为各平台生成的等价产物,方便直接校对。

二、输出总契约:Only JSON,无 Markdown、无前言、无解释

Prompt 的第一条铁律是输出纪律:

Output ONLY valid JSON matching the schema below — no explanation, no markdown fences, no preamble.

子智能体的全部产出是一份顶层包含 nodesedgeshyperedgesinput_tokensoutput_tokens 五个键的 JSON 片段,随后由编排方合并进整图。为什么要有这条纪律?因为 graphify 的语义缓存、增量更新与 build_merge 的"重抽取即替换"机制都依赖机器可解析、字段可对齐的分块输出——任何额外文字都会污染解析器。语义分块 JSON 在落盘前还会经过 graphify/semantic_cleanup.pyvalidate_semantic_fragment() 校验,该函数对不可信的智能体输出设有硬边界:默认单片段 ≤ 25 MB、节点 ≤ 10,000、边 ≤ 100,000、超边 ≤ 10,000、超边成员 ≤ 256、语义 ID ≤ 256 字符,防止失控或恶意响应耗尽内存或借节点 ID 逃逸 graphify-out 目录。

三、节点契约:六种 file_type 与 "rationale 不得喧宾夺主"

规范要求每个节点携带 file_type,且取值必须严格落在以下六个枚举值之一,任何其他值都会被拒绝

file_type 适用对象
code 代码符号(函数、类、变量等)
document 文档中的命名实体/概念
paper 论文中的概念与引用
image 图片内容所表达的实体
rationale 概念类节点:思想、原则、机制、设计模式
concept 其余通用概念

注意 rationale 的用法非常微妙,规范给出了两条并行指令防止滥用:

  1. "为什么"要存成属性,而不是节点:针对设计取舍、决策理由(WHY)这类说明性文字,"store as a rationale attribute on the relevant concept node — do NOT create a separate rationale node or fragment node"。即理由文本应附着在它解释的概念节点上,绝不能为了存一段理由而单独建一个"理由节点"。
  2. 只有当某物本身是可命名的实体/概念时才建节点;若这个可命名概念属于 idea、principle、mechanism、design pattern 这类"思想型"对象,就给它打 file_type:"rationale"

引擎侧同样内置了对应防护。语义清理器 graphify/semantic_cleanup.py 把"句子化"的 rationale 节点转化为关联节点上的属性,并定义 VALID_SEMANTIC_FILE_TYPES = frozenset({"code", "document", "paper", "image", "rationale", "concept"}),与 Prompt 中的六值完全一一对应;而 AST 抽取器本身在处理 Python/JS/TS 的 docstring 与 // WHY: 注释时,也以 file_type:"rationale" + rationale_for 关系建模(见 graphify/extract.py 的 Python 通道与 graphify/extract.py 的 JS/TS 通道),两条路径的语义最终殊途同归。

此外,graphify/build.py 还维护了一张 _FILE_TYPE_SYNONYMS 容错表,把子智能体常见的漂移写法归位(markdowndocumenttool/librarycodepattern/principle/constraintconcept 等),无法归位的兜底为 concept——这解释了规范中"Any other value is invalid and will be rejected"为何能真正落地:Prompt 端从严要求,构建端对已知别名做了一次有界的语义纠偏。

四、边契约:三种证据置信度与 "calls 永远单向、永不跨语言"

每条边都要声明证据性质 confidence,取三个层级之一:

层级 定义 典型信号
EXTRACTED 源文本中显式存在的关系 import、调用、引用、"see §3.2"这类字面线索
INFERRED 合理推断的关系 共享数据结构、隐含依赖
AMBIGUOUS 不确定——标注待复核,不许省略 解读存疑的关联

规范特别强调 AMBIGUOUS 的意义是"flag for review, do not omit":宁可把存疑关系标记出来送审,也不要悄悄丢掉,因为下游 review/analyze 流程正是靠 AMBIGUOUS 边、弱 INFERRED 关系等信号生成架构复核问题(见 graphify/analyze.py 对"无 AMBIGUOUS 边、无 INFERRED 关系"语料的提示逻辑)。

在边类型上,schema 允许八种关系:calls | implements | references | cites | conceptually_related_to | shares_data_with | semantically_similar_to | rationale_for。其中有两条硬约束:

  • 方向不可逆calls 边的 source 必须是调用方(正在发起调用的函数/类),target 必须是 callee,绝不能颠倒。
  • 永不跨语言calls 边必须停留在同一种语言内——Python 函数不能 calls 一个 JS/TS/Go/Rust/Java 符号,反之亦然,因为"跨语言调用边"是幽灵产物(phantom artifacts)。

第二条约束在构建端有实质性防护:graphify/build.py 定义了 _EDGE_LANG_FAMILY 语言族表,把 Python、JS/TS、JVM 系、C/C++/ObjC 系等按真实互操作边界分组,在边循环里丢弃"Python import time 误绑定到 time.ts"或"跨语言 INFERRED calls"这类幽灵边;对应回归面见 tests/test_cross_language_call_resolution.py

代码文件的抽取重点是 AST 找不到的语义边(调用关系、共享数据、架构模式),规范同时叮嘱:"Do not re-extract imports — AST already has those."——不要重复抽取 AST 已有的 import 结构。

五、多模态输入:图片要用"视觉理解"而非单纯 OCR

当语料含图片时,规范为子智能体定义了按图种区分的理解任务,核心是"understand what the image IS - do not just OCR":

图片种类 应抽取的内容
UI 截图 布局模式、设计决策、关键元素、用途
图表(Chart) 指标、趋势/洞见、数据来源
推文/帖子 将"主张"抽为节点,连同作者与涉及的概念
示意图(Diagram) 组件与连线关系
科研配图 它证明了什么、方法、结果
手写/白板 想法与箭头;不确定的识读标为 AMBIGUOUS

这意味着图片节点不是"图"本身,而是图里承载的概念与实体——它们与文档概念一样进入统一的知识图谱节点池,并参与后续的边与超边合并。

六、DEEP_MODE:--mode deep 下的激进推理

当用户以 graphify extract --mode deep 运行时,DEEP_MODE 占位符被置真,规范要求子智能体在 INFERRED 边上更激进:补出间接依赖、共享假设、潜在耦合;拿不准的一律标 AMBIGUOUS 而非省略。

在 CLI 层,graphify/cli.py 的 extract 用法串包含 [--mode deep]_VALID_MODES = {"deep"}graphify/cli.py),开启后打印 "deep mode enabled: richer semantic extraction"(graphify/cli.py)。--mode deep 还会切换语义缓存的命名空间:普通语义抽取命中 cache/semantic/,deep 抽取命中独立的 cache/semantic-deep/graphify/cache.py 相关注释),两者互不污染。正因如此,在热缓存的未变更代码库上跑 --mode deep 若只按 manifest 变更门控会静默空转(一次派发零文件),graphify/cli.py 专门把语义通道扩展到全部存活的 doc/paper/image 文件,由 deep 专属缓存决定命中/未命中——这是把"deep 更激进"真正落到运行语义的关键补丁。

七、semantically_similar_to:跨结构的语义相似边

规范为"两个概念解决问题相同、思想相同,却没有任何结构链接(无 import、无调用、无引用)"的场景引入了 semantically_similar_to 边,一律标 INFERRED,并配 0.6–0.95 的置信分。给出的合法样例:

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

同时强调节制:"Only add these when the similarity is genuinely non-obvious and cross-cutting. Do not add them for trivially similar things."——相似必须是非显然、跨切面的,平凡相似禁止添加。这条边正是 LLM 相比纯结构分析能带来的独特增量:把"长得很像但从不互见"的知识连成图谱,供后续检索与影响分析使用。

八、Hyperedges:三人成组的语义超边

3 个或更多节点显然共同参与某个共享概念、流程或模式,而两两成对的边不足以表达时,规范要求把它们收进顶层 hyperedges 数组。官方示例:

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

超边关系的合法取值为 participate_in | implement | form。规范同样强调克制:"Use sparingly — only when the group relationship adds information beyond the pairwise edges",且每分块最多 3 条超边。超边机制在构建端有专门的合并与剪枝处理,对应回归测试见 tests/test_build_merge_hyperedges_and_prune.py

九、confidence_score 的精确刻度:禁用 0.5,杜绝二值塌缩

这是全规范中最讲究的一处设计。规则要点:

  • 每条边都必须有 confidence_score,不得省略,永远不得拿 0.5 当默认值
  • EXTRACTED 边恒定 1.0
  • INFERRED 边从离散刻度中精确取值:
    • 0.95 直接结构证据(共享数据结构、具名跨文件引用)
    • 0.85 强推断(功能取向清晰、无直接符号链接)
    • 0.75 合理推断(共享问题域 + 形状相似,需解读)
    • 0.65 弱推断(主题相关、无形状证据)
    • 0.55 猜测性但合理(仅表层共现)
  • 若以上没有合适的值,宁可标 AMBIGUOUS 也不要给 0.4 或更低
  • AMBIGUOUS 边取 0.1–0.3

规范用生产观测解释了为什么放弃连续区间而采用离散刻度:

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.

即连续刻度在真实模型上会塌缩成二值(半数堆在 0.5、四成堆在 0.85+),离散评分刻度更能引导模型按档位对齐。这与引擎侧完全自洽:graphify/export.py 的注释明确记载 INFERRED 的默认值曾是 0.5、后来按 references/extraction-spec.md 删除;graphify/extract.pygraphify/extractors/engine.py 在生成推断边时也注释了"0.85 = strong inference on the extraction-spec rubric"。对应测试面见 tests/test_confidence.py

十、节点 ID 生成规范:确定性优先,杜绝孤儿幻影节点

节点 ID 是全图一致性的命门。规范规定格式为:

{stem}_{entity}

其中 entity 是符号名;stem去掉扩展名后的完整仓库相对路径,路径每个段都小写、非字母数字字符替换为下划线后以 _ 连接——必须保留每一层目录,而不是只留直接父目录,否则不同目录下的同名文件会互相冲突。官方示例:

文件 + 符号 正确 ID
src/auth/session.py + ValidateToken src_auth_session_validatetoken
lib/utils/helpers.py + parse_url lib_utils_helpers_parse_url
tests/test_foo.py + _helper tests_test_foo_helper
docs/v1/api/README.md + getUser docs_v1_api_readme_getuser
顶层文件 setup.py + my_func setup_my_func

两条最容易踩的坑被单独加粗:

  1. ID 必须与 AST 抽取器生成的 ID 完全一致。只写文件名(如 session_validatetoken)或只写直接父目录(如 auth_session_validatetoken)都会制造"孤儿幻影重复节点"(orphan ghost-duplicate nodes)。如果旧格式工程需要重抽,用户应执行 graphify extract --force 干净重建。
  2. 绝对禁止追加任何分块号/序号后缀(不得有 _c1_c2_chunk2 之类)。ID 必须仅由实体名确定——无论由哪个分块处理,同一实体必须永远产出同一 ID,这是分块并行与增量更新不产生重复节点的前提。

这一规则在引擎侧的根因是三个独立的 ID 生产者必须意见一致。graphify 以 graphify/ids.py 作为节点 ID 规范化的唯一事实来源,其模块文档开宗明义列出三方:① AST 抽取器(extract._make_id,确定性、逐语言);② 语义子智能体(LLM,即遵循本 spec 的 ID 规则);③ 图构建器(build._normalize_id,在 LLM 发出的 ID 带轻微大小写/标点漂移时对齐端点)。历史上 ID 漂移是反复出现的 bug 类别(Unicode 塌缩、同名文件冲突、AST 与 LLM 文件节点不一致等),因此该模块把归一化配方收敛到一处,并保证幂等、大小写无关稳定(graphify/ids.py)。这解释了为什么 spec 用一整段规定 ID 的拼写纪律——它不是风格建议,而是跨抽取器的握手协议。

十一、source_file 逐字透传规则与增量合并语义

规范对每个 node、edge、hyperedge 的 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 中的条目逐字符复制source_file。原因是下游流水线会在构建根处统一规范化分隔符并相对化路径,而"逐字绝对路径"保证全量构建与增量 --update 站在同一基线上,让 build_merge 的重抽取替换(replace-on-re-extract)命中已有节点而非累积出一个重复节点。语义缓存也以 source_file 为粒度逐文件持久化,省略该字段会令刚抽取的语义文档从 manifest 掉队(graphify/cli.py 中 manifest 相关逻辑对此有专门注释)。

十二、写回磁盘:必须用绝对路径 CHUNK_PATH

规范的最后一步是写盘纪律:

Then write the JSON to disk using the Write tool at this exact absolute path (no relative paths — Write resolves relative paths against an undefined cwd and the file will be silently lost): CHUNK_PATH

子智能体必须把结果 JSON 写到编排方传入的绝对路径 CHUNK_PATH。之所以强调"不用相对路径",是因为在多数 Agent 宿主中,Write 工具的相对路径会基于一个未定义的工作目录解析,文件会被"静默丢失"——分块结果丢失不会立即报错,只会在合并时表现为语义层缺失,是极难排查的失败模式。平台编排方(如 graphify/skill-opencode.md 的 Part B)会在派发前推导好该绝对路径(典型命名如 ${PROJECT_ROOT}/graphify-out/.graphify_chunk_0N.json),再随 Prompt 一并下发。

十三、附:完整抽取 JSON Schema(来自规范的原始单行结构)

规范要求子智能体严格按下列 schema 产出(以下为原文结构,字段含义按本章与前述小节解读):

{"nodes":[{"id":"auth_session_validatetoken","label":"Human Readable Name","file_type":"code|document|paper|image|rationale|concept","source_file":"<FILE_LIST path verbatim>","source_location":null,"source_url":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,"output_tokens":0}

逐键解读:

  • nodesid(按第十节的确定性规则)、label(人类可读名)、file_type(六值枚举)、source_file(FILE_LIST 逐字透传)、source_location(通常为 null,AST 层填充行号)、source_url / captured_at / author / contributor(默认 null)。
  • edgessource/target 为节点 ID;relation 八值枚举;confidence 三值;confidence_score 遵循第九节刻度;source_file 逐字透传;weight 默认 1.0。
  • hyperedgesid 为 snake_case、label 为可读标签、nodes 为成员 ID 数组(≥3)、relation 三值、confidence/confidence_score/source_file 与边同规则。
  • input_tokens / output_tokens:由编排方或子智能体填写的 token 统计字段。

十四、元数据透传与工程实现对照

规范还包含一条与常见博客抓取场景强相关的规则:若文件带 YAML frontmatter(--- ... ---),须把其中的 source_urlcaptured_atauthorcontributor 复制到该文件产出的每个节点上,让同一来源的实体共享来源元数据。

子智能体产出的片段并不会直接进图,而要经过多层工程处理:graphify extract 的语义通道读取 CLI 派发(graphify/cli.py 将 doc/paper/image 归为 semantic_files),结果经 graphify/build.pymerge_raw_extraction 与 AST 层合并(graphify/cli.py 的合并调用),期间 graphify/semantic_cleanup.py 负责清理句子化 rationale 节点、剔除非法 file_type 并对不可信片段做大小与 ID 边界校验。可验证该契约的测试还包括 tests/test_semantic_cleanup.pytests/test_semantic_fragment_sanitize.pytests/test_build_merge_hyperedges_and_prune.py

十五、小结:从 Prompt 纪律到图的确定性

把这份 extraction-spec 通读下来,可以提炼出 graphify 语义层设计的四条主线:

  1. 把 LLM 当作受约束的抽取器而非自由写作者:严格 JSON、无前言、无 Markdown 围栏,是后续机器化合并与缓存的前提。
  2. 用离散刻度驯服置信度塌缩:宁可 AMBIGUOUS,不用 0.5 摆烂——这是把不可靠的模型判断变成可排序、可审阅、可量化的图数据的核心手段。
  3. 用确定性 ID 与逐字 source_file 对齐多生产者:分块并行、增量更新、重抽取替换之所以不会产生幽灵重复节点,靠的是"ID 仅由实体确定"与"source_file 逐字透传"这两条硬纪律。
  4. 激进模式有独立的缓存命名空间与运行语义--mode deep 不只是改一行 Prompt,还牵动 cache namespace、语料门控宽度与构建端防护。

对于想在自己系统中复刻"文档→知识图谱"管线的开发者,这份 reference 本身就是一份高质量的工程样板:它把如何给子智能体写抽取任务、如何给模型判断配置信度、如何保证跨进程结果可合并这三类通用难题,压缩成了一段可逐字复用的 Prompt 与配套的引擎校验边界。

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

项目优选

收起
kernelkernel
deepin linux kernel
C
33
18
ops-transformerops-transformer
本项目是CANN提供的transformer类大模型算子库,实现网络在NPU上加速计算。
C++
1.13 K
2.75 K
pytorchpytorch
作为 Ascend for PyTorch 社区的核心组件,TorchNPU 是昇腾专为 PyTorch 打造的深度学习适配插件,使 PyTorch 框架能够直接调用昇腾 NPU,为开发者提供昇腾 AI 处理器的超强算力。
Python
857
1.35 K
docsdocs
暂无描述
Markdown
897
5.8 K
kernelkernel
openEuler内核是openEuler操作系统的核心,既是系统性能与稳定性的基石,也是连接处理器、设备与服务的桥梁。
C
529
593
ops-nnops-nn
本项目是CANN提供的神经网络类计算算子库,实现网络在NPU上加速计算。
C++
916
1.83 K
jiuwenswarmjiuwenswarm
JiuwenSwarm 是一款基于openJiuwen开发的智能AI Agent,它能够将大语言模型的强大能力,通过你日常使用的各类通讯应用,直接延伸至你的指尖。
Python
3.58 K
1.01 K
ops-mathops-math
本项目是CANN提供的数学类基础计算算子库,实现网络在NPU上加速计算。
C++
1.35 K
1.46 K
cann-learning-hubcann-learning-hub
CANN 学习中心仓,支持在线互动运行、边学边练,提供教程、示例与优化方案,一站式助力昇腾开发者快速上手。
Jupyter Notebook
1.01 K
515
AscendNPU-IRAscendNPU-IR
AscendNPU-IR是基于MLIR(Multi-Level Intermediate Representation)构建的,面向昇腾亲和算子编译时使用的中间表示,提供昇腾完备表达能力,通过编译优化提升昇腾AI处理器计算效率,支持通过生态框架使能昇腾AI处理器与深度调优
C++
547
388