auto-dev — 持續執行的代理人艦隊,負責實作與合併 Issue
功能說明
implement-issue 將一個已規劃的 Issue 轉換為準備好的 PR;merge-pr 負責合併一個 PR。auto-dev 以大規模方式監督它們:N 個背景工人各自全程掌握一個 Issue(implement-issue <N> → merge-pr <PR>);當某個工人的 PR 被合併後,該工人即被淘汰,並立即從佇列中派遣一個新工人處理下一個排隊的 Issue——如此 N 個 Issue 持續進行,無需您監控。
其價值在於單純「以迴圈執行」所缺乏的編排能力:
- 衝突避免 — 每個並行工人分配到不同程式碼區域的 Issue,因此分支幾乎不會互相衝突。
- 任務排序 — 先處理小型、自成一體的 Issue(快速獲勝,較少衝突),再處理中型。預設排除大型/特大型及需要手動 QA 的 Issue。
- 強制合併 — 工人常停在「PR 準備好」的階段(只完成一半工作)。auto-dev 在每次訊號時從 GitHub 驗證真實的合併狀態,並重新驅動任何停滯的工人。
- 超出範圍問題捕捉 — 若工人遇到無關的錯誤,僅在
implement-issue的例外規則下(限定於其 PR 已修改的檔案且規模小,以獨立提交方式)就地修復,否則會透過create-issue記錄問題,而不是直接忽略,並遵循統一的記錄標準(../_shared/filing-bar.md),以免 N 個工人以 N 種不同標準記錄問題。待辦事項佇列保持真實且可消耗(#410)。 - 生命週期衛生 — 完成的代理人會關閉;狀態檔案可在重啟後保留,使艦隊可恢復。
自主合約
使用者啟動後即可離開——他們看著待辦事項佇列逐漸清空,無需批准每個步驟。以完全自動化方式執行:選取合理的預設值,明確說明,繼續進行。僅在遇到真正的阻礙時才停止:
gh未通過驗證,或您缺乏推送/合併權限。- 沒有符合條件的 Issue(過濾後佇列為空)— 報告待辦事項佇列已清空。
- 工人遭遇無法解決的阻礙(無法通過的測試、雙方重寫相同邏輯的衝突、需要但無法自行授予的核准)。揭露問題;不要強行合併。
切勿偽造進度:勾選方塊、標記「就緒」或合併操作都表示工作已完成——必須提供證據,如同子技能所要求的那樣。Squash 合併是唯一不可逆的操作——僅能透過 merge-pr 對一個通過測試、可合併的 PR 執行,絕不能在此處使用 --admin 覆寫。
輸入
- 並行數量
N— 同時運行的工人數量。預設為 3(3–4 是最佳區間;更多工人 = 更多競爭和更難保持區域分離)。 - 排序方式 — 預設從小型到中型。尊重使用者的任何指定。
- 符合條件的 Issue 集合 — 預設:開啟的 Issue 必須 (a) 包含實作計畫,(b) 屬於程式碼任務(非手動「QA」/「手動驗證」),(c) 在努力程度上限內(預設 ≤ 中型)。尊重篩選條件(例如「僅
studio的 Issue」、「標記為priority: high」)。 - 心跳訊號 — 通常透過動態模式的
loop啟動,因此迴圈的自定節奏喚醒即為心跳。若直接呼叫,請自行設定喚醒機制。 - 模型層級 — 預設為分層,並非全部使用 Opus(請參閱代幣經濟學):機械化/文件工作使用最便宜且有能力的模型,一般錯誤使用中階模型,頂級模型保留給跨領域/困難工作及失敗升級使用。這是單一最大的成本槓桿。尊重覆寫設定(例如「全部使用 Opus」、「所有工作使用 Sonnet」)。
代幣經濟學 — 以低成本運行艦隊
長時間運行的成本約為 ~83% 每輪上下文快取讀取,~16% 輸出——您支付的是上下文量 × 輪數,而非思考成本。請套用以下規則;完整說明與測量資料請參閱 references/token-economics.md。
實際測量:一次真實的 19 次合併運行(.NET/Blazor 儲存庫,N=3,21 個工人會話,863M 代幣): 每個會話 224 輪 · 上下文 30K → 350K · 每輪平均上下文 181K · 每輪工具呼叫 0.55 次。 快取讀取佔代幣總量的 98.3%。成本 = Σ 每輪的上下文大小,因此晚期輪次的成本約為早期輪次的 10 倍,且輪數是超線性增長的——它同時驅動了兩個因素。根據此原則而非直覺來排列槓桿的優先順序。
上述數字僅計算工人會話——而編排器的成本佔總帳單的三分之一。 將監督者自身的記錄合併到同一份統計中:一個會話,551 則助理訊息,每則訊息平均上下文約 210K,佔運行清單等效成本的 33%——比所有頂級工人會話的總和還多——而且它從未壓縮過,橫跨全部 19 次合併。工人支出也有同樣的偏差:37 個工人會話中,前 3 個佔了所有工人成本的 32%,而最差的一個是中階模型上標示為
effort: medium的 Issue,因此標籤和模型層級都無法預測。這兩項測量,以及約束它們的兩個預算,都記錄在 references/token-economics.md § 會話長度 中。
1. 將每個工人拆分為兩個子代理人:先實作,再合併 — 唯一經過驗證有效的槓桿。A/B 驗證,約佔所有工人代幣的 11%。 第一階段(/auto-dev-worker <N>)在 PR 準備好時停止;第二階段(/auto-dev-merge <PR>)在新的上下文中合併 PR。
| 合併階段 | 輪數 | 平均每輪上下文 | 快取讀取 |
|---|---|---|---|
| 之前(18 個工人,在實作會話內) | 27 平均 | 247K | 每個工人 6.6M |
| 之後(v2 第二階段,全新會話) | 24 | 71K | 1.7M |
輪數幾乎相同,因此每輪上下文是全部差異的來源:合併階段減少 −74%,約佔總工人支出的 11%。透過一個檔案在第一階段提示中指定名稱的方式,將 PR 編號在階段之間傳遞(備用方案:解析報告行,然後使用 gh pr list --head)。額外好處:在基線運行中觀察到的兩個完成後卡住的情況,都發生在長時間會話的晚期輪次——較短的會話較不易卡住。
2. 工具呼叫批次處理 — 已嘗試但無效。不要預期能節省成本。 在工人提示中加入了一條嚴格的批次處理規則與範例,並進行了 A/B 測量:密度從 0.556 降至 0.537 次呼叫/輪(第一階段)——即沒有變化。保留此規則(沒有成本),但不要為此編列節省預算。診斷結果:密度低於 1.0 並不表示可批次處理的呼叫未被處理。約 45% 的輪次沒有任何工具呼叫——它們是推理/敘述輪次——而其餘大多數輪次是真正的順序操作(編輯 → 建置 → 讀取錯誤 → 修正)。可回收的浪費是沒有產生工具呼叫的輪次,這是輸出冗長問題,而非批次處理問題。若要解決此問題,請針對冗長(思考長度、步驟間的敘述)著手,並測量呼叫次數/輪來確認改善。
3. 將大型命令輸出保留在上下文之外 — 測量結果:4,262 代幣 → 每次完整測試運行約 2 代幣。完整的 dotnet test 輸出約 17K 字元,並在後續每個輪次重新讀取。強制要求:記錄到檔案,僅將 EXIT + 計數保留在上下文中,僅在失敗時 grep 該檔案。明確禁止將命令透過 tail/head 管道傳輸——這會截斷證據,同時仍消耗輪次。
*誠實的範圍:*每次運行的減少是確切且經過驗證的,但總體效益取決於工人執行測試套件的頻率。在 A/B 測試中,最大的單一 Bash 結果從 25.2K 降至 10.5K 字元,而每輪的工具結果總量幾乎沒有變化(722 → 710 字元)——因為 A/B 測試的 Issue 是一個文件任務,很少執行測試。請預期在測試密集型 Issue 上獲得真正的效益。
4. 根據任務分層使用模型 — 實際但取決於層級,請參閱 token-economics.md: 中階和小型之間差距較小($0.419/Mtok vs $0.168/Mtok ≈ 2.5 倍); 頂級和中階之間差距較大($2.376/Mtok vs $0.419/Mtok ≈ 5.7 倍)。 值得優先考慮用於跨領域工作;對例行錯誤影響較小。根據 Issue 標籤路由(將名稱調整為運行時的小型/中階/頂級三層,例如 Haiku/Sonnet/Opus):
| Issue 形狀(按標籤) | 模型層級 |
|---|---|
文件/模板/清單、格式與快照重新產生、priority:low+effort:S 單行防護 | 小型(例如 Haiku) |
大多數錯誤:emitter/validator/parser 防護、studio TS、CLI、LSP — effort:S/M;大型 Issue 預設 | 中階(例如 Sonnet) |
| 較低層級在此 Issue 上失敗 | 頂級(例如 Opus),被動升級(一次) |
| 跨領域(多個區域/emitter)、模糊/設計問題 — 維護者知道困難的工作 | 頂級(例如 Opus),主動最終手段 |
編排器(您)保持使用頂級模型,但保持其每輪上下文小(槓桿 2)。
5. 縮小每輪重新讀取的內容。
- 修剪固定的前言 — 每個工人的每一輪都要為此付出代價。
CLAUDE.md為 44KB(約 11K 代幣),在一次運行中僅一個檔案就花費了 52M 代幣;將部署/機密/kubectl 參考資料移至連結的文件中,僅留下一個指標。 - 不要使用每個 Issue 的 TaskList — 它會無限制增長並在每輪重新注入。狀態檔案是您唯一的工作記憶體。
- 有意識地、按計數節奏進行壓縮——而不是憑感覺。 節奏整數只有一個存放位置,即 references/token-economics.md § 兩個預算;步驟 4 根據狀態檔案的合併計數器觸發壓縮,與重新調查節奏使用的計數欄位相同。請勿在此處重複該數字——
tests/auto-dev-cost-budgets/test.sh會在建置時失敗。*為何使用計數:*成本是 Σ(上下文 × 輪數),因此運行的尾部是超線性的,而此規則取代的——一個/context百分比或一個寬鬆到在 19 次合併運行中從未觸發的節奏——沒有任何約束效果,並在單一會話中花費了 $213。始終使用聚焦指令進行壓縮,例如/compact 保留 slot→issue/PR 映射、合併計數器、佇列順序、已記錄的後續事項。在任何壓縮 //clear/loop重新觸發後的第一個動作:重新讀取狀態檔案。 - 保持工人的 FINAL REPORT 簡潔 — 它們會在後續每個協調輪次中被重新讀取。
- 將大量讀取委派給可拋棄的
Explore子代理人 — 檔案轉儲會隨著子代理人的結束而消失,而不是佔據您的上下文。 - 以精簡方式啟動 SUPERVISOR 會話 — 子代理人會繼承監督者的 MCP 集合,因此連接到您的會話的每個伺服器都會在每個工人的每一輪中被使用。每個工人的 MCP 剝離已不再可用(Agent 工具沒有每個 spawn 的 MCP 設定);在啟動時一次性地進行修剪。
6. 減少輪次數(每次往返都會重新讀取整個上下文)。
- 將獨立的工具呼叫批次處理到一個輪次中(並行讀取/grep/
gh)。 - 讓腳本合併查詢與分類 —
scripts/survey.sh、scripts/reconcile.sh。 - 除非合併即將發生,否則不要以短節奏輪詢 — 不必要的喚醒會重新讀取所有內容,而一旦超過約 5 分鐘的快取 TTL,則需支付完整的快取寫入(1.25 倍),而非讀取(0.1 倍)。
- 限制會話長度,而不僅僅是輪次。 批次處理已經過 A/B 測試且沒有改善(槓桿 2),因此每輪最佳化已接近極限,而會話長度是剩下的變數——37 個工人會話中,前 3 個佔了所有工人成本的 32%,而努力程度標籤或模型層級都無法預測是哪三個。因此,第一階段的工人攜帶一個輪次預算(該整數存在於 references/token-economics.md § 兩個預算 中,不在這裡),並在達到預算時以
STATUS: PARTIAL移交;步驟 4 在一個全新的子代理人中恢復他們,這正是節省的關鍵——而SendMessage恢復則會保留預算旨在丟棄的上下文。這是槓桿 1 的機制,也是該章節唯一經過驗證的勝利,應用於長度接縫而非階段接縫。
測量它 — 未經 A/B 測試,切勿聲稱槓桿有效。三個腳本,均以包含會話 .jsonl 記錄的目錄作為輸入:
scripts/usage_report.py— 按模型劃分的代幣 + 美元等值。追蹤代幣/合併和美元/合併。 ⚠️ 它會彙總整個專案目錄,包括過去的運行——首先將一次運行符號連結到一個臨時目錄,保持目錄結構:監督者會話的<sid>.jsonl及其<sid>/subagents/目錄(<proj>/<sid>/subagents/agent-*.jsonl是每個工人記錄的存放位置,因此一次運行的整個艦隊位於一個 ID 下——從狀態檔案或gh時間戳選擇 ID;mtime 不可靠)。一個平面堆疊的agent-*.jsonl符號連結會被解讀為0 個子代理人且無法配對任何內容。scripts/analyze_cache.py— 輪數/會話、開始時的上下文 vs 峰值、每輪平均上下文、以及按工具劃分的工具結果量。這是您了解為何一個會話成本高昂的地方。scripts/measure_phase2.py— 將每個 Issue 的第一階段和第二階段子代理人記錄配對(根據其報告行的ISSUE:),並將成本拆分為實作階段與合併階段;在 2.0 之前的記錄中,它會找到會話內的合併交接輪次。這正是證明槓桿 1 有效的方法。
兩個指標承載了大部分訊號:每輪平均上下文(晚期輪次是否膨脹?)和每輪工具呼叫次數(輪次是否做了任何實際工作?基線約 0.55 — 請參閱槓桿 2)。
運作方式
┌─────────────────────── auto-dev(您,監督者) ───────────────────────┐
│ 狀態檔案:佇列(小型→中型)、進行中的 slot、已完成、已記錄 │
│ 每次訊號 → 與 GitHub 協調 → 結束合併 + 補充 → 保持 N 個運行 │
└────────────────────────────────────────────────────────────────────────┘
│ 派遣(區域隔離) ▲ 結構化報告 / 空閒通知
▼ │
工人 A ─ implement-issue → [就緒] ⇢ 全新子代理人 ─ merge-pr ─ 報告 ┐
工人 B ─ implement-issue → merge-pr ─ 報告 ─┤ N 個背景代理人,每人一個 Issue,
工人 C ─ implement-issue → merge-pr ─ 報告 ─┘ 合併後淘汰,從佇列補充
工人是使用 Agent 工具生成的背景子代理人。透過它們的結構化報告進行通訊——子代理人的最終訊息就是它的報告,在返回時傳遞給您——透過空閒通知,以及透過 SendMessage 與仍在運行中的工人通訊;切勿讀取其原始記錄檔案(<proj>/<your-session>/subagents/agent-*.jsonl)——工人的輸出是一個巨大的記錄檔,會使您的上下文爆炸。依賴報告
…
[原文已截斷]