iT邦幫忙

2026 iThome 鐵人賽

DAY 9
0
AI Engineering

從 Claude Code 到無人值守:我的 AI Agent 工程化實戰系列 第 9 篇

Day 9|session 生命週期:從啟動到收尾誰在動

  • 分享至 

  • xImage
  •  

Day 9|session 生命週期:從啟動到收尾誰在動

有一支 hook 我寫完了:檔案在專案裡,4044 bytes,可執行,權限沒問題。它的職責是在派工前給一句政策建議,並把建議寫進派工稽核紀錄(我自己另外存了一份派工與用量的紀錄,下面簡稱紀錄資料庫)。本篇引用的數字都來自我自己機器上的這份紀錄,沒有公開,讀者無法重跑,只能當成單一案例看。

那張表目前有 564 筆,建議欄位只有 1 筆非空——而那 1 筆的派工標籤帶著明顯的測試字樣,研判是我自己手動探測寫進去的,不是它跑出來的。

所以:檔案存在、程式沒壞、也沒有任何錯誤訊息,但我盤點的時候它並沒有被註冊上去,也找不到任何它正常觸發過的證據。

Day 8 談的是攔截這件事本身。它留了一個缺口沒收:攔截規則自己是怎麼被掛上去的?如果掛載這一步可以悄悄不發生,那前一天寫的所有防線,都建立在一個沒人驗過的假設上。

事故:手改的設定活不過下一次啟動

先講另一個方向的意外,那件事讓我開始認真看啟動這一段。

前一篇結尾留下的那個前提——規則到底是怎麼被掛上去的——答案就在啟動這一段。每次啟動,啟動流程會把一份基準設定複製覆蓋各個設定檔,然後強制重設指定的 key,避免其他 session 曾經手改過的值殘留下來;另外有一段(這條是設定文件的自述,我這輪沒有重跑驗證)說啟動時會清空內建記憶機制的資料夾。也就是說,這層防線掛不掛得上,取決於那份基準裡有沒有它——而我曾經直接去改下游的設定檔想關掉某個當下很吵的行為,改完當輪有效,下次開起來又變回原樣。

換句話說,設定不是一份你可以就地編輯的狀態,它是每次啟動被重新生成的產物。要讓一個改動活下來,只能改進基準;改在下游,就只是幫自己爭取到這一輪。

這件事一開始很煩,後來我認為它是對的:所有 session 從同一個基準開始,行為才有可比性。代價是你必須知道基準在哪裡——而漏掛那個案例,正是有人(我)把檔案寫好了,卻沒有把它加進基準。

證據:掛點表、收尾順序,還有一個沒有掛點的時刻

session 生命週期泳道圖:啟動腳本、session 事件、hook、使用者四條泳道,橫軸為啟動到每輪到壓縮到收尾

同一條時間軸上四種角色——啟動腳本、session 事件、hook、使用者/主控——各自在做什麼。壓縮那一格沒有掛任何 hook,那不是省略,是實測結果。圖中「清空內建記憶目錄」一項為文件宣稱,我沒有實測。

我把生效中的掛點逐一列出來核對,一共 8 種事件有掛東西,以下列出其中 7 種。

依我自己的設定文件,啟動時掛一支,負責重建常駐指示、把規則注入進來;每次送出提示詞時再掛一支,把收尾規則補進去——注意這是每輪重注入,不是開場講一次就算數。這兩支的職責是文件上這樣寫的,我沒有另外驗證。工具呼叫前有 4 筆:1 筆是危險指令攔截,另外 3 筆是派工的自保鎖。工具呼叫後還有一筆攔截。subagent 起訖各掛一支記用量。

列這張表時我注意到一件事:同一支 hook 會出現在好幾個事件上。危險指令攔截掛在工具呼叫前、工具呼叫後,收尾那一串裡也有它;記用量那支掛在 subagent 起、subagent 訖,收尾也有。這不是重複貼上的疏失,是同一支程式在不同時點負責不同的事;但它也意味著「這支 hook 這一輪跑了幾次」不是一個直覺就答得出來的問題——要數,只能去翻掛點表。

