「マルチエージェントにしたら良くなるはず」——こう思ってエージェントを増やした結果、むしろ遅くなった経験はありませんか?
Anthropic のエンジニアチームは、チームが何ヶ月もかけて複雑なマルチエージェント構成を作った結果、単一エージェントのプロンプトを改善しただけで同等の結果が出たケースを何度も目にしてきたと語っています。
この記事では、Anthropic が公開したブログ「Building multi-agent systems: When and how to use them」の知見を整理し、「いつマルチエージェントにすべきか」「どう分割すべきか」の判断軸を実践的に解説します。
まず単一エージェントで限界を試す
マルチエージェントの話に入る前に、大前提を確認しておきましょう。
適切にツールを与えた単一エージェントは、多くの開発者が思っている以上のことができます。
エージェントを増やすたびに、以下のオーバーヘッドが発生します。
- 障害点の増加: エージェントごとに壊れるポイントが増える
- プロンプトの管理コスト: エージェントごとにプロンプトを書いてメンテナンスする必要がある
- トークンの爆発: マルチエージェントは同等タスクに対して 3〜10倍 のトークンを消費する
この3〜10倍のコスト増は、コンテキストの重複、エージェント間の調整メッセージ、ハンドオフ時の要約から生まれます。Anthropic は「計画・実行・レビュー・反復」を別々のエージェントに分けた構成を作ったチームが、ハンドオフのたびにコンテキストを失い、実作業よりも調整に多くのトークンを費やしていた事例を紹介しています。
つまり、マルチエージェントは「明確なメリットがコストを上回る場合」にだけ採用すべきです。
マルチエージェントが効く3つのパターン
Anthropic が「一貫してマルチエージェントが単一エージェントを上回る」と確認した場面は、以下の3つです。
パターン1: コンテキスト保護
LLM のコンテキストウィンドウは有限で、情報が増えるほど応答品質が下がります。あるサブタスクで生成された情報が後続のサブタスクに無関係なのに残り続ける——これがコンテキスト汚染です。
具体例: カスタマーサポート
注文履歴を調べながら技術的な問題を診断するサポートエージェントを考えてみましょう。
単一エージェントの場合、注文検索のたびに2,000トークン以上の履歴がコンテキストに積み上がります。技術的な問題を推論する段階では、この注文データはまったく不要なのに、コンテキストを圧迫して注意力を散らしてしまいます。
マルチエージェントの場合、注文検索を専用のサブエージェントに委任します。サブエージェントは完全な注文履歴を処理し、必要な情報だけを50〜100トークンに要約して返す。メインエージェントのコンテキストはクリーンなままです。
class OrderLookupAgent:
def lookup_order(self, order_id: str) -> dict:
# 独自のコンテキストで注文情報を処理
messages = [
{"role": "user", "content": f"注文 {order_id} の要点を取得して"}
]
response = client.messages.create(
model="claude-sonnet-4-6",
max_tokens=1024,
messages=messages,
tools=[get_order_details_tool]
)
# 必要な情報だけ返す
return extract_summary(response)
class SupportAgent:
def handle_issue(self, user_message: str):
if needs_order_info(user_message):
order_id = extract_order_id(user_message)
# コンパクトな要約だけ受け取る
summary = OrderLookupAgent().lookup_order(order_id)
context = f"注文 {order_id}: {summary['status']}, 購入日 {summary['date']}"
# メインエージェントのコンテキストはクリーン
messages = [
{"role": "user", "content": f"{context}\n\nユーザーの問題: {user_message}"}
]
return client.messages.create(
model="claude-sonnet-4-6",
max_tokens=2048,
messages=messages
)
コンテキスト保護が特に効くのは、サブタスクが 1,000トークン以上 の情報を生成するが、その大部分がメインタスクに不要な場合です。
パターン2: 並列化
複数のエージェントを並列で走らせることで、単一エージェントがカバーできない広さの情報空間を探索できます。
Anthropic の Research 機能はまさにこのアプローチです。リードエージェントがクエリを分析し、複数のサブエージェントを生成して異なる側面を並列調査。各サブエージェントが独立して検索し、要約した結果を返します。
import asyncio
from anthropic import AsyncAnthropic
client = AsyncAnthropic()
async def research_topic(query: str) -> dict:
# リードエージェントがクエリをファセットに分解
facets = await lead_agent.decompose_query(query)
# 各ファセットを並列でサブエージェントに調査させる
tasks = [research_subagent(facet) for facet in facets]
results = await asyncio.gather(*tasks)
# リードエージェントが結果を統合
return await lead_agent.synthesize(results)
async def research_subagent(facet: str) -> dict:
"""各サブエージェントは独自のコンテキストウィンドウを持つ"""
messages = [
{"role": "user", "content": f"調査: {facet}"}
]
response = await client.messages.create(
model="claude-sonnet-4-6",
max_tokens=4096,
messages=messages,
tools=[web_search, read_document]
)
return extract_findings(response)
ただし注意点があります。並列化の主なメリットは「速さ」ではなく「網羅性」です。 並列エージェントは合計のトークン消費は増えますし、総実行時間も単一エージェントより長くなることが多い。その代わり、単一エージェントではコンテキストの限界でカバーしきれない広さを調査できます。
Claude Code で日常的に使える並列化の例を挙げると、「このリポジトリの認証周りの実装を調査して」「APIエンドポイントの一覧を洗い出して」「テストカバレッジの状況を確認して」を同時に3つの Agent ツールで走らせるケースです。各サブエージェントが独立にコードベースを探索し、メインエージェントのコンテキストを汚さずに要約を返してくれます。1つずつ順番にやらせるより、はるかに網羅的で、メインのコンテキストもクリーンに保てます。
パターン3: 専門化
異なるタスクに異なるツールセット・システムプロンプト・ドメイン知識が必要な場合、専門化されたエージェントに分けることで信頼性が向上します。
ツールセットの専門化
単一エージェントに20個以上のツールを持たせると、適切なツールの選択精度が下がります。以下の3つの兆候が出たら、専門化を検討してください。
- ツールの数が多すぎる: 20個以上で選択を誤り始める
- ドメインの混同: データベース操作、API呼び出し、ファイル操作など無関係なドメインが混在
- ツール追加で性能低下: 新しいツールを足すと既存タスクの性能が落ちる
ただしマルチエージェント化の前に、Tool Search Tool(オンデマンドでツールを発見する仕組み)の導入を検討しましょう。すべてのツール定義を最初から読み込む代わりに動的に発見させることで、トークン使用量を最大85%削減しつつ選択精度を改善できます。
システムプロンプトの専門化
矛盾する振る舞いが必要な場合も分離が有効です。カスタマーサポートは共感的で忍耐強く、コードレビューは精密で批判的、コンプライアンスチェックは厳格、ブレインストーミングは創造的。これらを1つのエージェントで切り替えさせると、一貫性が失われます。
コンテキスト中心の分割原則
マルチエージェントを採用すると決めたとき、最も重要な設計判断は「どう分割するか」です。Anthropic は、多くのチームがこの判断を間違えていると指摘しています。
やりがちな失敗: 問題タイプで分割
「機能を書くエージェント」「テストを書くエージェント」「レビューするエージェント」のように作業の種類で分けると、ハンドオフのたびにコンテキストが失われます。テスト担当は実装の意図を知らず、レビュー担当は試行錯誤の経緯を知らない。
Anthropic の実験では、ソフトウェア開発ロールごとに専門化したエージェント群が、実作業よりも調整にトークンを多く費やしたという結果が出ています。
正しいアプローチ: コンテキスト境界で分割
機能を実装するエージェントが、そのテストも書くべきです。なぜなら実装のコンテキストを既に持っているから。コンテキストが真に分離できる場合にのみ作業を分割します。
分割がうまくいく境界
- 独立した調査パス: 「アジアの市場動向」と「ヨーロッパの市場動向」は共有コンテキストなしで並列調査できる
- クリーンなインターフェースを持つ分離コンポーネント: API仕様が明確なら、フロントエンドとバックエンドの作業は並列化可能
- ブラックボックス検証: テストを実行して結果を報告するだけの検証エージェントは、実装コンテキストが不要
分割がうまくいかない境界
- 同じ作業の逐次フェーズ: 同じ機能の計画→実装→テストは共有コンテキストが多すぎる
- 密結合コンポーネント: 頻繁にやり取りが必要な部分は同じエージェントに
- 共有ステートが必要な作業: 理解を頻繁に同期する必要があるなら分離しない
検証サブエージェントパターン
Anthropic が「ドメインを問わず一貫してうまくいく」と評価しているのが、検証サブエージェントです。
なぜうまくいくのか
検証は最小限のコンテキスト転送で成立するからです。検証エージェントはアーティファクトがどう作られたかを理解する必要がない。仕様を満たしているかどうかだけを判定すればいい。「伝言ゲーム問題」を構造的に回避できるパターンです。
最大の落とし穴: 早すぎる合格判定
検証エージェントの最も深刻な失敗モードは、1〜2件のテストを通しただけで「合格」と判定してしまうこと。
対策は明確です。
- 「テストスイート全体を実行し、すべての失敗を報告せよ」 と具体的に指示する(「ちゃんとチェックして」では不十分)
- 複数シナリオとエッジケースのテストを必須にする
- 失敗すべき入力でも確認させる(ネガティブテスト)
- 明示的な指示: 「完全なテストスイートを実行するまで合格と判定してはいけない」は必須文言
単一エージェントの限界を示すサイン
最後に、「そろそろマルチエージェントを検討すべき」という具体的なサインをまとめます。
| サイン | 対応 |
|---|---|
| コンテキストが上限に近づき、性能が劣化 | コンテキスト保護パターンを検討(ただしコンパクション等の進歩で閾値は変化中) |
| ツールが15〜20個以上で選択精度が低下 | まず Tool Search Tool を試す。それでもダメなら専門化 |
| 独立した並列処理が可能なサブタスクがある | 並列サブエージェントで網羅性を向上 |
これらの閾値はモデルの進化とともに変わります。あくまで現時点での実用的なガイドラインです。
まとめ
Anthropic のアドバイスは一貫しています。
最もシンプルなアプローチから始めて、証拠に基づいてのみ複雑さを追加せよ。
マルチエージェントにする前に確認すべき3つの条件:
- マルチエージェントが解決する本物の制約がある(コンテキスト上限、並列化の機会、専門化の必要性)
- 分割がコンテキスト境界に沿っている(作業タイプではなく、必要なコンテキストで分ける)
- 明確な検証ポイントがある(サブエージェントが完全なコンテキストなしで検証できる箇所)
Claude Code 自体が Orchestrator-Subagent パターンを採用しているように、まずは単一エージェント + 必要な場面でのサブエージェント委任から始める。それが最も投資対効果の高いスタート地点です。
もしあなたが今マルチエージェントの導入を検討しているなら、まず以下を試してみてください。
- 現在の単一エージェントのプロンプトを見直す。意外とそれだけで解決することが多い
- コンテキストが膨れている箇所を特定する。そこだけサブエージェントに委任するのが最小コストで最大効果
- 検証を別エージェントに分離する。実装と検証の分離は、ほぼすべての場面で投資対効果が高い
5つの連携パターン(Generator-Verifier / Orchestrator-Subagent / Agent Teams / Message Bus / Shared State)の詳細な比較と進化パスについては、Anthropic の続編記事「Multi-agent coordination patterns」で深掘りされています。