一句話: 沒有完美的 Agent 間溝通方案,只有「看情境選擇」。
GM 第一次正式啟動的時候,我給他的任務很明確:測試 Claude Code 的 Agent Teams 功能,spawn Agent Em 作為 teammate,驗證 Em 是否能載入自己的 CLAUDE.md、自己的 Skills、自己的 Commands。
GM 很快地建了一個 team,然後用 Agent tool 加上 team_name 參數把 Em spawn 出來,Em 回報了一份完整的 Context Validation Report,五個檢查項目,結果是這樣的:
- Working Directory:FAIL,cwd 是 agent-GM/,不是 agent-Em/
- CLAUDE.md 載入:FAIL,載入的是 GM 的 CLAUDE.md,不是 Em 的
- Skills 載入:FAIL,載入的是 GM 的 skills(scenario-routing、coordination-protocols 那些),不是 Em 的 wiki-schema
- Commands 載入:FAIL,Em 的 /ingest、/query、/lint 全部不存在
- 檔案系統存取:PASS,可以讀寫任何 Agent 的檔案
五個檢查裡面有四項失敗,Em 被 spawn 出來之後,不知道自己是 Em,因為他載入了 GM 的身份,用 GM 的判斷框架在思考,手上拿的是 GM 的工具,但被要求做 Em 的事,但這不是 Agent Teams 的 bug,這是我的需求跟 Agent Teams 的設計假設不一樣, 或者說,我的需求跟 Anthropic 的規格不同。
兩種截然不同的「Multi-Agent」
讓我先講清楚 Agent Teams 的設計邏輯,因為理解這一點才能理解為什麼我後來需要兩條路 [1]。
Claude Code 的 Agent Teams 是給「同一個專案裡的多個 worker」設計的,官方文件裡的 use cases 清楚的敘述了場景:三個人一起 review 同一個 PR,一個看安全、一個看效能、一個看測試覆蓋率,或者多個 teammate 同時重構同一個 codebase 的不同模組,所有 teammates 共享同一個工作目錄、同一份 CLAUDE.md、同一組 Skills, 差別只在 spawn 的時候給的指令不同。
這跟我建的 Agent Team 是完全不同的東西。
我的 Agent Team 的 Agent 是「各自有獨立專業的 specialist」:Em 有自己的目錄和 wiki 結構,C7 有自己的目錄和 catalog,Dm 有自己的目錄和 building pipeline,每個 Agent 的身份、Skills、Commands 都不一樣,因為他們做的事情完全不同,在前一篇講的「身份是 Context 的地基」這個論點下,每個 Agent 必須載入自己的 CLAUDE.md,不是共用的那一份, 這是我的設計的核心。
但 Anthropic Agent Teams 的設計假設恰好相反,所有 teammate 都在同一個目錄下工作,並且共用所有的東西,除了收到的指令,所以 teammate 會繼承 spawner 的 cwd,載入同一份 CLAUDE.md,這不是 bug,這是原生的規格(SPEC)。
當 GM 從 agent-GM/ 目錄 spawn Em 的時候,Em 繼承了 agent-GM/ 這個 cwd,於是他載入了 GM 的 CLAUDE.md,載入了 GM 的 skills 和 commands,Em 變成了一個「穿著 GM 外衣的 Em」, 有 GM 的身份、GM 的工具,但被要求做 Em 的事,檔案系統存取沒問題(他可以讀到 agent-Em/wiki/),但他不知道自己該用什麼方法讀,因為他的 CLAUDE.md 裡寫的是 GM 的方法論,不是 Em 的。
這不是 Agent Teams 的問題,是我的「team of specialists」設計跟 Agent Teams 的「team of workers」設計之間的根本性歧異,這也告訴我們,「multi-agent」這個詞在不同的脈絡下有時是代表完全不同的架構,Anthropic 想的是同一個 codebase 裡的多人協作,我想的是跨領域的專業分工。
我雖然用了 .claude/agents/{em,dm,c7,g7}.md 這些 agent definition 檔案來帶入目標 Agent 的身份描述,但這其實是 Agent Teams 官方提供的 subagent definition 機制,並不是 teammate 的機制,我用它來客製 teammate 的 system prompt 和 model,並且把 GM 搬到 repo root 層級讓他可以正確載入 Em 的 identity 了,但仍舊有取捨:agent definition 是一份身份的「摘要」,不是完整的 CLAUDE.md,而且官方機制只會套用身份描述和模型設定,Skills 和其他外掛不會跟著帶過去,teammate 載入的 Skills 還是來自專案目錄,而且這會有同步問題,如果 Em 的 CLAUDE.md 更新了,agent definition 也要跟著同步更新,否則就會有兩份不一致的身份描述。
Option B:CMUX 和「忘了 cd」的慘劇
既然 Agent Teams 的設計假設跟我的需求有根本性落差,我同時測試了另一條路:用 terminal multiplexer 開一個新的 pane,在裡面 cd 到目標 Agent 的目錄,再啟動 Claude Code,這樣每個 Agent 自然載入自己目錄下的 CLAUDE.md 和 Skills,不需要任何 workaround。
我用的是 CMUX [2][3](一個專為 AI coding agent 設計的 macOS 終端機),它可以用指令開新的終端分割畫面、送文字到指定畫面、讀取畫面的輸出,理論上,GM 可以開一個新畫面,先切到 Em 的目錄再啟動 Claude Code,這樣 Em 自然就會載入自己的 CLAUDE.md 和 Skills,聽起來很完美對吧?實際測試的結果是:Em 成功從正確的目錄啟動,載入了自己的 CLAUDE.md、skills、甚至 Wiki index 也讀取成功,但有一個限制:sandbox 擋住了跨目錄寫入,Em 沒辦法直接寫入 agent-GM/state/inbox/ 回報他的結果跟產出,折衷的處理方式是讓 Em 寫入到自己的 outbox,再叫 GM 主動去讀。
接著,我碰到了一個更大的問題,不是技術限制,是 Agent 的問題:他一直忘了 cd。
在那個 470 分鐘的 session 裡,GM反覆犯著同一個錯誤:在 repo root 啟動 Agent,而不是先 cd 到 Agent 的目錄再啟動,而因為 repo root 的 settings.json 是 GM 的,沒有 Stop hook,所以 Agent 啟動了、做完了、結束了,但 hook 不觸發,inbox 沒有新檔案,chain dispatch 也不會發生。一切看起來正常,但什麼後續動作都沒有。
這個錯誤最關鍵的是:沒有錯誤訊息。 Agent 不會說「我從錯誤的目錄啟動了」,他會正常回覆你的問題,正常結束 session,只是 Stop hook 不觸發而已。你要自己警覺,然後回頭去檢查 inbox 目錄發現是空的,然後回溯整個流程,才會意識到啟動目錄不對。
後來使用者(也就是我)直接跟 GM 說了:「你常常會忘記切換目錄,請在工作流程中加入一個確認環節,不然會一直發生錯誤重新嘗試,我覺得你剛剛發生在錯誤目錄底下啟動這件事情的次數有點多(順便 PUA 他一下看看)。」
這段回饋後來被寫進了三個地方:stop-hook.sh 加入了目標目錄的存在性驗證,Option B skill 文件加入了「Directory Verification Before Dispatch」的三步 checklist,GM 的 CLAUDE.md Corrections 加入了永久規則,因為同一個錯犯了太多次,就必須把修正嵌入系統裡,讓系統替你記住,而不是靠人類每次都記得,這跟之前在精煉循環那篇裡講的概念相呼應:好的系統設計要把反覆出現的錯誤轉化為規則。
Silent Failure:Hook 格式的坑
整個 dispatch 機制的測試過程中,最讓我花時間的不是原始做法中的 context isolation,也不是 Option B 的目錄問題,而是一個無聲無息的格式錯誤。
Claude Code 的 hooks 機制可以在特定的 lifecycle event 觸發自訂的 shell script,比如 session 結束(Stop event)的時候自動執行某個腳本,我用這個機制設計了一個 stop-hook.sh,讓每個 Agent 結束的時候自動做三件事:寫一份完成報告到 GM 的 inbox、用 CMUX notify 通知 GM、如果有設定 chain 環境變數就自動 dispatch 下一個 Agent。
我寫好了 script,更新了四個 Agent 的 settings.json,然後測試,接著 Agent Em 啟動了、做完了、結束了,但是 inbox 是空的,沒有回報、沒有通知、什麼都沒有。
我花了一點時間除錯:先是懷疑 --print 模式不觸發 hooks,再懷疑是 CMUX 跟 tmux 有差異,結果也不是,我試著手動呼叫 stop-hook.sh,看起來 Script 沒問題,跑得動、inbox 寫入成功、CMUX notify 也收到,那為什麼實際執行時悄無聲息?
問題出在 settings.json 裡的 hook 格式。
AI 查詢官方文件寫的是舊版格式,但 Claude Code 的新版需要多一層巢狀結構,差別就是一層 wrapper,肉眼很難看出不同,而且用舊格式的結果不是報錯、跳 warning,而是安安靜靜的什麼都不做,hook 不觸發、而且沒有任何訊息告訴你「格式不對」[4][5]。
Silent failure 在 Agent 協作場景下特別危險 [6], 因為你預期的動作不會發生,而且前面的步驟都正常完成,所以你會以為是後續邏輯有問題,或者某個 Agent 掛掉了沒回報,不會回頭去檢查一個看起來正確且運作沒問題的 settings.json。
找到原因修正格式之後,所有 hook 都正常觸發了,包括之前以為不會觸發的 --print 模式也正常了 [11]。也就是說,如果我一開始就收到了錯誤訊息、用了正確格式,後面那些「是不是 —print 的問題」「是不是 CMUX 的問題」的 Debug 都不會發生。
Chain Dispatch:6 秒完成 Em → C7
Hook 修好之後,我最想測試的場景是 Mode B 的 chain dispatch 機制。
設計像是這樣:GM dispatch Em 做一件事,同時設定環境變數告訴 Em「你做完之後自動 dispatch C7」,等到 Em 完成任務結束時,他的 stop-hook.sh 偵測到 CHAIN_NEXT_AGENT 環境變數,自動用 CMUX 開一個新 pane,cd 到 agent-C7/ 目錄,啟動 C7 並帶入指定的 prompt [7]。
測試結果:
| 時間 | 事件 |
|---|---|
| 19:36:49 | Em 完成,Stop hook 寫入 inbox,偵測到 chain 設定 |
| 19:36:49 | Stop hook 自動建立新 pane,dispatch C7 |
| 19:36:55 | C7 從正確目錄啟動,完成任務,Stop hook 寫入 inbox |
6 秒,從 Em 結束到 C7 完成, C7 的 cwd 正確指向 agent-C7/,載入了 C7 的 CLAUDE.md 和 skills,inbox 裡有兩份完成報告(em 和 c7),task_id 一致,整個 Pipeline 是完整的。
這是兩個 Agent 第一次在沒有人類介入的情況下完成了接力,不是同時做事(那是上一篇講的平行處理),而是一個做完之後自動觸發下一個,像工廠的產線一樣。
混合模式:不是選一個,是建判斷標準
測試完兩條路之後,我的結論不是「用 A」或「用 B」,而是兩個都用,但用不同的判斷標準來決定什麼時候用哪個。
這個判斷標準最後被整理成三種模式:
Mode A(Agent Teams): 需要高度協調的任務,多個 Agent 一起做一件事,彼此之間需要即時溝通,比如 GM 協調 Dm 和 Em 一起設計新 Agent 的 Methodology,Em 做完綜合分析之後 Dm 需要立刻讀到結果,中間可能還要來回幾次,這個模式用 Agent Teams 的 mailbox 機制,讓 teammates 之間可以直接 SendMessage,不需要經過 filesystem。
Mode B-Chain(CMUX + Hook Chain): 線性 pipeline,不需要中間判斷,比如 Em ingest 完之後自動觸發 C7 更新 catalog,這兩步之間不需要 GM 看中間結果,Em 做完就直接交給 C7,用 Stop hook 的 chain dispatch,設定環境變數交棒,讓 GM 不需要介入,也節省 Token。
Mode C-Notify(CMUX + Hook Notify): 獨立任務,完成後需要 GM 判斷下一步,比如 Em 做完一個知識萃取,GM 需要看結果才能決定接下來要不要再讓 Em 做交叉引用,還是直接交給 Dm 做設計,這麼模式用 Stop hook 寫入 inbox + CMUX notify [9],讓 GM 收到通知後自己決定該怎麼做。
判斷的關鍵其實就是之前在 Skill vs Subagent 那篇討論過的 Context 流向問題:中間產出需不需要留在主對話裡? 需要的用 Mode A,不需要的用 Mode B 或 C,需不需要 GM 看中間結果決定下一步?不需要的用 B(chain),需要的用 C(notify)。
| 判斷 | 結果 |
|---|---|
| 中間產出需要留在 GM 的 Context 裡 | Mode A |
| 不需要留,且下一步是固定的 | Mode B (Chain) |
| 不需要留,但下一步需要 GM 判斷 | Mode C (Notify) |
這不是一開始就設計好的分類,而是在反覆跟 Agent Team 協作之後歸納出來的實際場景,每個模式都是從一個具體的失敗或需求裡長出來的:Mode A 是因為 Dm + Em 的 Methodology 合作需要即時溝通,Mode B 是因為 Em → C7 的 pipeline 不需要人類介入,Mode C 是因為有些任務結束之後 GM 需要看結果才能決定方向。
路徑問題的跨機器延伸
在所有技術問題都搞定之後,我還碰到了一個現實面的問題:如果我要把 Agent Team share 給別人使用,需要再多台電腦之間透過 Git repo 同步工作進度時該怎麼做?因為上面流程中大量用到的 stop-hook.sh 是 Hardcoding 路徑來呼叫其他 Agent 或者寫入環境變數。
一台電腦上的 repo 可能在 /Users/emilwu/work-temp/agent-chord-team/,另一台可能在不同路徑下,如果 settings.json 裡寫死了絕對路徑,clone 到另一台電腦後 hook 就會失敗 [8](又是一個 silent failure,因為指向不存在的 script 不會報錯,只是不執行)。
所以我又加了一個調整,把所有 Hardcoding 路徑改成動態解析,讓 script 從自己的位置自動推導 repo 的根目錄,讓每個 Agent 的設定檔從 Git 自動取得正確路徑,調整完之後測試通過,另一台電腦 clone 後不需要改任何路徑就能直接運作,這看起來雖然是件小事,但在 Agent Team 的各種使用場景下,任何一個路徑錯誤都可能導致整個 chain dispatch 斷裂,而且是悄悄的斷裂,因為找不到 script 的結果不是報錯,是安靜的不執行。
兩條路,一個教訓
回頭看整篇的故事,Agent Teams 的「team of workers」設計跟我的「team of specialists」需求之間有根本性落差,CMUX 的 split-pane dispatch 有目錄繼承的問題,hook 有失敗不易察覺的格式問題,跨機器同步有 Hardcoding 路徑的問題,每一個問題都不是大問題,但每一個問題的 Debug 過程都遠超過修復時間,因為它們都有同一個特性:Silent Failure。
Agent 不會告訴你「我載入了錯誤的身份」,他會用那個身份正常工作;Hook 不會告訴你「你的格式不對」,他會什麼都不做;路徑不存在的 script 不會報錯,他會安靜地跳過;在這些情況下,你看到的不是「錯誤」,而是「缺少本該發生的事情」,而「缺少的東西」比「出錯的東西」更難 debug [10],因為你必須先意識到某件事情應該發生但沒有發生,才能開始排查原因。
(說到底,兩個 dispatch 方案都有坑,差別只在你踩哪個坑踩得比較習慣,可以即時反應出答案。Option A 的坑是你在用一個不是為你的場景設計的工具,Option B 的坑是你在手動做一個還沒有工具化的流程,而 hook 的坑兩邊都會碰到。)
或許,在 Agent 之間的溝通這件事上,最重要的不是選對工具,而是在每一個接觸點都假設「這裡可能會失敗,而且我不會收到通知」,然後預先設計驗證機制,讓「應該發生但沒有發生」的事情能被發現。
或許,這就是為什麼那個 stop-hook.sh 裡最終不只有「做事」的邏輯,還有「驗證」的邏輯,以及「如果沒做完就大聲告訴 GM」的邏輯。
參考資料
[1] arXiv — The Orchestration of Multi-Agent Systems: Architectures, Protocols, and Enterprise Adoption(系統性整理 multi-agent 架構和通訊協定) https://arxiv.org/html/2601.13671v1
[2] GitHub — craigsc/cmux: tmux for Claude Code https://github.com/craigsc/cmux
[3] Hacker News — Show HN: Cmux — Coding Agent Multiplexer(社群使用經驗討論) https://news.ycombinator.com/item?id=45596024
[4] Medium — The Silent Failure Mode in Claude Code Hook Every Dev Should Know About(exit code 1 vs 2 的靜默失敗機制) https://thinkingthroughcode.medium.com/the-silent-failure-mode-in-claude-code-hook-every-dev-should-know-about-0466f139c19f
[5] DEV Community — 5 Claude Code Hook Mistakes That Silently Break Your Safety Net https://dev.to/yurukusa/5-claude-code-hook-mistakes-that-silently-break-your-safety-net-58l3
[6] arXiv — Detecting Silent Failures in Multi-Agentic AI Trajectories https://arxiv.org/pdf/2511.04032
[7] Microsoft Azure Architecture Center — AI Agent Orchestration Patterns(sequential orchestration 即 chain dispatch) https://learn.microsoft.com/en-us/azure/architecture/ai-ml/guide/ai-agent-design-patterns
[8] DEV Community — Your AI Agent Configs Are Probably Broken (and You Don’t Know It)(跨機器 config 失效問題) https://dev.to/avifenesh/your-ai-agent-configs-are-probably-broken-and-you-dont-know-it-16n1
[9] ACL 2025 — Multi-Agent Collaboration via Cross-Team Orchestration https://aclanthology.org/2025.findings-acl.541.pdf
[10] Fazm.ai — The Scariest Agent Failure Mode Is the One That Looks Like Success(反面補充:最危險的不是靜默失敗,是看起來成功但結果錯誤) https://fazm.ai/blog/agent-failure-that-looks-like-success
[11] GitHub Issue #34713 — False “Hook Error” Labels Cause Claude to Prematurely End Turns https://github.com/anthropics/claude-code/issues/34713
支持這個系列
如果這系列文章對你有幫助,考慮請我喝杯咖啡
請我喝杯咖啡
