Ian Chou's Blog

CtxFST CH5 - 破除 GraphRAG 迷思:真正重要的不是 Graph,而是 Embedding 自己長出來的 Entity Graph

破除 GraphRAG 迷思:真正重要的不是 Graph,而是 Embedding 自己長出來的 Entity Graph

在討論 GraphRAG 或知識圖譜時,我們常聽到一句大白話:「Graph 就是向量搜尋(Vector Search)的導航圖。」

這句話本身沒錯,但太過通用了。這會讓人自動腦補成傳統的 Neo4j 知識圖譜,或者是人工手寫的 Keyword Graph。

如果你正在關注像 lance-graphhelixdb 這類新興工具,你真正要看懂的核心對比不是「Vector Search vs Graph」,而是:

  1. Chunk-level vector retrieval(段落向量檢索)
  2. Hand-written keyword graph(人工定義關鍵字圖譜)
  3. Entity embedding graph(實體嵌入圖譜)—— 這才是主角!

這支文章,我們來談談為什麼我們需要第三種,以及如何透過 5 種主流方法,將雜亂的文章自動昇華成這張圖。


核心金句:我們到底在解決什麼問題?

「Graph 不是重點,重點是把 Retrieval 從 Chunk Space 拉到 Entity Space,然後用 Embedding 自動生成 Entity 之間的圖。」

很多人以為 GraphRAG 的價值是做多跳查詢(Multi-hop);但 lance-graphhelixdb 真正厲害的地方在於:它把「關係定義」這件事從人手上拿掉了。

以往要做一張技能圖譜,你需要:

但在 Entity Embedding Graph 的世界:

Vector Search 只會幫你找到和 Query「文字語意接近」的段落(Chunk)。但很多關鍵的解法或技術,是 Query 根本沒直接說出來的,它們藏在實體與實體(Entity-to-Entity)的隱含語意鄰近上。我們做的,就是把這些鄰近關係先建成圖,再拿圖去導引後續的段落檢索。

這不是傳統的 Knowledge Graph,也不是純 Vector DB。這是用 Embedding Similarity 動態生成 Entity-Level Topology 的全新檢索生態。


實作關鍵:如何從文章中抽出這些 Entity?

要讓 Embedding 幫你畫圖,第一步是得先有乾淨、標準的 Entity(實體節點)

目前從雜亂的文章(Chunk)中提煉出 Entity,主要有以下 5 種方法(從傳統 NLP 到現代 LLM 皆有),而主流的 GraphRAG 和 KG-RAG 通常採用第一種(準確率最高、最易於擴展):

方法 原理與做法 代表工具 / 範例 優缺點分析
1. LLM Prompting
(最標準)
透過 Prompt 直接請 LLM 提取 Entity 與其關係描述。 GraphRAG 的 Prompt 機制、LangChain 的 LLMGraphTransformer ✅ 準確率極高 (90%+),非常靈活。
❌ 成本高,速度受限於大模型。
2. Rule-based 利用 Regex 或特徵字比對(名詞+動詞)來暴力抓取。 spaCy rule, NLTK chunker ✅ 快、完全免費。
❌ 嚴重受限於特定領域(例如只能抓已知技能名單)。
3. Pipeline
(NER + RE)
先做命名實體識別(NER),接著丟給關係分類器。 spaCy NER + pipeline, Stanford CoreNLP ✅ 穩定,中等準確度 (約 80%)。
❌ 需要自己花時間 Train 模型。
4. Transformer
(端到端)
使用 BERT 或 GPT 做 Fine-tune,進行 Joint Entity-Relation Extraction。 REBEL model, T5-RE ✅ 準確度高 (95%)。
❌ 需要撰寫/準備大量的 Training Data。
5. Bootstrapping 給定一小批 Seed Pairs,讓演算法自動去擴展 Pattern。 Snowball, Distant supervision ✅ 半監督學習,低人工成本。
❌ 雜訊很容易像滾雪球一樣擴散。

給「個人技能圖譜 (Skill Graph)」的實戰建議

如果你正在處理的是個人的技術筆記、職涯經歷或大約 200 個節點的技能圖譜,我強烈推薦使用 混合模式(Hybrid)

你的標準流程會是: LLM Extract ➡️ Dedup (去重) ➡️ Embed (轉向量) ➡️ Graph (建圖)


CtxFST Markdown 規範的獨特定位

你可能會想:「既然 Anthropic, GraphRAG 都已經在講 Contextual Retrieval,那我自己搞這套 Skill Chunk MD (CtxFST) 還有意義嗎?」

絕對有意義!而且不僅不是重複發明輪子,更是互補與領先。

