首页
/ graphify 的 Claw 技能文件:/graphify 九步流水线,把代码库变成可查询知识图谱的完整 Agent 运行手册

graphify 的 Claw 技能文件:/graphify 九步流水线,把代码库变成可查询知识图谱的完整 Agent 运行手册

2026-09-04 15:18:29作者:蔡怀权

graphify/skill-claw.md 是 graphify 项目为 "claw" 类 Agent 宿主编写的 /graphify 技能(Skill)运行手册:它规定 Agent 被调用后必须按什么顺序执行哪些命令、何时派发子 Agent、如何合并 AST 与语义两路抽取结果、怎样保证图谱不被静默损坏。读懂这份文件,你就能掌握 graphify 完整管线的每一步——从 Python 解释器自举、文件探测、并行实体抽取,到社区聚类、图谱健康检查、manifest 增量追踪与查询流程。

一、这份技能文件是什么

技能文件以标准 YAML frontmatter 开头,声明技能名 graphify 及触发条件:"对代码库架构、文件关系或项目内容的任何提问——尤其是存在 graphify-out/ 时,提问应优先被视为 graphify 查询"。其核心承诺是:

  • 把任意文件夹(代码、文档、论文、图片、视频)变成一个可导航的知识图谱,带社区检测;
  • 诚实的审计轨迹:每条边都标注 EXTRACTED / INFERRED / AMBIGUOUS 三种来源置信度;
  • 三种产物:交互式 HTML、可直接用于 GraphRAG 的 JSON、以及自然语言版的 GRAPH_REPORT.md

在仓库中,该技能文件的参考文档(references)独立存放于 graphify/skills/claw/references/,共 8 个文件:

  • extraction-spec.md —— 子 Agent 抽取提示词规范(JSON schema、节点 ID 规则、置信度准则、frontmatter、超边与视觉规则);
  • query.md —— BFS/DFS 遍历、--budget 上限、NetworkX 回退、path/explain 流程;
  • update.md —— --update--cluster-only 流程;
  • add-watch.md —— /graphify add--watch 流程;
  • exports.md —— wiki/Neo4j/FalkorDB/SVG/GraphML/MCP/benchmark 各导出;
  • github-and-merge.md —— clone、跨仓库合并、monorepo 流程;
  • transcribe.md —— 音视频转写;
  • hooks.md —— post-commit 钩子与 CLAUDE.md 集成。

二、完整命令与标志(Usage)

技能文件定义的调用面如下,全部继承自原文档:

/graphify                                             # 当前目录完整流水线(HTML 可视化;加 --obsidian 生成 vault)
/graphify <path>                                      # 指定路径完整流水线
/graphify https://github.com/<owner>/<repo>            # clone 仓库后跑完整流水线
/graphify https://github.com/<owner>/<repo> --branch <branch>  # clone 指定分支
/graphify <url1> <url2> ...                           # 多仓库 clone、各自构建、合并为跨仓库图
/graphify <path> --mode deep                          # 更彻底抽取,更丰富的 INFERRED 边
/graphify <path> --update                             # 增量:只重抽新增/变更文件
/graphify <path> --directed                            # 构建有向图(保留边方向 source→target)
/graphify <path> --whisper-model medium                # 使用更大的 Whisper 模型提升转写精度
/graphify <path> --cluster-only                       # 对已有图重跑聚类
/graphify <path> --no-viz                             # 跳过可视化,只出报告 + JSON
/graphify <path> --html                               # (HTML 默认生成,此标志无操作)
/graphify <path> --svg                                # 额外导出 graph.svg(可嵌入 Notion、GitHub)
/graphify <path> --graphml                            # 导出 graph.graphml(Gephi、yEd)
/graphify <path> --neo4j                              # 生成 graphify-out/cypher.txt 供 Neo4j
/graphify <path> --neo4j-push bolt://localhost:7687   # 直推 Neo4j
/graphify <path> --falkordb                           # 生成 cypher.txt 供 FalkorDB
/graphify <path> --falkordb-push falkordb://localhost:6379   # 直推 FalkorDB
/graphify <path> --mcp                                # 启动 MCP stdio 服务器供 Agent 访问
/graphify <path> --watch                              # 监听目录,代码变更自动重建(无需 LLM)
/graphify <path> --wiki                               # 构建 Agent 可爬取的 wiki(index.md + 每社区一篇)
/graphify <path> --obsidian --obsidian-dir ~/vaults/my-project  # vault 写到自定义路径
/graphify add <url>                                   # 抓取 URL 存入 ./raw,更新图
/graphify add <url> --author "Name"                   # 标注作者
/graphify add <url> --contributor "Name"              # 标注加入语料的人
/graphify query "<question>"                          # BFS 遍历——宽泛上下文
/graphify query "<question>" --dfs                    # DFS——追踪特定路径
/graphify query "<question>" --budget 1500            # 答案限定在 N token
/graphify path "AuthModule" "Database"                # 两概念间最短路径
/graphify explain "SwinTransformer"                   # 用自然语言解释某个节点

