0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

並列で走らせて壊さない — worktree とサブエージェントの分担設計

0
Posted at

仕様をタスクに割った次に来る現実は、「同時に何本走らせるか」だった。1本ずつ順番に流している間は綺麗に見えていた計画が、2本目·3本目を同じリポジトリで動かした途端に崩れる。同じファイルを両方が触る、片方が移動させたモジュールをもう片方が古いパスで参照する、migration が中途半端に走ったままテストが緑になる ─ この手の事故は、エージェントが優秀になればなるほど「一見動いている」ので厄介だ。

タスクの割り方は前回に書いた通りだが、割った後の「どう同時に走らせるか」は別レイヤの設計判断になる。この記事は、受託案件で数ヶ月まわしてきた並列運用のメモである。結論を先に置いておくと、並列度を上げるほど速くなるわけではない。筆者の環境では 3~4 本が境界だった。

複数のターミナルセッションで並行して動くコーディングエージェント

同じリポジトリで複数エージェントを走らせると何が壊れるか

先日、ある案件で「機能A·機能B·リファクタC·ドキュメント整備」の4本を同時に投げてみた。素直に同じ working directory で走らせた結果、10分後にはこうなっていた。

  • 機能A のエージェントが utils/date.ts を編集している最中に、リファクタC のエージェントが同ファイルを別ディレクトリに移動

  • 機能B が新しい依存を package.json に追記した直後、リファクタC が lockfile を再生成して衝突

  • ドキュメント整備が「現状のAPI」を読みに来た時点で、機能A の途中コードを「正」として書き起こす

どれもエージェント側の不具合ではなく、単に「同じ砂場で複数人が同時に穴を掘ると崩れる」というだけの話だ。人間の開発者ならブランチを切って separate な checkout を持つのだが、素の Claude Code セッションを何本も上げると、デフォルトでは同じ working directory を共有してしまう。

worktree で物理的に分離する

解は昔から git にある ─ git worktree だ。1つのリポジトリから複数の作業ディレクトリを切り出せる仕組みで、それぞれが独立したブランチとファイル状態を持つ。Claude Code 側も比較的最近のバージョンから worktree を前提にした運用がしやすくなっており、業界的にも AI エージェントを並列で回す文脈での使い方が広まってきている。

筆者の運用は極めて素朴で、案件のルートに .worktrees/ を掘って、そこにタスクごとの作業ツリーを吐き出すだけだ。

#!/usr/bin/env bash
# scripts/agent-worktree.sh
# 使い方: ./scripts/agent-worktree.sh feature-A
set -euo pipefail
TASK="$1"
BRANCH="agent/${TASK}"
PATH_WT=".worktrees/${TASK}"
既にあれば再利用、なければ main から切る
if ! git show-ref --verify --quiet "refs/heads/${BRANCH}"; then
git worktree add -b "${BRANCH}" "${PATH_WT}" main
else
git worktree add "${PATH_WT}" "${BRANCH}"
fi
echo "worktree ready: ${PATH_WT} (branch: ${BRANCH})"

あとは、各エージェントセッションをそれぞれ .worktrees/feature-A·.worktrees/refactor-C の中で起動する。ファイル衝突は物理的に起きなくなるし、片方が壊しても他方に波及しない。マージは人間側で PR ベースにまとめる ─ このレイヤだけは自動化を我慢している。理由は後述する。

worktree でも解決しないもの

ただし worktree は「ファイルの物理的衝突」を消すだけで、意味的な衝突は残る。たとえば feature-A と refactor-C が両方とも同じ関数のシグネチャに依存している場合、それぞれの worktree では緑になっても、後で main にマージした時点で片方が壊れる。これは worktree の問題ではなく、そもそもタスク分割の直交性が甘かったという話なので、前回書いた「タスクを割るときに依存グラフを人間側で先に見る」に戻ってくる。

サブエージェントに何を任せて、何を任せないか

並列運用のもう一つの軸は、メインのセッションからサブエージェントを spawn するかどうか、だ。ここは案件を重ねるうちに、かなり明確な線引きに落ち着いた。

任せていい仕事は、探索·横断調査·定型変換の3つに集約される。「このリポジトリ全体で Date をどう使っているか列挙して」「20個のコンポーネントに同じ prop を足して」「ログ形式を新旧両対応で書き換えて」─ この手のタスクはコンテキストを消費するばかりで判断が要らない。メインセッションのコンテキストウィンドウを守るためにも、サブに投げて要約だけ回収するのが正解だ。

任せてはいけない仕事は逆で、設計判断·外向きの変更·検収の最終判定である。「このドメインモデルを2つに分けるべきか」「この API のレスポンス形状をこう変えていいか」「マイグレーションを本番に流していいか」 ─ これらは、たとえサブエージェントが正論を返してきても、メインで責任を持つ人間(あるいは意思決定を担うメインセッション)が引き取るべきだ。ここを渡してしまうと、後から「なぜこの設計にしたのか」を誰も再構成できなくなる。

並列度についても最初は欲張って N=8 で走らせたのだが、結果を統合するレビューが追いつかず、結局 3~4 に落ち着いた。一般的にも並列サブタスクの sweet spot は3~5と言われていて、感覚としても合致する。「5つのタスクに分けて並列で調べて」のように個数を明示すると、なぜか結果の安定度が上がる ─ これは経験則で理屈はまだ言語化できていない。

並列度を上げると逆に遅くなる境界

並列は「実行時間」だけを見ると常に速いように錯覚するが、実際に案件のスループットで測ると、ある本数を境に逆転する。筆者の観測では、境界を決めているのは3つのボトルネックだ。

  • レビュー帯域 ─ 人間が1日に読める diff の量には上限がある。8本並列で走らせても、6本目以降は「レビュー待ち」で寝ている

  • マージ順序の再解決コスト ─ N本を main に取り込む間の rebase·conflict 解消が、Nに対して線形以上に伸びる

  • コンテキスト再構築 ─ 並列本数が増えるほど「どの worktree で何をやっていたか」を思い出すコストが増える。名前付けだけで解決しない

この3つのうち最初にサチュレートするのは、たいていレビュー帯域だ。だから並列度の上限は「エージェントが同時に何本走れるか」ではなく「あなたが1日にレビューできる PR は何本か」で決まる。筆者の場合はソロなので3~4本、レビュアが2名いる案件では6~7本まで伸ばせた。

もう一つ、地味だが効いたのは「並列で走らせるタスクは、実行時間ができるだけ揃うように選ぶ」ことだ。30分で終わるタスクと3時間かかるタスクを並べると、短い方が終わった後にレビューを挟むタイミングが崩れて、結局逐次より遅くなる。粒度をある程度揃えて投げると、レビューのリズムが崩れない。

まとめと次回

今回まとめると、worktree で物理的衝突を消し、サブエージェントには探索·横断·変換だけを任せ、並列度はレビュー帯域から逆算する ─ これが筆者の現時点の運用だ。ここに書いた数字(3~4本)はあくまで筆者の環境での話で、レビュー体制が違えば当然変わる。ただ、「並列度を上げるほど速い」という素朴な前提だけは、まず疑ってみる価値がある。

次回は「エージェントの出力をどこまで信じるか」 ─ 受け入れテストと検収の話を書く予定だ。並列で走らせて集まってきた PR を、どの粒度で人間が signoff するか、というレイヤの話になる。

筆者は 5years+ で AI/LLM を使った受託開発を担当している。

0
0
1

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?