iT邦幫忙

2026 iThome 鐵人賽

DAY 25
0
Claude AI

資深工程師的 Claude Code 工作筆記系列 第 25 篇

Day 25:多 session 協作,讓好幾個 Claude 一起做事又不互相踩到

  • 分享至 

  • xImage
  •  

前面講過把一個 session 的事派給 subagent(Day 18),也講過同時開好幾個 session 時用 worktree 隔離(Day 15)。這兩篇處理的是「怎麼分」。今天處理分完之後的事:好幾個 Claude 同時在做事,它們之間怎麼傳話、誰說了算、誰負責收尾,還有哪些地方最容易出事。

在本機最常用來讓多個 Claude 一起做事的機制有五個,名字很像,行為差很多。官方另外還有 dynamic workflows 與 projects,今天不展開。選錯形式,或選對了卻沒處理好共用資源,出的事通常不吵,只是靜靜地把某個人的修改蓋掉,或讓審查看了一份已經變掉的檔案。

五種形式,差在誰協調、誰共用什麼

形式 誰協調 彼此怎麼溝通 工作樹 預設狀態
subagent 主對話的 Claude 結果回報給呼叫它的對話 預設共用,可設 isolation: worktree 開
fork 主對話的 Claude 同上,但繼承整段對話 預設共用,可在呼叫時帶 isolation 互動 session 預設開
agent teams lead(主 session) 成員之間直接互傳,模型有任務工具時另有共享任務清單 共用,不隔離 關,實驗功能
背景 session(agent view) 你自己 只回報給你 編輯前自動進獨立 worktree 開,research preview
獨立 session 互傳訊息 你自己 純文字訊息 預設共用,要用 claude --worktree 開才隔離 開

幾個要點:

  • subagent 與 fork 的差別是 context。 subagent 從空白 context 開始,看不到你的對話歷史,只拿到委派訊息加上 CLAUDE.md 等專案設定(內建的 Explore 與 Plan 連 CLAUDE.md 都不載,細節見 Day 18)。fork 繼承整段對話,所以第一個請求能重用父層的 prompt cache,需要同樣背景的事用 fork 比開新的 subagent 省。用 /subtask <任務> 就能開一個,fork 不能再 fork。
  • agent teams 是唯一由 lead 統一協調、可以有共享任務清單的形式。 一般 subagent 主要把結果回報給呼叫者,Claude 有替它取名字的話,它也能用 SendMessage 跟其他具名 agent 傳話,但沒有共享清單;背景 session 只對你負責。想讓 A 的發現傳給 B,可以用 agent teams,也可以靠跨 session 傳訊。具名的 subagent 還能被 SendMessage 叫回來,帶著完整的對話歷史繼續做事;內建的 Explore 與 Plan 是一次性的,不能這樣續用。
  • 背景 session 的隔離是自動的,agent teams 的隔離不是。 這是今天最值得記住的不對稱。

官方給了三個選擇問題,很好用:誰協調(Claude 在對話內委派,還是你丟出去稍後回來看,還是由 Claude 規劃一群 worker)?工人要不要互相溝通?會不會改到同一批檔案?答案決定形式。

一個簡單的判斷順序:先問能不能用 subagent 解決。 任務能自成一塊、回報一份摘要就好,用 subagent。只有在成員之間需要互相質疑、互相交接中間結果時,才值得上 agent teams。組團隊之前,先確認比較輕的做法做不到。

五種協作形式的差別

agent teams:強,但要自己管邊界

啟用與意外組隊

agent teams 預設關閉,要設環境變數 CLAUDE_CODE_EXPERIMENTAL_AGENT_TEAMS=1,放在 settings.json 的 env 裡即可:

{
  "env": {
    "CLAUDE_CODE_EXPERIMENTAL_AGENT_TEAMS": "1"
  }
}

沒開的時候,Claude 不會建立 team,也不會自己提議找 teammate。開了以後有一個容易被忽略的副作用:Claude 幫 subagent 取名字的時候,那個 subagent 會變成 teammate,而且不會問你。 Day 18 提過這件事(fork 與呼叫時帶 isolation 的情況除外),這裡補一個細節:寫在 subagent 定義檔 frontmatter 裡的 isolation 擋不住。