微軟的 GraphRAG 和 Anthropic 的 Contextual Retrieval(證明了 Context 前置能提升 20% 檢索品質,但 Merge 過後非常難以微調)是在講大方向的解法。而 CtxFST 做的事情,是把 「Entity-First + Structured Chunking」格式化成了一套標準,讓你的技能圖更易於擴充(Scale)與分享。

我們來比較一下 CtxFST 目前的優勢:

你的 CtxFST 靈感 CtxFST 的實踐現況 CtxFST 的獨特定位(你的差異化優勢)
Context in metadata ✅ Core (將 Context 與 Tags 與 Chunk 本體分離) 專屬技能/職涯檢索:加入 prioritydependencies 欄位,直擊 Agentic RAG(代理型檢索)對於規劃步驟的需求。
Entity catalog ✅ Top-level entities (文件頂層宣告) 200 Nodes 最佳化:透過白名單提取 + Embedding 計算邊,大幅省下每次進 GraphDB 都要跑 LLM 關係萃取的昂貴成本。
Chunk linkage chunks[].entities 綁定 原生銜接生態系:無痛對接 LanceDB / HelixDB 發布,只需 1 步 Export,不用經過複雜轉檔。

圖不是取代向量搜尋的對手。有了這套標準化的 Markdown 結構,你正在做的,是用向量算出的相似度,去編織出那張沒有人為偏見的「完美語意導航圖」。


深入對比:Anthropic Contextual Retrieval vs CtxFST 欄位分離

在理解 CtxFST 的定位之前,我們要先認清一個基本問題:「拿什麼內容去算 Embedding?」 這個選擇直接決定了檢索系統的精準度。

RAG 的 4 種 Embedding 輸入策略

策略 輸入給 Embedding 的內容 適用場景 在 CtxFST 中的對應欄位
1. 純 Chunk Content 文章/段落正文 傳統 RAG 做法,語意最豐富但雜訊也最高。 chunks[].content
2. Context Only 高濃縮的語意摘要 CtxFST 核心,精準導航,雜訊極少。 chunks[].context
3. Context + Content 摘要與正文合併 Anthropic 的做法,平衡精準與細節。 context + content
4. Tags Only 關鍵字列表 快速過濾用途,通常不直接拿來算向量。 chunks[].tags

Anthropic 怎麼做?

2024 年 9 月,Anthropic 發表了 Contextual Retrieval。核心做法是策略 3:為每個 Chunk 先用小模型(如 Claude Haiku)生成一段 50-100 token 的上下文描述,然後物理性地接在原始 Chunk 前面一起做 Embedding。效果驚人:Top-20 的檢索失敗率直接降低了 67%

但這種合併法有兩個致命傷:

  1. 更新代價高:只想微調 Context 就得重算整段肥大 Chunk 的 Embedding。
  2. 對 Graph 不友善:摻雜長篇正文會讓實體關係變得模糊。

CtxFST 欄位分離 vs Anthropic 合併法的 5 大優勢

優勢維度 Anthropic (Merge) CtxFST(欄位分離) 這對你來說代表什麼?
更新彈性 改一段需全部重算 context 獨立算,免動本文 微調技能 Context 不會連累原文,省時省錢。
Hybrid 支援 向量與 BM25 混雜在同一堆字 Context 做向量,Tags/Entities 做精確篩選 tags='Python' 先 Filter,再從 context 算 Cosine 最準。
圖譜友好度 無結構化的長文本 entities[] 直轉 Nodes 與 Edges HelixDB 可以輕鬆把 entities[] 丟給 Graph 跑 SIMILAR
診斷與迭代 系統裡的黑盒 YAML 格式全透明、可讀、可編輯 改個 MD 檔馬上能看到 Graph 變化。
多模態潛力 僅限文字 YAML 可直接帶入 type: image 等結構 未來技能圖可以加教學架構圖(Diagram)。

最佳實踐:用 context 做主力 Embedding

在約 200 個技能節點的規模中,最推薦的做法是用 chunks[].context 這個 50-token 精華來做 Embedding:

# LanceDB 中 Schema 的設計範例
from lancedb.embeddings import get_registry

func = get_registry().get("sentence-transformers").create("bge-large-zh")

class CtxFstSchema(LanceModel):
    # 用 context 來自動產生 vector(策略 2)
    context: str = func.SourceField()
    
    # content 照存,但不拿來算 vector
    content: str
    
    # 透過 tags 做前置過濾
    tags: list[str]
    
    vector: Vector(func.ndims()) = func.VectorField()

這樣做的好處是:不論你教學文章的 content 怎麼修辭,只要技術重點(context)沒變,Embedding 向量就不會震盪!


📌 CtxFST 開源專案github.com/ctxfst