Agent Teams:死後清算 — Session 管理的六道裂縫
上一篇講了五種死法。這一篇講死後的系統性崩壞 — 當 agent 在會話裡死而復生、失憶重生、或拖活人下水時,整個 session 的生命週期是怎麼斷裂的。
知識漫畫系列 — 用最少的字,講最硬的技術。
本篇是《Mesh 拓撲與五種死法》的續篇。
前情提要
上一篇分析了 Agent Teams 中 teammate process 的五種終結方式。結論是:只有正常關機有完整協議,其餘四種都是靜默消失。
但那只是開始。
Agent 死了,故事才正式展開 — 因為它們死後的殘留效應,會把整個 session 的生命週期撕開六道裂縫。
裂縫一:先到先得的陷阱
Agent Teams 是全非同步的。你派出 5 個 agent,它們各自工作、各自回報。
問題出在:主 context 不等人。
時間軸:
t=0 Lead 同時派出 Agent A, B, C, D, E
t=10s Agent A 完成,回報結果
t=11s Lead 看到 A 的結果 → 認為「第一階段有結果了」→ 進入第二階段
t=15s Agent B 完成,回報結果
t=16s Lead 收到 B → 但已經在做第二階段的事 → B 的結果被忽略或重複處理
t=30s Agent C, D, E 陸續完成...
Lead 可能已經又派了新的 agent 做同一件事
沒有 barrier。沒有 waitAll()。沒有「等所有人到齊」。
inbox 是一個 JSON 文件追加寫入:
~/.claude/teams/{team}/inboxes/{lead}.json
Lead 在每個 turn 結束時消費 inbox。先到的先處理,晚到的可能被「第二階段的 Lead」當成新任務。
實測:一個 5 agent 團隊,同一件工作被發了 3 次,因為 Lead 忘了誰做過什麼。
裂縫二:失憶的 Compact
Claude Code 的 auto-compact 在 context window 用量達 80% 時觸發(v1.0.51 從 60% 調高)。
Compaction 做的事:把整個對話壓縮成一段文字摘要。
compaction 前:完整對話歷史(所有 tool call、agent 回報、任務狀態)
compaction 後:一段文字摘要 + 「從這裡繼續」
關鍵問題:摘要是純文字,不攜帶結構化狀態。
Compact 之後,模型不知道:
- 哪些 agent 還在運行中
- 它們的 agent ID 是什麼
- 它們負責什麼任務
- 哪些任務已完成、哪些在等待
所以當還在外面跑的 agent 終於回來了:
Agent D (t=45s): "我完成了 API schema 設計,這是結果..."
Lead (post-compact): "API schema?讓我看看... 好的,我來安排人做 API schema 設計。"
→ 派出 Agent F 做同一件事
Compact 殺死了記憶。Agent 從死裡歸來,卻發現主人已經不認識自己了。
CHANGELOG 修復記錄證實了這個問題的嚴重性:
| 版本 | 修復 |
|---|---|
| v2.1.0 | Fixed files and skills not being properly discovered when resuming |
| v2.0.7 | Fixed sub-agents using the wrong model during conversation compaction |
| v1.0.51 | Increased auto-compact warning threshold from 60% to 80% |
| v1.0.12 | Improved todo list handling during compaction |
調高閾值不是解法。它只是推遲了失憶的時間點。
裂縫三:Token 核爆
每個 sub-agent 的 transcript 是獨立的 JSONL 檔案,沒有大小上限。
實測數據(匿名化):
某 session 的 agent transcript 大小:
agent-aaa.jsonl → 425 MB
agent-bbb.jsonl → 256 MB
agent-ccc.jsonl → 19 MB
agent-ddd.jsonl → 12 MB
主 session → 22 MB, 1533 行
一個會話的 sub-agent 加起來超過 700 MB。
v2.1.0 加了 30K 字元截斷,但那只截斷回傳給主 context 的部分。Agent 自身的 transcript 完全不受控。
更糟的場景:多個並行 agent 同時完成並回報結果。
Agent A: 回傳 25K 結果
Agent B: 回傳 28K 結果
Agent C: 回傳 30K 結果
─── 同時寫入 Lead 的 inbox ───
Lead 下一個 turn: 消費 83K 新內容
+ 現有 context ≈ 75%
= 瞬間超過 80% → 觸發 compact
→ 回到裂縫二
並行 agent 的回報是 burst traffic。沒有背壓、沒有流量控制、沒有排隊機制。
裂縫四:Resume 的記憶黑洞
Session 持久化是 .jsonl 逐行追加。Resume 時需要重新載入整個檔案。
一個跑了 2 小時、用了 10+ agent 的 session,JSONL 可以到 20+ MB。
claude --resume <session-id>
↓
載入 22MB JSONL
↓
情況 A: 如果之前有 compact → 載入 compact summary(正確)
情況 B: 如果 compact boundary 損壞 → 載入完整歷史(22MB)
情況 C: 如果 orphaned tool_result 存在 → resume 直接失敗
CHANGELOG 記錄了多次相關修復:
| 版本 | 修復 |
|---|---|
| v2.1.9 | Fixed long sessions with parallel tool calls failing (orphan tool_result) |
| v2.1.7 | Fixed orphaned tool_result errors when sibling tools fail |
| v2.1.0 | Fixed session resume failures caused by orphaned tool results |
| v2.0.1 | Fixed session persistence stuck after transient server errors |
注意到模式了嗎?「orphaned tool result」反覆出現。
原因:當並行 tool call 中有一個失敗,其他的 tool_result 會變成「孤兒」— 有結果但沒有對應的 tool_use。Resume 時 API 要求 tool_use 和 tool_result 一一對應,孤兒存在就直接報錯。
並行越多,孤兒越多,resume 越脆弱。
裂縫五:孤魂野鬼
強制終止 session(Ctrl+C、關掉 terminal、token 用盡)後,留下的殘留:
~/.claude/teams/
├── team-alpha/ ← 上週的團隊
│ ├── config.json
│ └── inboxes/
│ ├── agent-1.json ← 還有未讀訊息
│ ├── agent-2.json
│ └── agent-3.json
├── team-beta/ ← 三天前的
│ └── inboxes/
│ └── ... 11 個 inbox
├── default/ ← 不知道什麼時候留下的
│ └── inboxes/ ← 沒有 config.json(不完整狀態)
└── ... 還有 6 個
系統沒有:
- PID tracking(不知道 process 是否還在)
- Orphan detection(不知道哪些 team 是活的)
- 自動清理(不會 GC 過期的 team 目錄)
- Resume 時的 team 狀態恢復(不知道之前 team 做到哪了)
每次用 Agent Teams 都會在磁碟上留下一層沉積物。清理只能手動。
# 目前唯一的「清理機制」
rm -rf ~/.claude/teams/team-*
裂縫六:Idle 風暴
Agent Teams 的 idle notification 設計有一個隱含假設:一個 agent idle 一次就夠了。
但實際上,每次 agent 的 turn 結束(沒有 tool call)都會觸發一次 idle notification。
實測數據(某個 team 的 10 秒內):
agent-1: idle (t=0.000s)
agent-1: idle (t=0.514s) ← 間隔 0.5 秒
agent-1: idle (t=0.951s) ← 間隔 0.4 秒
agent-1: idle (t=1.505s)
agent-1: idle (t=1.960s)
agent-1: idle (t=2.533s)
agent-1: idle (t=3.034s)
agent-1: idle (t=3.522s)
agent-1: idle (t=5.076s)
一個 agent 在 5 秒內發了 9 條 idle notification。
6 個 agent 的團隊,Lead 的 inbox 裡 69% 是 idle 垃圾。
每條 idle notification 都可能喚醒 Lead → Lead 消費 inbox → 觸發新 turn → 消耗 token → 加速 context 膨脹 → 更快觸發 compact → 回到裂縫二。
idle 風暴 → token 膨脹 → compact → 失憶 → 重複派工 → 更多 agent → 更多 idle
↑ │
└────────────── 正反饋迴路 ──────────────────────┘
v2.0.14 修了一次:「Fixed how idleness is computed for notifications」。
但根本問題沒變 — idle 是 per-turn 觸發,不是 per-session 觸發。
六道裂縫的交互作用
這六個問題不是獨立的。它們會互相放大:
┌──── 裂縫一(先到先得)
│ ↓
│ 重複派工
│ ↓
裂縫六(idle 風暴)→ token 爆炸 ← 裂縫三(token 核爆)
│ ↓
│ 裂縫二(失憶 compact)
│ ↓
│ 更多重複派工
│ ↓
│ 裂縫四(resume 失敗)
│ ↓
│ 強制重啟
│ ↓
└──── 裂縫五(孤魂野鬼)
一個 2 小時的複雜 session,可以經歷全部六道裂縫。
根本原因:缺少三大基礎設施
| 基礎設施 | 當前狀態 | 導致的裂縫 |
|---|---|---|
| 狀態機管理 | 無結構化 agent registry | 裂縫一、二、四 |
| 進程監督 | 無 PID tracking、無心跳 | 裂縫五、六 |
| 同步屏障 | 無 barrier / waitAll | 裂縫一、三 |
Agent Teams 是一個「訊息傳遞 + 共享任務列表」的鬆散協作框架。
它缺少分散式系統必須的三大件。用分散式系統的術語說:
有 message passing → 但沒有 delivery guarantee
有 task queue → 但沒有 exactly-once processing
有 process spawn → 但沒有 supervisor tree
對照:Process Isolation 為什麼能避免
| 裂縫 | Agent Teams | Process Isolation(如獨立 CLI session) |
|---|---|---|
| 先到先得 | Lead 不等人 | Orchestrator 等所有 worker 完成才推進 |
| 失憶 compact | 摘要丟失進行中狀態 | 每個 worker 獨立 context,互不影響 |
| Token 核爆 | Agent transcript 無上限 | 每個 task 獨立 context window |
| Resume 黑洞 | 載入龐大 JSONL | 每個 worker 獨立持久化 |
| 孤魂野鬼 | 無進程追蹤 | 獨立 process,結束即回收 |
| Idle 風暴 | per-turn notification | Worker 完成後直接結束 process |
核心差異:Agent Teams 是 in-process concurrency(協程),Process Isolation 是 true parallelism(進程)。
前者共享命運,一死俱死。後者各自獨立,壞一個不影響整體。
結論
上一篇的結論是:星型不是技術限制,是風險管理。
這一篇的結論是:Agent Teams 的 session 管理,缺少分散式系統的基礎設施。
它很適合短期、低複雜度的團隊任務 — 3 個 agent、做 10 分鐘、不需要 compact 的那種。
但一旦拉長到小時級、agent 數量超過 5 個、需要多階段協作,六道裂縫就會開始互相共振。
Agent Teams 的甜蜜點:
✅ 3-5 個 agent
✅ 10-15 分鐘
✅ 單階段任務
✅ 不需要 resume
危險區域:
❌ 5+ 個 agent
❌ 30+ 分鐘
❌ 多階段依賴
❌ 需要 compact 或 resume
這不是說 Agent Teams 不好。而是說它有適用範圍。
超出這個範圍,你需要的是進程級隔離 — 每個 worker 是獨立 CLI session,orchestrator 只做協調,不共享 context window。
延伸閱讀
- Agent Teams:Mesh 拓撲與五種死法 — 本文前篇
- 從 CMS 到 Agent SDK:遷移實戰 — Process Isolation 的實踐
- Multi-Agent 架構:平行執行模式 — Sub-agent 的基礎