說明: 本文由 AI(Claude)根據我的初始筆記與想法完成。
上一篇〈把計畫寫在票上〉談的是 agent 的狀態該存在哪裡——結論是抬到 issue tracker 的留言串上。但票上記的是階段與階段之間的交接:計畫、核准、PR、合併。一輪工作的內部怎麼跑,票管不到。
這篇談的就是那個內部。
而且要先講清楚,agent 最常出的錯,不是寫錯程式碼。是做了你沒要它做的事,然後告訴你做完了。
最直覺的防線,是讓 agent 每動一次手就問一次。這個做法會失敗,而且失敗得很安靜:問得太頻繁,人就開始無腦按 yes。那道閘門還在畫面上,但它已經不擋任何東西了。
真正的問題從來不是「問幾次」,而是被問的那一次,你手上有沒有足夠的資訊可以回答。
我現在的做法是把整輪切成八段,而其中只有第三段停下來等人:
1 估量 → 2 驗收條件 → 3 閘門〔等人〕→ 4 草圖
↓
8 收工 ← 7 重跑驗證 ← 6 合規審查 ← 5 實作迴圈
其餘七段沒有人在旁邊。它們是模型自己的紀律。
停下來的那一刻,吐出來的是四個欄位:
Size ▰▰▱ medium — 一行:範圍多廣、思考多深、多難還原
Acceptance:
- 一條可觀察的結果
Non-goals: 這一輪刻意不碰的東西
Changes: 動哪些檔案、意圖是什麼
四個欄位各有各的用處:
這四格真正的作用是:讓你在一次回答裡就把整輪講完。閘門之所以只有一道,是因為它值錢——資訊最完整的那一刻,你點一次頭。
問題來了。模型會忘記規則,尤其是便宜的模型。
而且忘記的方式很具體:寫在設定檔開頭的規則,到了第四十個回合,早就被推到脈絡的邊緣去了。 它沒有被違反,它只是不在視線裡了。一次載入的規則會隨對話衰減,這件事跟模型聰不聰明沒什麼關係。
所以我的解法很笨,但有效:每一回合重新注入。 每一則使用者訊息進來,hook 就把閘門的規格和審查的觸發條件重新貼回脈絡裡。規則不再是開場白,而是背景音。
這是整套設定裡最不起眼、卻最有效的一件事。
如果只能帶走一件事,我希望是這三條:
步驟長大了 ──→ 回到估量 (不是硬著頭皮做完)
驗證分歧了 ──→ 回到程式碼 (不是去改測試)
審查有發現 ──→ 回到程式碼,且在重跑之前
第一條:你當初給的那句話,涵蓋的是你當時看到的那份描述,不是它後來長成的樣子。範圍變寬、深度變深、還原變難——任何一項超出當初的估量,就該停下來重估一次,重新等你的話。做到一半才發現變成另一件事,卻仍拿著舊的許可繼續走,是我看過最常見的失控方式。
第二條:結果跟計畫不一致的時候,回到程式碼,不要回到測試。把測試改成通過,是所有捷徑裡最便宜也最致命的一條——它讓紅燈變綠,卻沒有讓任何東西變對。
第三條:審查發現的東西要在「重跑驗證」之前修完。順序不能顛倒,理由下一段就講。
「三則訊息之前測試是綠的」不算數。
證據必須跟它支撐的那句宣稱,來自同一個回合。 上一次綠燈之後你又改了東西,那次綠燈就不再描述現在這棵樹。沒有當回合的重跑就報完成,那不是事實,是穿著事實外衣的猜測。
順帶一個很小但很賺的坑:
set -o pipefail; flutter analyze 2>&1 | tail -6
沒有前面那句 set -o pipefail,shell 回報的是 tail 的離開狀態,而 tail 不管分析器抓到什麼都會成功。於是那個檢查會永遠顯示通過。這種東西一定要寫進規則裡,否則每隔一陣子就會再犯一次。
完成了什麼、延後了什麼、還不確定什麼。
「做完了」如果有東西被默默跳過,就是錯的。「測試通過」如果有測試被 skip、被標 pending、被 stub 掉,也是錯的。誠實的報告不好看,但使用者可以對一個被指出來的疑慮採取行動;對一個沒被說出口的空洞,他什麼也做不了。
這套的成本是真的:每一輪都要先寫一個 block。 小事情會覺得囉唆,所以留了三個出口——唯讀的回合直接豁免、用斜線指令叫起來的技能不再加外層閘門(叫它本身就是許可)、以及一句「就做吧」可以把整個 session 的閘門關掉。
更該說清楚的是另一件事:我沒辦法證明模型百分之百守得住這八段。 每回合注入只是讓它更難忘記,不是保證。所以下一步不是再加規則,而是去量它到底守了多少——那是另一篇要講的東西。
把閘門收斂成一道,讓人在資訊最完整的那一刻點一次頭;其餘七道交給紀律,再讓紀律每一回合重新注入,別指望它自己記得。剩下的偏移,靠那三條往回的邊收回來。