昨天介紹的是 Milvus bootcamp 的一種 GraphRAG 做法,用 entity 和 relation 做 Subgraph Expansion 來直接回推實際文本,但有個問題是這種作法幾乎沒有發揮向量資料庫的主要功能,也就是去做 Passage 和 Query 的相似度比對。Retrieval 幾乎把「Graph relevance」當成主要訊號,而沒有充分利用原始 Passage 本身和 Query 的 relevance。
實際上,GraphRAG 不只一種作法,今天來看看其他的 GraphRAG 是如何實做的:
Microsoft GraphRAG 在建立 Knowledge Graph (Indexing) 時會抽 Entity、Relationship、Claims (Optional),再進行 hierarchical community clustering (切成很多有主題性的群組) 與 community report generation (替每個群組寫摘要)。
用來回答:
某個 Entity 是誰?
它跟哪些東西有關?
某個人物有哪些關係?
先用 Query 找到相關 Entity,接著取得這些 Entity 周圍的 Relationship。概念上跟 Milvus 有點像,但多塞了一點東西:Microsoft GraphRAG 會把 Entity / Relationship 這類結構化資料格式化成 LLM 可以讀取的 Context,並和原始 Text Units、Community Reports 一起放進 Context Window。
實作上也會替不同類型的資料分配不同的 token budget,例如 text_unit_prop 用來控制 Text Units 的比例 (預設 0.5)、community_prop 控制 Community Reports 的比例 (預設 0.15),剩下的 Context Window 才留給 Entity、Relationship (預設 0.35)。
Query
↓
Semantic Entity Retrieval
↓
找到相關 Entities
↓
├─ Graph Context
│ └─ Relationships / Connected Entities
│
├─ Source Context
│ └─ Related Text Units
│
└─ Community Context
└─ Community Reports
↓
Ranking / Filtering / Context Budget
↓
LLM
用來回答這種本來就沒有一個明確的 Chunk 可以拿來 Vector Search 的 Query:
整批資料主要有哪些議題?
這幾千份文件中有哪些共同趨勢?
Microsoft GraphRAG 會利用 Leiden clustering 對 Entity Graph 做階層式分群,並替每個 Community 預先建立 Community Report。Community 並不是替原始文件貼上一個主題標籤,因此同一個 Text Unit 可以包含來自不同 Community 的 Entity;不同 Community 在更高一層也可能被歸納成同一個 Parent Community。
Global Search 時,系統會取得指定 hierarchy level 的 Community Reports,再使用 Map-Reduce 產生答案。map 階段把這些 reports 分批,每一批各自交給 LLM,產生一些和 Query 有關的 intermediate points,並替每個 point 給 importance rating。接著 reduce 把高重要度的 points 集合起來,再交給 LLM 生成最後答案。
Documents
↓
Entity / Relationship Extraction
↓
Knowledge Graph
↓
Hierarchical Leiden Clustering
↓
Community Reports
========================
Query time
========================
Community Reports
↓
MAP
每批 Report 各自回答 Query
並產生「重點 + importance score」
↓
挑出重要的 intermediate points
↓
REDUCE
把這些重點重新整理
↓
Final Answer
前面的方法基本上都是讓 Graph 去負責第一階段,是基於 Entity 和 Relationship,但為何我們不直接把文本本身當作 Node 呢?Neo4j 的VectorCypherRetriever 先找到向量上相關的 Vector Node,再以這些 Node 為入口做 Cypher Traversal,特別的地方在於這些 Node 不一定是 Entity,也可能是 Chunk 或 Document。
Query
↓
Vector Search
↓
找到 Semantic Relevant Nodes
↓
Graph Traversal
↓
取得周圍 Context
說了那麼多,但實際上並不是每個 Query 都需要 GraphRAG,實務上可以做 Query Routing:
「退款期限幾天?」
→ Normal RAG
「A 公司和 B 公司是什麼關係?」
→ Local Graph Search
「A 透過哪些人間接影響 B?」
→ Multi-hop Graph Search
「這批文件主要有哪些共同問題?」
→ Global / Community Search
不要想著全部都用 GraphRAG,而是讓 Vector、Graph 與原始 Text 各自負責自己擅長的事情。
我知道你出發點是好的,但是你先別出發。