想讓 AI 程式代理不重複同樣的錯誤,與其每次出錯都由人修改 CLAUDE.md,不如從工作階段紀錄中自動收集「使用者糾正的話」,分成兩條路使用。一條是把最近的糾正原樣顯示在該儲存庫下一個工作階段的第一個輸入(從第一次糾正就立刻學到);另一條是在同一個儲存庫中,同一種類型在不同日子出現兩次以上時,把它提升到提案帳本作為規則候選(固化成文字)。Claude Code 會把工作階段留成 JSON Lines(.jsonl),所以只要用正規表示式從使用者訊息中篩出「你漏掉了啦」「我不是說過不要做嗎」這類形式,再標上類型就可以了。
這篇文章是連載的第五篇,連載內容是把一個人使用的開發環境改成以 AI 代理為中心(AX,AI 轉型)的過程中,每天整理一個我做出來的機制。上一篇是hook 擋下沒有審查紀錄的提交的故事。
為什麼「出錯就修改 CLAUDE.md」還不夠?
代理一出錯,就要求它「為了不再重複這個錯誤,修改規則檔」,這個做法廣為人知,我一開始也是這樣做。有兩件事卡住了。
第一,修改的主體是人。糾正的話是在工作中很短地冒出來的。說完「不是那樣」「漏掉了啦」之後,就又回到工作,打開規則檔去修飾句子這件事就被拖延了。儲存庫一多,連要寫在哪個檔案都得先煩惱。
第二,一次糾正過的話,在那個工作階段結束後就消失了。模型在對話結束後什麼都不記得。隔天在同一個儲存庫開新的工作階段,它依同樣的假設犯了同樣的錯,而我又說了一次同樣的話。在成為規則之前的空白,才是問題所在。
糾正的話留在哪裡?
Claude Code 會把每個工作階段的所有訊息與工具呼叫,留在 ~/.claude/projects/<工作資料夾>/<工作階段 id>.jsonl。使用者訊息也原樣在裡面。所以只要依日期範圍掃過這些檔案,取出使用者訊息,再從中只挑出「糾正的話」的形式,就成了糾正案例。糾正之前代理做的工作(用什麼工具做了什麼)也在同一個檔案裡,所以也能一併留下「錯在哪裡」的要點。
一開始有一個只量測「糾正比率」的指標。比率能告訴你是不是變差了,卻不能告訴你錯在哪裡,無法成為修改指引的依據。所以在 2026-10-10,我另外做了一個直接把句子本身收集成案例的腳本。
哪些話算作「糾正」?
這裡花最久的是篩選的標準。像「再確認看看」「不是 ~ 嗎?」這類話,常常不是錯誤。我用手看了 30 天的樣本,有一半是這種再確認或懷疑。如果連這些也提升為規則,錯誤的規則就會堆積,讓代理變得更糟。所以我以精準度為優先,把依規則認定的類型縮減為四種。
TYPES = ( # 從前面開始取第一個符合的。以問號結尾時,只認定「違反指示」
("누락", re.compile(r"놓쳤|빠졌|빠뜨|빼먹|누락"), False),
("지시 위반", re.compile(r"말라(?:고|니까|니깐|했)|말랬|하지\s?말(?:라|랬|래|자)|하라고\s*[.!]*$"), True),
("전제 착오", re.compile(r"(?:그게|그거|이게)\s?아니|[가-힣A-Za-z0-9_.]+(?:이|가|게)\s?아니(?:고|라)(?=\s)"), False),
("결과 오류", re.compile(r"잘못(?:됐|되었|했|만들|계산|나왔)|틀렸|틀린|이상해|엉뚱|엉망"), False),
)
不符合規則的話,只收集成「其他」。在這之上又加了一些例外。「是我說錯了」是人這一邊的失誤,所以排除;「如果弄錯了」是假設,所以排除;像「嗯,不是那樣 …」這種先附和再說明的話也排除。其他工作階段傳來的訊息(以「[」開頭)與超過 200 字的長指示文,也不是糾正。「其他」之後會再向小型模型問一次,重新分到四種類型之一,但預設值是「不是糾正」。因為一個錯誤的糾正,比十個正確的糾正更有害。
收集到的案例用在哪裡?
有兩條路。
第一,顯示在下一個工作階段的第一個輸入。在工作階段的第一個提示進來時執行的 hook(UserPromptSubmit),會從該儲存庫最近 30 天的糾正中,只挑出類型已確定的,最多 4 筆,再加上審查代理或防護 hook 自己抓到的 2 個錯誤,只注入一次。用工作階段 id 留下標記檔,避免在同一個工作階段注入兩次。這樣一來,即使還沒成為規則,下一個工作階段從第一次糾正開始就已經知道了。
[最近的糾正] 這是使用者在這個儲存庫最近 30 天內糾正的話,
以及審查或自己找出的錯誤。在做出相同的假設、犯相同的錯誤之前,
先對照這份清單 — 引用作為依據時,要重新確認原文:
- 2026-10-20 遺漏:…
- 2026-10-18 違反指示:…
第二,重複出現時提升為規則候選。儲存庫與類型相同的案例,以「工作階段與日期都不同的單位」出現兩次以上,就會編號並提升到提案帳本。同一個工作階段、同一天的重複,只算一次,因為可能只是把同一個問題說了好幾次。完全沒有人的糾正、只累積了代理自己找出的東西的那一組,不提升而是保留。越是常呼叫審查的工作階段,沒有保留機制時提案就越是氾濫。帳本只寫儲存庫、類型、工作階段數與日期,原文只留在本機。
# 每天傍晚的自動化執行的一行 — 收集最近 4 天的案例,用模型重新分類「其他」,再把重複的類型提升到帳本
python3 scripts/corrections-collect.py --days 4 --llm --propose
# 查看被提升的那一組的案例(僅限本機畫面)
python3 scripts/corrections-collect.py --show <儲存庫>/<類型>
現在的一天有什麼不同?
這是依 2026-10-23 量測的值。從 2026-09-11 到 2026-10-21 收集到的案例有 363 筆,其中人糾正的話有 135 筆,審查代理、防護 hook、代理自己先發現的錯誤有 228 筆。依類型是:違反指示 80、結果錯誤 63、遺漏 48、前提錯誤 46,留在「其他」的有 126 筆。第一個輸入的注入,從 2026-10-11 起,在 141 個工作階段中進行了 297 次。提案帳本中提升了 32 個「糾正重複」項目,其中 27 個已被反映為規則句子或 hook。
改變的有兩件事。我不必再煩惱要把糾正的話寫在哪裡。工作中說一句話就繼續做,當天傍晚自動化就會收集起來,隔天該儲存庫的工作階段看過那句話之後才開始。而且寫進規則檔的句子,被限制在「重複出現兩次以上的東西」,所以因為一次的惱火而增加規則的情況變少了。也有代價。因為是以正規表示式為基準,「其他」是最大的一組,藏在裡面的真正糾正,要等到模型重新分類去抓出來。
常見問題
工作階段紀錄檔在哪裡,裡面有什麼?
Claude Code 會依工作資料夾,在 ~/.claude/projects/<資料夾名稱編碼後的值>/ 底下,為每個工作階段放一個 .jsonl 檔。一行是一則訊息,依序包含使用者訊息、代理訊息、工具呼叫與結果。本文的腳本只讀其中的使用者訊息與前一個工具呼叫。
糾正的原文可以推到 git 嗎?
不推。糾正的話裡會混入正在處理的資料、檔名,有時甚至是祕密值。案例檔只放在本機資料夾,含有祕密值或 SQL 的句子,不留原文,只留遮蔽的標記。要送到 git 的提案帳本,只寫儲存庫、類型、工作階段數與日期。
為什麼不一開始就讓模型全部分類?
因為精準度。如果錯誤的糾正成為規則,代理就會去遵守離譜的規則。所以我只先認定以規則為基礎的四種類型,模型只用來重新分類「其他」。即使如此,一個模型的判定,也要在另一個模型對同一個問題重新分類且兩者一致時,才以與規則判定相同的份量計算。不一致就退回「其他」。