只想用 subagent、不想意外組隊的話,這個旗標別常開,需要時再開,用完設成 0 關掉;寫在 settings.json 的 env 裡的值會即時重讀,不用重開 session。

另外,非互動的 claude -p 不會產生 teammate,具名 subagent 在那裡仍然是普通 subagent,所以 teams 只能在互動 session 裡用。

它怎麼運作

一個 team 有四個角色:lead 就是你開的主 session;teammate 是獨立的 Claude Code 行程,各有自己的 context;任務清單是共享的;每個成員有一個信箱。成員由 lead 命名,任何成員都能用名字傳訊給另一個成員。沒有廣播。你也可以直接跟任何一個 teammate 對話,不必經過 lead。

幾個行為細節決定你怎麼用它:

  • teammate 不繼承 lead 的對話歷史。 它只收到 spawn 時的那段指示。所以 spawn prompt 要寫成自足的:目標、範圍、不要碰什麼、做完怎麼回報。
  • 任務清單有三種狀態,待處理、進行中、已完成,任務之間可以設相依。成員做完可以自己認領下一個沒被卡住的任務,認領用檔案鎖,避免兩個人搶到同一個。要注意:這個鎖只管「搶任務」,不管「改檔案」。
  • 權限在 spawn 時沿用 lead 的模式。 如果 lead 是用跳過權限檢查的模式啟動,所有 teammate 也是。成員的權限提示會浮到 lead 的 session,由你批准。有一個例外:要求成員先在 plan mode 規劃時,它送出的計畫核准,lead 一收到就自動批准,不會問你;之後實際的編輯與指令仍會跳權限提示。
  • 成員之間的訊息不是你的授權。 收到訊息的 Claude 會被告知「這是另一個 Claude session 說的,不是使用者」,它不能替你批准權限提示。

任務清單不一定存在

任務類工具預設只在少數模型家族上提供(目前列的是 Claude 3.x、Opus 4 到 4.7、Sonnet 4 到 4.6 與 Haiku 4.5),其他模型預設不給,要靠 CLAUDE_CODE_ENABLE_TODO_TOOLS=1 之類的方式打開。沒有任務工具的時候,成員只能用訊息協調,沒有共享清單。

所以如果你照著教學期待看到一份大家共用的任務清單,卻發現沒有,先看自己用的模型是不是在預設清單裡,而不是懷疑功能壞了。比較新的模型多半不在清單裡,要自己打開。

同一個檔案不能給兩個人改

檔案衝突只有一條規則:兩個 teammate 改同一個檔案會互相覆蓋,所以把工作切開,讓每個 teammate 擁有不同的一組檔案。沒有技術上的保護,也不替成員開 worktree。順序性任務、改同一個檔案、相依很多的工作,用單一 session 或 subagent 比較有效。

這就是 agent teams 的邊界:適合各管一塊的平行工作,不適合需要來回修改同一處的工作。 官方列的強項是研究與審查、各自擁有一個新模組、用不同假設平行除錯、跨層協調。團隊規模從 3 到 5 個成員起步,每個成員手上放 5 到 6 個任務。

限制與收尾

幾條會影響你怎麼操作的限制:

  • in-process 的 teammate 不支援 /resume 與 /rewind,resume 之後 lead 可能傳訊給一個已經不存在的成員,這時要叫 lead 重新 spawn。
  • 任務狀態會落後,成員忘了標完成,會卡住依賴它的任務。
  • 一個 session 只能有一個 team,不能巢狀,lead 不能移交。
  • 關閉成員要等它做完手上的請求或工具呼叫,所以會慢。
  • 成本明顯高於單一 session,官方成本頁給的數字是在 plan mode 下約 7 倍。成員做完就請它關閉,不然它會一直吃 token 直到 session 結束。

收尾方面,沒有獨立的清理指令。session 結束時 team 的設定目錄自動移除,但任務清單目錄會留在本機,保留多久由 cleanupPeriodDays 決定。如果用 tmux 分割畫面,session 結束後 tmux session 還留著,就用 tmux ls 找出來,再 tmux kill-session -t <名稱>。

TeammateIdle 與 TaskCompleted 兩個 hook 事件可以用 exit 2 擋下來(Day 17),回饋給成員繼續做。

背景 session:隔離是自動的,但有例外

