十数個の AI agent を同時に動かす方法

深くすり合わせるのは各プロジェクトのメイン agent とだけ。別の agent が 5 分ごとに全員を巡回し、作業の重なりと私の判断待ちだけを報告します。

私は 8 つのプロジェクトを並行して進めています。多いときには 17 個の agent が動いています。

管理には Herdr を使っています。コーディング agent 向けのターミナルワークスペースで、agent ごとにペインが 1 つあり、それぞれが作業中・ブロック中・完了・待機中のどれなのかを Herdr が判別します。agent 同士で互いの出力を読んだり、メッセージを送り合ったりすることもできます。

ただ、ツールが解決するのは「見えること」までです。本当のボトルネックは私の注意力です。ペインを切り替えるたびに、そのプロジェクトの文脈を頭の中で組み立て直さなければなりません。agent が増えるほど、私自身がシステム全体でいちばん遅い部分になっていきます。

そこで、構造を 2 段に分け、さらに私の代わりに巡回する agent を 1 つ置きました。

メイン agent とは深く話し、全員は浅く読む

「要対応」の通知・短い報告 私 方向づけ・判断 オーケストレーター 5 分ごとに巡回 メイン agent Aプロジェクト A メイン agent Bプロジェクト B メイン agent Cプロジェクト C メイン agent Dプロジェクト D 単独で作業 実装レビューチーム aチーム bチーム c分解レビュー 深さの上限:サブ agent はさらに下を起動しない
  • 私がメイン agent と深くすり合わせる
  • オーケストレーターが読む・通知する・中継する
  • 私への通知
  • メイン agent がサブ agent を起動し、受け入れ確認する

2 種類の会話が同時に進みます。

  • 私とメイン agent:深い対話。 各プロジェクトには、そのプロジェクトの文脈をすべて持つメイン agent が 1 つあります。設計、計画、未決事項は、このメイン agent と直接すり合わせます。
  • オーケストレーターと全 agent:浅い読み取り。 オーケストレーターはどのプロジェクトも担当しません。5 分ごとに全 agent の最新の出力を読み、私の対応が必要なことだけを報告します。

これで、プロジェクトを 1 つずつ切り替えなくても全体を把握できます。深く入る必要があるときは、1 つのプロジェクトに入り、1 つのメイン agent とだけ話します。

構造は 2 段まで。 メイン agent はサブ agent を起動できます。レビュー担当、1 つの PR の実装担当、並行して動く複数のチームなどです。サブ agent はさらに下の段を起動しません。そのため、どの agent も文脈を持つメイン agent から 1 段以内にあり、成果物はメイン agent が受け入れ確認をします。これ以上深くすると責任の境界があいまいになり、文脈も段ごとに失われていきます。

4 つの役割

  • 私: 各メイン agent と方向を決め、私の判断が必要な問題、承認ダイアログ、Web 画面で私にしかできない操作に対応します。クラウドリソースへの書き込みやインフラの変更といったリスクの高い操作は、私自身が承認します。
  • メイン agent: 1 つのプロジェクトについて、文脈、計画、PR、現在の状態を記録するファイルに責任を持ちます。自分が出した PR は、CI、レビューコメント、コンフリクトを含めてマージまで責任を持ちます。サブ agent を起動し、その成果物を受け入れ確認します。
  • サブ agent: メイン agent のために、範囲のはっきりしたタスクを 1 つこなします。PR の実装、設計のレビュー、1 回分のクリーンアップなどです。報告先はメイン agent で、終わったら閉じます。
  • オーケストレーター: プロジェクトも PR も担当しません。5 分ごとに全 agent を巡回し、私の対応が必要なことを報告し、作業が重なっている双方に通知し、私の回答をそのまま中継します。

5 分ごと:先に重なり、次に要対応

5 分 タイマー 1 · 重なりのチェック worktree、変更した領域、 オープン PR とそのファイル 2 · 要対応のチェック 状態、返答、ダイアログ、 ディスク、Docker 3 · 報告 短い報告 次の回 通知はステップ 1 の中で送る。私の回答は回と回の間に中継する