三、调用时的强制规则与快速路径

技能文件用几段硬规则约束 Agent 行为,避免浪费与误操作:

  1. 帮助短路:若用户调用 /graphify --help(无其他参数),逐字打印 Usage 段后停止——不运行任何命令、不探测文件、不默认路径为 .
  2. 快速路径(已有图):先检查 graphify-out/graph.json 是否存在(相对当前工作目录)。若存在,且用户请求是关于代码库的自然语言问题("X 怎么工作?""谁调用了 Y?""追踪 Z 的数据流")而非显式重建命令(--update--cluster-only、或暗示全新抽取的路径/URL),则跳过步骤 1–5,直接进入 query 流程,立即运行 graphify query "<question>"——不跑 detect、不查语料规模、不要求用户缩小范围。
  3. 路径默认值:未给路径就用 .,不追问用户。
  4. URL 识别:路径参数以 https://github.com/http://github.com/ 开头时视为 GitHub URL,先执行 Step 0,再用解析出的本地路径继续。

四、流水线逐步拆解

Step 0 — GitHub 仓库与多路径合并(仅 URL 或多路径时)

仅当路径是一个或多个 GitHub URL、或需要合并多个本地子目录时执行;纯本地路径跳过此步。具体 clone、跨仓库合并与 monorepo 流程见 github-and-merge.md

Step 1 — 确保 graphify 已安装(解释器自举)

这是技能文件中最长的一段 bash 逻辑,核心是三级探测出正确的 Python 解释器,因为不同宿主(uv tool、pipx、venv、系统安装)下 python3 未必能 import graphify

  1. 优先 uv tool run --from graphifyy python -c ... 取 uv 工具链的内置解释器(现代 Mac/Linux 上最可靠);
  2. 否则读取 which graphify 得到的可执行文件首行 shebang,验证其能 import graphify 后采用;
  3. 兜底 python3

import graphify 失败,则用 uv tool install --upgrade graphifyypip install graphifyy(含 --break-system-packages 兜底)补装。随后两行关键的状态持久化

mkdir -p graphify-out
"$PYTHON" -c "import sys; open('graphify-out/.graphify_python', 'w', encoding='utf-8').write(sys.executable)"
# 保存扫描根,让无参的 graphify update 知道下次去哪找
echo "$(cd INPUT_PATH && pwd)" > graphify-out/.graphify_root

技能文件强调:后续所有 bash 块中,一律用 $(cat graphify-out/.graphify_python) 替换 python3。后文还专门设有"子命令解释器守卫"——运行 --update--cluster-onlyquerypathexplainadd 前先检查 .graphify_python 存在,缺失(例如用户删了 graphify-out/)则重新走一遍 shebang 探测并写回。

Step 2 — 探测文件(detect)

