graphify 工作原理:三遍提取管线、Leiden 社区检测与置信度标注体系深度解析
graphify 工作原理三遍提取管线、Leiden 社区检测与置信度标注体系深度解析【免费下载链接】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 仓库中的 docs/how-it-works.md 展开完整覆盖其核心脉络三遍处理管线AST 代码提取、音视频转录、LLM 语义提取、Leiden 社区检测、EXTRACTED/INFERRED/AMBIGUOUS 三级置信度标注、Token 收益基准、并行提取与 SHA256 缓存机制以及最终graph.json的节点-边数据格式。读完之后你将不仅知道 graphify 做什么还能从源码层面验证它怎么做的——包括各阶段的关键实现文件、缓存目录布局、置信度打分细则以及如何用仓库自带示例复现并核对全部数据。三遍处理管线The Three Passesgraphify 对语料库的处理分为三个独立的 Pass每个 Pass 针对不同的文件类型成本特征也完全不同Pass 1 和 Pass 2 完全本地、不消耗任何 API 调用只有 Pass 3 会调用 LLMClaude。Pass 1 — 代码结构提取免费无 API 调用Tree-sitter 解析代码文件提取类、函数、导入关系、调用图和行内注释。整个过程在本地运行不涉及任何 LLM支持 25 种语言。SQL 文件获得特殊待遇表、视图、外键和 JOIN 关系都是确定性提取的。关于 SQL 的确定性提取可以从 SQL 提取器 看到其工程细节文件开头就有一段针对CREATE FUNCTION/PROCEDURE的恢复正则它专门处理 T-SQL 的方括号定界标识符[dbo].[usp_Load]、PostgreSQL 的双引号标识符public.fn以及CREATE OR REPLACE/CREATE OR ALTER等方言差异——注释中明确说明这些模式必须在两处恢复点解析时的 ERROR 节点扫描和整文件兜底扫描共享同一正则否则同一条语句会产出两个名称不同的节点。此外注释掩码扫描器 是一个线性字符扫描器而非正则因为它需要同时处理嵌套块注释SQL Server 和 PostgreSQL 都支持嵌套/* */、单引号字符串空化避免EXEC(NCREATE PROC ...)这类动态 SQL 伪造出例程节点以及保留定界标识符原文——这正是恢复正则必须看到的内容。一个关键边界代码文件在正常管线中不会被发送到 LLM 语义提取器。如果语料库只包含代码文件Pass 3 会被完全跳过语义提取只服务于文档、论文、图片和转录文本。这一设计直接决定了 Pass 1 的确定性同一段代码在任何机器上、任何次数运行产出完全一致的图结构。Pass 2 — 视频与音频转录本地无 API 调用视频和音频文件使用 faster-whisper 转录。为了让转录文本聚焦于你的领域转录 prompt 会用你当前代码图中连接度最高的 god nodesgod 节点来初始化。转录结果有缓存重跑时会跳过已处理文件。transcribe.py 实现中可以看到具体机制god 节点注入 promptbuild_whisper_prompt取前 10 个 god 节点的 label拼接成Technical discussion about {topics}. Use proper punctuation and paragraph breaks.形式的初始 prompt 传给 Whisper。也支持通过环境变量GRAPHIFY_WHISPER_PROMPT直接覆盖。模型与硬件默认模型为base可通过GRAPHIFY_WHISPER_MODEL调整推理固定为 CPU int8WhisperModel(model_name, devicecpu, compute_typeint8)beam_size5。缓存转录结果写入graphify-out/transcripts/{文件名}.txt只要转录文件已存在且未指定forceTrue直接返回缓存路径——这就是重跑跳过已处理文件的实现。URL 支持支持http://、https://、www.前缀的 URL通过 yt-dlp 仅下载音频流且下载前会先经过validate_url校验阻断私有 IP 与非法 scheme。Pass 3 — 文档、论文、图片Claude 子代理消耗 TokenClaude 并行处理 markdown、PDF、图片和转录文本。每个子代理读取一批文件并输出一个 JSON 片段节点、边以及任意 group relationships超边。所有片段最终合并为一张图。JSON 片段的确切 schema 定义在 llm.py 中节点含id、label、file_type、source_file等字段边含relation、confidence、confidence_score超边含nodes列表与participate_in|implement|form三类 relation。在 Pass 3 之前可选的转换器会先把受支持的指针/二进制格式转换为 Markdown sidecar落在graphify-out/converted/下Office 文件.docx、.xlsx需要安装[office]extra。对应 pyproject.toml 中的office [python-docx, openpyxl]。Google Workspace 快捷方式.gdoc、.gsheet、.gslides是显式 opt-in命令行加--google-workspace或设置环境变量GRAPHIFY_GOOGLE_WORKSPACE1并且要求已认证的gwsCLI。社区检测Leiden 算法且不需要嵌入向量社区发现使用 Leiden 算法——一种按边密度聚类的图聚类方法节点之间连接越多越可能落入同一个社区。一个反直觉但重要的设计决策是不需要任何嵌入。Claude 提取的语义相似边semantically_similar_to本来就在图里因此它们直接参与社区形状的塑造——图结构本身就是相似度信号没有单独的嵌入步骤也没有向量数据库。cluster.py 是这一机制的完整实现源码比文档描述多了几层工程考量三级实现回退_partition优先直接调用graspologic_native.leidenRust 原生扩展——注释解释了为什么绕过 graspologic 包本身导入整个包会连带导入 umap/pynndescentnumba 会在 import 时 JIT 编译实测要多花 7–19 秒而原生调用约 1 秒。原生扩展不可用时回退到graspologic.partition.leiden两者都缺失时回退到 NetworkX 内置的 Louvainseed42。确定性加固输入图会先对边做规范化排序——对无向图边端点按字符串排序后再排属性做json.dumps(sort_keysTrue)。注释引用了一个实测案例914 节点图上同一输入在PYTHONHASHSEED1和2下分别得到 70 个和 69 个社区原因就是 CPython 每进程独立的字符串哈希顺序让同一条边的端点方向翻转从而扰动了顺序敏感的 Louvain。resolution 参数resolution 1.0得到更多更小的社区 1.0得到更少更大的社区默认 1.0。超大社区拆分超过全图 25% 节点且至少 10 个节点的社区会在子图上再跑一遍 Leiden 拆分第二遍还会对 cohesion社区内实际边数/最大可能边数低于 0.05 且节点数 ≥ 50 的社区再拆分——针对的是文档枢纽节点例如连接一切的CLAUDE.md把互不相关的子系统拉进同一社区的问题。确定性标签label_communities_by_hub在无 LLM 后端时用社区内度数最高的节点结构枢纽命名社区报告里读起来是auth/log_action而不是Community 70平局按节点 id 打破以保证逐次运行稳定。置信度标注每条关系都有出处标签每条关系edge都被标注为三个标签之一标签含义EXTRACTED直接来自源码如一次函数调用、一条 importINFERREDClaude 做出的合理推断附带confidence_score0.0–1.0AMBIGUOUS不确定——在报告中被标记出来供人工复核EXTRACTED边的置信度恒为 1.0。INFERRED边使用离散刻度discrete rubric0.95— 近乎确定显式的跨文件引用只有一个合理目标0.85— 强证据命名 上下文一致0.75— 合理有上下文支撑但不显式0.65— 弱仅命名相似0.55— 推测性这个离散刻度不是文档里的抽象约定源码中真实执行export.py 明确定义了_CONFIDENCE_SCORE_DEFAULTS {EXTRACTED: 1.0, INFERRED: 0.55, AMBIGUOUS: 0.2}并注释说明 0.8 这类值既不在字段里直接出现1.0/0.95/0.9/0.85也不在离散 INFERRED 集合{0.55, 0.65, 0.75, 0.85, 0.95}中extract.py 与 extractors/engine.py 里代码自动推断出的边同样被刻意钉在 0.85 而不是 0.8注释写明rubric 是离散集合。resolution.py 中有直接结构证据具名跨文件引用的解析结果则被赋予 0.95。Token 基准收益随语料规模复利增长首次运行需要提取并构建图——这一步消耗 Token。此后的每次查询读取的是紧凑的图而不是原始文件。收益从这里开始复利累积。文档给出的实测数据混合语料Karpathy 仓库 5 篇论文 4 张图片共 52 个文件相比直接读取原始文件每次查询的 Token 减少 71.5 倍。语料文件数压缩比Karpathy 仓库 论文 图片5271.5xgraphify 源码 Transformer 论文45.4xhttpx合成 Python 库6~1xToken 压缩比随语料规模扩大。6 个文件本来就能装进上下文窗口——那里的图价值在于结构性清晰而不是压缩。到 52 个文件时收益迅速放大。这些数据可以自行验证仓库的每个worked/目录都保留了原始输入文件和真实输出。例如 worked/karpathy-repos/GRAPH_REPORT.md 与 worked/karpathy-repos/graph.json 就是 52 文件语料的完整产物还有 worked/httpx/6 文件的 Python 库、worked/mixed-corpus/混合语料可对照检查。并行 AST 提取绕过 GIL 的真正多进程代码文件使用ProcessPoolExecutor并行提取——绕开 Python GIL 实现真正的多进程。文档/论文/图片批次则以并行 Claude 子代理方式分发。在 84 个代码文件的语料上并行 AST 提取比顺序执行快约 1.66 倍。_extract_parallel的实现细节值得注意worker 数默认取os.cpu_count()历史上曾有, 8)上限注释说明在 32 线程工作站上这会造成 4 倍减速故移除可用环境变量GRAPHIFY_MAX_WORKERS覆盖且不超过未缓存文件数避免小任务开空转 worker。Windows 61 上限Windows 下ProcessPoolExecutor受 CPythonWaitForMultipleObjects限制硬性封顶 61 个 worker代码在此显式 clamp保证自动计算、环境变量与--max-workers三条路径在 61 核以上机器上都合法。失败回退Windows spawn 模式下调用方缺少if __name__ __main__:保护会导致BrokenProcessPool此时整个池返回False调用方回退到进程内顺序提取——更慢但正确。单个 future 失败的文件也会在进程内重试一次而不是让per_file槽位留空造成静默数据丢失。并行阈值_PARALLEL_THRESHOLD 20extract.py小批量直接走顺序路径不付进程创建开销。SHA256 内容缓存重跑只处理变化的文件每个被提取的文件都按内容哈希做指纹。重跑时完全跳过未变化的文件——只有新增或修改过的文件会重新走提取流程。缓存位于graphify-out/cache/。cache.py 的实现比算个 SHA256精细得多哈希的构成file_hash是SHA256(文件内容 相对路径 salt)。路径 salt 保证两个不同路径的相同内容不会共享同一条提取缓存对 Markdown 文件.md只对 YAML frontmatter 以下的正文做哈希这样reviewed、status、tags这类纯元数据改动不会使缓存失效。stat 快速路径完整读文件算哈希在大语料上很贵因此维护一个基于(size, mtime_ns)的 stat 索引持久化为cache/stat-index.json。但文件系统的 mtime 粒度是纳秒级存储、毫秒级甚至 2 秒级打戳NTFS 约 15.6msFAT/exFAT 2 秒同尺寸编辑可能落在同一个 mtime tick 内。_stat_sig_fresh用 git 的 racily clean 概念封住这个洞只有当mtime 粒度(默认2秒) indexed_at_ns读取内容的时刻时才信任缓存否则回退到完整 SHA256——保证两种不同内容绝不可能共享同一个摘要。粒度可用GRAPHIFY_MTIME_GRANULARITY_MS覆盖0 表示禁用该保护。两类缓存的版本策略不同见cache_dirAST 缓存位于graphify-out/cache/ast/v{版本号}-s{schema}/按包版本和缓存键 schema 命名空间隔离。原因是 AST 条目是 graphify 自己的提取器代码产出的提取器修复发布后纯内容哈希会导致新版本继续回放修复前的旧结果其他版本的条目在首次使用时被清扫。语义缓存位于graphify-out/cache/semantic/故意不按版本命名空间——条目由 LLM 从文件内容产生每次发版都作废会导致未变化文件被重新计费。取而代之的是按提取 prompt 的指纹分目录p{fingerprint}/prompt 没变则条目跨版本存活prompt 变了才失效兼得不重复计费与不混用不同年代的提取。强制重跑graphify extract --force/graphify update --force或GRAPHIFY_FORCE1跳过缓存读取、全量重新分发。图格式NetworkX node-link 超边输出的graph.json使用 NetworkX 的 node-link 格式。每个节点包含id— 稳定标识符label— 人类可读名称file_type—code、document、paper、image、rationalesource_file— 来源文件关于如何在节点上补充面向 AI 导航的紧凑可选摘要RFC: file-level node summaries 提出了两种候选方案可作为深入阅读。每条边包含source、target— 节点 idrelation— 动词短语如calls、imports、implements、semantically_similar_toconfidence—EXTRACTED、INFERRED或AMBIGUOUSconfidence_score— 浮点数仅 INFERREDsource_file— 该关系被发现的出处连接 3 个及以上节点的组关系超边hyperedges存放在G.graph[hyperedges]中。build.py 的合并逻辑处理了两种存储位置顶层hyperedges键和嵌套在 node-link 结构中的graph.hyperedges——后者由G.to_json写入因为 node-link 序列化没有 root 概念重建后的图在序列化前需要两个位置都可读。小结确定性与 LLM 的分工边界把三遍管线放在一起看graphify 的架构主线非常清晰能用确定性算法解决的绝不交给 LLM。Pass 1 的 AST 提取和 SQL 关系是逐字节可复现的这解释了为什么 AST 缓存按提取器版本命名空间——缓存的正确性以提取器代码为界Pass 2 的 Whisper 转录是本地模型只有 Pass 3 的文档语义理解消耗 Token而且其产出的每条边都带着 EXTRACTED/INFERRED/AMBIGUOUS 标签与离散置信度刻度让机器从原文直接看到的和模型推断出来的在数据层面严格可区分。社区检测再在这些边上做聚类时语义相似边与结构边同等参与——这就是没有向量库却仍有语义信号的来源。所有关键数字71.5x 压缩、1.66x 并行加速、25 语言支持都可以用worked/目录下的真实输入输出自行复现核对。【免费下载链接】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),仅供参考