CtxFST CH28 - 完整的導航比喻:Phase 1-7 各自對應什麼
CtxFST CH28:完整的導航比喻,Phase 1-7 各自是什麼
CH26 說 graph 是地圖,world state 是 GPS,planner 是導航。
但那只講了三層。整個架構有七層。如果要把比喻講完整,每一層到底對應導航系統的什麼?
這篇把它一次講清楚。然後回答一個關鍵的效率問題:如果地圖很大,系統會不會變慢?
完整對照
Phase 1-4(Graph) = 地圖資料庫
Phase 5 (Prompt Adapter) = 車上的顯示螢幕
Phase 6 (World State) = GPS 定位
Phase 7 (Planner) = 導航演算法
一層一層看。
Phase 1-4:地圖資料庫
Phase 1 到 Phase 4 做的事情,就是建地圖。
-
Phase 1(Parser) — 讀懂地圖的原始格式。把
.ctxfst.md解析成 entities、chunks、relations。就像把測量數據轉成道路資料。 -
Phase 2(Index) — 把道路資料存進資料庫。建立 entity table、chunk table、edge table。讓所有資料可以被查詢。
-
Phase 3(Entity-aware Retrieval) — 查地圖。你問「附近有加油站嗎?」,系統從資料庫裡找到匹配的 entity 和相關的 chunks。
-
Phase 4(Graph Expansion) — 沿著道路展開。找到加油站之後,再沿著 relation edges 看一看:這個加油站旁邊有什麼?它連接到哪條路?上游是什麼?
四個 phase 做完,你拿到的是一包叫 ContextPack 的東西。裡面有:
ContextPack {
matched_entities // 查到的地點
entity_chunks // 地點的詳細資料
expanded_entities // 附近的相關地點
graph_chunks // 沿路展開找到的資料
fused_chunks // 融合排序後的結果
}
這就是地圖查詢的結果。一大包原始資料。
Phase 5:車上的顯示螢幕
地圖資料庫可能有整個城市的每一條路、每一棟建築、每一個路口。但你的車上螢幕就那麼大。
Phase 5(Prompt Adapter)做的事是:決定現在該顯示什麼,塞不下的裁掉,然後格式化成駕駛看得懂的畫面。
螢幕大小 = Token Budget
LLM 的 context window 有限。就算模型支援 200K token,你也不會想把整個地圖資料庫塞進 prompt。因為:
- Token 要錢
- 資訊太多反而干擾 LLM 的注意力
- 大部分資料和當前問題無關
所以 Phase 5 有一個 token budget,就像螢幕有固定的像素數。超出 budget 的內容會被裁掉。
Priority = 什麼先顯示
不是所有資訊同等重要。Phase 5 用 priority 排序,確保最重要的先佔螢幕:
## Missing Preconditions (priority 100) ← 最重要:前方路斷了
## Active States (priority 90) ← 你目前在哪
## Relevant Entities (priority 80) ← 附近的重要地標
## Related Entities (Graph) (priority 60) ← 沿路展開的相關地點
## Supporting Chunks (priority 50) ← 補充資料
如果 token budget 不夠,從低 priority 開始砍。先犧牲「補充資料」,最後才犧牲「前方路斷了」。
沒有 Phase 5 會怎樣?
就像把整張城市地圖的原圖丟給駕駛。
資訊全在。但看不懂、來不及看、塞不進視野。
駕駛需要的不是完整的地圖,而是「現在這個路口該怎麼轉」。Phase 5 把地圖資料庫的查詢結果,壓縮成駕駛此刻需要的那一小塊視野。
Phase 6:GPS 定位
GPS 做一件事:告訴你,你在哪。
Phase 6(World State)也做一件事:告訴系統,這個 session 走到哪了。
WorldState {
active_states: ["state:resume-uploaded", "state:resume-parsed"]
completed_skills: ["upload-resume", "analyze-resume"]
blocked_by: []
goal: "state:report-generated"
}
四個欄位,完整描述「你在這裡」:
active_states— 目前滿足的條件(你在地圖上的位置)completed_skills— 走過的路(已經經過的路口)blocked_by— 前方封路(卡住的原因)goal— 目的地(你要去哪)
GPS 的特性
GPS 有幾個重要特性,Phase 6 完全對應:
即時更新。 你每走一步,GPS 座標就更新。Phase 6 也是——每次 skill 執行完成,applyPostconditions() 就更新 active_states 和 completed_skills。
不受地圖大小影響。 地球有多少條路,跟你的 GPS 定位速度無關。你的座標就是一個點。Phase 6 也是——不管 graph 有多少 entity,你的 session state 就是那幾十條記錄。
斷電不丟失。 GPS 掉線了重連,位置還在。Phase 6 的狀態存在 SQLite,session 關了再開,狀態還在。不像 LLM 的 context,session 一斷就全忘了。
不需要理解地圖。 GPS 不需要知道道路怎麼連接的、交通規則是什麼。它只負責「你在這裡」。Phase 6 也是——它不做 routing、不做 planning,只追蹤狀態。
Phase 7:導航演算法
導航演算法做的事是:根據你在哪(GPS)和你要去哪(目的地),在地圖上找出最佳路線,然後告訴你下一個路口怎麼轉。
Phase 7(Planner)也做同樣的事:
輸入:
WorldState(GPS) → 你在哪、做過什麼、被什麼卡住
Goal(目的地) → 你要達成什麼狀態
Graph(地圖) → entity 之間的 REQUIRES / LEADS_TO 關係
輸出:
NextAction(下一個路口)→ 現在該執行哪個 skill
導航不是把所有路都列出來
Google Maps 不會告訴你「從台北到高雄有 47,832 條可能的路線」。它只告訴你最佳的 1-3 條。
Phase 7 也是。它不是列出 graph 裡所有的 skill chain,而是:
- Goal-aware pruning — 只看和目標相關的路徑
- Completed skills 降權 — 走過的路不重複推薦
- Blocked-aware routing — 前方封路就繞道
- Relation-aware weighting —
REQUIRES比SIMILAR重要
最後輸出一個明確的建議:「下一步做 X,因為 Y 已完成,Z 條件已滿足。」
導航會即時重算
你開過頭了,導航會重新規劃路線。不會堅持原來的路線叫你回頭。
Phase 7 也是。每次 skill 執行完、state 更新後,planner 會重新評估。如果中間出了意外(某個步驟失敗、使用者改了目標),它會根據新的 state 重新 plan。
state 更新 → planner 重算 → 新的 next action
state 更新 → planner 重算 → 新的 next action
state 更新 → planner 重算 → 新的 next action
...
這個 loop 會一直跑到 goal 被滿足,或者使用者中斷。
合在一起看
┌─────────────────────────────────────────────┐
│ Phase 7: Planner(導航演算法) │
│ "下一個路口右轉" │
│ 輸入:GPS + 目的地 + 地圖 │
│ 輸出:下一步指令 │
├─────────────────────────────────────────────┤
│ Phase 6: World State(GPS) │
│ "你在這裡" │
│ 即時更新、斷電不丟、不受地圖大小影響 │
├─────────────────────────────────────────────┤
│ Phase 5: Prompt Adapter(顯示螢幕) │
│ "現在該看這些資訊" │
│ Token budget = 螢幕大小,priority = 顯示順序 │
├─────────────────────────────────────────────┤
│ Phase 1-4: Graph(地圖資料庫) │
│ "所有的路、所有的地點、所有的連接" │
│ Parser → Index → Retrieval → Expansion │
└─────────────────────────────────────────────┘
四層的關係:
- 地圖資料庫提供原始資料
- 顯示螢幕把原始資料壓縮成 LLM 看得懂的視野
- GPS追蹤你在哪
- 導航演算法根據你在哪 + 你要去哪,決定下一步
缺任何一層,系統都不完整:
- 沒有地圖 → 不知道世界長什麼樣
- 沒有螢幕 → 資訊太多,LLM 消化不了
- 沒有 GPS → 不知道走到哪了
- 沒有導航 → 知道地圖、知道位置,但不知道下一步怎麼走
地圖很大的時候,誰會變慢?
這是一個很直覺的擔心:如果 graph 有 10,000 個 entity、50,000 條 relation,效率撐得住嗎?
答案:要看是哪一層。
Phase 6(GPS):不受影響
World state 是 session-scoped 的。不管地圖有多大,你這個 session 的狀態就是那幾十條記錄。
-- checkPreconditions 的查詢
SELECT state_key FROM world_states
WHERE session_id = 'abc'
AND state_key IN ('state:resume-uploaded');
這是 primary key lookup。SQLite 在這種查詢上是微秒級的。就算 graph 有一百萬個 entity,這個查詢的速度完全不變。
Graph entities: 10,000 → checkPreconditions: 0.1ms
Graph entities: 100,000 → checkPreconditions: 0.1ms
Graph entities: 1,000,000 → checkPreconditions: 0.1ms
因為 checkPreconditions() 根本不碰 graph。它只碰 world_states 表,而那張表的大小只取決於你這個 session 做了多少事,和 graph 大小無關。
GPS 不會因為地球有更多道路就定位更慢。
Phase 7(導航):輕微影響,但有天然限制
Planner 做 skill chain search 時,理論上要在 graph 裡找路徑。如果全圖遍歷,確實會隨 graph 大小增長。
但實務上,planner 不會搜全圖。兩個天然限制:
Goal-scoped pruning。 Planner 只搜從「當前 active_states」到「goal」的可達路徑。大部分 entity 和你的目標無關,直接跳過。
全圖:10,000 entities
Goal-reachable subgraph:通常 < 50 entities
Relation type 過濾。 Planner 只沿 REQUIRES 和 LEADS_TO 走。SIMILAR 和其他語意關係不參與路徑搜尋。
全部 relations:50,000
Operational relations(REQUIRES / LEADS_TO):通常 < 500
過濾完之後,planner 實際遍歷的子圖非常小。
這就像導航不會搜索地球上所有的路。它只在你附近、通往目的地方向的道路裡搜。
Phase 3-4(地圖查詢):受影響最大
Graph retrieval 是真正受地圖大小影響的層。
Query → vector search 100K chunks → top-50 → graph expand 1-hop
Vector search 的時間隨 chunk 數量增長(雖然用 ANN index 可以壓到 sublinear)。Graph expansion 的時間隨 relation 密度增長。
但這是 retrieval 的經典問題,有成熟的解法:
- ANN index(HNSW、IVF)讓 vector search 不需要全掃
- Pre-filter by entity type 減少搜索空間
- 限制 expansion depth(只走 1-hop,不走 2-hop)
而且 Phase 3-4 的查詢發生在「理解問題」階段,不是「追蹤狀態」階段。查詢慢一點影響的是回應延遲,不是狀態正確性。
Phase 5(螢幕):不受影響
Phase 5 的輸入是 ContextPack,不是完整的 graph。不管 graph 有多大,ContextPack 的大小取決於 retrieval 回傳了多少結果(通常 top-50),不取決於 graph 總量。
Phase 5 只是對這 50 條結果做 priority 排序和 token budget 裁切。跟地圖大小無關。
效率總結
| 層 | 受地圖大小影響 | 原因 | 對使用者的影響 |
|---|---|---|---|
| Phase 1-4(地圖查詢) | 受影響 | Vector search + graph expansion 隨資料量增長 | 回應延遲增加 |
| Phase 5(螢幕) | 不受 | 輸入是固定大小的 ContextPack | 無 |
| Phase 6(GPS) | 不受 | Session-scoped,只查自己的狀態 | 無 |
| Phase 7(導航) | 輕微 | Goal-scoped pruning 大幅縮小搜索範圍 | 極端情況下路徑搜索稍慢 |
最慢的是地圖查詢(Phase 3-4),但那是 retrieval 的老問題,有成熟解法。World state 和 planner 基本不受影響。
一個完整的執行流程
把四層串起來,看一次完整的流程:
使用者問:"下一步該做什麼?"
Phase 3-4(查地圖)
query → entity match → graph expansion
→ ContextPack(找到 5 個相關 entity、20 個 chunks)
Phase 6(查 GPS)
db.getWorldState(sessionId)
→ active_states: [state:resume-uploaded, state:resume-parsed]
→ completed_skills: [upload-resume, analyze-resume]
→ goal: state:report-generated
Phase 5(顯示螢幕)
ContextPack + WorldState → 結構化 prompt
→ "Resume 已解析。Generate Report 的 preconditions 已滿足。"
→ token budget 裁切,priority 排序
Phase 7(導航演算法)
current state + goal + graph
→ Generate Report 的 preconditions 都在 active_states 裡
→ completed_skills 裡沒有 generate-report
→ 推薦:Generate Report
回應使用者:
"下一步:Generate Report。
原因:resume 已解析完成,這是通往 report-generated 的下一個步驟。"
四層各做各的事,合在一起就是一個完整的導航系統。
為什麼要把比喻講完整
不是因為比喻本身重要。而是因為比喻講完整之後,幾個常見的混淆就自動消失了:
「Phase 6 會不會很慢?」 — 不會。GPS 定位是 O(1),和地圖大小無關。
「Phase 5 為什麼不直接把 graph 塞進 prompt?」 — 因為螢幕就那麼大。你不會把整張城市地圖原圖丟給駕駛。
「Phase 7 需要搜全圖嗎?」 — 不需要。導航只搜你附近、通往目的地方向的路。
「沒有 Phase 6,Phase 7 能不能運作?」 — 不能。沒有 GPS 的導航不知道你在哪,就算有地圖也算不出路線。
「Phase 1-4 和 Phase 6-7 的關係是什麼?」 — 前者建地圖,後者用地圖。建地圖和用地圖是兩件不同的事,所以 graph layer 可以換(CH25),但 GPS 和導航要自己建。
收尾
一句話版本:
Phase 1-4 是地圖資料庫,Phase 5 是顯示螢幕,Phase 6 是 GPS,Phase 7 是導航演算法。地圖可以很大,但 GPS 定位永遠是一個點,導航只搜你附近的路。所以 world state 不會因為 graph 變大而變慢。
完整版本:
| Phase | 導航比喻 | 做的事 | 效率特性 |
|---|---|---|---|
| 1-4 | 地圖資料庫 | 建圖、索引、查詢、展開 | 隨資料量增長 |
| 5 | 顯示螢幕 | Priority 排序、token budget 裁切 | 固定大小輸入 |
| 6 | GPS | 追蹤 session 狀態 | O(1),不受地圖影響 |
| 7 | 導航演算法 | Goal-aware routing、next action | Goal-scoped,輕微影響 |
四層各有職責,各有效率特性,缺一不可。
這就是為什麼整個 Phase 1-7 的設計,不是七個功能的堆疊,而是一個導航系統的四個組件。每個組件解決一個不同的問題,合在一起才能讓 agent 從「有地圖」變成「會開車」。