$(cat graphify-out/.graphify_python) -c "
import json
from graphify.detect import detect
from pathlib import Path
result = detect(Path('INPUT_PATH'))
# 用 Python 写 sidecar 而非 shell 重定向,避免 PowerShell 宿主的控制台编码漂移(#2528)
Path('graphify-out/.graphify_detect.json').write_text(json.dumps(result, ensure_ascii=False), encoding='utf-8')
print(f'Detected {result[\"total_files\"]} files')
"

结果不许 cat 出来,只呈现干净摘要:

Corpus: X files · ~Y words
  code:     N files (.py .ts .go ...)
  docs:     N files (.md .txt ...)
  papers:   N files (.pdf ...)
  images:   N files
  video:    N files (.mp4 .mp3 ...)

零文件的类别整行省略。对应实现是 graphify/detect.py#L1665detect(),其文件分类枚举 FileType 与技能文件里的类别一一对应:code / document / paper.pdf)/ image / video。技能文件随后要求 Agent 按探测结果行动:

  • total_files 为 0:以 "No supported files found in [path]." 终止;
  • skipped_sensitive 非空:报告数量并列出被跳过的文件名,让误标敏感的源码/文档可见、可改名或移动(#2106);
  • total_words > 2,000,000 或 total_files > 500:给出警告,然后按文件数算出第一级子目录 Top 5 供用户选择缩小范围——规则细节包括:从 detect JSON 读 scan_root(始终为 INPUT_PATH 的绝对路径)、合并五类文件列表、剔除 scan_root + "/graphify-out/" 前缀的转换 sidecar、无子目录的根直属文件记作 (root);若全部在 (root) 则不追问,改建议 --no-cluster 跳过昂贵聚类后继续;
  • 否则直接进入 Step 2.5(有视频时)或 Step 3。

文件数上限 500 与源码常量一致:graphify/detect.py#L53 定义 FILE_COUNT_UPPER = 500,同文件还有词数阈值常量 CORPUS_UPPER_THRESHOLD = 500_000(超出即提示 token 成本)——技能文件里的 200 万词预警是 Agent 层的更激进阈值,两者共同构成"语料健康检查"。

Step 2.5 — 视频与音频(仅有视频文件时)

detect 返回零 video 文件则整步跳过。有音视频时,按 transcribe.md 先转写成文本,转写稿在 Step 3 中当作文档处理。--whisper-model 标志在这里起作用。

Step 3 — 实体与关系抽取(双轨并行)

技能文件把抽取拆成两路并明确要求同一消息内并行派发:"Run Part A (AST) and Part B (semantic) in parallel. Dispatch all semantic subagents AND start AST extraction in the same message."——文档注明并行可在大语料上省 5–15 秒。

API key 硬性规则:graphify 不需要任何 API key,Agent 绝不向用户索要、绝不因此阻塞。代码走 AST 结构抽取,纯代码语料(最常见的 /graphify .)完全跳过语义抽取。语义抽取(仅文档/论文/图片)只在 GEMINI_API_KEY/GOOGLE_API_KEY 已设置时用 Gemini;否则宿主 Agent 本身就是 LLM。graphify 不读 ANTHROPIC_API_KEYOPENAI_API_KEY 或其他任何 provider key——"若你发现自己要提示、等待或停止于缺 key,那是对本技能的误读"。未设置 key 时只打印一次提示(pip install 'graphifyy[gemini]',默认模型 gemini-3-flash-preview,可用 GRAPHIFY_GEMINI_MODEL--model 覆盖)后继续,不等待。若 key 已设置,则改用 graphify.llm.extract_corpus_parallel(files, backend="gemini") 而非派发子 Agent。

Part A — 代码文件的 AST 结构抽取

$(cat graphify-out/.graphify_python) -c "
import sys, json
from graphify.extract import collect_files, extract
from pathlib import Path

code_files = []
detect = json.loads(Path('graphify-out/.graphify_detect.json').read_text(encoding='utf-8'))
for f in detect.get('files', {}).get('code', []):
    code_files.extend(collect_files(Path(f)) if Path(f).is_dir() else [Path(f)])

if code_files:
    result = extract(code_files, cache_root=Path('INPUT_PATH'))
    Path('graphify-out/.graphify_ast.json').write_text(json.dumps(result, indent=2, ensure_ascii=False), encoding='utf-8')
    print(f'AST: {len(result[\"nodes\"])} nodes, {len(result[\"edges\"])} edges')
else:
    Path('graphify-out/.graphify_ast.json').write_text(json.dumps({'nodes':[],'edges':[],'input_tokens':0,'output_tokens':0}, ensure_ascii=False), encoding='utf-8')
    print('No code files - skipping AST extraction')
"

底层实现是 graphify/extract.py#L5859extract():两遍处理——先逐文件结构抽取(类、函数、import),再做跨文件 import 解析,把文件级 import 转成类级 INFERRED 边(如 DigestAuth --uses--> Response)。它支持 parallel=True 时按未缓存文件数决定是否启用 ProcessPoolExecutor 多核抽取,max_workers 默认为 cpu_count(或 GRAPHIFY_MAX_WORKERS)。文件收集器 collect_filesgraphify/extract.py#L7289。代码文件支持面可以从 graphify/detect.py#L44CODE_EXTENSIONS 看出——覆盖 Python、TS/JS 全家族、C/C++/CUDA、Go、Rust、Java、Kotlin、C#、Swift、PHP、Lua、Zig、PowerShell、Elixir、Objective-C、OCaml、Julia、Vue/Svelte/Astro、Dart、Verilog、SQL、Fortran、Pascal/Delphi、Terraform、.sln/.csproj、XAML/Razor 等上百种扩展名。

Part B — 语义抽取(并行子 Agent)

快速路径:若探测发现文档、论文、图片均为零(纯代码语料),整体跳过 Part B 直达 Part C;但必须先写空语义文件,否则 Part C 无条件读 .graphify_semantic.json 会抛 FileNotFoundError

$(cat graphify-out/.graphify_python) -c "
import json
from pathlib import Path
Path('graphify-out/.graphify_semantic.json').write_text(json.dumps({'nodes':[],'edges':[],'hyperedges':[],'input_tokens':0,'output_tokens':0}), encoding='utf-8')
"

派发纪律(原文用粗体强调):必须使用 Agent 工具;逐个自己读文件被明令禁止(慢 5–10 倍);派发前先打印时间估算:读 detect JSON 的 total_words,估算 Agent 数为 ceil(uncached_non_code_files / 22)(块大小 20–25),每批约 45 秒,总时长约 45s × ceil(agents/并行上限)。

Step B0 — 先查抽取缓存。关键细节是 SPEC_PATH:它必须是本技能文件旁边那份 references/extraction-spec.md绝对路径,同一个路径要同时传给 B0 的读缓存和 B3 的写缓存——缓存条目"归属"于产生它的抽取提示词,graphify 升级若改了提示词,旧条目会被重新抽取而非重放,未变的提示词则继续命中(#1939)。

$(cat graphify-out/.graphify_python) -c "
import json
from graphify.cache import check_semantic_cache
from pathlib import Path

detect = json.loads(Path('graphify-out/.graphify_detect.json').read_text(encoding='utf-8'))
# 只把内容文件送去语义抽取。代码已由 Part A 的 AST 遍覆盖;
# 在这里展平所有类别会让子 Agent 重读每个源文件(#1392)。
# 视频已在 Step 2.5 先转写成文档。
all_files = [f for cat in ('document', 'paper', 'image') for f in detect['files'].get(cat, [])]

cached_nodes, cached_edges, cached_hyperedges, uncached = check_semantic_cache(all_files, root='INPUT_PATH', prompt_file='SPEC_PATH')

# 总是(重)写缓存文件:有命中就写;否则删除上次残留,
# 确保 Part C 不会合并过期的 .graphify_cached.json(#1392)。
if cached_nodes or cached_edges or cached_hyperedges:
    Path('graphify-out/.graphify_cached.json').write_text(json.dumps({'nodes': cached_nodes, 'edges': cached_edges, 'hyperedges': cached_hyperedges}, ensure_ascii=False), encoding='utf-8')
else:
    Path('graphify-out/.graphify_cached.json').unlink(missing_ok=True)
Path('graphify-out/.graphify_uncached.txt').write_text('\n'.join(uncached), encoding='utf-8')
print(f'Cache: {len(all_files)-len(uncached)} files hit, {len(uncached)} files need extraction')
"

只有 .graphify_uncached.txt 里列出的文件才派发子 Agent;全部命中缓存则直接进 Part C。这套缓存机制在源码中即 graphify/cache.py#L1233check_semantic_cache()——docstring 明确说明:mode 参数选择缓存命名空间(deep 模式读写 cache/semantic-deep/,不会与标准模式互相遮蔽,#1894);prompt_file 参数把命中限定在"由同一提示词产生"的条目上,这正是技能文件 B0/B3 要求传同一 SPEC_PATH 的原因。

Step B1 — 分块:每块 20–25 个文件;每张图片单独一块(视觉需要独立上下文);同目录文件分在同一块,提高跨文件关系抽取概率。

Step B2 — 单条消息内派发所有子 Agent:每个块一次 Agent 调用,全部放在同一条响应里才会并行;串行调用等于白派。且必须 subagent_type="general-purpose"——禁用 Explore,因为它是只读的,无法把块结果写到磁盘,会静默丢弃抽取结果。每块的结果写入 CHUNK_PATH(必须为绝对路径,由 $(pwd)/graphify-out/.graphify_chunk_0N.json 推导——注意是工作目录而非 .graphify_root 的扫描目录,#1392)。子 Agent 的提示词模板取自 extraction-spec.md,仅在至少一块含有文档/论文/图片时才加载;纯代码语料永远读不到它。

Step B3 — 收集、缓存、合并

  • 成功信号是 graphify-out/.graphify_chunk_NN.json 落盘且含有效 JSON 的 nodes/edges
  • 文件缺失通常意味着子 Agent 被派成只读类型——必须打印警告"chunk N missing from disk — subagent may have read-only. Re-run with general-purpose agent.",不许静默跳过;
  • 超过一半的块失败/缺失则停止并让用户重跑;
  • 每个 Agent 调用完成后,从 Agent 工具结果的 usage 字段读出真实 token 数写回块 JSON(块 JSON 自带的是占位零);
  • 合并所有块为 .graphify_semantic_new.json
  • 写缓存时再次传同一个 SPEC_PATH——"用与读取不同的提示词写,条目就会落在下次运行不会看的地方"(#1939)。save_semantic_cache 实现见 graphify/cache.py#L1379
  • 最后把缓存命中与新结果合并进 .graphify_semantic.json,节点按 id 去重,然后清理临时文件(.graphify_cached.json.graphify_uncached.txt.graphify_semantic_new.json)。

Part C — AST + 语义合并为最终抽取

# 合并:AST 节点在前,语义节点按 id 去重
seen = {n['id'] for n in ast['nodes']}
merged_nodes = list(ast['nodes'])
for n in sem['nodes']:
    if n['id'] not in seen:
        merged_nodes.append(n)
        seen.add(n['id'])

merged_edges = ast['edges'] + sem['edges']
merged_hyperedges = sem.get('hyperedges', [])
# → 写入 graphify-out/.graphify_extract.json

注意超边(hyperedges)只来自语义路:它表示 3 个及以上节点共享同一概念,是 LLM 才能归纳出的关系。

Step 4 — 建图、聚类、分析、产出

技能文件提醒:代码块中的 directed=IS_DIRECTED 要按是否给了 --directed 替换为 True/False——True 构建保留边方向(source→target)的 DiGraphFalse 是默认的无向 Graph。对应实现 graphify/build.py#L798build_from_json(extraction, *, directed=False, root=None) 与之一致:root 参数把语义子 Agent 产出的绝对 source_file 路径相对化,让所有节点共享一致的路径键(#932),这正是技能文件在 Step 4/5 反复传 root='INPUT_PATH' 的原因(与 --update 运行手册对齐,#1361)。

核心步骤块(节选):

G = build_from_json(extraction, root='INPUT_PATH', directed=IS_DIRECTED)
# 在任何写操作之前设守卫:空抽取不许覆盖好的 graph.json / GRAPH_REPORT.md(#1392)
if G.number_of_nodes() == 0:
    print('ERROR: Graph is empty - extraction produced no nodes.')
    raise SystemExit(1)
communities = cluster(G)
cohesion = score_all(G, communities)
gods = god_nodes(G)
surprises = surprising_connections(G, communities)
labels = {cid: 'Community ' + str(cid) for cid in communities}
questions = suggest_questions(G, communities, labels)

# 先导出,并遵守 #479 收缩守卫:新图比现有 graph.json 小时 to_json 返回 False(不写任何东西)
wrote = to_json(G, communities, 'graphify-out/graph.json')
if not wrote:
    print('ERROR: refused to shrink graphify-out/graph.json (existing graph has more nodes; #479).')
    print('If this shrink is intentional (you deleted files), re-run a full build with --force.')
    raise SystemExit(1)
report = generate(G, communities, cohesion, labels, gods, surprises, detection, tokens, 'INPUT_PATH', suggested_questions=questions)
Path('graphify-out/GRAPH_REPORT.md').write_text(report, encoding='utf-8')
# 另写 .graphify_analysis.json:communities / cohesion / gods / surprises / questions

两处守卫值得注意,都能在源码里找到对应:空图守卫防止全量重建覆盖已有好图;收缩守卫(#479)在 graphify/export.py#L266to_json() 中返回布尔值——新图节点数少于现有 graph.json 时什么都不写,只有图真的写出去了才允许生成 GRAPH_REPORT.md 和分析 sidecar,确保报告永远不描述一个 graph.json 里不存在的图(#1392)。若此步打印 ERROR: Graph is empty,停止并告知用户,不得继续标注或可视化。分析函数分别位于 graphify/analyze.py#L109god_nodes()(Top-10 高度中心性节点)、graphify/analyze.py#L133surprising_connections()graphify/analyze.py#L428suggest_questions();聚类与内聚评分在 graphify/cluster.py#L223cluster()graphify/cluster.py#L357score_all()

Step 4.5 — 图谱健康检查(只读完整性闸门)

这是标注前的非破坏性诊断,专门暴露增量更新与 AST/LLM ID 不匹配的三种"静默损坏"模式:同端点边塌缩、悬空/缺失端点、自环。只读、永不中止:

from graphify.diagnostics import diagnose_extraction, format_diagnostic_report
summary = diagnose_extraction(extraction, directed=IS_DIRECTED, root='INPUT_PATH')
print(format_diagnostic_report(summary))
flags = [f'{summary[k]} {label}' for k, label in (
    ('dangling_endpoint_edges', 'dangling-endpoint edges'),
    ('missing_endpoint_edges', 'missing-endpoint edges'),
    ('self_loop_edges', 'self-loop edges'),
    ('directed_same_endpoint_collapsed_edges', 'collapsed (directed) edges'),
    ('undirected_same_endpoint_collapsed_edges', 'collapsed (undirected) edges'),
) if summary.get(k, 0)]
print('GRAPH HEALTH WARNING: ...' if flags else 'Graph health: OK (no dangling/missing/collapsed edges).')

实现见 graphify/diagnostics.py#L156:它逐条规范化边,区分 missing_endpoint_edges(source/target 为空)、dangling_endpoint_edges(端点不在节点 ID 集合中)、self_loop_edges,并用 directed_pairs / undirected_pairs 两个 Counter 统计同端点重复——正是技能文件要求打印的五个指标来源。若出现 GRAPH HEALTH WARNING,按"Honesty Rules"必须在最终总结中呈现(图中仍有损坏痕迹,但图可用,不中止)。

Step 5 — 社区标注

graphify-out/.graphify_analysis.json,为每个社区根据节点标签写 2–5 词的自然语言名(如 "Attention Mechanism"、"Training Pipeline"、"Data Loading")。然后用真实标签重新生成报告(标签会影响建议问题的措辞)、把 labels 存为 .graphify_labels.json 供可视化器使用,并重新导出一次 graph.json 使节点携带 community_name(#2490)——由于与 Step 4 使用同一份抽取数据,#479 收缩守卫在节点数上必然通过;若仍被拒,呈现守卫信息而不是强推。labels 需替换代码块中的 LABELS_DICT 占位符,如 {0: "Attention Mechanism", 1: "Training Pipeline"}

Step 6 — Obsidian vault(可选)+ HTML

HTML 恒生成(除非 --no-viz);Obsidian vault 仅在显式给出 --obsidian 时生成——它每个节点产一个文件,默认关闭:

graphify export obsidian   # 或 graphify export obsidian --dir ~/vaults/my-project
graphify export html       # 图 > 5000 节点时自动聚合为社区视图
# 或:graphify export html --no-viz

Step 6b–8:wiki、Neo4j、FalkorDB、SVG、GraphML、MCP、benchmark 导出全部只在对应标志出现时运行--wiki--neo4j/--neo4j-push--falkordb/--falkordb-push--svg--graphml--mcp),或当 total_words 超过 5,000 时跑 token 缩减 benchmark。无导出标志的默认运行跳过全部。各项细节见 exports.md。一个顺序约束:--wiki 导出要在 Step 9 清理之前运行,因为 wiki 还要读 .graphify_labels.json

Step 9 — 保存 manifest、更新成本追踪器、清理、汇报

这是增量能力(--update)的地基。技能文件给出的 manifest 保存逻辑有三个源码级要点,恰好与 graphify/cli.py#L88_stamped_manifest_files() 文档字符串逐条对应:

  1. 只盖戳真正产出结果的语义文件:某文档的块失败或遗漏,其 manifest 条目必须保持未盖戳,下次 --update 会重新排队;否则它被标记"完成"、内容永远丢失(#2015)。代码文件(AST 是确定性的)恒盖戳;
  2. root 相对化:manifest 键相对扫描根存储,使落盘 manifest 在 clone/机器间可移植,后续 --update 匹配缓存文件而不是全量 miss(#1417);
  3. 清除未盖戳文件的旧 semantic_hash:本次派发但未盖戳的文件仍带着上次运行的 stale hash,clear_semantic 清掉它,detect_incremental 才能重新排队(#1948)。

技能文件实际执行的是:

from graphify.cli import _stamped_manifest_files
_corpus = detect.get('all_files') or detect['files']          # --update 时 all_files 是完整语料,files 是变更子集
_manifest_files = _stamped_manifest_files(_corpus, extract, Path('INPUT_PATH'))
_sem_types = ('document', 'paper', 'image')
_dispatched = {f for t, fl in detect['files'].items() if t in _sem_types for f in fl}
_stamped = {f for fl in _manifest_files.values() for f in fl}
_cleared = _dispatched - _stamped
_scan = {f for fl in _corpus.values() for f in fl}            # 原始完整语料,排除新排除文件而非伪装成删除(#1908)
save_manifest(_manifest_files, root='INPUT_PATH', scan_corpus=_scan, clear_semantic=_cleared or None)

save_manifest 实现在 graphify/detect.py#L2112。随后更新 graphify-out/cost.json 累计成本追踪器(每次运行追加日期/输入输出 token/文件数,并累加总计),最后清理临时 sidecar:

rm -f graphify-out/.graphify_detect.json graphify-out/.graphify_extract.json \
      graphify-out/.graphify_ast.json graphify-out/.graphify_semantic.json \
      graphify-out/.graphify_analysis.json
find graphify-out -maxdepth 1 -name '.graphify_chunk_*.json' -delete 2>/dev/null
rm -f graphify-out/.needs_update 2>/dev/null || true

汇报格式固定:

Graph complete. Outputs in PATH_TO_DIR/graphify-out/

  graph.html            - interactive graph, open in browser
  GRAPH_REPORT.md       - audit report
  graph.json            - raw graph data
  obsidian/             - Obsidian vault (only if --obsidian was given)

然后只粘贴 GRAPH_REPORT.md 的 God Nodes、Surprising Connections、Suggested Questions 三段进对话(不贴全文),再立即主动探索:挑报告中最有趣、跨社区边界最多的建议问题,问 "The most interesting question this graph can answer: [question]. Want me to trace it?"。技能文件的收尾宣言点出了它的设计哲学:"The graph is the map. Your job after the pipeline is to be the guide."——每个回答以自然的追问结尾,让会话像导航而非一次性报告。

五、查询流程(query 快速路径的落地)

graphify-out/graph.json 已存在且用户提问关于语料的内容时,从图回答而不是重建

graphify query "<question>"

关键规则:遍历前先用图自身的词汇表扩展问题,防止措辞不匹配把答案坍缩成噪声;若 graphify query CLI 不可用,回退为对 graph.json 的内联 NetworkX 遍历;回答只用图输出中有的内容,引用具体事实时引用 source_location。BFS/DFS 两种遍历模式、--budget token 上限、NetworkX 回退细节、save-result 反馈,以及 /graphify path/graphify explain 流程,全部在 query.md

/graphify add <url>(抓 URL 入语料)与 --watch(文件变更自动重建、无需 LLM)不属于默认构建,流程见 add-watch.md--update(只重抽新增/变更文件)与 --cluster-only(对现有图重跑聚类)见 update.md

六、Honesty Rules(诚实规则)

技能文件末尾用四条硬约束收束整个 Agent 行为,与 Step 4 的空图守卫、Step 4.5 的健康警告、#479 收缩守卫一脉相承:

  • 永不虚构边:不确定就用 AMBIGUOUS;
  • 永不跳过语料检查警告(大语料必须提示用户);
  • 报告中始终显示 token 成本(对应 Step 9 的 cost.json 与输出);
  • 内聚分数不以符号遮掩——展示原始数字;
  • 图超过 5,000 节点时未经用户确认不得跑 HTML 可视化(对应 Step 6 中 HTML 导出"超过 5000 节点自动聚合为社区视图"的行为)。

七、小结:技能文件与源码的对应关系

技能文件环节 源码落点
Step 2 文件探测 graphify/detect.py#L1665 detect()L44-L49 扩展名分类
Step 3 Part A AST graphify/extract.py#L5859 extract()L7289 collect_files()
Step 3 B0/B3 语义缓存 graphify/cache.py#L1233 check_semantic_cache()L1379 save_semantic_cache()
Step 4 建图 graphify/build.py#L798 build_from_json()
Step 4 分析/报告 graphify/analyze.py#L109 god_nodes()graphify/report.py#L96 generate()graphify/export.py#L266 to_json()
Step 4.5 健康检查 graphify/diagnostics.py#L156 diagnose_extraction()
Step 9 manifest 盖戳 graphify/cli.py#L88 _stamped_manifest_files()graphify/detect.py#L2112 save_manifest()

graphify 的技能文件本质上是一份"写给 Agent 的确定性施工图":它把 LLM 的不确定性约束在语义抽取这一环,其余环节——解释器自举、缓存指纹、空图/收缩双守卫、诊断闸门、manifest 盖戳——全部是可从源码复核的确定性逻辑。这正是 graphify 项目 "本地确定性 AST 解析、每条边可解释、无向量库" 设计主张在 Agent 集成层的完整落地。

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

项目优选

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