claude agents 開 agent view,claude --bg "任務" 直接在背景開一個 session,/background 把目前的對話移到背景,/fork 在 agent view 功能沒被關掉時(預設是開的),則是把整個 session 複製成新的背景 session;功能關掉的話,/fork 改成開 fork subagent,/subtask 也不能用。每個背景 session 是獨立行程,由常駐的 supervisor 管,關掉終端機也不會停。

檔案方面,編輯檔案之前,Claude 先把 session 搬進 .claude/worktrees/ 下的獨立 worktree,並行的 session 可以讀同一份 checkout,但各自寫自己的。要留意的例外有五個:

  • 用 ← 或 /background 把已經在編輯的 session 移到背景,它繼續在原處改。
  • 已經在 linked worktree 裡。
  • 要寫的檔案本身就在某個 linked worktree 裡,例如 session 或它的 subagent 自己用 git worktree add 開出來的。
  • 不是 git repo,而且沒設 WorktreeCreate hook。這時 session 直接寫工作目錄,彼此沒有隔離,不要同時派會改同一批檔案的並行 session。
  • 寫入的位置在工作目錄之外。

完成之後,背景 session 的預設行為是 commit,有 remote 就 push,需要的話開 draft PR,但絕不 push 到 main 或 master、不 force push、不 merge。預設行為可以被覆蓋: 任務指示、CLAUDE.md 或記憶裡寫了「commit 與 push 由我自己處理」,它就把 git 留給你。想要「只有主 session 能 push」,就要把這句寫進它讀得到的地方,光靠另一份沒人引用的檔案是不夠的。另外,只寫「不 push」它可能連 commit 都交還給你,刪 session 前先確認有 commit。

刪除要小心。 在 agent view 刪掉 session,會一併移除 Claude 為它建立的 worktree,連同沒 commit 的修改;有還沒 push 的 commit 時會拒絕並提示 --discard-unpushed。想留的先 commit。

另一個限制是額度:背景 session 和互動 session 一樣耗額度,同時跑十個,用得大約是一個的十倍快。

獨立 session 之間傳訊息

這是最輕量的一種,不用啟用任何東西(版本要夠新)。你用自然語言告訴 Claude「去問另一個終端機的那個 session,遷移做完了沒」,或用 @ 加 session 名字,Claude 內部用 ListAgents 找對象,用 SendMessage 送出。session 取好名字很有用:/rename 或啟動時 --name,名字就是它的地址。

幾個行為值得知道:

  • 只傳純文字。 不帶對話歷史,也不帶檔案。要搬整段對話請 resume。
  • 送達時機。 對方正在回合中,訊息在兩次工具呼叫之間被讀到,不會打斷執行中的工具;對方閒置,則會開一個新回合來處理。
  • 同一台機器走本機 socket,不經過 Anthropic 的伺服器。 跨機器或雲端才會經過。
  • 收件端有防線。 訊息會被標示為來自另一個 session;訊息裡的指令(例如 /compact)只是文字,不會被執行;收件的 Claude 會被要求不要因為別的 session 的請求去改權限設定或 CLAUDE.md,也不能替你核可權限。沒設 crossSessionInbound 時,收件匣依雙方的權限模式決定:只要一邊是跳過權限檢查的模式、另一邊不是,訊息就先暫扣等你核准,核准對話框預設五分鐘(dialogExpiry)沒回應就丟棄;其餘情況直接送達。crossSessionInbound 可以設成接受、暫扣或拒絕。背景 session 常見的搭配是 worker 跳過權限檢查、主 session 不是,這時送給 worker 的訊息會卡在核准框,回報的方向也一樣:worker 回給你的訊息,五分鐘沒按核准就丟棄。所以「凍結」要等對方回報已停手才算數,兩邊的權限模式盡量一致。
  • 有迴圈保護。 兩個 session 互相回覆形成的來回,會因為限流、重複訊息丟棄與佇列上限而自己停下來。

適合的用途是交接一個發現、告訴對方「合進去了」、查長時間工作的進度、跨機器傳話。它沒有共享任何東西,是通知機制,不是協作機制。

協作最容易出事的地方

下面是把上面的機制放在一起,會露出來的接縫。

協作最容易出事的五個接縫

一、同一個工作樹,後寫的悄悄蓋掉先寫的

