任務說明 5.3——「在 multi-agent 系統中實作錯誤傳播策略」,隸屬於 Claude Certified Architect — Foundations(CCA-F)考試的 Domain 5(Context Management 與 Reliability,佔比 15%)。儘管 Domain 5 是各領域中權重最輕的,但它的情境密度極高:每道 multi-agent 題目——而 multi-agent 題目在 Domain 1(27%)也大量出現——最終都會收束到「當 subagent 出問題時該怎麼辦?」這個核心。錯誤傳播是決定 multi-agent 系統究竟能優雅降級、安全停止,還是雪崩式全面故障的關鍵縫合線。
這份學習筆記帶你走過 CCA-F 考生必須能在架構層級設計的完整錯誤傳播面向:為什麼巢狀 agent 系統會產生新的失敗邊界、如何將錯誤分類為暫時性與永久性、區域性與級聯性、何時 fail-fast 勝過 fail-safe、如何隔離 subagent 崩潰使 coordinator 存活、跨 agent 邊界傳遞而不失語義的結構化錯誤 payload 的精確形狀、coordinator 如何決定是否 retry 失敗的 subagent、當只有部分 subagent 成功時如何繼續處理部分結果、如何累積軟性失敗直到觸發硬性中止門檻、用 circuit breaker 模式停用反覆出錯的 subagent、如何沿著回報鏈將根因錯誤上浮至頂層 coordinator,以及除錯這一切所需的 distributed tracing 面向。最後的陷阱章節與六題 FAQ,將每個抽象概念連回考試中最密集測試這個任務的兩個情境:multi-agent-research-system 與 customer-support-resolution-agent。
錯誤傳播的挑戰 — 巢狀 Agent 系統中跨邊界的失敗
單一 agent Claude 系統只有一個失敗邊界——agentic loop 本身。工具失敗時,迴圈看得到;迴圈決定中止時,呼叫方看得到。Multi-agent 系統則有幾層 agent 就有幾個失敗邊界。一個 coordinator 衍生三個 subagent,每個 subagent 再各自衍生兩個 subagent,就形成至少三種邊界類型:工具對 subagent、subagent 對 coordinator、coordinator 對呼叫方。每個邊界都是一個讓錯誤被吞噬、扭曲或演變為靜默級聯的機會。
為什麼邊界很重要
邊界是執行上下文交接的點。在單一 agentic loop 內部,Claude 把所有 tool_result——包括錯誤——都當作連續對話的一部分來看。跨越 agent 邊界,只有你明確傳遞的內容才可見。一個災難性失敗的 subagent 不會自動告知 coordinator 發生了什麼;它只會回傳你的整合程式碼決定回傳的值。這個決定,就是錯誤傳播策略。
Multi-Agent 系統的三種失敗模式
- 靜默降級 — subagent 失敗後回傳一個看起來合理的佔位結果。coordinator 信任這個佔位值,將它合成進最終答案,使用者收到了沒有任何錯誤指示的捏造內容。這是最糟糕的失敗模式,因為它是隱形的。
- 級聯失敗 — subagent 失敗後拋出一個例外,例外向上穿透 coordinator,使整個執行崩潰,即使其他 subagent 都是健康的。一個無法在任何 subagent 缺席時繼續運作的 coordinator,過於脆弱。
- 無限 retry — coordinator 無限期地 retry 失敗的 subagent,耗盡 token 與執行時間預算,卻始終無法產出輸出。circuit breaker 存在的目的,正是為了預防這種失敗模式。
Error propagation 是一套機制,用於將 multi-agent 系統某一層的失敗,以具有足夠結構化細節的形式,傳遞給上一層,讓上一層能夠決定要 retry、跳過、降級還是中止。Error propagation 是錯誤處理的架構補充:錯誤處理決定在失敗現場做什麼;error propagation 決定失敗現場告訴上游什麼。沒有明確 propagation 策略的 multi-agent 系統,就是一個會靜默捏造答案的系統。 Source ↗
為什麼 CCA-F 考這個
社群通過考試的報告反覆指出,Domain 5 有情境題要求考生選出 coordinator 在 subagent 回傳結構化錯誤時的正確行為。干擾選項幾乎永遠是「無限 retry」、「靜默丟棄該 subagent」或「中止整個執行」——而每種選項在特定情境下是正確的,在其他情境下是錯的。把 error propagation 做對,是區分 720 分及格與 900 分以上的核心分水嶺。
錯誤分類 — 暫時性 vs 永久性、區域性 vs 級聯性
設計任何 propagation 策略之前,必須先對錯誤進行分類。CCA-F 要求識別兩個正交軸。
軸一:暫時性 vs 永久性
- 暫時性(Transient) — 根本原因預期會在不需要人工介入的情況下自行解決。例如:網路超時、速率限制節流、短暫的資料庫競爭、下游服務重新啟動。暫時性錯誤是 retry 的候選對象。
- 永久性(Permanent) — 根本原因不會在不改變輸入、設定或外部狀態的情況下自行解決。例如:格式錯誤的輸入、權限被拒、資源不存在、schema 違規。永久性錯誤絕對不能 retry;retry 只會浪費預算並掩蓋真正的問題。
這個區別至關重要:對永久性錯誤執行 retry 的 coordinator,會在放棄前耗盡迭代上限;而對暫時性錯誤不執行 retry 的 coordinator,則會在第一次網路抖動就中止。
軸二:區域性 vs 級聯性
- 區域性(Local) — 錯誤只影響一個 subagent 的工作,不會使其他平行 subagent 已完成的工作失效。一個無法連上某個特定來源的研究 agent,從其他三個來源取得的結果仍然有效。
- 級聯性(Cascading) — 錯誤會使上游的前提假設或依賴此 subagent 輸出的下游工作失效。若「驗證使用者身份」的 subagent 失敗,每個後續的「取得使用者資料」subagent 現在都在無效的前提上運作。
區域性錯誤是部分失敗處理的候選對象(以現有的結果繼續)。級聯性錯誤必須短路下游工作。
四象限矩陣
| 區域性 | 級聯性 | |
|---|---|---|
| 暫時性 | 在 subagent 內部 retry;若 retry 耗盡,coordinator 以部分結果繼續 | 加 backoff 後 retry;若 retry 耗盡,中止整個 pipeline |
| 永久性 | 跳過此 subagent;coordinator 以部分結果繼續並標注缺口 | 立即中止;pipeline 的前提已損毀 |
CCA-F 干擾選項經常打亂這四個象限。陷阱模式是對永久性區域性錯誤提供「retry 三次」作為答案,或對級聯性永久性錯誤提供「以部分結果繼續」。考試當天在選擇 propagation 策略之前,先用四象限矩陣過濾情境:它是暫時性還是永久性,是區域性還是級聯性?答案幾乎是機械式地推導出來的。 Source ↗
Fail-Fast vs Fail-Safe 策略 — 何時中止、何時優雅降級
錯誤傳播策略處於兩個極端之間的光譜:fail-fast(在發現問題的第一時間停止)與 fail-safe(即使系統部分異常,仍持續產出有用的輸出)。兩個極端都不是放諸四海皆準的正解;CCA-F 測試你能否根據情境選擇正確的策略。
Fail-Fast
Fail-fast 策略在最早偵測到問題時中止執行。coordinator 停止衍生新的 subagent,將錯誤連同完整上下文向上回報,讓呼叫方決定如何處理。適用情境:
- 下游工作依賴失敗步驟的正確性(級聯性永久性錯誤)。
- 系統處理關鍵狀態變更(金融交易、醫療紀錄、破壞性操作)。
- 部分輸出比沒有輸出更危險(缺少條款的法律文件無法使用;跳過並繼續會產出危險的東西)。
- 呼叫方是人類或其他自動化系統,只能從明確的錯誤訊號中恢復。
Fail-Safe
Fail-safe 策略讓 coordinator 在 subagent 失敗後繼續運行,產出一個盡力而為的結果,並明確標注哪些部分成功、哪些部分失敗。適用情境:
- Subagent 工作彼此獨立(區域性錯誤)。
- 部分結果對使用者仍有真實價值(四個來源中的三個仍然是有用的研究)。
- 使用者能從部分答案做出有根據的決策(解決了帳單問題的客服 agent 即使產品資訊查詢失敗,仍能完成其核心任務)。
- 中止的成本很高(使用者挫折、工作損失、錯過 SLA)。
Coordinator 的角色
Fail-fast vs fail-safe 的決策實際上是在 coordinator 層級落實的。Subagent 通常不知道自己的失敗是級聯性的還是區域性的——只有 coordinator 掌握依賴關係圖。coordinator 讀取結構化錯誤,對照自己對哪些 subagent 是關鍵、哪些是可選的認識,選擇策略。
當考試題目描述一個 multi-agent 研究系統,其中四個 subagent 各自調查獨立主題,正確策略幾乎永遠是 fail-safe 加部分結果處理。當考試題目描述一個客服 agent 其中「驗證客戶身份」的 subagent 失敗,正確策略幾乎永遠是 fail-fast——你不能在未驗證身份的情況下安全繼續。判斷關鍵在於:下游工作是否依賴失敗的這個步驟。 Source ↗
錯誤隔離 — 防止 Subagent 失敗使 Coordinator 崩潰
一個拋出未處理例外的 subagent,如果你沒有設計隔離機制,可能會拖垮 coordinator 的整個執行。CCA-F 的期望是:subagent 的呼叫必須包裹在隔離原語中,將原始失敗轉換為 coordinator 能夠推理的結構化回傳值。
三層隔離
- 例外邊界 — 每個 subagent 呼叫必須置於 try-catch(或語言對應的等效結構)區塊內。在呼叫點捕獲 subagent 內部未處理的例外,並將其轉換為結構化錯誤回傳值。絕對不要讓 subagent 例外以原始形式向上傳播。
- 資源隔離 — Subagent 不應與 coordinator 共用可變的狀態。若 subagent 破壞了自身的對話歷史,這個破壞不能波及 coordinator 的歷史。Agent SDK 的 subagent 原語預設提供這種隔離——每個 subagent 在自己的 context window 中執行。若你天真地將 subagent 訊息合併進 coordinator 的訊息歷史,就會失去這個隔離。
- 超時牆 — 每個 subagent 呼叫必須有最大執行時間預算。卡在緩慢工具上的 subagent,不能讓 coordinator 無限期等待。超時是隔離的一部分,因為它防止「hung subagent」演變成「hung coordinator」。
Subagent Context 隔離不等於錯誤隔離
這是 CCA-F 錯誤傳播面向中被測試最多次的細微差異。Subagent 的 context 是隔離的——subagent 看不到 coordinator 的對話歷史,反之亦然。這種隔離對 token 管理與資訊隱藏很有用。它不能自動隔離錯誤。若 subagent 拋出例外而你的程式碼未在呼叫點捕獲,即使 context 是分離的,coordinator 的程序仍然會崩潰。
社群通過報告特別點名這個陷阱。干擾選項的說法是「subagent 有隔離的 context,因此它們的錯誤無法破壞 coordinator」。這個說法只有一半正確。Context 隔離防止對話歷史汙染,但不能防止程序層級或控制流程層級的破壞。你仍然需要在每個 subagent 呼叫周圍明確使用 try-catch。混淆 context 隔離與錯誤隔離的答案是錯的。 Source ↗
Agent SDK 中的隔離機制
當你使用 Agent SDK 的 subagent 原語時,SDK 提供預設的隔離:subagent 在自己的迴圈中執行,其結果(或錯誤)以結構化值回傳給 coordinator,coordinator 以一個可以推理的觀察值形式接收它。你仍然需要檢查那個結果上的錯誤指示器,並決定如何處理。SDK 不會替你發明 propagation 策略。
跨 Agent 邊界的結構化錯誤 Payload — 保留錯誤語義
當錯誤跨越 agent 邊界——從 subagent 到 coordinator,或從 coordinator 到呼叫方——它必須攜帶足夠的結構化資訊,讓接收方能夠決定如何行動。像「出了什麼問題」這樣的通用字串,迫使每個接收方都只能猜測。
每個跨邊界錯誤 Payload 必備的五個欄位
errorCategory— 受控詞彙分類:transient、permission、business、internal、validation。告訴接收方屬於四象限中的哪一個。isRetryable— 布林值。直接編碼 retry 決策,讓接收方不必從 category 重新推導。message— 對失敗情況的簡潔、人類可讀的描述。可行動化的敘述,而非 stack trace 傾印。context— 關於失敗現場的結構化元資料:哪個 subagent、哪個工具、哪個輸入、哪次迭代。對除錯以及 coordinator 正確歸因失敗至關重要。correlationId— 將此錯誤連結回頂層請求的 distributed tracing 識別碼。對可觀測性至關重要(稍後說明)。
為什麼結構化 Payload 很重要
只收到字串的 coordinator 必須對那個字串做模式匹配,才能決定如何行動。若 subagent 函式庫改變了錯誤措辭,coordinator 的邏輯就會靜默地失效。收到結構化 payload 的 coordinator 可以用確定性的程式碼對 errorCategory 與 isRetryable 做分派。這與 Domain 2 對 MCP 工具錯誤測試的模式相同——當消費者是 coordinator 而非 Claude 時,消費模式是一樣的。
沿鏈保留語義
當 coordinator 將錯誤重新拋給自己的呼叫方時,它不能將結構化 payload 折疊成字串。要包裝(wrap),而不是攤平(flatten)。頂層呼叫方仍然應該能看到原始的 errorCategory、原始 subagent 的身份,以及原始的 context——而不是七層的「步驟 X 發生錯誤:步驟 Y 發生錯誤:步驟 Z 發生錯誤」。
結構化錯誤 payload 是一個跨越 agent 邊界的機器可讀物件,至少包含:errorCategory(受控詞彙)、isRetryable(布林值)、message(人類可讀)、context(結構化元資料)以及 correlationId(distributed tracing ID)。結構化 payload 讓 coordinator 能夠做出正確的 retry、跳過或中止決策,而不必靠猜測。通用字串錯誤是典型的反模式,因為它迫使每個接收方從文字中重新推導語義。
Source ↗
Coordinator 層級的 Retry 決策 — Coordinator 何時應 Retry Subagent
一旦 coordinator 從 subagent 收到結構化錯誤,下一個決策是:retry 該 subagent、跳過它,還是中止?coordinator 層級的 retry 邏輯,與單一 agentic loop 內部的 retry 邏輯有微妙的差異。
Retry 決策樹
- 讀取結構化錯誤上的
isRetryable。若為 false,不要 retry;根據情況跳過(區域性)或中止(級聯性)。 - 若
isRetryable為 true,檢查此 subagent 在本次 coordinator 執行中的 retry 預算。若該 subagent 已被 retry N 次(典型 N = 2 或 3),停止 retry。 - 若 retry 預算尚有餘裕,在 retry 前執行指數退避——等待 1 秒、再 2 秒、再 4 秒。立即 retry 通常會再次觸及相同的暫時性條件。
- 若 retry 成功,以其結果繼續。若再次失敗,遞增失敗計數器並回到步驟 2。
- 若 retry 預算耗盡,視該 subagent 的失敗為該 subagent 的終結,並套用適當的 fallback(區域性則進行部分結果處理;級聯性則中止)。
Retry 預算 vs 迭代上限
一個有三個 subagent、每個 subagent 兩次 retry 預算的 coordinator,外部迴圈的有效執行次數最多可達九次(三個 subagent 各三次嘗試)。結合每個 subagent 內部的 agentic loop 迭代上限,總 token 包絡可能相當大。預算規劃是設計的一部分。
冪等性考量
Retry 只有在 subagent 的工作是冪等的情況下才是安全的。每次執行都會建立一筆資料庫紀錄的 subagent,不能安全地 retry——retry 會產生重複紀錄。每次執行都是抓取並摘要文件的 subagent 是冪等的——retry 是安全的。在設計階段就區分這兩種情況。若 subagent 不具冪等性,在其定義中編碼這一點,讓 coordinator 無論 isRetryable 如何都拒絕 retry。
描述 subagent 執行破壞性操作(寫入生產資料庫、發送電子郵件、呼叫付費 API)的 CCA-F 情境,不應搭配 coordinator 層級的 retry。建議對破壞性操作自動 retry 的答案是錯的。Retry 只適用於冪等工作;破壞性工作應 fail-fast 並升級給人工處理。 Source ↗
部分失敗處理 — Coordinator 以可用的 Subagent 結果繼續
Fail-safe 策略在實作上看起來是這樣的:coordinator 收集每個 subagent 的結果,將缺席與錯誤視為缺口,並以現有的資料產出最佳答案。
標注缺口的模式
每個部分結果都必須明確標注缺少的內容。說「根據查詢到的三個來源」的研究摘要是誠實且可稽核的;說「根據四個來源」但只有三個來源回應,是捏造的謊言。
標注發生在最終合成步驟。coordinator 收集 subagent 輸出時,建立一個同時記錄成功結果和失敗佔位符的資料結構,然後將這個結構傳遞給合成提示,並附上明確標注缺口的指令。
門檻邏輯
部分失敗處理只有在最低完成度門檻以上才是安全的。若研究 agent 預計查詢四個來源,但只有一個回應,「部分結果」就不算部分——它只是單一來源。事先定義門檻:
- 絕對值 — 至少 N 個 subagent 成功。
- 比例值 — 至少 X% 的 subagent 成功。
- 關鍵性加權 — 特定 subagent 標記為「必要」,其失敗無論其他 subagent 成功幾個都強制中止。
考試情境中的優雅降級
multi-agent-research-system 情境是典型的 fail-safe 候選:四個主題研究者餵給一個合成者;失去一個是可以接受的,失去三個則不行。customer-support-resolution-agent 情境則混合策略:身份驗證 subagent 是關鍵(失敗時 fail-fast),而建議文章 subagent 是可選的(fail-safe)。
錯誤累積 — 在硬性中止前追蹤多次軟性失敗
不是每個錯誤都是個別致命的。coordinator 可能容忍一次偶發的工具呼叫失敗或一次 subagent 的小故障,但若這個模式反覆出現,就必須中止。錯誤累積是區分噪音與真正故障的機制。
累積器模式
在整個 coordinator 執行過程中維護一個失敗計數器——按 subagent、按工具或全域計算。每當發生軟性失敗(tool_result 的 is_error: true、errorCategory: transient 的結構化錯誤、只有在最後一次嘗試才成功的 retry),就遞增計數器。當任何計數器超過門檻,升級 coordinator 的應對方式:
- 低於門檻:記錄日誌、繼續,依賴內建的 retry 邏輯。
- 達到門檻:發出可觀測性警報,切換到更安全的策略(降低並行度、延長超時、使用更簡單的工具路徑)。
- 超過門檻:硬性中止整個執行並升級給人工審查。
為什麼累積勝過逐一反應
對每一次軟性失敗都中止的 coordinator,對生產環境而言太過脆弱。對累積失敗完全不反應的 coordinator,太過寬鬆,會高興地在降級狀態下燒完預算。累積門檻讓你能夠容忍噪音底線,同時仍能捕捉持續性故障。
Multi-Agent 情境中的累積
一個衍生十個主題 subagent 的研究 coordinator,可能容忍一兩個個別失敗(部分結果處理),但若在同一次執行中有四個以上失敗就硬性中止——因為在一次執行中有四個失敗,很可能代表的是上游故障,而非個別來源問題。
錯誤累積檢查清單(考試當天前請牢記):
- 按 subagent 和按錯誤類別維護計數器。
- 每次軟性失敗都遞增,包括最終才成功的 retry。
- 在執行開始前設定門檻,而非動態設定。
- 門檻超過時升級應對——不要等到硬性中止。
- 在每次新的 coordinator 執行開始時重置計數器。
若某個答案描述的 coordinator 只對當前錯誤作出反應,沒有任何累積歷史,就是缺少 CCA-F 所期望的可靠性模式。 Source ↗
Circuit Breaker 模式 — 在反覆失敗後停用失敗的 Subagent
Circuit breaker 是業界標準的模式,用於防止下游失敗淹沒上游系統。CCA-F 要求你認識這個模式、知道它的三種狀態,以及——最重要的——知道它是你自己實作的設計模式,而非 Agent SDK 的內建功能。
三種狀態
- Closed(關閉) — 正常運作。請求流向 subagent。計算失敗次數。
- Open(開路) — 失敗次數已超過門檻。所有請求在 coordinator 層直接被拒絕,甚至不嘗試 subagent。快速失敗取代緩慢失敗。
- Half-Open(半開) — 冷卻期結束後,允許一個探測請求通過。若成功,breaker 回到 Closed 狀態。若失敗,breaker 再次 Open,進入另一個冷卻期。
Breaker 的好處
沒有 breaker 的情況下,coordinator 對一個持續失敗的 subagent,每次執行都會重新 retry,在幾乎必然失敗的嘗試上浪費 token 和延遲。Breaker 讓 coordinator 在 subagent 被證明不健康後,可以完全跳過它,為仍然正常工作的 subagent 保留資源。在部分失敗情境中,這是純粹的優化:你更快地得到健康 subagent 的輸出。
Breaker vs 累積器
累積器在單次執行中追蹤錯誤,以決定何時中止。Breaker 在多次執行(或更長的時間窗口)中追蹤錯誤,以決定何時停用。它們是互補的,而非替代關係。生產環境中的 multi-agent 系統通常兩者都有。
Breaker 是模式,不是 SDK 功能
這是 CCA-F 錯誤傳播面向中被測試第二多的細微差異。Claude Agent SDK 沒有內建 subagent 呼叫的 circuit breaker。若你的設計依賴 circuit breaker,你有責任自行實作它——無論是透過 subagent 呼叫的包裝函式、在你的執行環境中使用 Polly 或 resilience4j 這類函式庫,還是在你的 coordinator 中使用自訂狀態。
常見的干擾選項聲稱「啟用 Agent SDK 的 circuit breaker」或「在設定中設定內建 subagent circuit breaker」。兩種說法都是錯的。Circuit breaker 是模式選擇,由你在 coordinator 的呼叫包裝函式中實作;它不是你用 flag 開關的 SDK 內建功能。將 circuit breaker 描述為 SDK 設定的答案是錯誤的。 Source ↗
錯誤回報鏈 — 將根因錯誤上浮至頂層 Coordinator
在深層的 multi-agent 系統中,三層以下發生的錯誤,必須以保留根因的形式讓頂層 coordinator 看到。錯誤回報鏈是讓這成為可能的紀律。
包裝而非攤平
當第 N 層的 coordinator 捕獲第 N+1 層 subagent 的錯誤時,它必須將那個錯誤包裝進自己的結構化 payload——加入自己的 context——而不是將它折疊成通用字串。第 N-1 層的接收方應該能夠從外層包裝一路鑽到內層根因。
概念上,payload 鏈看起來像俄羅斯套娃:
- 外層包裝:
{ source: "synthesis_coordinator", errorCategory: "subagent_failure", cause: ... } - 中層包裝:
{ source: "topic_coordinator", errorCategory: "tool_failure", cause: ... } - 最內層:
{ source: "web_search_tool", errorCategory: "transient", message: "connection timeout" }
根因歸屬
頂層日誌與面向使用者的錯誤訊息,應優先呈現最內層錯誤的 category 與 message,同時保留完整鏈結供除錯使用。像「因為搜尋工具逾時,我們無法完成您的請求」這樣的面向使用者訊息,比「合成 coordinator 失敗:主題 coordinator 失敗:web 搜尋工具失敗:逾時」更清楚,即使後者更完整。
Correlation ID 的關聯
鏈中每個錯誤都帶有相同的 correlationId。這讓可觀測性層能夠事後從 distributed traces 重建完整的錯誤樹——在終端使用者的錯誤回報是薄薄的摘要,但工程師需要完整鏈結的情況下,這是不可或缺的。
Multi-Agent 錯誤的可觀測性 — Distributed Tracing 與 Correlation ID
看不見的東西就無法除錯。沒有明確的可觀測性,multi-agent 錯誤傳播是隱形的。CCA-F 要求考生知道生產 multi-agent 系統的最低可觀測性面向。
每個 Subagent 呼叫應發出的事件
- 開始事件 — 時間戳記、subagent 名稱、coordinator 的 correlationId、父 span ID、輸入 token 數。
- 工具呼叫事件 — subagent 內部的每個
tool_use與tool_result(與單一 agent 迴圈可觀測性面向一致)。 - 結束事件 — 時間戳記、持續時間、最終狀態(成功 / 軟性錯誤 / 硬性錯誤)、輸出 token 數、失敗時的結構化錯誤 payload。
Correlation ID
correlationId(或 traceId)是頂層 coordinator 產生、並傳播至每個 subagent 呼叫、工具呼叫與錯誤 payload 的唯一識別碼。它是讓你從日誌重建整個跨 agent 流程的主鍵。
沒有 correlation ID,coordinator 及其 subagent 的日誌是三條分開的河流,你無法判斷哪個 subagent 的日誌行屬於哪次 coordinator 執行。有了 correlation ID,每個 agent 上的每一行日誌都能拼接成單一 trace。
Distributed Tracing 的 Span
每個 subagent 呼叫是 coordinator 父 span 下的一個 span。subagent 內部的每個工具呼叫,是 subagent span 下的子 span。產生的樹狀結構,視覺化呈現了整個執行的精確形狀——包括哪個 subagent 花了多少時間、哪些工具呼叫失敗、以及延遲在哪裡累積。當 span 與 correlationId 被正確發出時,追蹤工具(OpenTelemetry、Datadog APM 等)能原生渲染這個樹狀結構。
為什麼可觀測性是 Propagation 策略的組成部分
錯誤傳播是錯誤發生後你對它做什麼。可觀測性是錯誤發生時你看到什麼。沒有可觀測性,即使是正確傳播的錯誤也只能靠猜測來除錯。CCA-F 情境有時會將問題框架為「你如何知道這個 multi-agent 系統正在故障?」——答案永遠是結構化日誌加 correlation ID 加 distributed tracing,而不是「ssh 進伺服器後 grep 搜尋」。
Multi-agent 可觀測性在 CCA-F 上不是選配。建議在不先加入 tracing 與 correlation ID 的情況下修復故障 multi-agent 系統的情境答案是錯誤的。沒有可觀測性,你既無法推理跨 agent 的錯誤,更無法有意義地傳播它們。 Source ↗
白話說明
Error propagation 在抽象層面難以掌握,直到你將它錨定在具體情境上。以下三個類比涵蓋了這個概念的完整面向。
類比一:醫院急診分流網絡 — 錯誤分類與 Fail-Fast vs Fail-Safe
想像一家醫院有一個主要分流台(coordinator),將進來的病患分派給專科病房(subagent):心臟科、放射科、骨科和一般實驗室。一名病患因胸痛進來。分流台同時向四個病房送出請求。心臟科很快回報心電圖結果;放射科回報胸部 X 光;骨科回報沒有相關發現;但一般實驗室回報其離心機壞了,血液檢查要等兩個小時。現在分流台必須做決定。若缺少的血液檢查是關鍵的(疑似心臟病發的心肌酶檢查),分流台就 fail-fast——升級給值班醫師,不假裝擁有完整的資訊。若缺少的實驗室結果是可有可無的(例行維生素 D 檢查),分流台就 fail-safe——產出一份標注「維生素 D 待補,明日重試」的報告。這週第三次壞掉的離心機是級聯性永久性問題(訂購新機,不要一直 retry),而偶爾故障的離心機是暫時性的(重開機後重試)。醫院也有一條規則:若單一班次有三件設備壞掉,就升級給部門主管——這是錯誤累積。若某件設備在一個月內壞了十二次,就停止向它派工,直到維護人員確認修好為止——這是 circuit breaker。每個病患、每項檢查、每個技師都帶有相同的入院 ID,讓任何問題都能被追溯——這是 correlationId。一個具備良好 error propagation 的 multi-agent Claude 系統,就是一家永遠不會假裝缺少的結果已存在、也永遠不會因為一台機器壞了就停擺的醫院。
類比二:貨櫃碼頭 — 隔離與邊界
想像一個貨櫃碼頭,有多台吊車,每台正在裝載不同的船。若其中一台吊車的液壓系統在起吊中途故障,你不希望這個故障級聯到鄰近的吊車、拖垮碼頭控制塔,或讓正在裝載的船沉沒。每台吊車在一個有自動斷路的鋼筋隔離區內運作,將故障隔離在原地:吊車停止、警報響起、控制塔收到一份結構化事故報告(3 號吊車、液壓壓力喪失、貨物已暫停、故障時間),其他吊車繼續工作。這就是錯誤隔離。控制塔的事故報告是結構化 payload,而不是慌亂地喊「某台吊車某個地方出問題了!」——它明確說明是哪台吊車、哪類故障(機械 vs 電氣 vs 操作員 vs 天氣)、是否可 retry(冷卻十分鐘)還是永久性的(叫維修),以及將此事故連結到貨運清單的參考編號。碼頭工頭不會根據一台吊車的警報就決定中止整艘船的裝載;他看的是依賴關係圖——第 7 艘船能帶著六個貨櫃中的四個出港嗎?若是,fail-safe 進行部分裝載;若否,fail-fast 並重新排期。沒有這套協作機制的貨櫃碼頭,每次吊車小故障都會演變成全碼頭停工。沒有隔離機制的 multi-agent 系統,每次 subagent 例外都會讓 coordinator 崩潰。
類比三:電力電網 — Circuit Breaker 與級聯預防
城市電力電網是 circuit breaker 模式最直白的類比,因為這個名稱本身就來自電力工程。當一個變壓器故障時,附在那個變壓器上的斷路器跳開——在故障能燒毀鄰近設備之前,將變壓器從電網其餘部分切斷。斷路器是區域性故障與級聯停電之間的邊界。每個家庭都有一個(總開關),每個社區變電站都有一個,每條輸電線都有一個,就像 multi-agent 系統的 coordinator 層次結構一樣,層層堆疊。斷路器跳開後,電網操作員不會立即重新合閘;他們先等待冷卻期(半開狀態),然後嘗試一次測試通電。若故障是暫時性的(一根樹枝落在電線上且已清除),斷路器保持合閘,服務恢復。若故障是永久性的(變壓器本身損毀),斷路器立即再次跳開並保持開路,直到人工介入。沒有斷路器的電網,任何單一故障都會造成整個地區停電——這正是持續 retry 死亡 subagent 的 multi-agent Claude 系統所發生的事。重要的是,斷路器不是電網操作員「在控制軟體中用開關啟用」的東西——它們是必須安裝和接線的實體裝置。CCA-F 測試這個細節:subagent 的 circuit breaker 是你實作的模式,不是你切換的 SDK 設定。
考試當天選用哪個類比
- 關於分類、fail-fast vs fail-safe、部分失敗處理的題目 → 醫院急診分流類比。
- 關於隔離邊界、結構化 payload、防止崩潰傳播的題目 → 貨櫃碼頭類比。
- 關於 circuit breaker、反覆失敗停用、級聯預防的題目 → 電力電網類比。
常見考試陷阱
CCA-F Domain 5 在 multi-agent 系統的 error propagation 方面,持續利用六種反覆出現的陷阱模式。以下每個陷阱都在社群通過報告中以合理干擾選項的形式出現過。
陷阱一:假設 Context 隔離等於錯誤隔離
Subagent 在隔離的 context window 中執行,這保護了 coordinator 的對話歷史不被 subagent 訊息汙染。干擾選項將這個事實延伸成錯誤的宣稱:subagent 失敗無法影響 coordinator。它可以影響。未捕獲的 subagent 例外仍然會讓 coordinator 的程序崩潰;回傳格式錯誤輸出的 subagent 仍然會破壞 coordinator 的合成步驟。你仍然需要在每個 subagent 呼叫周圍明確使用 try-catch 加輸出驗證。將 context 隔離視為自動錯誤隔離的答案是錯的。
陷阱二:將 Circuit Breaker 視為 SDK 內建功能
Circuit breaker 模式在分散式系統中廣為人知,因此考生假設 Agent SDK 一定有提供。它沒有。「啟用 SDK 的 subagent circuit breaker」或「在 settings.json 中設定 circuit-breaker 門檻」這類干擾選項是捏造的。Circuit breaker 是你在 coordinator 的 subagent 呼叫包裝函式中實作的設計模式。將其描述為 SDK 開關的答案是錯誤的。
陷阱三:對永久性錯誤執行 Retry
Retry 適用於暫時性錯誤。權限被拒、schema 違規或資源不存在,不會因為等待後重試而變得可 retry。干擾選項對權限錯誤提供「加指數退避後 retry 三次」作為答案;這既浪費(在明知無望的嘗試上消耗 token 和時間預算)又具有潛在危險(在破壞性操作上,第二次和第三次嘗試可能加劇損害)。永遠以 isRetryable: true 作為 retry 的門控條件。
陷阱四:攤平錯誤鏈
捕獲 subagent 錯誤並以純字串重新拋出的 coordinator,會毀掉恢復邏輯與除錯所需的根因資訊。干擾選項建議「在重新拋出前將錯誤轉換為描述性訊息」——這聽起來負責任,但實際上抹除了結構。正確的行為是將內層結構化錯誤包裝進外層結構化錯誤,保留完整的巢狀結構。面向使用者的訊息可以簡化;記錄的 payload 絕不能被攤平。
陷阱五:Retry 不具冪等性的 Subagent
寫入資料庫、發送電子郵件或扣款信用卡的 subagent,不能安全地 retry。Retry 可能重複副作用。干擾選項將「對任何暫時性錯誤 retry 交易 subagent」作為正確答案;這是錯的。不具冪等性的 subagent 遇到任何錯誤都必須 fail-fast,並移交給人工審查或補償 subagent。冪等性是 subagent 工作的屬性,而非錯誤類型的屬性。
陷阱六:對每個區域性錯誤都中止
Fail-fast 不永遠是正確的。當 subagent 彼此獨立且部分輸出有價值時,在第一個區域性錯誤就中止,會浪費健康 subagent 的工作成果。干擾選項將「任一主題 subagent 失敗時中止研究 pipeline」框架為「安全」的選擇;在 multi-agent-research-system 情境中,為了與一個失敗的來源保持一致性而犧牲三個成功的來源,fail-safe 部分結果路徑才是正確的。在決定中止之前,務必先檢視錯誤是區域性的還是級聯性的。
練習錨點
Error propagation 概念在六個 CCA-F 情境中的兩個最集中出現。將以下內容視為測試任務 5.3 的情境叢集題的架構骨幹。
Multi-Agent-Research-System 情境
在這個情境中,一個頂層研究 coordinator 衍生一組主題 subagent(通常四到八個),每個 subagent 透過呼叫 web 搜尋、文件讀取和摘要工具,研究一個獨立主題。subagent 回報後,一個合成 subagent 將它們的輸出整合成最終報告。這裡的 error propagation 題目幾乎永遠落在 fail-safe 和部分結果象限:一或兩個主題 subagent 因暫時性網路錯誤失敗;coordinator 必須決定是否繼續。正確答案幾乎永遠包括:(1)帶有 errorCategory 和 isRetryable 的結構化錯誤 payload,(2)帶有指數退避且有預算上限的 coordinator 層級 retry,(3)在最終合成中明確標注缺少來源的部分結果處理,以及(4)低於此門檻就完全中止的閾值(例如,少於一半的 subagent 成功)。預期會有提供「第一次失敗就中止」或「無限 retry」作為錯誤路徑的陷阱。
Customer-Support-Resolution-Agent 情境
在這個情境中,一個客服 coordinator 將進入的工單路由給一系列 subagent:身份驗證、帳戶查詢、知識庫搜尋和回應起草。與研究情境不同,這些 subagent 不是獨立的——下游工作依賴上游結果。這裡的 error propagation 題目測試 fail-fast 象限:若身份驗證失敗,每個後續的 subagent 都在無效的前提上運作,不能繼續。正確答案通常包括:(1)在 coordinator 偵測到級聯性錯誤(身份失敗是關鍵的),(2)立即 fail-fast 並升級給人工客服,而非 retry,(3)將結構化錯誤回報上浮給呼叫方,讓人工客服看到根因,以及(4)在身份驗證 subagent 周圍加 circuit breaker,讓該服務的持續中斷不至於阻塞整個佇列。預期會有將此情境與研究情境混淆的陷阱——在未驗證身份的情況下部分解決客服工單是危險的,因此部分結果處理在這裡是錯誤的。
FAQ — Error Propagation 前五大問題
錯誤如何從 subagent 傳回 coordinator?
它們只能透過你的程式碼在 subagent 呼叫點產生的回傳值來傳播。coordinator 不會自動「看到」subagent 錯誤;它看到的是你的包裝函式回傳的值。正確的模式是:用 try-catch 包住每個 subagent 呼叫,將任何捕獲到的例外轉換成帶有 errorCategory、isRetryable、message、context 和 correlationId 的結構化錯誤 payload,然後將那個 payload 作為 subagent 的結果回傳。coordinator 接著檢查結果,並對 errorCategory 做分派,決定要 retry、跳過還是中止。在呼叫點未被捕獲的 subagent 例外,會讓 coordinator 的程序崩潰,無論 context 隔離如何——context 隔離保護的是對話歷史,而非控制流程。
Subagent Context 隔離是否自動防止錯誤級聯到 coordinator?
不。這是 error propagation 面向中被測試最多次的細微差異。subagent context 隔離意味著 subagent 在自己的對話歷史中執行,不會滲入 coordinator 的歷史——這防止了歷史汙染,並有助於 token 管理。它不能防止程序層級或控制流程層級的級聯:未處理的 subagent 例外仍然會讓 coordinator 崩潰,格式錯誤的 subagent 結果仍然會破壞 coordinator 的合成。你需要在每個 subagent 呼叫周圍明確使用 try-catch 加輸出驗證,才能實現真正的錯誤隔離。社群通過報告一致指出,混淆 context 隔離與錯誤隔離是最常見的干擾選項之一。
Coordinator 何時應 retry 失敗的 subagent,何時應以部分結果繼續?
當錯誤 payload 的 isRetryable 為 true、此 subagent 的 retry 預算尚未耗盡,且 subagent 的工作是冪等的(retry 不會重複副作用)時,執行 retry。在 retry 之間使用指數退避——典型值 1 / 2 / 4 秒——以避免立即再次觸及暫時性條件。當錯誤是永久性的或 retry 預算耗盡、該 subagent 是區域性的(其他 subagent 的工作仍然有效)、且下游合成步驟能誠實地標注缺口時,以部分結果繼續。當錯誤是級聯性的(下游工作依賴此 subagent)或整次執行中累積的軟性失敗超過預設門檻時,中止整個執行。
Circuit Breaker 模式是 Agent SDK 的內建功能嗎?
不是。Circuit breaker 是你自己實作的設計模式,通常作為 subagent 呼叫的包裝函式,或透過你執行環境中的 resilience 函式庫。Agent SDK 提供帶有 context 隔離和結構化結果的 subagent 原語,但它沒有隨附可設定的 circuit breaker——不存在你可以切換的 circuitBreaker: { threshold: 5 } 設定。Circuit breaker 在多次執行(或一段時間窗口)中追蹤失敗次數,在門檻超過時開路,等待冷卻,然後在完全重新合閘之前以單一請求探測。將 circuit breaker 描述為 SDK 設定 flag 的答案是捏造的,在考試上是錯的。
如何在多個 Coordinator 層之間保留根因錯誤資訊?
包裝而非攤平。當外層 coordinator 捕獲來自內層 coordinator 或 subagent 的結構化錯誤時,它應該加入自己的 context(哪個內部元件失敗、在第幾次迭代、輸入是什麼),同時將原始結構化 payload 保留為 cause 欄位。產生的錯誤是巢狀結構,最外層包裝反映 coordinator 看到失敗的位置,最內層反映真正的根因。每一層都共享相同的 correlationId,讓 distributed tracing 能將整個鏈結拼接在一起。面向使用者的訊息可以摘要根因(例如「web 搜尋工具逾時」),但記錄的 payload 應保留完整的巢狀結構,讓工程師不必靠猜測就能除錯。建議「在重新拋出前將內層錯誤轉換為描述性字串」的答案會毀掉你需要的資訊,是錯誤的答案。
延伸閱讀
- Subagents in the Agent SDK — error propagation: https://docs.anthropic.com/en/docs/claude-code/sdk/subagents
- Handle tool calls — tool_result format and structured errors: https://docs.anthropic.com/en/docs/agents-and-tools/tool-use/handle-tool-calls
- Orchestrate teams of Claude Code sessions (Agent Teams): https://code.claude.com/docs/en/agent-teams
- Building effective agents — escalation and failure handling: https://docs.anthropic.com/en/docs/build-with-claude/agentic-loop
- Tool use with Claude — overview and agentic loop: https://docs.anthropic.com/en/docs/agents-and-tools/tool-use/overview
Related ExamHub topics: Multi-Agent Orchestration with Coordinator-Subagent Patterns, Structured Error Responses for MCP Tools, Escalation and Ambiguity Resolution, Validation, Retry, and Feedback Loops for Extraction.