CtxFST CH16 - 先別急著變聰明:為 Agent Loop 補上 End-to-End Test Suite
CtxFST CH16:先別急著變聰明,先為 Agent Loop 補上 End-to-End Test Suite
到了 CH15,CtxFST 的 world model runtime 已經長得很像一個真正的 agent system 了。
它已經有:
world_state.py管理 runtime stateskill_selector.py做 deterministic selectionagent_loop.py把 selection、execution、writeback 接成閉環goal-aware routing讓 selector 開始知道 goal 在哪裡
這時候很自然會想繼續往前衝,例如:
- relation-aware routing
- multi-step planning
- 更強的 graph weighting
- 更真實的 executor
但如果這時候直接衝下去,會有一個很大的風險:
你開始讓系統變聰明了,卻沒有一個穩定的方法知道它是不是還正常。
所以這一章的主題很簡單,也很工程:
在繼續升級 planner 之前,先把 agent loop 的 end-to-end 測試基線補起來。
為什麼這一章很重要?
因為前面幾章雖然已經把 runtime 組件都做出來了,但在沒有完整測試之前,你真正擁有的還比較像是:
- 一組可跑的 scripts
- 一些手動驗證過的流程
- 一個看起來已經很像產品的原型
這還不算真正穩。
尤其到了 CH15 之後,selector 已經不再只是簡單排序器,而是會開始參考:
current_subgraphgoal_proximitycompleted_skillsidempotent規則
這時候如果沒有自動化測試,你後面每改一次 routing,都很難確定自己到底是:
- 改進了 planner
- 還是默默破壞了 loop
所以這章最核心的觀點就是:
在 world model runtime 裡,test suite 不是附屬品,而是後續演化的基線。
這不是單元測試而已,而是 runtime contract 測試
這次新增的 tests/test_agent_loop.py 值得強調的一點是,它不是只在測某個函式有沒有回傳對的值。
它更像是在測:
整個 agent loop 的行為契約有沒有成立。
也就是說,它測的是這些更大的問題:
- goal 到達時會不會停?
- 沒 candidate 時會不會正確結束?
- failure 時會不會按規則停下來或繼續?
- state 會不會正確累積?
- graph writeback 會不會留下正確的
COMPLETEDedges? - idempotent 與 non-idempotent skill 會不會被正確重跑或跳過?
- goal-aware routing 會不會真的讓比較靠近目標的 skill 排前面?
這些都不是單一模組能回答的問題,而是整個 runtime 協作之後才會出現的行為。
所以我會把這份測試定義成:
CtxFSTworld model runtime 的第一套 end-to-end contract tests。
為什麼現在補測試,比 relation-aware routing 更急?
因為 relation-aware routing 當然很值得做,但在那之前你需要一個可靠的 baseline,否則你連「變更是否讓系統更好」都很難判斷。
目前的狀況其實很清楚:
已經有的
world_state.pyskill_selector.pyagent_loop.pytests/test-skillsgoal-aware routing
還缺的
- 自動化、可重複、可 assert 的 e2e 驗證
這裡的優先順序其實很工程常識:
- 先把今天的行為固定下來
- 再去做更複雜的 routing 升級
不然你會進入一種很危險的狀態:
- 每次改都覺得好像更聰明
- 但其實可能只是在破壞之前已經成立的 contract
所以這章不是保守,而是為後續加速鋪路。
這次測試到底覆蓋了什麼?
這份測試總共 20 個 cases,涵蓋 7 類核心行為。
1. Happy Path:三步 skill chain 正常到達 goal
這是最基本但也最重要的情境。
測試驗證:
analyze-resume -> match-skills -> generate-plan會按正確順序執行- 所有
postconditions會累積進active_states completed_skills會正確記錄- 最後 goal 會真的被達成
這組測試其實就是整個 world model loop 的黃金路徑。
如果這裡壞掉,後面一切都不用談了。
2. Goal Already Satisfied:一開始就已達成目標
這個 case 很容易被忽略,但很重要。
如果 goal 一開始就存在於 active_states,那 loop 應該:
- 立刻結束
iterations = 0- 不應該再執行任何 skill
這其實是在測 runtime 有沒有最基本的停止條件意識。
3. No Candidates:沒有任何可執行技能
這裡測兩種情況:
- preconditions 永遠不滿足
- skills list 本身是空的
兩種情況都應該正確回傳:
goal_reached = Falseterminated_reason = "no_candidates"
這很重要,因為真實系統裡常常不是失敗,而是 simply 沒路可走。
4. Stop On Failure / Continue On Failure
這一組在測 loop 對執行失敗的行為策略。
stop_on_failure=True
預設情況下:
- skill 執行失敗後應立即停止
terminated_reason = "execution_failure"- failed skill 要被記錄
stop_on_failure=False
在允許繼續的模式下:
- loop 可以跳過失敗 skill
- 改走其他可行技能
- 仍有機會達成 goal
這組測試很有價值,因為它證明 loop 已經不只是「一路成功才算成立」,而是已經開始具備 workflow 容錯語意。
5. Max Iterations:避免無限迴圈
world model runtime 最怕的其中一件事,就是 agent 一直重做同一件事。
這組測試驗證:
- 當 skill 可反覆執行但永遠到不了 goal 時
- loop 會在
max_iterations被正確終止
這是在保護 runtime,不讓它變成卡住的 state machine。
6. Graph Writeback:COMPLETED edge 是否正確寫回
這組測試非常關鍵,因為它直接對應 CH14 的核心主張。
測試驗證:
- skill 成功執行後,graph 真的會 append
COMPLETEDedges - failure 情況下不應該產生這些邊
- 邊的
properties例如timestamp、status也應該存在
這代表測試不只在驗 state,也在驗 graph execution trace。
7. Goal Proximity Routing 與 Idempotent Re-execution
這兩組測試是在保護最新加入的 planner 行為。
Goal proximity
驗證:
- 比較靠近 goal 的 skill 真的排更前面
- 如果 proximity 不可算,會正確 fallback
這是在保護 CH15 的成果。
Idempotent / non-idempotent
驗證:
idempotent=True的 skill 可以被重跑idempotent=False的 skill 完成後不應再重跑
這是在保護整個 selector 的行為契約。
20/20 全數通過,代表了什麼?
這次測試結果很乾淨:
20/20 passed
這個數字本身當然很好看,但我覺得更重要的是它代表了三件事。
1. 目前的 runtime backbone 已經相當穩
因為這次測的不是單點,而是跨三個檔案:
如果這三層之間的 contract 有任何明顯錯位,通常不太可能一次 20 個都過。
2. goal-aware routing 現在有 baseline 保護了
這點很重要。
因為在 CH15 之後,selector 的排序規則已經變得更聰明,也更複雜。
現在有了專門的測試 case 去保護:
- closer skill ranks first
- unknown proximity fallback 正常
這代表你接下來要做 relation-aware routing 時,不再是裸改。
3. CtxFST 的 agent loop 已經不再只是 demo
這是我最在意的一點。
當一個系統只有 demo,沒有測試時,它還比較像 concept proof。
但當它開始有:
- 正常路徑測試
- failure path 測試
- termination 測試
- writeback 測試
- routing 測試
它就開始比較像一個真的 runtime 了。
這份測試最有價值的地方,不是 coverage,而是 confidence
我覺得要特別說明的是,這份測試最有價值的地方,不只是數量,也不是單純追求 coverage 百分比。
真正的價值是:
它讓你之後敢改 selector、敢改 executor、敢改 graph writeback。
沒有這份測試時,每一次重構都很像在拆炸彈。
有了這份測試後,你至少知道:
- 哪些 contract 不能壞
- 哪些 failure mode 已經有被固定住
- 哪些行為是 v2 runtime 的既有承諾
這種 confidence,對後續架構演進比任何單次 feature 都重要。
這也讓下一步變得更清楚
有了這套測試之後,接下來最自然的兩步其實就很明確了。
1. Relation-Aware Routing
目前 _goal_hop_distances() 還是把所有 edge 當等權重處理。
下一步可以開始區分:
REQUIRESLEADS_TOSIMILARCOMPLETED
例如:
REQUIRES/LEADS_TO距離 = 1SIMILAR距離 = 3COMPLETED不參與 proximity path
這樣 selector 會更像在走因果路徑,而不是語意近鄰。
2. Multi-Step Planning
目前 selector 仍然是 greedy single-step。
未來可以升級成:
- 從當前 state 模擬 2 到 3 步 skill chain
- 看哪條路徑最有機會到達 goal
- 再回頭挑第一步 skill
這會讓系統從 router 進一步長成真正的 lookahead planner。
但重點是,現在你終於可以在有測試保護的情況下做這些事。
這章真正完成了什麼?
如果用一句話總結:
CH16不是讓CtxFST變得更聰明,而是讓它開始變得更可靠。
這句話非常重要。
因為很多系統死得不是因為功能太少,而是因為每往前加一層功能,就把前一層默默弄壞。
所以這章的價值不在於又多了一個 feature,而在於:
CtxFSTworld model runtime 第一次有了正式的 regression safety net。
這會直接改變整個專案接下來的演化速度與穩定性。
結語:會跑很重要,但可驗證才是真的開始成熟
如果回頭看這幾章的節奏:
CH13證明 loop 能跑CH14證明 loop 會寫回世界CH15證明 loop 開始有方向感CH16則補上最後一個工程上不可少的東西:可驗證性
所以這章最重要的結論,不是「多了 20 個 tests」。
真正的結論是:
從這一章開始,
CtxFST的 agent loop 不再只是可運作的原型,而是開始有條件成為可持續演化的 runtime。
因為一個世界模型真正成熟的前提,不只是它能表示世界、能改變世界、能朝目標前進。
還要包括:
你能穩定地驗證,它今天仍然按照你以為的方式運作。
這,就是 CH16 的意義。
參考實作
📌
CH13讓 loop 跑起來,CH14讓 loop 寫回世界,CH15讓 loop 朝 goal 前進,而CH16則讓這一切開始變得可驗證、可維護、可演進。
- ← Previous
CtxFST CH15 - Goal-Aware Skill Routing:讓 skill_selector.py 真的朝目標前進 - Next →
CtxFST CH17 - Relation-Aware Routing:讓 Selector 分得出因果邊和相似邊