為 AI 代理人臃腫的指令檔案進行無損瘦身
一個恆常載入的代理程式指令檔案增長到 33,000 個 token。本文將說明我們如何在不刪除任何一句話的情況下,將其縮減至一個 10KB 的路由中樞,並證明沒有遺失任何內容。
大多數 AI 編碼代理會在每個會話中載入一個專案指示檔。它一開始只是一頁的慣例,然後慢慢變成團隊的雜物抽屜:部署手冊、事件事後檢討、結構遷移筆記、前端怪癖。我們的檔案達到了 253 行和 67KB,大約 33,000 個 token,在代理讀取任何一行程式碼之前就已注入。這篇文章描述了將其縮減為一個 10KB 路由中心的重構過程、必須保留下來的安全規則,以及證明這次移動沒有遺失任何東西的驗證。塑造這一切的限制是:任何內容都不能被刪除,只能被移動或合併。
指令檔案為何會膨脹:一條沒有目標的規則
檔案的增長並非因為任何人的疏忽。而是源於一條聽起來很負責任的規則:「每當政策或設定變更時,立即更新指令檔案。」這條規則沒有路由機制。每個專案都將其操作細節添加到那個保證會被讀取的檔案中,因為那是未來代理程式唯一保證會查看的地方。
這是在您自己的設定中,值得辨識出的結構性原因。一個總是載入、只增不減的單一檔案,會單調地增長。沒有人有立場移除任何警告,因為每個警告都是透過過去的某個事件才贏得其一席之地。一年後,我們的表格儲存格裡有十個段落的歷史紀錄,而代理程式在每個會話中都為此支付了 token 成本,包括那些從未觸及這些段落所描述的子系統的會話。
浪費的不只是金錢。一個 33,000 token 的前導文會分散注意力。模型在長篇內容中,明顯會遺漏埋藏在中間的指令。我們最需要代理程式遵守的警告,正與數月前關於爬蟲怪癖的段落相互競爭。
按主題拆分,但保留停止閘門
解決方法顯而易見:將細節移至可隨需閱讀的主題文件中,並保持中樞文件精簡。我們最終產出了八份操作文件(部署、雲端資源、管理網站、授權、語音管道、資料收集、爬取、夜間批次處理),外加一份與遷移檔案本身放在一起的遷移 README。每份文件都完全擁有其領域。中樞文件則為每個主題保留一行說明和一個指標。
有兩項設計決策比檔案佈局更為重要。
首先,索引不能只是一份客氣的連結清單。有時間壓力的操作人員會掃過清單就開始寫程式。我們將其寫成一份條件式路由表:「修改授權或席位邏輯:您必須先閱讀 docs/ops/license.md。」這聽起來只是表面上的差異。但在實務上,以先決條件形式表達的指令會被遵守;而以參考資料形式表達的連結則會被跳過。我們還加了一行,告訴操作人員在不確定某個東西在哪裡時,應該在 docs 目錄中 grep 關鍵字,而不是閱讀整個檔案。
其次,這也是防止意外發生的部分:有些警告絕不能移動。如果「部署前執行待處理的結構遷移」這句話只存在於操作人員可能不會打開的文件中,那麼總有一天,操作人員會在沒有閱讀的情況下進行部署,而該警告所記錄的事件將會再次發生。我們在中樞文件裡一個名為「停止閘門」的標題下保留了七條這樣的警告,每一條都是一個摘要後的不變原則,其細節則委派給其他文件:
- 任何部署前都需檢查遷移狀態;若不清楚,切勿部署。回滾時應先還原映像檔;之後才考慮還原結構。
- 變更受控的執行期環境變數時,僅使用附加標記;「全部取代」的變體會無聲地清除不相關的設定。
- 絕不將使用者語音逐字稿、翻譯或秘密值寫入日誌、文件或提交中。
- 資料庫 IP 允許清單的標記會覆寫整個清單;應先讀取目前清單,再修補其聯集。
- 所收集音訊的保留與同意規則為不變原則;在接觸它們之前,請先閱讀資料文件。
- 針對生產儲存區的破壞性或覆寫式指令,需要先確認目標、衝擊範圍及回滾計畫。
- 絕不繞過、刪除或削弱付費端點的驗證、速率限制或試用期故障關閉邏輯。
我們使用的挑選規則是:如果忽略某個警告會導致服務中斷、資料遺失、合規性違規或客戶可見的故障,該警告就留在中樞文件;如果忽略它只會浪費一個下午的時間,就移出去。依據的是忽略的代價,而非使用頻率。
還有一行放在中樞文件的最頂端,在所有內容之上:當文件與程式碼不一致時,程式碼才是真相;更新文件,絕不要為了符合過時的文件而「修正」運作正常的程式碼。當操作人員發現矛盾並朝錯誤的方向解決時,一個拆分的文件系統會遭遇到最嚴重的失敗。
證明搬移動作沒有遺漏任何東西
「我們搬了所有東西,相信我們」並不是驗證。我們最初的計畫是用 grep 抽查幾個獨特的 token。一位審閱者指出了抽樣無法捕捉到的三種失敗模式:一個 token 可能存留下來,但其周圍的句子卻被掏空;即使文本從未離開舊檔案,新舊檔案的聯集也會通過檢查;以及文本可能被放到錯誤的文件中。抽樣只能證明樣本本身,別無其他。
我們改為執行以下全自動化的步驟:
首先,從編輯前所建立的原始檔案快照中,提取每一個行內程式碼片段。這意味著每一個用反引號引用的指令、旗標、路徑和識別碼。我們得到了 583 個獨特的片段。在經過空白字元正規化後,每一個片段都必須以固定字串(而非正規表示式)的形式,出現在新文件的聯集中的某處,因為像 $1::text[] 這樣的片段充滿了 regex 元字元。
其次,提取每一個包含警告標記的句子(也就是我們文件中使用的「禁止」、「必要」、「注意」等詞語,以及警告表情符號)。我們得到了 61 個句子。因為這次遷移是逐字搬移而非重寫,所以在正規化後,每個句子都必須一字不差地存在於某處。這就是讓檢查變得強大的訣竅:一個被移動的句子會連同其條件、嚴重性和原因一起被搬移。只有三個句子未能通過檢查,而每一個都有記錄在案的理由:一個與重複的句子合併了,一個被拆分到不同的表格列中,一個的內部交互參照被刻意重寫。任何沒有理由的失敗都會導致停止交付。
第三,將位元組核算作為異常偵測器,而非一道關卡。新檔案的總大小是原始檔案的 129%(標頭、指標和新的「停止閘門」章節增加了文本)。如果這個數字是 60%,我們就會去追查原因。我們刻意不將其設為通過/失敗的門檻,因為一次合法的去重複過程可能會縮小總大小,而一次錯誤的搬移即使保留了錯誤的文本,也可能通過門檻。
片段檢查立刻就證明了其價值。有一個句子,是關於網頁伺服器子指令與一個名稱相似的即時子指令有所區別的註記,在遷移地圖中被遺漏了。沒有人能在重複閱讀 67KB 的內容後,發現一個遺漏的子句。一個針對 583 個片段的固定字串比較在幾秒鐘內就捕捉到了這個問題,我們在交付前將其還原。
使用全新的代理程式對路由進行冒煙測試
文字驗證證明了內容的保留,但並不能證明新的佈局能夠正常運作。為此,我們給予一個全新的代理程式會話僅新的 10KB 中樞文件,並問了三個問題:在修改席位授權邏輯之前,你應該閱讀什麼?你如何部署管理員 Web 服務?以及,請清除生產環境中的快取。
前兩個問題的回答都路由到了正確的文件,並引用了遷移閘門。第三個問題才是值得我們為之設計的:代理程式拒絕執行任何操作,引用了破壞性工作的停止閘門,詢問是哪個環境以及哪個金鑰前綴,並提議進行範圍性刪除,而非完全清除。這種拒絕正是將停止閘門保留在永遠載入的檔案中的全部意義所在。如果你的冒煙測試無法讓代理程式拒絕某件事,那麼這個測試就太軟弱了。
保持精簡:修正規則,而不僅是檔案本身
最後一次的變更是為了防止在六個月後重蹈覆轍。原本的增長規則(「永遠更新指令檔案」)被一個路由規則所取代:常設規則、座標和停止閘門放在中樞(hub)裡,並有 120 行和 10KB 的硬性上限;操作細節、旗標和事件歷史記錄放在擁有該領域的主題文件中;決策理據放在設計日誌中;而程式碼本地的陷阱則放在其所保護的程式碼旁的註解中。當中樞超過上限時,必要的回應是將內容分割出去,而不是協商上限。
最後提供一些數字作為規模參考。中樞的大小從 67KB 降至 10KB 以下,在每次代理程式執行時,節省了約 28,000 個 token 的會話上下文。驗證套件大約是 40 行的 Python 和 shell 程式碼。整個遷移過程,包括三輪審查和驗證工具的開發,花費了一天的工作時間。如果您的代理程式指令檔案已超過數千個 token 且持續增長,這種瘦身方式成本低廉,節省的 token 會每日複利,並且透過範圍級別的驗證,您不必在小檔案和安全檔案之間做出選擇。