docs/superpowers/ design + plan(2026-05-04,分支 v7,issue #698)specs/…-design.md(設計,本文主體)與 plans/…-plan.md(實作計劃,checkbox 逐步)。上游用 superpowers 的 subagent-driven-development 流程落地。graphify extract 每次執行都從零重建整張圖——不管改了什麼都把全部檔案重新送 LLM。對一個每天更新的 1000 檔 markdown 語料,這很貴。AuthManager、AuthenticationManager、auth_mgr)。除了精確字串正規化外,沒有語意去重。graphify extract)detect (full or incremental, auto-detected)
↓
AST extract (code files, AST cache-aware)
↓
Semantic LLM extract (doc/paper/image files, semantic cache-aware)
↓
build_merge (merge into existing graph, prune deleted nodes)
↓
deduplicate_entities (normalize → entropy gate → MinHash/LSH → Jaro-Winkler → community boost → optional LLM)
↓
cluster (full graph, always re-run)
↓
score_all + god_nodes + surprising_connections
↓
write graph.json + .graphify_analysis.json + manifest.json
graphify-out/manifest.json + graphify-out/graph.json 都存在 → 進入增量模式。不需要任何 flag。第一次跑永遠是全量。
detect_incremental(target) 取代 detect(target),回傳 new_files、unchanged_files、deleted_files。new_files 走 AST + LLM 抽取。build_merge(new_chunks, prune_sources=deleted_files) 取代 build_from_json——併入既有圖、把已刪檔案的節點剪掉。manifest.json 只在成功完成後寫入(中途當機不會弄壞下次的 diff)。check_semantic_cache(files) 切成 (cached_results, uncached_files)。uncached_files 送 extract_corpus_parallel。save_semantic_cache(fresh_results),以內容雜湊為 key。source_file 更新到新路徑(與既有 AST cache 同模式)。[graphify extract] incremental: 20 changed, 980 cached, 2 deleted
[graphify extract] graph: 4,821 nodes, 12,304 edges, 43 communities
[graphify extract] tokens: 18,432 in / 6,201 out, est. cost: $0.08
改動範圍:graphify/__main__.py 的 elif cmd == "extract": 區塊約 5 處。
新模組 graphify/dedup.py,單一職責,從 build.py 在建圖後呼叫,回傳去重後的 (nodes, edges)。七個步驟:
| Step | 做法 | 說明 |
|---|---|---|
| 1. 精確正規化 | 接上 build.py 的既有 deduplicate_by_label | 抓跨檔案的 case/標點變體。免費,本來就寫好了。 |
| 2. 熵門檻 | entropy < 2.5 bits/char 的 label 跳過模糊比對 | 短歧義名(AI、DB、x)太危險,不自動合併。只有高熵 label 進下一步。 |
| 3. MinHash + LSH blocking | datasketch,3-gram、128 排列、threshold 0.7 | 候選對用 O(n) 產生(而非 O(n²))。1 萬節點 < 1 秒。 |
| 4. Jaro-Winkler 驗證 | rapidfuzz,≥ 0.92 | 抓錯字、複數、空格變體。低於門檻的對丟棄。 |
| 5. 同社群加分 | 兩個節點共享 Leiden community ID 加 +0.05 | Graphify 特有優勢——社群結構是 GraphRAG/LightRAG 沒用的強訊號。 |
| 6. Union-find 合併 | 確認的對餵進 union-find → 連通分量 → 每個分量合併成一節點 | 邊重新指向生還者;自環丟棄;偏好較短、非 chunk 後綴的 ID 當生還者。 |
| 7. 可選 LLM 仲裁 | --dedup-llm flag | 歧義對(0.75–0.85)每 30 個一批、每批一次 LLM 呼叫;1 萬節點約 $0.01。預設關閉。 |
去重在 build_merge/build_from_json 之後、cluster 之前執行。順序很重要:圖越乾淨,社群偵測越好。
# in build.py
G = build_merge(...) # or build_from_json
G = deduplicate_entities(G) # new step
communities = cluster(G) # unchanged
datasketch — 必裝(加入 [project.dependencies])rapidfuzz — 必裝(加入 [project.dependencies])tests/test_dedup.py)。source_file 正確更新。--dedup embed(MiniLM cosine)——明確排除,不引入 PyTorch 相依。graphify update(AST-only)——既有 AST cache 已處理。cache.py(semantic cache)、dedup.py(七步去重)、build_merge 都在 程式碼對照 · ops 裡能對到實作。增量更新解決「每次重跑都全部重做」的問題。核心機制是 manifest.json:記錄上次的檔案狀態,下次跑時只處理新增或修改的檔案。自動偵測,不需要 flag。
實體去重解決「同實體不同名字」的問題。七個步驟從精確正規化到可選 LLM 仲裁,形成一個完整的去重管線。關鍵設計:用 MinHash/LSH 產生候選對(O(n) 而非 O(n²)),再用 Jaro-Winkler 驗證。
整合點很重要:去重在 build_merge 之後、cluster 之前執行。圖越乾淨,社群偵測越好。
graphify extract .,觀察輸出:所有檔案都被處理。graphify extract .。觀察輸出:只有 1 個檔案被重新處理,其他 9 個從快取讀取。| 錯誤訊息 | 原因 | 解決方式 |
|---|---|---|
manifest.json: file not found | 首次執行或 manifest 被刪除 | 這是正常的,首次執行永遠是全量 |
dedup: entropy too low | label 熵值 < 2.5 bits/char | 短歧義名(如 AI、DB)不自動合併,這是設計如此 |
build_merge: graph conflict | merge 時遇到衝突 | 檢查是否有重複的節點 ID |
semantic cache: stale entry | 快取的 source_file 路徑已改變 | 快取會自動更新 source_file 到新路徑 |
前面示範單機手動操作;這次是維運情境:你有一個團隊 wiki,每晚同步外部 repo + 筆記,1000 份 markdown 每天變動約 20 份,你要讓「建圖」變成無人值守的 nightly job,並控制成本。
graphify extract corpus/ 產生 manifest + graph.json(費用較高的一次,可接受)。rsync/git pull 更新 corpus,再 graphify extract corpus/——自動偵測到 manifest + graph.json 存在 → 進入增量模式,只對 new_files(約 20 份)跑語意抽取,其餘 980 份走 semantic cache 命中。incremental: 20 changed, 980 cached, 2 deleted」這行——deleted 的檔案由 build_merge(prune_sources=deleted_files) 從圖中剪除。source_file 自動更新到新路徑(AST/semantic cache 同模式)。--max-spend 防月結爆表。增量不是「少做一點」的優化,而是一套一致性契約:
deduplicate_entities 在 build_merge 之後、cluster 之前——圖越乾淨,社群偵測越好;但這也意味著「社群會因為去重結果而漂移」,跨版比較社群數時要小心。cluster 是每次全圖重跑(設計文件明寫 "cluster (full graph, always re-run)")。加上去重可能把節點合併,社群數和社群成員每次都可能微調。若你把「社群穩定」當成「系統沒壞」的指標,會誤判——社群漂移是正常行為,社群 ID 跨跑漂移才該查(那是確定性失效)。| 症狀 | 可能原因 | 解決方案 |
|---|---|---|
| 每次執行都顯示全量重建 | manifest.json 或 graph.json 被刪/被清(CI 工作目錄沒持久化) | 把 graphify-out/ 放進持久化 volume;確認不跑 --no-cache |
| 改 prompt 後快取仍命中 | semantic cache key 沒含 prompt fingerprint | 檢查 prompt_fingerprint 是否納入 key;版本化你的 extraction-spec |
| 檔案改名後出現「ghost 節點」 | 改名但內容變了 → cache miss,舊節點未 pruned | 確認 manifest 正確偵測 deleted + new;檢查 build_merge 的 prune_sources |
| 圖節點數不減反增(刪了一堆檔) | deleted_files 偵測失敗(檔案被移到 ignore 目錄?)或 prune 沒生效 | 看 detect_incremental 的 deleted 清單;確認沒被 ignore 規則吃掉 |
| 合併後社群「亂成一團」 | 去重把不同實體誤併(Jaro-Winkler 閾值太鬆、缺社群加分護欄) | 檢查去重步驟 4/5 的門檻;考慮 --dedup-llm 仲裁 0.75–0.85 歧義對 |
前面的 Worked Example 是維運情境的 nightly job。這次是CI/CD 整合:你們的 monorepo(500 檔 Python + 200 檔 TypeScript)用 GitHub Actions,每次 PR 要跑圖分析、每次 merge 要更新圖、預算控制在每月 $20 以內。
graphify extract . --check-drift——自動偵測到 manifest.json → 增量模式 → 只重抽變更檔案 → 如果圖跟程式碼不同步就 fail check。這防止「圖過期」的 PR 被合併。graphify extract .——增量更新圖 + 用 --max-spend 5 限制每次 merge 的 token 預算。Manifest 只在成功完成後寫入,即使 CI 當機也不弄壞下一次 diff。graphify extract --dedup-llm(啟用 LLM 仲裁),比較啟用前後的節點數——如果差異 >5%,代表七步去重的 Jaro-Winkler 閾值可能太鬆。graphify extract . --no-cache——消除增量累積的去重偏差,比較重建前後的圖差異(社群數、god nodes、節點數)。| 面向 | 考量 | 實務建議 |
|---|---|---|
| 效能 | MinHash/LSH 去重在 1 萬節點 <1 秒;但 union-find 合併後的邊重指向可能改變圖結構 | 監控去重前後的節點數/邊數比;如果邊數下降 >10%,代表去重把不同實體誤併 |
| 品質 | manifest.json 是 diff 的真相來源;中途當機時下次以舊 manifest 為基準 | 確認 manifest 只在成功完成後寫入(設計如此);定期用 graphify extract --check-drift 驗證圖與程式碼同步 |
| 安全 | semantic cache 的 key 含 prompt fingerprint;prompt 一改快取自動失效 | 版本化你的 extraction-spec;不要手動改 cache 檔案;--no-cache 會清空整個快取目錄 |
| 面向 | 本文(增量更新) | 相關文 | 差異說明 |
|---|---|---|---|
| 增量機制 | manifest.json 自動偵測 + detect_incremental + build_merge | 架構總覽 | 架構頁只描述靜態 pipeline(detect→export),不涉及增量模式 |
| 去重 | 七步去重管線(精確正規化→LLM 仲裁) | 運作原理 | 運作原理頁講信任標籤(EXTRACTED/INFERRED),不涉及去重邏輯 |
| 快取 | semantic cache 含 prompt fingerprint 失效條件 | 程式碼對照 · ops | 程式碼對照頁逐函數講 check_semantic_cache、save_semantic_cache |
| 測試 | 五種測試類型(單元/整合/增量/改名/刪除) | 實作案例 | 實作案例頁展示真實產出的 GRAPH_REPORT,但不展示增量測試過程 |
graphify extract .,第二次觀察到「只有 1 個 changed」的增量行為graphify benchmark 驗證圖的品質指標