graphify 语义抽取子代理规范(extraction-spec)全解:将文档、论文与图像可靠编码为知识图谱 JSON
graphify 通过两阶段构建知识图谱:先由本地确定性 AST 抽取器覆盖代码结构,再由并行的语义子代理把文档、论文与图像中的命名概念、实体、引用与推理关系转成统一 JSON。本指南围绕驱动这些子代理的 extraction-spec 参考提示词,完整拆解其节点 ID 确定性规则、证据分级与置信度标尺、语义相似边与超边约束、六类 file_type、以及逐字复制 source_file 等硬性要求,帮助你理解(或自行驱动)语义抽取管道,并让产出与 AST 抽取结果在合并时不会产生"幽灵重复节点"。
关联文档本体为 skillgen 渲染各平台技能文件后生成的 golden 副本 tools/skillgen/expected/graphify__skills__agents__references__extraction-spec.md,它与仓库内实际随技能分发的同构文件 graphify/skills/agents/references/extraction-spec.md 内容一致;除 agents 外,graphify/skills/ 下每个平台(claude、kiro、opencode、vscode、codex 等)都有各自同名副本。
一、这份规范解决什么问题:AST 之外的语义抽取通道
graphify 的抽取管道分为互补的两路:
- AST 路径(结构化):对代码文件做本地确定性解析,产出
imports、calls、类型关系等结构性边——见 graphify/extract.py 与 graphify/extractors/。 - 语义路径(LLM 子代理):当语料中至少存在一个文档、论文或图像 chunk 时,启动多个语义抽取子代理,负责捕获"AST 无法发现"的语义边:跨文件共享数据结构、架构模式、文档/论文中的命名概念、引用关系、图像里的设计信息等。纯代码语料会直接跳过该阶段,永远不会读取本规范。
两种产出最终合并成同一张图。规范开头即说明该提示词的使用方式:每个语义子代理逐字接收下面这份 prompt,仅替换五个占位符——FILE_LIST(文件清单)、CHUNK_NUM(当前 chunk 序号)、TOTAL_CHUNKS(总 chunk 数)、DEEP_MODE(是否深度模式)、CHUNK_PATH(本 chunk 结果写入的绝对路径)。它同时规定了三个"铁律":输出只能是合法 JSON(无解释、无 markdown 围栏、无前言);节点 ID 必须与 AST 抽取器完全一致;每条边都必须带合规的 confidence_score。
二、触发时机与编排上下文:技能文档中的 Step 3 Part B
extraction-spec 不是独立运行的工具,而是技能编排流程的一部分。以 graphify/skill-agents.md 的 Step 3 Part B 为例,整个语义抽取分四步:
| 步骤 | 动作 | 与 spec 的关系 |
|---|---|---|
| B0 | 先查抽取缓存 check_semantic_cache |
通过 prompt_file='SPEC_PATH' 把缓存条目归属于这份提示词文件(issue #1939) |
| B1 | 分块 | 每个 chunk 20–25 个文件,每张图像独占一个 chunk(视觉需要独立上下文),同一目录文件尽量同 chunk |
| B2 | 单条消息并行派发所有子代理 | 把 spec 提示词作为任务描述逐字传入,替换占位符 |
| B3 | 收集、写缓存、合并 | 校验 graphify-out/.graphify_chunk_NN.json 是否落盘,汇总进 .graphify_semantic_new.json |
关键机制:缓存键归属 SPEC_PATH。SPEC_PATH 是随 SKILL.md 同目录分发的 references/extraction-spec.md 的绝对路径——"当 graphify 升级改动了这份 prompt,旧 prompt 产出的缓存条目会被重新抽取而不是被回放;未变化的 prompt 则保留缓存条目"。这也解释了为何本规范如此强调"子代理必须把 JSON 写入指定的绝对路径 CHUNK_PATH",以及各平台技能(如 codex/opencode 的"内联返回 JSON"变体)如何差异化适配。底层实现在 graphify/cache.py:check_semantic_cache 同时接收 prompt 与 prompt_file 参数,提示词内容(或其文件)参与缓存键计算。
编排方还要求派发前先做估算(未缓存非代码文件数 /22 约等于 agent 数,约 45s/批);若某个 chunk 结果文件缺失,则提示子代理可能以只读型被派发,需改用 general-purpose 类型重跑;超过一半 chunk 失败则停下要求重跑。
三、证据分级与按文件类型的抽取规则
3.1 三种证据分级(confidence)
| 分级 | 语义 | 使用场景 |
|---|---|---|
EXTRACTED |
源中显式存在的关系 | import、call、引用、"see §3.2"式交叉引用 |
INFERRED |
合理的推理关系 | 共享数据结构、隐含依赖 |
AMBIGUOUS |
不确定的关系 | 标记出来供复查,不得省略 |
3.2 代码文件
语义子代理对代码只补语义边(调用关系、共享数据、架构模式),绝不重新抽取 import——那些 AST 已覆盖。
calls 边有两条不可违反的方向与语言规则:
source必须是调用方(发起调用的函数/类),target必须是被调用方,严禁反向;calls边必须限定在同一门语言内:Python 函数不能calls一个 JS/TS/Go/Rust/Java 符号,反之亦然——跨语言调用边是幽灵伪影(phantom artifacts),永远不要产出。
3.3 文档 / 论文文件
抽取命名概念、实体与引用。对于设计缘由(为什么做此决策、权衡、设计意图),规范明确要求:
- 作为
rationale属性存放在相关概念节点上,不要单独创建 rationale 节点或 fragment 节点; - 只有当某事物本身就是命名实体或概念时才为它建节点;
- 概念类节点(想法、原则、机制、设计模式)使用
file_type:"rationale"; file_type必须是且只能是六个枚举值之一:code、document、paper、image、rationale、concept——任何其他值都非法,会被拒绝。
3.4 图像文件(视觉理解)
规范强调"用视觉理解图像是什么,不要只做 OCR":
| 图像类型 | 应抽取的内容 |
|---|---|
| UI 截图 | 布局模式、设计决策、关键元素、用途 |
| 图表 | 指标、趋势/洞察、数据来源 |
| 推文/帖子 | 主张(claim)作为节点、作者、提及的概念 |
| 示意图 | 组件与连接关系 |
| 科研图 | 论证了什么、方法、结果 |
| 手写/白板 | 想法与箭头连线;不确定的解读标记为 AMBIGUOUS |
3.5 YAML frontmatter 元数据继承
如果某文件带有 YAML frontmatter(--- ... ---),则把其中 source_url、captured_at、author、contributor 复制到该文件产出的每个节点上,保证溯源元数据不丢失。
四、置信度标尺:为什么禁止 0.5,以及五档离散分值
规范给出的置信度体系是全文最容易出错的部分,值得单独一节:
confidence_score在每条边上都必填——绝不省略、绝不默认取 0.5;EXTRACTED边恒为1.0;INFERRED边只能从下面五个离散档位中精确选取一个;AMBIGUOUS边取0.1–0.3。
| 分值 | 含义 |
|---|---|
| 0.95 | 直接结构证据(共享数据结构、具名跨文件引用) |
| 0.85 | 强推理(清晰的功能对齐,但没有直接符号链接) |
| 0.75 | 合理推理(共享问题域 + 相似形状,需要解读) |
| 0.65 | 弱推理(主题相关,无形状证据) |
| 0.55 | 推测但合理(仅表层共现) |
规范同时解释了为什么用离散档位而非连续区间:"模型遵循离散评分表比连续区间更好;生产观测到的双峰分布(>50% 落在 0.5、>40% 落在 0.85+)表明连续区间指导被坍缩成了二值判断"。兜底规则是:如果没有任何一档适用,就把边标记为 AMBIGUOUS,而不要给 0.4 或更低的分(该区间不属于 INFERRED 的合法取值)。
这条规则并非只约束 LLM:仓库中 AST 抽取器产出的 INFERRED 边同样遵守同一标尺。默认分值定义在 graphify/export.py 的 _CONFIDENCE_SCORE_DEFAULTS 中(EXTRACTED=1.0、AMBIGUOUS=0.2、INFERRED≠0.5),并由 tests/test_inferred_confidence_rubric.py 锁定:测试显式断言 INFERRED 默认值属于离散集合 {0.55, 0.65, 0.75, 0.85, 0.95} 且不等于被禁止的 0.5。该测试文档串中记录了一次真实违规:graphify 自身上 128 条 INFERRED 边中 54 条缺失分值(落入默认 0.5)、74 条硬编码了不在集合内的 0.8(issue #2813)——正是这类漂移促使 rubic 被写成守护测试。
五、两种"成组/跨域"机制:语义相似边与超边
5.1 semantically_similar_to 语义相似边
当本 chunk 内两个概念解决问题相同或表达同一思想、却没有任何结构链接(无 import、无 call、无引用)时,可以添加一条标记为 INFERRED 的 semantically_similar_to 边,confidence_score 反映相似程度(0.6–0.95)。规范给出的典型例子:
- 两个都校验用户输入、但从不互相调用的函数;
- 代码里的一个类与论文中描述同一算法的概念;
- 处理同一失败模式但方式不同的两个错误类型。
注意约束:只有当相似性真正非显然且跨领域(cross-cutting)时才加;琐碎相似严禁加边。这也解释了为何 graphify/analyze.py 在消费语义图时把 semantically_similar_to 单独看待——它是"真正的跨边界洞察"。
5.2 超边(hyperedge)
当 3 个或更多节点显然共同参与某一个共享概念、流程或模式,而仅靠两两成对边表达不出来时,把它们写进顶层 hyperedges 数组:
- 实现同一协议/接口的所有类;
- 认证流程中的所有函数(即使它们不互相调用);
- 论文某节中构成一个连贯想法的所有概念。
约束:克制使用——只有当群组关系提供了超越成对边的信息时才加;每个 chunk 最多 3 条超边。超边 ID 为 snake_case,relation 只能是 participate_in、implement、form 三者之一。
六、节点 ID:从仓库路径到确定性标识符
节点 ID 是语义抽取与 AST 抽取能否合并成同一张图的关键契约:
- 格式为
{stem}_{entity}; stem= 去掉扩展名后的完整仓库相对路径,每一级路径段都保留,段与段之间用_拼接(每段转小写、非字母数字字符替换为_);entity= 符号名,同样规范化;- 字符集限制:仅小写
[a-z0-9_],禁止点号与斜杠。
规范给出五个可直接对照的示例:
| 路径 + 符号 | 结果 |
|---|---|
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 |
必须使用每一级目录,而不是只取最近一级父目录——这保证了不同目录下的同名文件拥有互不相同的 ID。规范特别警告:如果只取文件名(如 session_validatetoken)或只取最近父目录(如 auth_session_validatetoken),就会制造孤立幽灵重复节点。CRITICAL 铁律:永远不要在 ID 上追加 chunk 号、序号或任何后缀(禁止 _c1、_c2、_chunk2 之类);ID 必须仅由标签(label)确定性地推导——同一个实体无论由哪个 chunk 处理,都必然得到同一个 ID。
这套规则在代码侧有精确对应。_file_stem 在 graphify/extractors/base.py 中实现:保留完整路径(去扩展名)作为路径段,make_id 随后把分隔符折叠为下划线;注释中的示例与规范完全同构(docs/v1/api/README.md -> docs_v1_api_readme),并注明"使用全部段而非仅最近父目录(#1504)",避免同名文件互相覆盖成 last-writer-wins 单节点;顶层文件保留裸 stem(setup.py -> setup)。规范文本与代码实现之间还有专门的漂移守护测试 tests/test_extraction_spec_ids.py:它用正则直接从各平台分发的 extraction-spec.md 中解析出全部 path + entity → id 示例,再调用真实的 _file_stem/_make_id 逐一断言相等——任何一侧被改动导致示例失效都会让测试失败。
若你正在重新抽取一个用旧版"最近父目录"格式构建过的项目,规范给出的迁移动作是让用户运行 graphify extract --force 全量重建,以获得干净的路径级 ID。
七、输出 JSON Schema 逐字段解析
子代理必须生成与下列 schema 完全一致的抽取 JSON(提示词原文):
{"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}
各对象字段含义如下:
node 字段
| 字段 | 说明 |
|---|---|
id |
按第六节确定性规则生成的节点 ID |
label |
人类可读名称 |
file_type |
六选一:code|document|paper|image|rationale|concept |
source_file |
来源文件路径,必须与 FILE_LIST 中逐字一致(见第八节) |
source_location / source_url / captured_at / author / contributor |
溯源与元数据;frontmatter 存在时从 YAML 继承 |
edge 字段
| 字段 | 说明 |
|---|---|
source / target |
起止节点 ID;calls 边方向与同语言约束见 3.2 |
relation |
枚举:calls|implements|references|cites|conceptually_related_to|shares_data_with|semantically_similar_to|rationale_for |
confidence |
EXTRACTED|INFERRED|AMBIGUOUS |
confidence_score |
必填;按第四节标尺取值,EXTRACTED=1.0,INFERRED 取离散五档,AMBIGUOUS 取 0.1–0.3 |
source_file / source_location / weight |
溯源与权重 |
hyperedge 字段:id(snake_case)、label、nodes(≥3 个成员 ID)、relation(participate_in\|implement\|form)、confidence(仅 EXTRACTED/INFERRED)、confidence_score、source_file。
顶层还包含 input_tokens 与 output_tokens(占位 0;编排层会在每个 Agent 完成后用工具结果 usage 字段的真实计数回填)。
注意:schema 骨架中的 auth_session_validatetoken 只是便于阅读的占位写法,真实 ID 一律采用第六节的全路径规则。
八、source_file 逐字复制规则:与增量构建的对齐关键
source_file 规则适用于每一个 node、edge 与 hyperedge:
- 取该来源文件在
FILE_LIST中原样出现的路径——逐字、绝对; - 不缩短为 basename、不重新相对化、不剥除任何目录前缀、不改动分隔符(引擎会在下游对分隔符做规范化并按构建根相对化);
- 直接逐字符复制
FILE_LIST条目。
这样做的根本目的写在规范末尾:让完整构建与增量 --update 站在同一基准上,build_merge 的 replace-on-re-extract 才能命中既有节点,而不是不断累积出重复节点。换言之,source_file 的一致性直接决定了"同一文件被重新抽取时是替换旧节点还是长出第二份"这一去重语义。这与仓库中增量更新/去重的整体设计同源,可进一步阅读 docs/superpowers/specs/2026-05-04-incremental-updates-dedup-design.md。
九、CHUNK_PATH:必须写绝对路径,避免 JSON 静默丢失
每个语义子代理在生成 JSON 后,必须用 Write 工具把它写入一个精确的绝对路径 CHUNK_PATH。规范特别强调:不允许用相对路径——"Write 会把相对路径解析到某个未定义的 cwd,文件会被静默丢失"。编排侧(如 skill-agents.md 的 B2 步骤)会预先从 PROJECT_ROOT=$(pwd) 推导出形如 ${PROJECT_ROOT}/graphify-out/.graphify_chunk_0N.json 的绝对路径再派发;子代理结果文件是否存在于磁盘,正是编排层判定本次派发成功与否的信号(read-only 型子代理不会落盘,会触发"re-run with general-purpose agent"警告)。
十、下游消费与守护测试:规则不会悄悄漂移
语义子代理产出的 nodes/edges/hyperedges 最终被构建合并(build_merge)、缓存(cache)与下游分析消费。graphify/analyze.py 会依据同一套字段约定工作:confidence 缺省视为 EXTRACTED、对 semantically_similar_to 特殊对待、AMBIGUOUS 边以低置信度提示("Edge tagged AMBIGUOUS — confidence is low")方式呈现、建议新增边也携带 confidence 字段并按分级排序。
仓库把"提示词示例"与"真实实现"绑定成了守护测试网,防止手写的规范文本与代码静默漂移:
- tests/test_extraction_spec_ids.py:解析 spec 中全部节点 ID 示例,断言
_file_stem+_make_id的产出与之一致,同时锁定两种被警告的错误形态确实非法; - tests/test_inferred_confidence_rubric.py:断言 INFERRED 默认值属于五档离散集合、不等于禁止值 0.5,EXTRACTED/AMBIGUOUS 默认值保持 1.0/0.2;
- tools/skillgen/gen.py 及 golden 输出(含本指南所依托的 tools/skillgen/expected/ 目录):负责把同一份 spec 渲染到
graphify/skills/<host>/references/的各平台副本,skillgen --check对 expected 目录做一致性校验。
对读者而言,最实用的经验是:当需要为 graphify(或类似两阶段管道)设计自己的 LLM 抽取提示词时,把"节点 ID 确定性、置信度离散标尺、source_file 逐字一致、绝对路径落盘"这四条写成显式规则并配守护测试,才能让并行子代理的输出真正可合并、可缓存、可增量。
atomcodeClaude Code 的开源替代方案。连接任意大模型,编辑代码,运行命令,自动验证 — 全自动执行。用 Rust 构建,极致性能。 | An open-source alternative to Claude Code. Connect any LLM, edit code, run commands, and verify changes — autonomously. Built in Rust for speed. Get StartedRust0624
Hy4-previewHy4 preview 是由腾讯混元团队研发的新一代混合专家(MoE)旗舰模型。模型总参数量 770B,每个 token 激活 49B,主干共包含78层,第一层采用标准 FFN,其余 77 层均为 MoE 结构,每层包含 256 个路由专家与 1 个共享专家,每个 token 激活 top-8 路由专家及共享专家。主干之外原生内置 1 层 MTP(总参数量 10B,激活 0.7B)以支持投机解码。Python00
GLM-5.3GLM-5.3 与 GLM-5.2 使用相同的基座模型——所有提升均来自后训练。与 GLM-5.2 相比,它在复杂编程和长程任务上的表现显著提升。Jinja00
GLM-5.3-FlashGLM-5.3-Flash (320B-A18B),是GLM-5系列的首个原生多模态模型。320B总参数,能力超过GLM-5.2Jinja00
Spark-X2.5-4BSpark-X2.5-4B 旨在让强大的 AI 更实用、更高效、更易获得。在广泛日常任务中表现强劲,涵盖对话、写作、翻译、推理、编码、工具调用以及智能体工作流,并在同等规模的开源模型中取得领先成绩。Spark-X2.5 将面向效率的架构与最高 1M tokens 的原生上下文窗口相结合,并支持 200 多种语言。Python00
Spark-X2.5-1.7BSpark-X2.5-1.7B 旨在让强大的 AI 更加实用、高效且易于获取。这些模型在广泛的日常任务中表现出色,涵盖对话、写作、翻译、推理、编程、工具调用和智能体工作流,并在同等规模的开源模型中取得领先结果。Spark-X2.5 将面向效率的架构与最高 1M tokens 的原生上下文窗口相结合,并支持 200 多种语言。Python00