ARTICLE DETAIL

资讯详情

深耕编程入门与网站建设的一线实战洞察。

graphify extraction-spec 详解:语义提取子代理的 Prompt 契约与确定性节点 ID 规范

graphify extraction-spec 详解:语义提取子代理的 Prompt 契约与确定性节点 ID 规范 graphify extraction-spec 详解语义提取子代理的 Prompt 契约与确定性节点 ID 规范【免费下载链接】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本文围绕 extraction-spec.md 展开。该文档是 graphify把任意代码库连同文档、SQL、配置转成可查询知识图谱的 /graphify 技能在构建流水线 Step 3 Part B 中下发给每个“语义提取子代理”的完整 prompt 模板它规定了子代理必须遵守的边级置信度准则、file_type枚举、语义相似边与超边hyperedge规则、节点 ID 的确定性生成格式以及最终输出的 JSON Schema 与source_file逐字verbatim路径规则。读完本文你能理解 graphify 如何用一个“纯文本契约 漂移守卫测试”保证 LLM 语义提取结果与 AST 确定性提取在同一个图上无缝合并并能复现其节点 ID、置信度评分与增量更新不产生重复节点的关键机制。1. 文档定位何时加载、由谁消费extraction-spec.md 开头的加载条件写得很明确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.也就是说它只在语料中至少存在一个文档、论文或图片分块chunk时才被加载纯代码语料直接跳过 Part B永远不会读这个文件。这与 skill-claw.md Step 3 的流程一致Part AAST 确定性提取与 Part B语义子代理并行调度而纯代码语料走 Fast path——先写一个空的.graphify_semantic.json让 Part C 合并阶段有输入然后直接进入 Part C。每个语义子代理都会逐字收到这份 prompt其中 5 个占位符由调度方替换占位符含义FILE_LIST本分块负责处理的文件路径列表必须是 verbatim 绝对路径见第 8 节CHUNK_NUM/TOTAL_CHUNKS当前分块编号 / 总分块数DEEP_MODE是否以--mode deep运行决定推断边的激进度CHUNK_PATH结果 JSON 的落盘绝对路径完整版 spec 要求例如${PROJECT_ROOT}/graphify-out/.graphify_chunk_0N.json从源码结构看这份 claw 目录下的拷贝并非手工维护的独立文件。仓库里所有宿主claude、codex、opencode、kilo、copilot、claw、droid、trae、kiro、pi、windows 等的references/extraction-spec.md都由 skillgen 从单一源头 extraction-spec.md完整版与 extraction-spec-compact.md紧凑版即本文引用的 claw 版本所对应的源渲染生成tools/skillgen/expected/下还留有各宿主的黄金输出用于skillgen --check校验。这种“一份源、多宿主分发”的机制是后文所有跨宿主行为一致性的前提。2. 子代理的总则只输出 JSON且遵守三级置信度prompt 的第一段规则就锁死了输出形态You are a graphify extraction subagent. Read the files listed and extract a knowledge graph fragment. Output ONLY valid JSON matching the schema below - no explanation, no markdown fences, no preamble.随后是三条核心的边级置信度confidence tier规则EXTRACTED源文件中明确存在的关系import、call、citationINFERRED合理推断共享结构、隐含依赖AMBIGUOUS不确定——标记出来不要省略flag it, do not omit。这三档不是装饰它们贯穿到下游。例如 export.py 中为缺失confidence_score的边提供了回退默认值_CONFIDENCE_SCORE_DEFAULTS {EXTRACTED: 1.0, INFERRED: 0.55, AMBIGUOUS: 0.2}——其中 INFERRED 回退用的是准则集{0.55, 0.65, 0.75, 0.85, 0.95}的最弱值 0.55 而非 0.5源码注释明确指出 0.5 是被 spec 明文禁止的“抛硬币”默认值参见 #2813AMBIGUOUS 回退到区间 0.1–0.3 的中点 0.2。也就是说spec 里的每一句话都能在合并/导出代码里找到对应的实现或护栏。3. 分文件类型的提取规则3.1 代码文件只补 AST 找不到的语义边Code files: semantic edges AST cannot find. Do not re-extract imports. When addingcallsedges: source is the caller, target is the callee, never reversed; keepcallswithin one language.三条约束各有原因不要重提 import——import 边由确定性 AST 提取器Part A负责语义子代理重复输出会造成重复边calls方向不可反——source 恒为调用方target 恒为被调方。完整版 spec 还进一步强调calls边必须留在单一语言内部“a Python function cannotcallsa JS/TS/Go/Rust/Java symbol … cross-language call edges are phantom artifacts, never emit them”因为跨语言“调用”在没有运行时桥接时只是幻象边phantom edge语义边聚焦 AST 表达不了的东西共享数据、架构模式等。3.2 文档/论文文件六种 file_type 与 rationale 属性对 doc/paper 文件spec 要求提取命名概念、实体与引用并对file_type做了硬枚举约束file_typeMUST be one of exactly these six values:code,document,paper,image,rationale,concept. Any other value is invalid and will be rejected.同时规定“决策理由”WHY decisions were made必须作为rationale属性挂在相关节点上而不是单独建一个 rationale 节点概念性节点思想、原则、机制用file_type:rationale命名概念用file_type:concept。这个“属性而非节点”的设计避免图谱被碎片化理由节点污染仓库中 rationale 相关测试 也围绕该约定验证行为。3.3 图片文件用视觉理解“它是什么”而非 OCRImage files: use vision — understand what the image IS, not just OCR完整版 spec 给出了更细的分类指导UI 截图提取布局模式与设计决策图表提取指标与趋势推文/帖子提取论断与作者架构图提取组件与连接关系手写/白板内容把不确定的读法标为 AMBIGUOUS。这条规则对应 graphify 对图片语料的一等公民处理graphify/skills/claw/references/同目录体系下的视觉处理路径。3.4 DEEP_MODE 与语义相似边DEEP_MODE--mode deep时激进地输出 INFERRED 边——间接依赖、共享假设、潜在耦合拿不准的标 AMBIGUOUS 而不是丢弃。skill-claw.md 明确要求在 Step 3 开始前记住--mode deep是否出现并把DEEP_MODEtrue传给 Part B 的每个子代理“do not lose it”语义相似边当两个概念解决同一问题或表达同一思想、但没有任何结构性链接无 import、无 call、无 citation时加一条semantically_similar_to边标 INFERREDconfidence_score取 0.6–0.95且仅限“非显而易见的跨文件关联”Non-obvious cross-file links only。完整版 spec 还举了三个例子两个互不调用的用户输入校验函数代码里的类与论文里描述的同一算法以不同方式处理同一失败模式的两个错误类型。3.5 超边HyperedgesHyperedges: if 3 nodes share a concept, flow, or pattern not captured by pairwise edges, add a hyperedge to a top-levelhyperedgesarray. Use sparingly. Max 3 per chunk.超边捕捉“3 个及以上节点共同参与但成对边表达不了”的群体关系relation取值participate_in | implement | form每分块最多 3 条。值得注意的历史背景见 CHANGELOG早期graphify extract --backend …的原生 LLM promptllm.py 中的_EXTRACTION_SYSTEM只在输出 Schema 里展示了空hyperedges:[]、从未解释什么是超边导致所有原生后端静默产出 0 条超边而 skill 路径本 spec 完整文档化超边却能产出——两条提取路径的 prompt 发生了漂移。修复后原生 prompt 携带了相同的“3 个及以上节点共同参与”指令与填充示例使同一语料下两条路径的超边行为一致。这是“spec 即契约、多路径必须对齐”这一工程原则的又一例证。3.6 YAML frontmatter 传播If a file has YAML frontmatter (--- ... ---), copysource_url,captured_at,author,contributoronto every node from that file.四个溯源字段会被复制到该文件产出的每个节点上保证节点级可溯源provenance。4. 离散置信度评分准则confidence rubricspec 中最“反直觉”也最关键的一段是对confidence_score的强制要求confidence_score is REQUIRED on every edge — never omit it, never use 0.5 as a default. EXTRACTED 1.0 always.置信档位允许的取值语义EXTRACTED恒为1.0源文件中显式存在的关系INFERRED只能从五档中选一个0.95/0.85/0.75/0.65/0.550.95 直接结构证据0.85 强推断0.75 合理推断0.65 弱推断0.55 推测但可信AMBIGUOUS0.1–0.3不确定标记而非省略五档 INFERRED 分值的含义以完整版 spec 的标注为准0.95— 直接结构证据共享数据结构、具名的跨文件引用0.85— 强推断清晰的功能对齐无直接符号链接0.75— 合理推断共享问题域 相似形态需要解释0.65— 弱推断主题相关无形态证据0.55— 推测但可信仅表层共现。为什么用离散档位而不是连续区间完整版 spec 直接给出了生产观察“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”——即连续区间引导会被模型坍缩成二值分布而离散准则反而被更忠实执行。如果五档都不适用应标 AMBIGUOUS 而不是硬选 0.4 或更低。这个准则同样渗入代码实现AST 侧各发射点都自带评分注释中反复引用“the rubric in references/extraction-spec.md”如 extract.py 中“0.85, not 0.8: the rubric in references/extraction-spec.md …”以及 extractors/engine.py、extractors/resolution.py 处同样按此准则取值 0.85/0.95。测试 test_inferred_confidence_rubric.py 则把该准则锁定为回归约束。5. 节点 ID确定性、全路径、与 AST 提取器一致这是整份 spec 里工程密度最高的部分Node ID format: lowercase, only[a-z0-9_], no dots or slashes. Format{stem}_{entity}where stem is the full repo-relative path with the extension dropped, every segment joined with_(each lowercased with non-alphanumeric chars replaced by_) and entity is the symbol name similarly normalized. Use every directory level, not just the immediate parent.src/auth/session.pyValidateToken→src_auth_session_validatetoken. Top-level files use just the filename stem. This must match the AST extractors ID. Never append chunk or sequence suffixes — IDs must be deterministic from the label alone.拆解成可执行的生成规则字符集仅小写字母、数字、下划线stem仓库相对路径去掉扩展名后保留每一级目录段与段之间用_连接每段小写化、非字母数字字符替换为_entity符号名做同样的归一化根级文件只用文件名 stemsetup.py→setup符号my_func→setup_my_func禁止追加任何 chunk 序号或序列后缀如_c1、_chunk2——同一实体无论被哪个分块处理必须产生同一个 ID必须与 AST 提取器生成的 ID 完全一致否则同一个符号会被拆成互不相连的“幽灵重复节点”ghost-duplicate nodes。为什么强调“每一级目录”extractors/base.py 中_file_stem的 docstring 解释了动机对应 issue #1504若 stem 只取“父目录 文件名”则docs/v1/api/README.md与docs/v2/api/README.md都会塌缩成api_readme同名文件在不同目录相互碰撞为“last-writer-wins”的单一节点并静默丢图。全路径 stem 使二者分别得到docs_v1_api_readme与docs_v2_api_readme。CHANGELOG 记录了这次破坏性变更“Breaking — node IDs now include the full repo-relative path (#1504, #1509)”并说明 AST 提取器、LLM system prompt、extraction-spec 与两处手工复制的 stem helper 已对齐到同一条规则修复 #1509 的 AST↔LLM 分歧。ID 的最终生成由 ids.py 完成make_id(*parts)先把各 part 拼接再交给normalize_id——后者对输入迭代执行NFKC(casefold(s))直到不动点带 6 次硬上限然后[^\w] → _、折叠连续下划线并去首尾源码注释说明这是为组合附加符序列如希腊 ypogegrammeni 做的收敛处理见 #2614。语义子代理产出的 ID 因此能被确定性地与 AST 侧 ID 对齐或重映射。5.1 漂移守卫spec 里的每个例子都是可执行测试正因为 spec 是“LLM 的 ground truth”它一旦与代码漂移就会制造幽灵节点。test_extraction_spec_ids.py 是一个专门的守卫测试用正则path entity → id箭头为 U2192从所有发行中的 spec 文件里解析出每个 ID 示例扫描graphify/skills/**与tools/skillgen/fragments/**下所有extraction-spec.md排除build/与expected/对每个示例调用生产代码本身extract._file_stem_make_id重放断言结果与 spec 写死一致若一个都解析不到文件搬走或示例格式变了就 loudly fail防止守卫本身空转另有一条test_cautionary_wrong_forms_are_actually_wrong把 spec 中警告的反例只用文件名session、只用直接父目录auth也锁定到代码上确保警告不会过期。也就是说claw 这份 spec 里的例子src/auth/session.pyValidateToken→src_auth_session_validatetoken不只是文档示例而是 CI 会逐条重放的断言。6. 输出 JSON Schema 逐字段说明spec 要求子代理输出恰好如下结构无其他文本{ 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按第 5 节规则file_type是第 3.2 节的六值硬枚举溯源四元组source_url/captured_at/author/contributor默认 null仅在 frontmatter 传播规则触发时填充edgesrelation八值枚举中calls、cites等显式关系应标 EXTRACTED1.0conceptually_related_to、shares_data_with、semantically_similar_to、rationale_for通常是 INFERRED 并套用第 4 节五档准则weight默认 1.0hyperedges仅 EXTRACTED/INFERRED 两档示例中 0.75 落在 INFERRED 准则内nodes为成员节点 ID 列表最多 3 条/分块input_tokens / output_tokens供上层统计成本skill 流水线会汇总到cost.json一类产物。下游对这份 JSON 有解析护栏llm.py 中的解析器会强制nodes/edges/hyperedges为 dict 列表并把超边成员引用强制转为可哈希标量 ID#2486防止模型把成员写成对象导致后续去重崩溃。7. source_file 逐字规则全量构建与增量更新共用同一基准spec 的最后一条规则看似琐碎实则是增量正确性的基石source_file RULE: set source_file to the FILE_LIST path for that file VERBATIM (absolute, no shortening to basename, no re-relativizing, no separator change). Keeps full build and --update on one base so build_merges replace matches instead of duplicating.即节点、边、超边的source_file必须与 FILE_LIST 中该文件的路径逐字符一致——不得缩成 basename、不得重新相对化、不得改分隔符路径的正则化与对构建根的相对化由下游引擎统一做。其直接收益是“全量构建”与--update增量重建落在同一节点键基准上当某文件被重新提取时build_merge能替换replace-on-re-extract旧节点而不是追加出一个重复节点。CHANGELOG 中 #1366 的修复正是围绕这条规则固化下来的“the extraction-specsource_fileis pinned to the verbatim path, so the full build and incremental updates never drift on node-key base”更早的 #1344/#1361 还处理了--update时误删已变更文件新节点的回归更新 runbook 现在只修剪真正被删除的文件变更文件交给 build_merge 的替换机制对账。8. 工程闭环这条 prompt 还参与了缓存命名空间从源码结构看这份 spec 不只是运行时下发的文本它还是语义缓存的命名空间指纹来源之一。cache.py 与 cli.py 中语义缓存条目按“提取 prompt 的指纹”归入cache/semantic/p{fingerprint}/镜像 AST 缓存的v{version}/布局skill-claw.md 要求调度方把 spec 的绝对路径SPEC_PATH在 Step B0 与 B3 之间原样传递——graphify 升级若改变了 prompt旧 prompt 产出的缓存条目就会被重新提取而不是被回放prompt 未变则条目保留#1939。这解释了为什么 spec 的逐字加载而非意译是硬要求prompt 文本即缓存键的一部分。9. 小结一份 spec四道防线把 extraction-spec.md 放回 graphify 的整体架构里看它同时承担四重职责每一重都有对应实现或测试兜底LLM 输出契约——JSON Schema 六值file_type 离散置信度准则由 export.py 的回退默认值与解析护栏兜底AST↔LLM 对齐契约——节点 ID 全路径规则必须与 _file_stem/make_id 一致由 test_extraction_spec_ids.py 逐条重放 spec 示例防止漂移增量一致性契约——source_fileverbatim 规则保证全量与--update共用节点键基准build_merge替换而非复制#1366;缓存一致性契约——spec 文本指纹参与语义缓存命名空间cache/semantic/p{fingerprint}/#1939prompt 变更自动使旧缓存失效。如果你想在自己的语料上验证这些行为可以直接查看 worked/ 目录下 httpx、mixed-corpus 等已构建好的样例含graph.json、GRAPH_REPORT.md与review.md对照其中节点 ID、confidence_score分布与超边结构检验本文描述的规则在真实产物上的体现。【免费下载链接】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),仅供参考
返回列表