你實際使用哪些 AI 代理程式命令?稽核它們
自訂代理程式指令累積的速度比您淘汰它們的速度還快。請從工作階段記錄中計算實際使用量,然後停用無效的指令,而不刪除它們。
你為編碼代理程式所寫的每個自訂命令,起初都是個好主意。寫了二十幾個之後,那個資料夾就成了博物館。我統計了數千份會話紀錄中的實際調用次數,發現我的一半命令在兩個月內一次都沒被調用過。清理工作很簡單。但要正確解讀這些數字,卻非易事。
指令會累積,使用量卻不會
代理程式指令是一套封裝好的指令集:一個包含定義檔的資料夾,當你輸入斜線名稱時,代理程式會載入它。撰寫一個指令需要花費一個下午的時間。淘汰一個指令則不需任何成本,所以沒有人會這麼做。
這堆指令不僅僅是雜亂無章。每個定義都會在每次會話中,將其名稱和描述提供給代理程式的上下文,而擁擠的命名空間會導致模型選錯工具。但真正的成本以另一種形式顯現。我的 26 個指令並不是 26 個相同的東西。它們是三種不同類型的物件,放在同一個扁平的資料夾中。
從會話日誌計數,而非記憶體
代理程式會將對話記錄寫入磁碟,通常每個會話一個 JSON-per-line 檔案。模型所做的每一次工具呼叫都以結構化區塊的形式記錄在其中。該檔案樹是一個沒人想到要去查詢的使用情況資料庫。
命令的調用會以工具使用區塊的形式出現,其輸入中包含命令名稱。對整個樹狀結構執行一次 grep,就能得到一個排序列表:
# adjust the JSON shape to match your agent's transcript format
rg -o -I '"name":"<ToolName>","input":\{"<field>":"([^"]+)"' -r '$1' \
--glob '*.jsonl' "$TRANSCRIPT_DIR" | sort | uniq -c | sort -rn
匹配區塊,而非單純的名稱。對指令字串進行寬鬆的 grep 搜尋,也會捕捉到每次該名稱僅僅是在文章中被提及的情況,這會最大程度地灌水那些不常用的指令。這與你想要的結果正好相反。
最重要的一個步驟,就是按時間來分割計數。執行兩次,一次針對所有內容,另一次則針對過去 60 天內動過的檔案:
find "$TRANSCRIPT_DIR" -name '*.jsonl' -mtime -60 > recent.txt
rg -o -I '"name":"<ToolName>","input":\{"<field>":"([^"]+)"' -r '$1' $(cat recent.txt) \
| sort | uniq -c | sort -rn
累計總數會騙人。它們會將你去年春天大量使用、六月就棄用的指令,與你今天早上才執行的指令,歸類在同一個類別中。在我的資料中,這兩個欄位在大約三分之一的清單上有所出入。某個指令的累計呼叫次數有數百次,但近期一次也沒有。另一個指令的累計呼叫次數僅有十幾次,但每週仍在使用。
零次呼叫不一定代表無用
我的三個指令顯示呼叫次數趨近於零,卻是整組檔案中負載最重的部分。
它們是一個更大型管線指令的主體。該管線並不會將它們作為工具來呼叫。它會從磁碟讀取其定義檔,並遵循其中的步驟。從日誌來看,那三個指令看起來像是被棄用了。一旦刪除它們,管線就會在執行期間中斷。
這是一個常見的陷阱。使用情況的遙測資料只看得到你檢測工具所知的進入點。透過檔案讀取、shell 外部執行或文件參考的組合方式,對遙測來說是不可見的。在你根據零次呼叫採取行動前,請在你的其餘工具中 grep 檔案路徑,而不僅僅是指令名稱:
# does anything else read the definition file directly?
rg -n '<commands-dir>/[a-z-]+/<definition-file>' .
那一個指令就將刪除清單變成了保留清單。對「去年有數百次直接呼叫,本季為零」的正確解讀,並非該指令已無作用,而是有個較新的管線將其吸收為一個進入點,且其底層步驟在每次父層的叫用時仍會執行。
所以,那個單層資料夾裡有三種類型的東西:我直接呼叫的、管線會讀取的,以及沒有任何東西會碰到的。只有第三類是可清理的對象。對於第二類,我修改了它們的描述,說明管線是預期的進入點,並將檔案完全保留在原位,因為管線硬編碼了那些路徑。
透過深度停用,而非刪除
對於那 13 個休眠中的項目,刪除它們感覺不對。它們能正常運作,也有文件記錄。我可能六個月後會需要用到其中一個。
大多數代理程式 (agent) 透過掃描剛好一層深的目錄來發現指令:對於每個子目錄,檢查是否有定義檔。沒有遞迴。與其相信文件,不如閱讀您自己代理程式的載入器 (loader)。在我檢查的那一個中,其行為是明確的。如果一個目錄本身沒有定義檔,其子目錄就絕不會被檢查。
這就提供了一個免費的停用機制。將資料夾再往下移一層:
mkdir -p commands/_attic
git mv commands/old-command commands/_attic/old-command
定義現在位於第二層深度。掃描器永遠不會觸及它。該指令從選單中消失,並停止耗用上下文,而它的每一個位元組都還在磁碟上,也還在版本控制中。還原只需一個 git mv 指令即可。
請注意這裡真正起作用的是什麼。不是資料夾名稱中的底線,也不是工具承諾會遵循的命名慣例。是深度的改變。在依賴此方法之前,請先驗證您自己的代理程式的掃描行為,因為一個會遞迴地 glob 定義檔的載入器,會默默地讓每個封存的指令保持活動狀態。有兩位審閱者為我指出了完全相同的風險,只有在閱讀了載入器的程式碼後才解決了這個問題。
閱讀該程式碼還帶來了另一個發現。掃描器也接受符號連結作為指令。我有一個符號連結指向另一個指令資料夾作為語言別名,這意味著該指令在每個會話中都被註冊了兩次。別名已經由描述文字處理了。這個符號連結是純粹的重複,直到我閱讀了探索機制如何運作後才發現。
清理過程中出了什麼問題
移動本身很簡單。文件才是出錯的地方,而且同一個缺失在三個不同的檔案中浮現了三次。
**編輯時行號會變動。**我的計畫將編輯操作以絕對行號範圍、由上到下列出。在 496 行刪除一行後,後面所有的範圍都會差一行。在某個檔案中,目標區段的標頭最終比計畫中開始的位置高了一行,所以刪除操作移除了內文,卻在水平線下留下了一個孤立的標頭。接著,完全相同的錯誤在第二個檔案中出現,然後又在一個有九個範圍的第三個檔案中出現。解決方法既無趣又絕對:從檔案底部向上編輯,或是以字串而非數字作為錨點。
**驗證範圍必須與編輯範圍相符。**我寫了一個檢查,用來確認整個 repo 中沒有任何過時的參照,但接著只列出了四個要編輯的檔案。第五個檔案中卻有一個參照。這個檢查在我執行之前就注定會失敗。如果你的驗收標準掃描了整個目錄,那麼該目錄中的每個檔案都應在範圍內,不然該標準就需要一個明確的排除清單。
**不要更新封存項目內的路徑。**封存的定義檔本身就包含其舊路徑。將這些路徑改寫成新的封存位置看起來很整潔,但卻是錯的:還原資料夾時會將其移回原始路徑,而改寫過的參照屆時將指向空無一物。封存檔內看似過時的路徑,對於該封存預期還原的狀態而言,才是正確的路徑。
還有一個值得記錄的決定。我原本計畫從一個設定檔中刪除整整兩個區段,結果發現其中一個區段記載了仍在運行的基礎設施。它提到的指令已經停用,但底下的掛鉤 (hooks) 和腳本 (scripts) 卻沒有。刪除該區段會移除對線上運作機制的唯一描述。我刪除了關於指令的那兩行,並保留了其餘部分。
常見問答
我需要多少次工作階段,這些數字才會有意義? 足夠讓您最近的視窗包含正常的工作組合。對我來說,每天使用兩個月就綽綽有餘了。如果您最近的欄位總呼叫次數少於幾百次,請將低計數視為雜訊而非證據。
我應該刪除而不是封存嗎? 如果儲存庫有歷史紀錄,刪除是可復原的,且能留下最乾淨的樹狀結構。當您預期在不重新啟動內容的情況下查閱其內容時,封存是較好的選擇,這對於您可能仍會手動執行其步驟的指令來說是常見情況。兩者都是可逆的。選擇一種方式並保持一致。
如果一個指令已停用,但文件仍然告訴人們使用它,該怎麼辦? 在同一次變更中修正文件,並檢查整個儲存庫,而不僅僅是明顯的檔案。腳本、子專案中的 README 檔案以及工作流程指南都會累積參考資料。我的參考資料分散在五個檔案中,其中一個還告訴讀者要呼叫我即將封存的指令。
修剪清單真的能改善任何可衡量的指標嗎? 上下文的節省是真實的,但很小。更大的影響是選擇的準確性:較少近乎重複的描述意味著較少的錯誤選擇。我不會僅僅為了 token 數量而這麼做。我會這麼做是因為,在一個資料夾中,若三種不同的物件看起來一模一樣,這個資料夾最終會誤導您。