オーケストレーターは毎回同じ順序で動きます。重なりのチェック、要対応のチェック、そして報告です。

この 2 つのチェックが、この仕組みの中心です。agent が増えると、よくある問題は 1 つの agent の誤りではありません。2 つの agent がそれぞれ正しく動いていても、合わさると衝突すること。あるいは、ある agent が私を待って止まっているのに、私がそれに気づかないことです。

重なりのチェック:1 つの領域に 1 つの方向

メイン agent 同士は、互いの文脈を見られません。

重なりとは、2 つの agent が両方とも変更または決定している 1 つの領域のことです。モジュール、ドキュメントやアーキテクチャ決定記録(ADR)、インターフェースの取り決め、PR、デプロイなどです。オーケストレーターはパスだけでなく意味で照合します。たとえば services/foo と docs/spec/foo は同じ領域です。

重なりを見つけると、オーケストレーターは双方に同時に通知します。どちらかがその領域を再び変更する前に、双方が相手の計画を知り、合意していなければなりません。

次のものは重なりとはみなしません。

  • メイン agent と自分のサブ agent(同じタスク指示を共有しているため)
  • 読むだけ、またはレビューするだけの agent
  • 一方の変更がすでにマージされている領域

24 時間以内に通知済みで、その後新しい変更がない組み合わせには、再度通知しません。

例:2 つのフロントエンド PR が同じファイルを変更

プロジェクト B と E は、同じフロントエンドのリポジトリでそれぞれ別のアプリを開発しています。

  • 前日、オーケストレーターはリポジトリの共有部分(コンポーネントライブラリ、モックのバックエンド、インターフェースの取り決め)について双方に初めて通知し、どちらがどの共有ファイルを変更してよいかで合意しました。
  • 10:11、プロジェクト E の PR が開発ガイドとロックファイルを変更していて、次にマージされる予定でした。プロジェクト B が新しく出した骨組みの PR も、同じ 2 つのファイルを変更していました。オーケストレーターの判断は、方向は一致している(別のアプリ)が、後からマージする側がコンフリクトする、というものでした。双方に通知し、この組み合わせを記録しました。
  • 10:12、2 つの agent が直接やりとりし、E を先にマージして B が後でリベースすることで合意しました。それぞれ状態ファイルに記録しました。
  • 10:16、E の PR がマージされ、開発環境にデプロイされました。
  • 10:36、B のリベースが完了しました。開発ガイドには双方の変更が残り、ロックファイルは変化なし。型チェック、lint、テスト、ビルドはすべて通りました。

この間、私には何も聞かれませんでした。報告に「通知済み……方向は一致」という 1 行が加わっただけです。

プロジェクト B への通知はおおよそ次のとおりです。プロジェクト E には立場を入れ替えた同じ内容が届きました。

重なりのチェック(オーケストレーターより):あなたとプロジェクト E は、フロントエンドのリポジトリの共有ファイル(開発ガイドとロックファイル)を両方とも変更しています。
- あなた:骨組みの PR がこの 2 つのファイルを変更しています。
- 相手:同じ 2 つのファイルを変更する PR が、まもなくマージされます。
- 判断:方向は一致(別のアプリ)。ただし、後からマージする PR はコンフリクトします。
これらのファイルを再び変更する前に、計画を 1 通のメッセージで相手に送り、返事を読み、どちらがリベースするかを決めて、その合意を状態ファイルに書いてください。
合意できない場合、またはこれが人間の決めるべき選択である場合は、これらのファイルの変更を止め、返信でそう伝えてください。

大事なのは最後の一文です。合意できない衝突や、本来私が決めるべきことは、agent 同士で勝手に片づけられません。その作業は止まり、「あなたが対応すべき衝突」として私の報告に上がってきます。

要対応のチェック:何を「私の対応が必要」とするか

