247,694 條指令的生命週期攤開來看,一個模式很扎眼:指令活得越久,被刪掉的機率反而越低——直到有人受不了,把整份 CLAUDE.md 砍掉重寫。
CLAUDE.md 為什麼只會變長
如果你維護過餵給 coding agent 的規則檔——CLAUDE.md、.cursorrules,或任何一份寫給 agent 看的指令清單——大概都遇過同一種漂移:新規則一直加進去,舊規則沒人敢刪。8 月 11 日掛上 arXiv 的一篇論文,把這種漂移量化到了小數點。作者 Kushal Chakrabarti 追蹤了 1,867 個 GitHub repo,發現這些檔案不只是「偶爾會變大」,而是只會變大,直到 repo 退休,或者有人把整份檔案重寫掉為止。乍看是老問題「沒人有空清乾淨」,但論文用一套刪除風險的存活分析,把最直覺的幾個解釋一個個推翻。這篇論文只有一位作者,8 月 11 日才掛上 arXiv,還沒經過同儕審查,第 3 節的資料是觀察性的,只能建立相關;真正的因果證據要留到第 4 節的受控實驗才出現。
一次 commit 淨增 4.9 條指令的檔案
先講清楚論文怎麼算「指令」。作者把檔案裡的文字分成兩類:一個子句層級、可執行的祈使句算一條指令,其他說明、範例、標題都歸進 payload,不計入統計。用這個定義去掃 1,867 個 repo,找出 1,801 個至少有兩個版本的檔案,追蹤了 299,440 次版本間轉換,從中萃取出 247,694 條完整的「指令生命週期」——每一條指令從第一次出現到被刪除或至今仍存在的完整記錄。
這個操作型定義決定了整份統計站不站得住腳。如果指令的定義太寬鬆,連範例、註解都算進去,成長數字會被灌水;論文把統計範圍收斂在「子句層級、可執行的祈使句」,代價是可能漏掉一些用比較迂迴的方式表達的規則,但換來的是每一條被算進去的東西,都是真的會影響 agent 行為的規則,而不是說明文字。
結果是整個生命週期成長 226%,略多於三倍;平均下來,每次 commit 淨增 4.9 條指令。「淨增」已經扣掉了同一次 commit 裡刪掉的那些,也就是說新增的速度長期贏過刪除的速度。檔案唯一會變小的時刻,是有人把它整份重寫;但重寫前指令數是持續上升的,重寫那一刻砍到只剩重寫前的 59.5%,接下來 10 次 commit 裡又幾乎回到 91.5%——重寫之後的成長率甚至比重寫前更快,每次 commit 平均多長 4.9%,重寫前只有 4.1%。重寫不是解法,只是把時鐘撥回去,然後跑得更快。
這不只是檔案衛生問題。指令檔會被塞進每一次任務的 context 裡,變成 agent 執行時的背景設定——檔案越肥,agent 要從越多條指令裡分辨哪些跟眼前任務相關,論文後面談到的雜訊指令會拖累正確指令的遵循率,說的正是這個代價的具體數字。某種意義上,這是技術債的一個特化版本——差別在於技術債通常有工具追蹤(TODO、issue、linter 警告),指令檔的「債」卻沒有任何形式的標記,它就混在其他規則裡,看起來跟昨天新增的規則一樣正常。
| 指標 | 數值 |
|---|---|
| 追蹤 repo 數 | 1,867 |
| 多版本檔案數 | 1,801 |
| 版本間轉換次數 | 299,440 |
| 指令生命週期數 | 247,694 |
| 生命週期成長幅度 | +226% |
| 每次 commit 淨增指令數 | +4.9 |
| 刪除風險 log-hazard 斜率 | -0.032/commit |
| comment 介入後 excess(T=51) | +211.3% → +1.4% |
| WildIFEval 指令遵循率(3 輪維護) | 50.4% → 62.0%(+23.1%) |
| 重寫瞬間指令數剩餘比例 | 59.5% |
| 重寫後 10 次 commit 內恢復比例 | 91.5% |
| 重寫後 vs 重寫前每 commit 成長率 | 4.9% vs 4.1% |
對照著看更有感覺:如果把 247,694 條指令生命週期換算回一份份檔案,論文報告的中位數規模是 39 條指令——不是一份精簡的清單,而是幾十條規則疊在一起,彼此還可能互相牽動。等到後面談刪除成本的時候,這個 39 條的中位數會再出現一次,因為它決定了「窮舉子集合」這件事到底有多不切實際。
真正有意思的不是「檔案在長大」,而是為什麼它停不下來。作者對每條指令做了存活分析(survival analysis),把「這條指令會不會在下一次 commit 被刪掉」當成一個隨年齡變化的風險(hazard)。結果算出來的 log-hazard 斜率是 -0.032/commit——年齡每增加一個 commit,被刪掉的相對機率就再往下掉一截。換算成曲線大概是這樣:一條指令活到第 50 次 commit 時,相對被刪機率只剩剛出生時的兩成左右。
拖動滑桿看不同 commit 齡的相對刪除機率 · 曲線換算自 log-hazard 斜率 -0.032/commit
以這個速度粗略推算:一份從 10 條指令起步的新專案,只要新增持續小幅贏過刪除,不用太多次 commit 就可能逼近論文報告的 39 條中位數規模——複利不需要哪一次特別誇張的 commit,只要「贏一點點」持續發生。這是把論文的平均速度往前推算的說法,不是論文本身給出的具體案例。
問題來了:為什麼指令活得越久,越沒人敢刪?論文給了幾個直覺解釋,一一拿資料去撞。
指令只是過時了?
最直覺的猜法是「過時論」:codebase 會演進,某條指令原本是為了擋一個特定 bug,等那個 bug 相關的程式碼被重構掉,這條指令自然該被清掉。如果這個理論成立,年齡應該是刪除的風險因子——指令越老,跟現在的程式碼對不上的機率越高,被刪的機率應該隨年齡上升。
過時論的吸引力在於它符合大多數人對維護工作的直覺——程式碼會過時,文件也會過時,指令沒理由是例外。如果 CLAUDE.md 是一份自然語言寫成的技術文件,這個類比甚至有點道理。但論文選擇用可觀察的刪除行為去檢驗它,而不是停在類比層次。
論文把這個預測寫得很直白:過時論和「記憶流失」論對 hazard 隨年齡變化的方向給出完全相反的預測,前者預測 hazard 隨年齡上升,後者預測它下降。實測結果是後者——log-hazard 斜率是負的(-0.032/commit),年齡越大,被刪的相對機率越低,方向跟過時論完全相反。單看這一個係數,過時論就站不住腳。
只是沒人管,純屬疏忽?
退一步想,也許根本不需要一個精緻的機制——單純是沒人有時間清理,規則堆著堆著就沒人碰了。這個「疏忽論」的可證偽預測也很明確:如果只是隨機沒空管,hazard 隨年齡下降的速度不該因為維護者人數而系統性不同——一個人維護和五個人接力維護,理論上都是同樣的疏忽機率。
論文剛好測了這個交乘效果:多作者維護的檔案裡,hazard 隨年齡下降的速度明顯更陡,交乘項係數是 -0.021(z=-11.7,統計上非常顯著)。如果只是隨機沒空清,作者人數不該讓下降曲線系統性變陡;但它確實變陡了,而且陡得很一致。這指向一個更具體的機制:不是沒人管,而是接手的人,比起原作者,更沒有資格判斷「這條規則現在還需要嗎」。
這個交乘項係數在統計上代表什麼:如果把「維護者人數」和「指令年齡」兩個變數分開看,各自對刪除機率都有主效應;但論文額外估計了兩者相乘的交乘項,結果顯著為負,意味著「年齡拖慢刪除」這件事在多作者檔案裡被放大了,不是兩個獨立效應疊加而已。這正是純粹疏忽論解釋不了的地方——疏忽不該挑人數去加重。
論文的樣本本身就是 GitHub 上的公開 repo,貢獻者來去更頻繁——如果這個機制成立,開源專案照理會比穩定的內部團隊更容易中招,這是合理的延伸,但論文沒有直接比較兩種情境。
預測:指令會隨 codebase 演進失去對應,年齡越大越該被刪,hazard 應該隨年齡上升。
資料:實測 log-hazard 斜率是負的(-0.032/commit)——年齡越大反而越少被刪,方向相反。
結論:不成立。
預測:如果只是單純沒空清、隨機疏忽,hazard 隨年齡下降的速度不該系統性受維護者人數影響。
資料:多作者維護的檔案裡,這個下降明顯更陡(交乘項係數 -0.021,z=-11.7)。
結論:疏忽論解釋不了這個交乘效果,指向更具體的機制。
預測:如果理由跟著寫下它的人一起流失,應該同時看到「hazard 隨年齡下降」與「多作者檔案下降更快」兩個現象。
資料:兩者都對上了——這是論文認定成立的機制,也是後續介入實驗要驗證的假說。
結論:目前證據最一致的解釋。
真正的原因:刪除的代價是 2 的 |D| 次方
論文替這個機制取了個名字:catastrophic remembering,故意跟 continual learning 領域的 catastrophic forgetting 對著喊。作者的說法是:在 catastrophic forgetting 底下,梯度學習器覆蓋了它該保留的東西;在 catastrophic remembering 底下,維護者保留了他該覆寫掉的東西。兩者是同一種失衡的鏡像,一個丟了該記的,一個記了該丟的。
機制怎麼運作:一份指令檔通常是多人接力編輯的,原作者知道「為什麼加這條」——可能是擋某個具體的 regression,可能是回應某次 code review 的意見——但這個理由通常不會寫進檔案,只存在那個人的腦子裡。等下一個人接手,理由已經跟著人一起流失了。理由沒了,刪除就變成一件危險的事:後繼維護者沒辦法確定這條規則是不是還在保護某個他不知道的邊界情況。結果是新增的速度長期贏過刪除的速度,指令只會越堆越多。
論文說的隱性理由,不是什麼玄妙的概念——就是那句沒人寫下來的「因為上次 staging 環境掛掉是這個原因」。這句話留在原作者腦子裡的時候完全免費,一旦這個人離職、換組,或者只是隔了半年忘記細節,同樣的資訊要重新問出來,成本就從一句話變成一次考古。
指數級的驗證成本不是誇飾。一份指令檔裡任兩條規則都可能互相牽動——刪掉第 12 條,會不會讓第 3 條原本被它擋住的邊界情況重新冒出來?要誠實回答這個問題,理論上得把現有指令的每一種子集合組合都推演一遍,確認少了這一條之後,整體行為還是對的。指令數每多一條,需要考慮的組合就翻倍,這正是「代價是 2 的 |D| 次方」的來源。多作者維護的檔案下降得更陡(見上一節的交乘項係數),也剛好對上這個解釋:接手的人越多,能完整重建這些組合關係的人就越少,於是集體選擇最安全的動作——什麼都不刪。
論文把這個直覺寫成一個複雜度論證:記錄一條指令的隱性理由(也就是在旁邊寫一句「為什麼」),成本是 O(1)——當下多打幾個字而已。但事後想從整份 instruction論文定義:一個子句層級、可執行的祈使句,其他文字算 payload,不計入指令統計。 集合裡,反推「這條理由是什麼、刪了會不會連動壞掉某個沒寫出來的邊界情況」,成本是 O(2^|D|)——要驗證的是這條指令跟現有 |D| 條指令之間所有可能的依賴子集合。理論上的 D*論文定義:讓約束滿足程度最大化的最小指令集合,即「理論最優」的指令集合。 ——也就是真正必要、拿掉不會出錯的最小指令集合——在一般情況下根本算不出來。這個不對稱本身,就是 excess論文定義:目前指令數除以 D* 再減一,衡量「超出最優集合多少比例」。 只增不減的引擎:加一條指令幾乎零成本,安全刪掉一條的驗證成本卻是指數級的。
從觀察資料到受控實驗,論文其實用了兩把不同的尺——excess 這個比例,要靠已知的最優指令集合 D* 才算得出來,而 D* 在真實世界裡是不可計算的;第 3 節能測的是真實 GitHub 資料裡的指令數成長和刪除風險,不是 excess。這正是第 4 節要把 IFEval 反過來、人工造出「D* 已知」的可驗證世界的原因——只有在那個受控環境裡,excess 才有辦法被直接測量。
換成團隊日常的說法:與其把 CLAUDE.md 當成一份規則清單去維護,不如把它當成一份帶著決策記錄的清單——每條規則後面掛著「為什麼」,不是寫給 agent 看,是寫給下一個接手的人看的。
把理由寫進 comment,excess 從 +211.3% 掉到 +1.4%
光靠相關性沒辦法證明因果,論文因此設計了一個受控實驗:把標準的指令遵循基準 IFEval「反過來」用。正常情況下 IFEval 是拿一組已知指令去測 agent 遵不遵守;論文把指令本身藏起來,只留下背後的驗證器(verifier)當作隱性的約束集合,讓模擬的維護者只憑一個任務目標和「被審查過的回饋」去重建這份指令檔——這樣一來,真正的最優指令集合 D* 是已知的,可以精確算出每一步的 excess 是多少。介入手段很簡單:讓一部分維護者在每條指令旁邊寫一句 comment,把「為什麼加這條」的隱性理由記下來;另一部分維護者不寫。
這個反轉的巧妙之處在於:正常的 benchmark 沒辦法告訴你「最優指令集合」長什麼樣,因為你不知道 agent 真正需要哪些指令才能通過測試;把指令藏起來、只留下驗證器,等於把答案卷倒過來出題——維護者能不能在多輪修改後重建出跟驗證器完全對齊的最小指令集合,變成一個可以精確測量的量,而不是憑印象判斷。
跑到第 51 步時,沒有 comment 的那組指令集合來到 excess +211.3%(±105.3 個百分點,還在往上走)——指令數已經是最優值的三倍多;有 comment 的那組則收斂下來,貼著最優值落在 +1.4%。換算下來,寫 comment 這一個習慣讓最終的多餘指令少了 99.3%。這不是相關性,是同一套模擬環境、同一組任務目標下的直接對照。
接下來作者把同樣的反轉手法套到更接近真實場景的 WildIFEval 上,這次用真人可能寫出的指令,而不是程式化的驗證器。經過 3 輪維護,有 comment 那組的指令滿足率從 50.4% 提升到 62.0%,絕對值差 11.6 個百分點(95% 信賴區間 5.1 到 18.3pp),換算成相對提升是 23.1%。寫理由不只是讓檔案變瘦,agent 實際遵循指令的表現也真的變好了。
這裡有一個容易被忽略的細節:實驗裡混進提示詞的雜訊指令——從其他題目裡隨機抽來、跟眼前任務無關的指令——不是安靜地待在檔案裡而已,它們會讓 agent 連提示詞裡本來就該遵循的那些指令都做不好。在 64 個 world、K=1、G=16 的條件下,正確率從沒有雜訊時的 65.6% 掉到 41.5%,差距是 24.1 個百分點。多餘的指令不是中性的背景雜音,它會實際擠壓 agent 的注意力。
這個結果值得留一個保留:受控實驗驗證的規模是 2-3 條指令的最優集合,而真實 CLAUDE.md 檔案的中位數指令數是 39 條——機制在小規模下成立,不代表在 39 條規則彼此纏繞的真實檔案裡效果一樣乾淨。論文對工具開發者的建議因此也是保守的:coding agent 工具可以提供 comment 語法,讓一條指令的隱性理由能傳到下一個維護者手上,但這仍然是「可以」,不是已經驗證過在真實規模下同樣有效的定論。
Next time:下次看到一份只會變長的設定檔、prompt 或規則清單,先別問「這條還有用嗎」——先問「刪掉它、確認不會引發回歸的驗證成本有多高」。如果答案接近窮舉整個集合的子集合,這份文件就會一直長下去,除非有人把當初寫下這條規則的理由,跟規則本身一起留下來。這篇論文提供的不是一個工具,而是一個問法——把「刪除很危險」翻譯成「刪除的驗證成本有多高」,問題就從一種說不清的擔心,變成可以被觀察、被降低的工程指標。