兩個寫入者讀了同一份檔案,各自改完整份寫回,後寫的那份會蓋掉先寫的,沒有警告,git status 只顯示這個檔案被修改。用 worktree 隔離以後,這件事沒有消失,而是延後到合併的時候變成明確的衝突,但至少看得見了。

所以規則是:能隔離就隔離;不能隔離的就切檔案範圍,一個檔案同一時間只有一個人有寫入權。 agent teams 沒有替你做這件事,要在 spawn 的指示裡寫清楚每個成員的檔案範圍。

二、審查還在改的東西

這個最隱蔽。審查者開始讀的時候,作者其實還在動筆,審查報告裡帶行號的發現,到交出來時已經指到別的行,報告看起來正常,其實有一批早就失效。

做法是三步:

  1. 先下凍結指令,等對方回確認再派審查。 「做完了」和「不會再改了」是兩回事。對方回報「定版」,可能只是這一輪結束。
  2. 審查前後各記一次內容指紋。 行數加一個內容雜湊就夠。前後不一致,就停下來回報,不要交報告。
  3. 不要用修改時間判斷檔案是否靜止。 修改時間會被工具保留或改寫(例如 cp -p、切換分支),多個寫入者併發時順序也可能對不上。用內容判斷。

指紋可以這樣記,前後各一次:

wc -l report.md && shasum -a 256 report.md   # 前後要用同一個指令

凍結期間連「明顯是對的小修正」也先不要動,記下來等解凍。那種改動污染審查,因為改動本身是對的,事後沒人會懷疑那幾條發現已經失效。

三、轉述別的 session 說的事,沒有核對

另一個 session 說「那個修正已經合進去了」,你把它原樣轉給別人,後來發現其實沒有。跨 session 傳來的訊息是第二手資料,Claude Code 也會標明它來自另一個 session,不是你。要轉述之前,自己用 git 或 API 看一次。 這只要幾秒,錯了的代價卻是後續判斷全建立在假的前提上。

四、誰有權做對外的事

push、開 MR、留言、寫共用資料庫,這些動作做了就收不回。多個 session 同時存在時,容易出現「實作的那個 session 順手做掉」或「聽說使用者同意了」。

機制本身已經把底線畫好:別的 session 傳來的訊息不是使用者的授權,收到的 Claude 不能拿它當作批准。可以把這條延伸成流程:對外動作只由一個主 session 執行,而且授權必須是使用者在這個主 session 裡直接下的指令。 實作方在凍結之後回報成果,主 session 核對完內容指紋,再執行對外動作。實作方如果拒絕執行轉達來的授權,那是它做對了。

五、共用資源沒有排班

dev server 與瀏覽器分頁這類共用資源會互相污染,Day 15 已經講過,這裡只補多 session 協作才有的部分:動共用資源之前先確認對方的狀態。對方閒置,不代表它不會再動,你再送一則訊息就會把它叫醒。背景 session 用 claude agents 看狀態;其他 session 可以請 Claude「等那個 session 做完時通知我」,不要自己一直傳訊息去問,那反而會把它叫醒(這個通知只送一次,雙方版本都要夠新)。是執行中就等,或者明講「這個環境交給你,我不碰」。交接也要講明白:誰現在用、用到什麼時候、交給誰,共用的資料庫與展示環境同理。

三個常見場景,可以這樣選

場景一:要同時查三個互不相干的問題。 每個問題都要讀一堆檔案,你只要結論。用 subagent 三個並行派出,各回一份摘要。不需要成員互相講話,也不需要隔離,因為都只讀不寫。

場景二:同一個 repo 裡有三件獨立的修改要做,你想去忙別的。 用背景 session,一件事一個,各自進自己的 worktree。它們彼此不需要溝通,要注意的是額度消耗。

場景三:一個大功能,前端、後端、測試各自成塊,而且後端做到一半要告訴前端 API 長什麼樣。 成員之間需要溝通,這才是 agent teams 的位置,前提是三塊的檔案範圍切得開,並在 spawn 指示裡寫明。如果前後端改的是同一批檔案,或每一步都依賴前一步的結果,就退回單一 session,用 subagent 處理其中可獨立的查詢。