重なりのチェックの後、オーケストレーターは agent ごとに、私を待っているかどうかを判断します。鍵は「私の対応が必要」を明確に定義することです。広すぎると報告がノイズだらけになり、私はすぐに読まなくなります。狭すぎると、本当に止まっている agent を見落とします。

対応が必要:

  • 承認や質問のダイアログで止まっている。報告にはダイアログの原文を引用する。
  • 最後の返答が私に判断・選択・操作を求めていて、まだ答えがない。権限チェックで拒否された操作も含む。
  • 自分では直せない失敗を報告している。
  • ホストの異常:ディスクの空きが 30 GiB 未満、または Docker が応答しない。全 agent のビルドと E2E テストがこの 2 つに依存している。
  • 引き継ぎを監視するプロセスが 10 分以上ポーリングしていない。

対応は不要:

  • チームメイトの承認や CI を待っている。「待ち」の行に入れる。
  • agent の入力欄に残っている文字。私がまだ送っていない入力か提案であって、質問ではない。
  • 中継した回答ですでに解決した質問。

対応不要の agent は、作業中・待ち・待機中のどれか 1 行にだけ入ります。待機中の agent には直近の作業領域を書き添えるので、新しいタスクを渡すか閉じるかを判断できます。

報告

報告の形はいつも同じです。最初に重なり、次に私の対応が必要なこと、最後に作業中・待ち・待機中を 1 行ずつ。次はある日の午前の報告で、名前は置き換えてあります。

重なり:あなたの対応が必要な衝突はありません。通知済み:フロントエンドのリポジトリの開発ガイドとロックファイル(プロジェクト B ↔ プロジェクト E、方向は一致)。

対応が必要:
1. プロジェクト B(新しいアプリの骨組み):フロントエンドのリポジトリに、社内 npm パッケージの読み取り権限を付与してください。
2. プロジェクト A(性能):サービスを 1 vCPU に下げるインフラ変更。残しますか、閉じますか?

作業中:プロジェクト B の実装担当(アプリの骨組み)、プロジェクト C のチーム c(E2E シナリオ 16 本)
待ち:  プロジェクト C のチーム a(承認 1/2)、プロジェクト D(承認 1/2)
待機中:雑務(Docker とディスクの整理)、テストカバレッジの監査
ホスト:空き 313 GiB、Docker 正常

数秒で読み終わり、自分の作業に戻れます。

その日の午前の 3 件の通知

  • 09:45 Docker が止まっていて、プロジェクト C のチーム c が E2E シナリオ 16 本を実行できず、メイン agent がダイアログで尋ねてきました。私が「Docker を起動」を選ぶと、オーケストレーターが起動してダイアログに回答しました。シナリオが流れ、チーム c が PR を出しました。
  • 09:53 プロジェクト B が、GitHub の Web 画面で私にしかできない操作を必要としていました。フロントエンドのリポジトリに、社内パッケージの読み取り権限を付与することです。設定を終えると、オーケストレーターが「完了」と中継し、プロジェクト B はすぐに最初のフロントエンド PR に取りかかりました。
  • 09:53 プロジェクト A が朝の起動時の負荷を測定し終え、サービスを 1 vCPU に下げるインフラ変更を残すか閉じるかを尋ねてきました。「残して着手」と答えると、数分後に PR が出ました。Terraform plan には想定どおりの変更だけが出ていました。

オーケストレーターがいなければ、Docker が止まっていることに気づくのは、たまたまプロジェクト C を見たときになっていたはずです。

注意力は判断のために残す

この仕組みで大事なのは、agent の数ではなく、注意力の配分です。

  • 方向やトレードオフを決められるのは私だけなので、メイン agent とは深く話す。
  • 「誰が私を待っているか」「誰と誰がぶつかっているか」は明確に定義でき、定期的に確認できるので、オーケストレーターに任せる。
  • 2 段の構造によって、どの agent の成果物も、文脈を持つメイン agent が受け入れ確認する。

agent はいくつでも並行して動かせますが、判断する人は 1 人だけです。その人の注意力は判断のために残し、それ以外は仕組みに任せます。

← すべての記事