實跑優先於紙上排序

依照計畫,stage 路由硬化排在生態級 episode 實跑之後,因為理論上路由「應該差不多夠用」。 第一個真實 episode 跑完,5 步全部命中 code stage,試圖連線 8081(code server), 但那個 port 當時根本沒開。

追查後找到根因:模型在子任務拆解時把「查閱知識圖中關於 graphify_tools 的依賴」 改寫成「查閱與 graphify_tools 相關的程式碼」。 「程式碼」三個字被 code stage 關鍵字匹配器抓到,graph 的語境蒸發。 「資訊性邊界」——理論上可以正常工作但沒有硬性測試——在真實負載下變成硬故障。

路由硬化:兩條修法都是通則

第一條修法:把 code 意圖關鍵字裡的名詞「程式」剔除,只留動詞(寫、建立、修改……) 和兩個常見委派動詞(「編寫」「構建」)——這是從實跑 log 觀察到模型拆解時愛用的動詞。 名詞改觸發很容易誤命中,動詞觸發意圖明確。

第二條修法:新增 goal-level graph fallback—— 如果子任務沒有明確的寫碼意圖,但長期目標欄位含有 graph 相關關鍵字, 就路由到 graph stage。這是治「模型改寫吃掉關鍵字」的通則, 不是針對這次「程式碼」字眼的窄修補。

修完後新增守門腳本 verify_stage_routing.py,12/12 通過, 含這次實跑失敗的逐字回歸案。全套重跑:bridge 5/5、graph stage 7/7、 feedback 11/11、delegation 2/2。原本被 False 的資訊性「全迴圈自然路由 code stage」翻 True。

4 個跨 repo episode,記憶真實回寫

路由修好後,4 個跨 repo 真實 episode 全數完成,記憶回寫 ~/.graphify/memoryLESSONS.md 生成——路徑派生從「已斷言」變「已實跑」。 實跑同時暴露了引用降噪的必要:_cited_nodes 裡有三種噪音。

第一種:子字串比對("gemma" 命中 "gemma4_e4b_agent_runtime")→ 改用 token 等值比對。 第二種:rationale/doc 節點(label 是中文長句)混進引用 → 只收 file_type=code。 第三種:跨 repo 撞名(maintypes 在 5.7k 節點的 global 圖到處都是)→ 單 token 短於 6 字元一律排除。 修後 CITE-FILTER 從 4 筆噪音縮到 1 筆精準,LESSONS 裡的 Tentative 欄全為真實符號。

週保養排程:自舉的最後一塊拼圖

加了一個 launchd 排程 com.nomad.graphify-global-refresh, 每週一 08:10 自動執行 global graph 更新。 關鍵坑:wrapper script 必須把 ~/.local/bin 加進 PATH, 因為 graphify 是透過 uv tool 安裝的,launchd 的預設 PATH 找不到。

排程實跑 log 顯示 agent-kit 圖從 648 升到 654 節點—— 本日新寫的程式碼被自動收錄。這是週保養排程「永遠跟上現碼」的活證明。

關鍵教訓

實跑優先於紙上排序:「應該差不多夠用」的邊界在真實負載下可以直接變成硬故障。先跑、後排序,不要等到序列清完再跑。

泛化修法勝過窄修補:「剔除名詞意圖關鍵字」和「goal-level fallback」是通則,不是針對「程式碼」三個字的補丁。通則在未見過的輸入也成立;窄修補只修已見過的失敗。

引用噪音的三個來源要逐一封堵:子字串比對、非 code 節點混入、跨 repo 撞名——每一種都需要不同的過濾策略,不能用同一條規則解決。

守門腳本要含實跑失敗的逐字案:從失敗輸入直接加進測試集,才能確保同一個輸入不會再次失敗。

launchd PATH 和互動 shell PATH 不同:uv tool 裝的 CLI 在 ~/.local/bin,launchd 找不到;wrapper 必須顯式設定。

來源:個人開發日誌 2026-07-19(下午)· Graphify agent-kit · commits 0c31c90 / e2eb080 · verify_stage_routing 12/12 · 4 跨 repo episode 記憶全回寫