還有一種:你自己開兩三個終端機,各用 claude --worktree <名稱> 開一個 session,只靠跨 session 傳訊互相通知。這種做法最彈性,也最容易出事,沒有任何一方負責整體,要靠下面那份協議來補。

把規矩寫成一份協議

上面五條可以寫成一份很短的協議,只放不會變的規則。要讓它生效,要做兩件事。第一,在專案的 CLAUDE.md 裡獨立一行寫 @COORDINATION.md 引入(不要加反引號,加了就變成純文字,不會匯入),teammate 與背景 session 都會載入 CLAUDE.md。這兩個檔要先 commit,有 remote 的話還要 push(或合併)進預設分支,因為 --worktree 開出的 worktree 預設從 remote 的預設分支建立,沒進去就讀不到;不想先 push,可以在 settings.json 寫 "worktree": { "baseRef": "head" }。第二,啟動每個 session 時指定名字與角色,例如 claude --bg --name worker-a "你是 worker-a,只改 src/api/**",互動版是 claude --worktree worker-a --name worker-a "你是 worker-a,只改 src/api/**"。coordinator 也要 --name coordinator。名字同時是跨 session 傳訊的地址。下面是示意版(內容是中性的範例):

# COORDINATION.md(示意)

## 角色
- coordinator:唯一能 push、開 PR、寫共用資料庫的 session。
- worker-a、worker-b:只在自己的 worktree 工作,完成時 commit 到自己的分支,但不 push、不開 PR,並回報 commit 給 coordinator。

## 檔案範圍
- worker-a:`src/api/**`
- worker-b:`src/ui/**`
- 沒列在上面的檔案,先問 coordinator 再動。

## 共用資源
- dev server 與共用資料庫的使用權,用跨 session 訊息交接,持有者明講「交給你了」。不要把「現在歸誰」寫在這份檔裡。

## 審查規則
- coordinator 說「凍結」之後,worker 停手、把修改 commit 起來,再回報 commit SHA;沒收到回報就不算凍結,審查以那個 SHA 為準。
- 審查前後各記一次 `wc -l` 與 `shasum -a 256`,不一致就回報,不交報告。

## 轉述規則
- 引用其他 session 的說法之前,先用 `git log` 或 API 自己核對。

這份東西不長,但它把「誰可以寫哪裡、誰可以對外、什麼時候算凍結」這三件最容易吵起來的事,變成開工前就講好的事。另外,請 Claude 寫給別的 session 的訊息時,可以要求它第一句就是祈使句的指令(「現在開始做 X,這是新指令」),確認與背景放後面。對方可能正在忙,讀到訊息時情況已經變了,開頭是回顧的訊息可能被當成回顧。

一份短協議管三件事

今天的重點

  • 五種形式,差在誰協調、誰能互相講話、工作樹共不共用。能用 subagent 就先用,agent teams 留給成員之間需要互相質疑與交接的平行工作。
  • agent teams 預設關閉,開了之後具名的 subagent 會自動變 teammate,不會問你。它不隔離檔案,要自己切範圍。
  • 背景 session 會自動進獨立 worktree,但有五個例外,不在 git repo 裡(又沒設 WorktreeCreate hook)就完全沒有隔離;它預設還會自己 commit 與 push,要自己寫明由誰處理 git。
  • 跨 session 訊息是純文字通知,不是授權,也不共享任何東西。
  • 做法是把規矩寫成一份短協議:凍結後才審查,用內容指紋而不是時間戳,對外動作只由主 session 執行,共用資源明講誰在用。

上一篇
Day 24:記憶與 context,讓長時間的工作不失憶,也不撐爆 context
下一篇
Day 26:權限規則與 sandbox,兩層邊界各擋什麼
系列文
資深工程師的 Claude Code 工作筆記 共 30 篇
圖片
  熱門推薦
圖片
{{ item.channelVendor }} | {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

1 則留言

0
helenanova
iT邦新手 5 級 ‧ 2026-10-09 23:26:25

這張表把「worktree 預設隔不隔離」列出來很有用,agent teams 預設關閉這點最容易踩到。我會用一個小實驗驗證:讓兩個成員同時改同一個檔案,看後寫入的是覆蓋還是產生衝突,再對照 isolation: worktree 開啟後的行為。這樣選形式的依據是實測結果,而不是只靠文件描述。

我要留言

立即登入留言