實跑優先於紙上排序
依照計畫,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/memory,
LESSONS.md 生成——路徑派生從「已斷言」變「已實跑」。
實跑同時暴露了引用降噪的必要:_cited_nodes 裡有三種噪音。
第一種:子字串比對("gemma" 命中 "gemma4_e4b_agent_runtime")→ 改用 token 等值比對。
第二種:rationale/doc 節點(label 是中文長句)混進引用 → 只收 file_type=code。
第三種:跨 repo 撞名(main、types 在 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 必須顯式設定。