CtxFST CH10 - 全端實戰:用 Entity Embedding Graph 打敗純 Vector Search,發現你筆記中的未知領域
CtxFST CH10:全端實戰——用 Entity Embedding Graph 打敗純 Vector Search,發現你筆記中的未知領域
在前面 9 個章節中,我們已經建立了從 Schema 到 Entity Profiles 到 Similarity Graph 的完整概念體系。
現在,是時候把所有的理論摺疊起來,攤開一張真正跑得動的完整程式碼展演了。
這篇文章會帶你走完以下流程:
- 用
sentence-transformers+LanceDB為 17 個技能名詞做 Embedding - 不寫任何一條手動邊,讓 Cosine Similarity 自動建出一張語意圖譜
- 用 Graph Expansion 實戰破解「Unknown Unknowns(不知道自己不知道的)」場景
- 回頭對比純 Vector Search 的結果,看出碾壓級差距
準備好了嗎?讓我們開始!
回顧:建圖的三種方式
在開始之前,快速回顧我們之前介紹過的三種方法:
| 方式 | 原理 | 缺點 |
|---|---|---|
| 方式一:關鍵字匹配 | Tags / Keywords 碰在一起就算相似 | 表面重疊,語意膚淺 |
| 方式二:手動寫關係 | 人工定義 REQUIRES, SIMILAR_TO |
慢、無法 Scale、主觀 |
| 方式三:Entity Embedding Graph ⭐ | 讓 Embedding 自動算出語意邊 | 本章教的方法! |
方式三的核心想法:不用手寫關係,讓 Embedding 的語意相似度自動發現技能之間的隱含連結。
Step 1:Embedding 所有技能
from sentence_transformers import SentenceTransformer
import lancedb
import networkx as nx
model = SentenceTransformer("BAAI/bge-m3")
# ① 定義技能名單
skills = [
"OpenClaw", "Node.js", "LLM API", "Anthropic Claude", "OpenAI",
"Telegram Bot", "Browser Automation", "Puppeteer", "Playwright",
"Shell Scripting", "LangChain", "Agent Architecture", "FastAPI", "Hono",
"Tool Calling", "Discord Bot", "Edge Runtime"
]
vectors = model.encode(skills)
# ② 存進 LanceDB
db = lancedb.connect("data/skills.lance")
skill_table = db.create_table("skills", [
{"name": s, "vector": v.tolist()}
for s, v in zip(skills, vectors)
], mode="overwrite")
到這一步,17 個技能已經被向量化並存入 LanceDB。它們各自佔據向量空間中的一個座標點。
Step 2:零手動建圖——讓 Embedding 自己畫邊
def build_entity_graph(table, top_k=5, threshold=0.3):
"""用 embedding cosine similarity 自動建立 skill 之間的語意邊。"""
skills_data = table.to_pandas()
graph = nx.Graph()
for _, row in skills_data.iterrows():
graph.add_node(row["name"])
for _, row in skills_data.iterrows():
results = table.search(row["vector"]).limit(top_k + 1).to_list()
for r in results:
if r["name"] != row["name"] and r["_distance"] < threshold:
similarity = 1 - r["_distance"]
graph.add_edge(row["name"], r["name"], weight=round(similarity, 3))
return graph
skill_graph = build_entity_graph(skill_table)
就這樣,我們沒有手動寫任何一條邊。 系統自動產出了以下關聯:
Telegram Bot ──0.76──> Discord Bot ← 同類 chat app
Telegram Bot ──0.74──> OpenClaw ← 都涉及聊天整合
OpenClaw ─────0.83──> Agent Architecture ← 都是 AI Agent
OpenClaw ─────0.78──> LangChain ← Agent 框架生態
Agent Architecture ─0.85─> LangChain ← Agent 建構
Agent Architecture ─0.77─> LLM API ← 底層能力
Agent Architecture ─0.79─> Tool Calling ← Agent 核心能力
LLM API ──────0.88──> OpenAI ← 同一類
LLM API ──────0.86──> Anthropic Claude ← 同一類
Browser Automation ─0.82─> Puppeteer ← 同領域工具
FastAPI ──────0.71──> Hono ← 都是輕量 Web 框架!
注意最後一條:FastAPI → Hono(0.71)。一個是 Python 框架,一個是 TypeScript for Edge Framework。它們在 source code 或名稱上完全不相關,但 Embedding 自動發現「它們的使用場景相近——都是輕量級 Web 框架」。這就是語意圖的威力。
另外觀察一條路徑:Telegram Bot → OpenClaw → Agent Architecture → Tool Calling——這整條鏈路是 Embedding 自動跑出來的,不需要人工定義任何一步。
Step 3:Graph-Enhanced 檢索——Entity Graph Search
有了圖做為導航,我們可以開發出遠超純 Vector Search 的檢索策略:
def entity_graph_search(query, model, skill_table, skill_graph,
chunks_table, top_k=5, hops=2):
"""
Entity Embedding Graph 檢索流程:
Query → Seed Skills → Graph Expansion → Guided Chunk Retrieval
"""
query_vec = model.encode([query])[0]
# Step 1: 找 Seed Skills(Entity-Level 最近鄰)
seed_results = skill_table.search(query_vec).limit(3).to_list()
seed_skills = {r["name"] for r in seed_results}
# Step 2: 沿 Graph 擴展 N Hops
expanded = set()
for skill in seed_skills:
if skill in skill_graph:
neighbors = nx.single_source_shortest_path_length(
skill_graph, skill, cutoff=hops
)
expanded.update(neighbors.keys())
all_skills = seed_skills | expanded
# Step 3: 用 Skill Set 導航 Chunk 檢索
chunks = chunks_table.search(query_vec).limit(top_k * 3).to_list()
guided = [c for c in chunks
if any(s.lower() in c["text"].lower() for s in all_skills)][:top_k]
return guided
在每次搜尋中,它做了三件事:
- 找起點(Seed):用 Vector Search 確定 Query 最相關的 3 個 Entity
- 沿圖擴展(Expansion):沿著語意邊走 N 步,蒐集周邊的 Entity
- 導航檢索(Guided Retrieval):用擴展後的 Entity 集合過濾用 Vector 找到的 Chunks
實戰 Demo:真正的碾壓差距
場景一:Telegram Bot 聊天機器人開發
使用者提問:「我想做一個 Telegram 聊天機器人,能接 AI 自動回覆,有什麼技術可以參考?」
Graph 導航過程:
Seed skills: {Telegram Bot, LLM API, Discord Bot}
Expanded skills (+4): {OpenClaw, Agent Architecture, Tool Calling, Node.js}
| 排名 | 純 Vector Search | Entity Graph Search |
|---|---|---|
| 1 | Telegram Bot API 整合入門 | Telegram Bot API 整合入門 |
| 2 | Discord Bot 建置指南 | 🎯 OpenClaw 安裝與設定 |
| 3 | LINE Bot 開發教學 | LLM API 整合:OpenAI + Claude |
| 4 | 聊天機器人 FAQ 設計 | 🎯 LangChain Agent 架構設計 |
| 5 | 對話式 UI 設計模式 | 🎯 Node.js Event Loop 深入理解 |
差異總結:
- OpenClaw 被拉出來了(Graph 路徑:
Telegram Bot → OpenClaw)——使用者根本不知道有這個完整的 AI Agent 參考實作! - LangChain Agent 架構出現了——Vector Search 完全找不到,是 Graph 從
Agent Architecture連過來的。 - 3 篇重複的 Bot 教學被擠掉,讓位給更實用的跨領域結果。
場景二:Unknown Unknowns(未知的未知)——真正的 Aha Moment
這是整篇文章最震撼的段落。
知識庫裡有三篇文章:
- Chunk A:「FastAPI 高併發框架深度指南」
- Chunk B:「Express.js 路由設計與中間件模式」
- Chunk C:「Hono 實戰:為 Edge Runtime 設計的極速微型 Web 框架」
注意:Chunk C 完全沒提到 Python 或 FastAPI。使用者根本不知道 "Hono" 這個關鍵字存在。
使用者提問:「我用 Python FastAPI 寫 REST API 很熟了,想部署到 Cloudflare Workers 降低延遲,有什麼框架推薦?」
純 Vector Search 的結果
[0.627] FastAPI 高併發框架深度指南 ← 使用者已經會了
[0.793] 從需求推導 FastAPI ← 還是 FastAPI
[0.802] Edge Runtime 全面解析 ← 概念性文章,沒推具體框架
[0.825] FastAPI 踩坑紀錄 ← 還是 FastAPI
[0.829] 從 Python 到 FastAPI:升級你的工具箱 ← 還是 Python 生態
Chunk C(Hono 實戰)完全沒出現。 5 篇裡有 3 篇是使用者已經會的 FastAPI。為什麼?因為 Hono 那篇文章的文字裡沒有 Python、FastAPI、REST API 這些詞——在向量空間中,它離 Query 太遠了。
Entity Graph Search 的結果
Seed skills: {FastAPI, Edge Runtime, Python}
Expanded skills (+3): {Hono, Cloudflare Workers, Node.js}
^^^^
Graph 自動發現:FastAPI ──0.71──> Hono
[0.627] FastAPI 高併發框架深度指南
[0.802] Edge Runtime 全面解析
[0.836] 🎯 Hono 實戰:為 Edge Runtime 設計的極速微型 Web 框架 ← 找到了!
Chunk C 出現了! Graph 做了一件 Vector Search 做不到的事——它沿著語意邊從 FastAPI 走到 Hono:
FastAPI ──0.71──> Hono(embedding 發現:都是輕量 Web 框架)
↓
skill "Hono" 裡的 chunks 被打撈出來
↓
Chunk C:Hono 實戰 🎯
系統主動搭了一座橋,把使用者「不知道關鍵字是什麼」的技術精準地遞到他面前。
這就是 Unknown Unknowns——你不知道自己不知道什麼,但 Graph 替你知道了。
Entity 從哪裡萃取出來?五大方法比較
要讓 Embedding 幫你建圖,首先你得有乾淨的 Entity (技能節點)。以下是從文件中提取 Entity 的五種主流方法:
| 方法 | 原理 | 代表工具 | 準確率 | 成本 |
|---|---|---|---|---|
| 1. LLM Prompting (最標準) | 直接請 LLM 提取 Entity + 關係描述 | GraphRAG Prompt、LangChain LLMGraphTransformer |
90%+ | 高 |
| 2. Rule-based | Regex / Pattern 白名單比對 | spaCy rule, NLTK chunker | 依名單 | 免費 |
| 3. Pipeline (NER+RE) | NER → 關係分類器 | spaCy NER pipeline、Stanford CoreNLP | ~80% | 中 |
| 4. Transformer (端到端) | BERT/GPT Fine-tune Joint ER | REBEL model、T5-RE | 95% | 高 (需 Train) |
| 5. Bootstrapping | 給 Seed Pairs 讓演算法自動擴展 | Snowball、Distant Supervision | 變異大 | 低 |
推薦策略:Hybrid(白名單 + LLM)
對於 200 個節點規模的技能圖譜,最穩的做法是:
- Regex 白名單:先準備核心技能清單,碰到名單內的就直接命中(雜訊 = 0)。
- LLM 輔助:遇到新領域的文章,用結構化輸出擴展字典:
# 使用 Instructor + Pydantic(比 LangChain 更穩定)
import instructor
from pydantic import BaseModel
from openai import OpenAI
class Relation(BaseModel):
source: str
target: str
relationship: str # "REQUIRES", "IMPLEMENTS", "SIMILAR_TO"
class GraphExtraction(BaseModel):
nodes: list[str]
edges: list[Relation]
client = instructor.from_openai(OpenAI())
graph_data = client.chat.completions.create(
model="gpt-4o",
response_model=GraphExtraction,
messages=[{"role": "user", "content": "FastAPI 是一個 Python 框架..."}]
)
標準流程:LLM Extract → Dedup → Embed → Graph。
框架選型指南:不只有 LangChain
LangChain 方便但不是唯一選擇。以下是四大替代方案:
| 方案 | 靈活性 | 最適合誰 |
|---|---|---|
| 原生 API + Instructor/Pydantic | ⭐⭐⭐ 最高 | 追求穩定輸出、想看清底層邏輯的開發者 |
| LangChain | ⭐⭐ 中等 | 快速原型、已經在用 LangChain 生態系的人 |
| Microsoft GraphRAG | ⭐ 低 (封裝重) | 超大文件、需要「全域社群摘要」的場景 |
| LlamaIndex Property Graph | ⭐⭐⭐ 高 | 需要深度整合圖庫(Neo4j、FalkorDB)的場景 |
- Instructor + Pydantic:直接利用 OpenAI 的 Structured Outputs,強制 JSON 格式輸出,極度穩定。
- Microsoft GraphRAG:微軟官方開源(
pip install graphrag),獨有 Community Detection 社群偵測功能。 - LlamaIndex:最新的 Property Graph Index 允許自定義提取邏輯,並支援多種圖形檢索算法。
- FalkorDB:專為 LLM 設計的高性能圖資料庫,內建
GRAPH.SEARCH搜尋。
業界實證:不只是我們在做
這套「透過 Embedding Similarity 自動連邊,再用 N-hop 做圖擴展」的技術,在業界已經有非常扎實的實踐:
- LinkedIn 的 Skill Graph:他們發現純 Vector Search 找人才時會漏掉「相似技能」(例如搜 Java 漏掉 Scala)。建立 Entity Graph 後,自動擴展到相鄰技能,大幅提升了召回率。
- Neo4j 的 Vector-Graph Hybrid Search:他們的 Demo 展示了如何透過 Embedding 找到某個零件後,自動沿圖尋找受影響的供應商——這與我們從
Telegram Bot聯想到OpenClaw的邏輯完全相同。 - LlamaIndex 的 Property Graph Index:允許系統自動提取 Entity 並根據語意相似度建邊,官方文檔明確指出這能解決「跨文件隱含關係」問題。
結論:從「段落檢索」進化到「概念導航」
| 維度 | 純 Vector Search | Entity Embedding Graph |
|---|---|---|
| 檢索對象 | Chunk(段落) | Entity(概念)→ 再定位 Chunk |
| 關聯發現 | 只有 Query 直接語意命中的 | 沿圖擴展,發現隱含連結 |
| Unknown Unknowns | ❌ 永遠找不到 | ✅ Graph 自動搭橋 |
| 重複率 | 高(同類 chunk 擠爆排名) | 低(不同領域的 chunk 被引入) |
| 建構成本 | 零(只存向量) | 低(Embedding 自動建邊) |
以前,你的 RAG 只會回覆你已經知道的東西。
現在,Entity Embedding Graph 會主動把你「不知道自己不知道」的答案遞到你面前。
這就是整個 CtxFST 系列從 CH1 到 CH10 一路走來,最終要到達的目的地。
📌 CtxFST 開源專案:github.com/ctxfst