收尾那一串最能看出設計意圖。一輪結束時 6 支依序跑:完成推播、危險指令攔截、未 review 變更提醒、模型降級提醒、逐輪用量記錄,最後才是強制收尾摘要。

順序不是隨便排的——收尾摘要那支負責刪掉痕跡檔,它必須排最後,否則後面的人就查不到本輪有沒有真的收過尾。責任鏈的先後,在這裡是靠陣列順序硬編出來的。

逐輪用量記錄那支是後來才加的(上線於 2026-09-05),插在模型降級提醒之後、強制收尾摘要之前——新增一支 hook 不只要決定它做什麼,還要決定它排在誰前面、誰後面。

然後是那個空格:這 8 種事件裡沒有「壓縮」。

我盤點這份設定時,沒有看到任何掛在壓縮事件上的機制會自動把規則和狀態補回去。開場注入過的東西,壓縮後還在不在,取決於摘要有沒有帶到;先前花了幾輪才問出來的狀態,壓縮後多半就沒了。

這一段沒有 hook 接手,責任直接落回主控(發號施令的那個對話本身)身上:得自己重問一次。我自己盤點的時候反覆看到同一個模式——持久儲存的東西不會自動出現在新的 context 裡,一律要主動查。持久,不等於自動可見。

解法:讓「有沒有跑過」變成看得到的事

兩個 hook 案例:左邊是檔案就位但未註冊,右邊是判斷依據被自身內容誤導而放行

兩次都不是 hook 寫錯,是「什麼時候被呼叫、憑什麼判定」錯了。

漏掛那個案例的修法其實很短:在啟動流程補一段,把它併進派工前的掛點。難的不是修,是發現。它不報錯、不留 log,唯一的徵狀是資料庫某個欄位一直是空的——如果我沒去數那 564 筆,這支 hook 可以永遠躺在那裡。

另一個案例方向相反:hook 有掛、每輪都跑,但判斷錯了。強制收尾摘要的第一版是去對話紀錄裡比對指令字串,來判斷本輪有沒有收過尾。問題出在我正在改收尾工具本身的那些輪次——那些字串會字面出現在改動內容和測試輸出裡,於是它判定「跑過了」,放行。恰好是最該攔的場合:正在動收尾機制,最需要確認它還有效。

修法是換掉判斷依據:不再讀對話紀錄的文字,改成看兩個痕跡檔——一個由收尾摘要寫、一個在記憶存檔成功後產生——並要求 900 秒內的新鮮度。回歸測試 25 個 case,把第一版那兩個失敗情境留著當釘子。

我的判讀是:這兩個案例的共通性,是hook 的正確性和 hook 的生效與否是兩回事。前者可以靠測試保證,後者只能靠掛點清單和資料落地去驗。所以現在多了一條檢查:新增一支 hook,除了跑它的測試,還要回頭查它該寫的東西有沒有真的寫進去。

責任鏈也因此被我拆成兩句話記著:誰負責寫入,誰就要留下可查的落點;誰負責清理,誰就得排在最後。 前半句擋的是漏掛——沒有落點,漏掛就是隱形的;後半句擋的是順序錯置——清理的人先跑,後面的人看到的就是一個已經被抹掉的現場。

新問題:那這條命活多久才對

生命週期到這裡算是清楚了:誰負責還原、誰負責注入、誰負責記錄、誰負責清理,每一格都有人。

但把整條軸拉開看,會看到另一件事。同一個 session 活得越久,每一輪要重付的 context 就越貴,而壓縮又不是免費的——壓縮之後還得自己補問一次狀態。這條命不是越長越划算。這是待驗的推測,我沒有對照組。

那什麼時候該讓它結束?中層經理(我把一整批工作交給一個中層的 subagent 統包,再由它去派下面的執行者)那一層,我的答案是跑完一輪就銷毀,明天講為什麼。


明日預告:Day 10|為什麼中層經理跑完一輪就結束


上一篇
Day 8|危險指令攔截與 hooks 為什麼會出現
下一篇
Day 10|為什麼中層經理跑完一輪就結束
系列文
從 Claude Code 到無人值守:我的 AI Agent 工程化實戰 共 13 篇
圖片
  熱門推薦
圖片
{{ item.channelVendor }} | {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言