Schema 穩定後的自然產物:實作能自動生長邊界的 Entity Graph Builder
Schema 穩定後的自然產物:實作能自動生長邊界的 Entity Graph Builder
在上一篇文章 《做 GraphRAG 之前,為什麼要先「穩定 Schema」?》 裡,我們建立了 CtxFST 的 v1.1 核心規格,同時嚴格遵守著一個信念:Schema 本身只是固定的節點與區塊(Edges 與相似度不屬於此層)。
有了這堅實的基礎,我們終於能來到最令人興奮的一步:打造一張由 Embedding 構成的 Entity Graph!
而最好的是,在實作這張圖譜時,我們完全不需要再去修改現有的 CtxFST Spec 規格書。因為這支生長 Graph 的程式,只是一個單純的「下游轉換器(Downstream Builder)」。
這篇文章,讓我帶你看看這套設計帶來的威力,以及剛出爐的 build_entity_graph.py 實作成果。
為什麼說這「不需要改 Schema」?
只要你有了前置作業:
- Markdown 文件 (定義了
entities節點清單,以及各chunks所掛載的實體) export_to_lancedb.py腳本,負責產出乾淨、具備 JSON Schema 驗證的chunks.json
那麼,你要做 Similarity Graph 的原材料已經 100% 備齊了。
我加入了一支新的下游腳本——skill-chunk-md/scripts/build_entity_graph.py。
它的運作邏輯完美體現了什麼叫作 關注點分離 (Separation of Concerns):
- 輸入:讀取上游已經定型輸出的
chunks.json。 - 處理:把 Entities 抽取為 Nodes,然後根據各個 Chunk 到底連擊到哪些 Entities,將 context 蒐集起來做成一段可嵌入的文字敘述(Representation text)。接著,計算 TF-IDF + Cosine Similarity 來得知兩兩節點的語意相似分數。
- 輸出:最終的
score會轉化為 Entity 之間的SIMILAREdges 並存成entity-graph.json。
這不是作者在 YAML Frontmatter 用人工填寫的固定欄位,這是計算出來的動態關聯結果!
build_entity_graph.py 腳本的運作解密
這支剛加入的腳本提供了「最小可用版但極具體」的展示,完全不需要安裝複雜的 PyTorch 或去叩 OpenAI 的昂貴 API,它讓想嘗試架構的人立刻就能看見 GraphRAG 最初心的樣貌。
支援的三大實用參數
--mode:有兩種選擇:metadata:快、乾淨,只拿實體的name+type+aliases去算相似度。contextual(預設):更準。它會把那些連去該實體的 Chunk Contexts 都納入描述。這最能體現所謂的「血緣親屬 (Bloodline Relatives)」,因為是在實際業務邏輯中碰在一起,而不是單純名詞長得像。
--top-k:設定每個節點最多產出幾條相似邊線(例如 3,避免圖過度密集變成毛線球)。--min-score:設定相似度閥值(例如 0.15),過濾掉太微弱的無意義碰觸。
實際輸出的 JSON 結構搶先看
{
"nodes": ["entity:fastapi", "entity:python", "entity:pandas", "entity:go"],
"edges": [
{
"source": "entity:fastapi",
"target": "entity:python",
"relation": "SIMILAR",
"score": 0.63
},
{
"source": "entity:fastapi",
"target": "entity:pandas",
"relation": "SIMILAR",
"score": 0.97
}
]
}
從範例解析「血緣關係 (Bloodline Relatives)」的威力
我們拿實際案例來跑測試,對比了 --mode metadata 與 --mode contextual 兩種運算模式。這份測試完美地展現出為什麼「把 Chunk Context 加進 Embedding 裡」能讓圖譜變得更有人味:
| 實體對照 (Entity Pair) | Metadata 模式分數 | Contextual 模式分數 | 導致差異的真實原因 |
|---|---|---|---|
FastAPI ↔ Pandas |
0.21 |
💥 0.97 |
在範例文件中,它們都頻繁共存於同一個 Chunk (skill:python) 裡面,而且 Context 描述高度重疊,它們是強烈關聯的技術棧工具! |
FastAPI ↔ Python |
0.23 |
0.63 |
FastAPI 只有出現在 1 個區塊,但 Python 出現在 3 個,有交集但權重被稀釋。 |
Go ↔ Python |
0.54 (最高) |
0.53 |
Metadata 模式給的分數最高,因為兩者都是 type: skill(屬性相同被誤認親密);Contextual 將其校正為普通同袍關係(各自負責一個 API 區塊)。 |
Go ↔ FastAPI |
0.23 |
0.16 |
因為在內文的 Chunk 中,這兩個技術從未並肩作戰過,它們本來在業務面就是兩條平行線。 |
看到這裡就會發現:在 metadata 模式下,機器覺得 Go 與 Python 最像(它們都叫程式語言);但在 contextual 的真實圖譜裡,系統知道 FastAPI 與 Pandas 才是最強的連結,因為你的文章中告訴系統「這兩個傢伙總是一起出現在資料處理與後端建置中」。
這,就是方式 B:「血緣親屬」的極致展現。
為什麼只提供輕量的「Reference Builder」?
眼尖的讀者可能會問:「為什麼這支腳本只使用 TF-IDF + Cosine Similarity,而不直接整合強大的 sentence-transformers、OpenAI、Gemini 或 LanceDB Vector Ops?」
答案是:為了維持 CtxFST 作為「規格與教學」專案的純粹性,也是一個最安全的選擇。
build_entity_graph.py 的定位是一個 Lightweight Reference Builder(輕量參考建置器),它具有幾個重要特質:
- 零外部依賴:任何人
clone專案下來,不需要註冊 API Key,也不用安裝肥大的 PyTorch 機器學習框架,就能一條龍跑完「撰寫 CtxFST ➡️ export JSON ➡️ build entity graph」的流程。 - 高可讀性:它是最佳的教材,用純 Python 展演了圖譜建構的最核心邏輯。
- 安全且解耦:完全不跟特定雲廠商或單一神經網路框架綁在一起。
對於一個「規格 + Skill」型的 Repository 來說,這種零依賴的小實作是最好的示範。它讓任何人都能馬上跑出成果,同時,只要你理解了概念,這支 Scripts 的邏輯隨時可以被你抽換。
生產環境升級指南:Production-grade embedding pipeline (out of scope for this repo)
當你要將這套架構推向正式的 Production(商業生產環境)時,我們強烈建議將這層基礎的 TF-IDF 邏輯抽換成重型的 Embedding Backend。這些進階的實作方向適合獨立拆解成專屬的 Repo 或 Microservice,而不是與標準規格混作一團。
以下是常見的進階實作升級策略:
- sentence-transformers 版本:若對隱私與離線運算要求極高,可以搭載如
BGE、Nomic甚至M3等開源輕量化模型,建立專屬的本地化知識圖譜。 - OpenAI / Gemini 版本:呼叫強大的商用大語言模型(如
text-embedding-3-small或text-embedding-004),它的語義理解能力極細膩,能建立最高品質的 Entity Graph 邊界。 - LanceDB Native Pipeline 版本:如果你的上游檢索庫已經使用 LanceDB,則可以直接利用其內建的
Embedding Functions原生功能。透過 Python API 或 Rust 讓資料抽取、Embedding 計算到相似度建圖合併在同一個資料流中,效能無可匹敵。
總結來說:CtxFST Repo 負責定義穩定的標準與參考實作;而真正強大的 Embedding 基礎設施,則交給你的正式產品線來發揮!
Separation of Concerns 驗證:一條完整的 Pipeline 閉環
我們回頭來看這次架構升級有沒有違反我們立下的任何紀律?
ctxfst-spec.md(Formal Spec):維持 Frozen v1.1 —— 沒動!schema.json(Validation):維持 Freeze Draft-07 —— 沒動!export_to_lancedb.py(上游匯出):依舊照著標準產出 JSON —— 沒動!build_entity_graph.py(新增角色下游 Builder):純粹去「消費」上游的 JSON。
腳本只讀 Schema 產出的通用資料,然後算出來的 SIMILAR Edges 完全沒有逆向塞回 CtxFST 的 Markdown 或 Metadata 裡,這證明了我們這條流水線在職責劃分上的正確性!
有了這支腳本,我們正式完成了從文本到 Graph DB 匯入規格的黃金四部曲打通:
Markdown 撰寫 ➡️ export_to_lancedb.py (提取) ➡️ build_entity_graph.py (關聯) ➡️ 匯入 Lance Graph / HelixDB / Neo4j
準備好把這些生成的 .json 拋進圖資料庫了嗎?我們的 Entity Embedding Pipeline 這下真正成型了!
- ← Previous
做 GraphRAG 之前,為什麼要先「穩定 Schema」?CtxFST 的規格化之路 - Next →
實戰指南:從 .ctxfst.md 到 chunks.json,破解 export_to_lancedb.py 的角色與輸出協定