GraphRAG + 證據選擇,為什麼很像自然語言的 AST?
GraphRAG + 證據選擇,為什麼很像自然語言的 AST?
我很喜歡用一句話描述 GraphRAG:
GraphRAG 是把「可被走訪、可被組合、可被稽核」的知識結構顯式化。
如果你有編譯器 / 靜態分析背景,這會讓你立刻想到 AST(Abstract Syntax Tree)。
這個類比在「只有 GraphRAG」時已經像;但當你把 證據選擇(evidence selection) 加進來,就會更像,因為整條管線開始呈現一種熟悉的形狀:
建結構 → 走訪/擴張 → 找出最小充分子結構 → 下游推理 / 生成
本文把這個類比拆解到工程層級,並補上你可以拿來做系統設計討論的細節:什麼地方像、什麼地方不像、哪裡最容易踩坑。
先對齊名詞:GraphRAG 與 Evidence Selection 在做什麼?
GraphRAG(圖式檢索)
GraphRAG 通常會把資料切成「節點」並建立「關係」:
- 節點:文件、段落、實體(公司/產品/條款/人名)、概念、事件
- 邊:引用、定義、同義/別名、依賴、因果、例外、版本演進、同一主題等
查詢時不只做相似度檢索,還會沿著關係擴散或做子圖擷取,把跨文件、跨實體、多跳的上下文找齊。
證據選擇(Evidence Selection)
證據選擇的目標不是「把資訊變短」,而是:
- 從候選內容中挑出 能支持結論 的最小片段集合
- 保留定位資訊(可追溯、可引用)
- 去重、分組、按推理順序拼裝,形成「證據包」
你可以把它看成把上下文從「材料堆」升級成「可稽核證據包」。
核心類比:GraphRAG + Evidence Selection ≈ AST + Program Slicing
一張對照表(工程語言版)
| 編譯/分析系統 | 自然語言/知識系統 |
|---|---|
| Parse source code | 從文件抽實體、抽關係、建圖 |
| AST(中介表示 IR) | Knowledge Graph / Document Graph(中介表示 IR) |
| Traversal / dataflow | 圖擴散、路徑搜尋、多跳檢索 |
| Program slicing | Evidence subgraph / evidence spans selection |
| Pretty-print / lowering | Context assembly(把證據包轉成 LLM 可吃的格式) |
| Typecheck / lint | Verifier / self-check(答案是否被證據支持) |
類比成立的關鍵,不是「都有圖」,而是 都有 IR + selection + verification 這種「把推理變成可控流程」的結構。
為什麼「加上證據選擇」之後更像?
如果你只做 GraphRAG 而不做 evidence selection,你常會停在:
- 「我拿到一堆相關節點」
- 「我把它們塞進 prompt」
這比較像把整棵 AST 直接丟給後端,期望後端自己找到正確的 expression;可行但不優雅,且容易被雜訊拖垮。
而 evidence selection 會強迫系統回答一個很編譯器的問題:
為了支持這個結論,最少需要哪幾個節點/片段?
一旦你開始做「最小充分」:
- 你的上下文就會變成「一段段可引用、可對齊」的證據
- 你可以做 coverage(是否包含每個 claim 的支撐片段)
- 你可以做回歸測試(同樣的 query,證據包是否穩定)
這就是 slicing 的精神:只保留會影響結論的那部分 IR。
更精準一點:GraphRAG 更像哪一種 AST?
如果你說的 AST 是「語法樹」,GraphRAG 並不完全像,原因是:
- AST 的邊語義由語法規則決定,且可嚴格驗證
- GraphRAG 的邊多是抽取或推斷,會有錯、缺漏、歧義
所以更準確的說法是:
GraphRAG 更像「自然語言的 IR(資訊檢索的中介表示)」
而不是「100% 可證明正確的語法樹」
也因此,GraphRAG 系統要更重視:
- 邊的信心分數(confidence)
- 多路證據一致性(cross-evidence consistency)
- 可回放的查詢路徑(audit trail)
一個可落地的設計:Evidence Subgraph as the Contract
要把「像 AST」的好處吃到,你需要把輸出契約(contract)從「chunks」提升為「evidence object」。
一個實用的 evidence 物件至少包含:
{
"claim": "答案中的一個可驗證敘述",
"evidence": [
{
"source_id": "doc:policy-2025-11",
"locator": { "page": 12, "section": "3.2", "span": "L45-L62" },
"quote": "原文片段…",
"edge_path": ["term:GDPR", "refers_to", "clause:3.2"]
}
]
}
重點在於:
locator讓你可以回到原文edge_path讓你知道這份證據是怎麼被圖走訪帶回來的claim把「生成」拆成可驗證單元,而不是一次生成整段不可稽核的文字
這就像 AST node 帶著 source location,讓你可以把 warning/error 精確貼回原始程式碼。
實務流程:從 query 到 evidence subgraph
下面是一個簡化但足夠工程化的流程:
flowchart TD Q[Query] --> P[Parse intent / entities] P --> S[Seed retrieval] S --> X[Graph expansion] X --> C[Candidate subgraph] C --> R[Rerank nodes/paths] R --> E[Evidence selection: minimal supporting set] E --> A[Context assembly] A --> G[Generate claims + citations] G --> V[Verify each claim] V -->|retry| X V -->|ok| O[Answer]
這裡的關鍵不是「有圖」,而是中間那個 E:
- 不做
E:你是在做「圖式檢索 + 堆料」 - 做了
E:你才是在做「圖式檢索 + 可稽核推理」
一個小小的 pseudo-code(把 slicing 味道做出來)
def answer(query):
seeds = seed_retrieve(query) # dense/keyword/metadata
subgraph = expand_graph(seeds, hops=2) # graph traversal
ranked = rank_nodes_and_paths(query, subgraph)
evidence = select_minimal_support(query, ranked) # slicing
claims = generate_claims(query, evidence, citations=True)
verdict = verify(claims, evidence)
if verdict.need_more_evidence:
query = rewrite_query(query, verdict.missing_aspects)
return answer(query)
return claims
select_minimal_support 的概念就是:不要讓「更多」假裝成「更準」。
什麼時候這個類比會失效?
-
你的關係邊不穩定
- 抽取的關係錯、版本沒更新、同義詞沒規範化,整張圖會像壞掉的 AST:走訪得到錯誤依賴。
-
你把摘要當證據
- AST slicing 的輸出仍然是原始 IR 的子集;如果你用摘要替代原文片段,就像 slicing 後又把 node 改寫成另一份不可追溯的碼。
-
你沒有 verifier
- 沒有 verifier 的 GraphRAG 更像「把 IR 丟給生成器」而不是「可驗證的推理系統」。
結語:把 GraphRAG 當成 AST,最大的收益是“工程可控性”
把 GraphRAG 類比成 AST 不是為了炫技,而是為了讓系統討論更精準:
- 你不是在做「更聰明的 LLM」
- 你是在做「更可控的 IR + selection + verification pipeline」
而 evidence selection 是讓 GraphRAG 真正像 AST 的那個關鍵齒輪:它把上下文從「一堆材料」變成「最小充分證據包」,讓準確率、成本、可稽核性都能進入可工程化迭代的範圍。