Strands AgentsのSwarmで自律協調型マルチエージェントを試してみた

Strands AgentsのSwarmで自律協調型マルチエージェントを試してみた

2026.02.02

こんにちは。サービス開発室の武田です。

前回の記事ではGraphパターンについて紹介しました。今回は Swarm パターンを試してみます。

Swarmとは

Swarmは、複数のエージェントが自律的に協調して複雑なタスクを解決するパターン です。従来の階層的なマルチエージェントシステムとは異なり、中央制御なしで自律的な協調を実現します。

公式ドキュメントでは次のように説明されています。

A Swarm is a collaborative agent orchestration system where multiple agents work together as a team to solve complex tasks.

「協調的なエージェント編成システム」であり、複数のエージェントがチームとして協力して複雑なタスクを解決するという説明ですね。従来の順序的・階層的なマルチエージェントシステムとは異なり、共有作業メモリをもつ自己組織化チームとして動作します。

なぜこのパターンを使うのか

公式ドキュメントでは、Swarmの主要な特徴として次の点が挙げられています。

特徴 説明
Self-organizing teams 共有作業メモリをもつ自己組織化チーム
Tool-based coordination ツールを通じたエージェント間協調
Dynamic task distribution エージェントの能力に基づく動的タスク分配
Emergent intelligence 共有コンテキストを通じた集合知能

「自己組織化」「動的タスク分配」「集合知能」というキーワードがSwarmの本質を表しています。Graphのように開発者がフローを明示的に定義するのではなく、エージェント自身が状況を判断して協調するのが特徴ですね。

基本的なしくみ

このパターンの構造を図で示すとこうなります。

strands-agents-swarm-autonomous-agent-collaboration_1.png

Swarmでは、各エージェントに handoff_to_agent というツールが自動的に付与されます。エージェントは自分のタスクを完了した後、または別のエージェントの専門性が必要と判断した場合に、このツールを使って制御を引き継ぎます。

handoff_to_agentの役割

handoff_to_agent は、Swarmが各エージェントに自動付与する調整ツールです。エージェントはこのツールを使って、別のエージェントに制御を渡します。

# LLMが内部的に呼び出すhandoffのイメージ
handoff_to_agent(
    agent_name="専門家の名前",
    message="引き継ぐ内容やコンテキスト"
)

重要なのは、開発者がhandoffのタイミングや条件をコードで書かない ことです。LLMが会話の文脈を理解して「今この専門家に任せるべき」と自律的に判断します。

共有コンテキスト

Swarmの重要な特徴として 共有コンテキスト(共有作業メモリ) があります。公式ドキュメントによると、Swarmは次の情報を含む共有コンテキストを維持します。

  • 元のタスク説明
  • タスクに関わったエージェントの履歴
  • 前のエージェントが提供した知識
  • 協調可能なエージェントのリスト

すべてのエージェントがこれらの情報にアクセスできるため、handoffを受けたエージェントは「なぜ自分に引き継がれたのか」「これまでに何が行われたか」を理解したうえで作業を継続できます。

実装例1: 基本形(リサーチャー → ライター)

まずはシンプルな2エージェント構成の例から見ていきましょう。

ユースケース

リサーチャーが情報を調査し、ライターが文章を作成するという流れを実装します。

エージェントの定義

https://github.com/TAKEDA-Takashi/study-for-strands-agents/blob/main/03-swarm/01_basic_swarm.py#L17-L37

リサーチャーのシステムプロンプトで「調査が完了したら、その情報をライターに引き継いでください」と記載しています。これは強制ではなく「示唆」です。LLMが適切なタイミングと判断した時点でhandoffが実行されます。

Swarmの構築

https://github.com/TAKEDA-Takashi/study-for-strands-agents/blob/main/03-swarm/01_basic_swarm.py#L39-L46

Swarm の構築はシンプルです。nodes にエージェントのリストを渡し、entry_point で開始エージェントを指定します。max_handoffsmax_iterations は安全機構として設定しておきます。

実装例2: 動的ルーティング(カスタマーサポート)

次に、Swarmの真価が発揮される動的ルーティングの例を見てみましょう。

ユースケース

カスタマーサポートで、受け付けが問い合わせ内容に応じて専門担当に振り分けます。ただし会話の途中で「技術的な問題かと思ったら、実は料金の問題だった」と問題の本質が変わることもあります。

strands-agents-swarm-autonomous-agent-collaboration_2.png

受け付けエージェント

https://github.com/TAKEDA-Takashi/study-for-strands-agents/blob/main/03-swarm/02_dynamic_routing_swarm.py#L23-L37

受け付けエージェントは問い合わせ内容を分析し、技術・請求・解約のいずれかの担当に振り分けます。

専門担当エージェント

https://github.com/TAKEDA-Takashi/study-for-strands-agents/blob/main/03-swarm/02_dynamic_routing_swarm.py#L39-L83

技術サポートのシステムプロンプトがポイントです。「対話を通じて、実は技術的な問題ではなく別の問題だと判明した場合は、適切な担当者にhandoffしてください」という指示があります。これにより、会話を進める中で問題の本質が変わった場合に動的にルーティングが変更されます。

Swarmの構築

https://github.com/TAKEDA-Takashi/study-for-strands-agents/blob/main/03-swarm/02_dynamic_routing_swarm.py#L85-L92

4つのエージェントをSwarmに登録しています。Graphのように条件関数を書く必要はありません。

Graphでこれを実装すると?

Graphで同様の動的ルーティングを実装しようとすると、条件関数で「プラン制限の話題が出た」ことを判定する必要があります。

# Graphの場合(難しい)
def should_handoff_to_billing(state: GraphState) -> bool:
    # 「プラン制限」「料金」などのキーワードで判定?
    # 文脈を理解した判断は難しい
    return "プラン" in str(state.results.get("tech_support").result)

単純なキーワードマッチングでは、「これは表面上は技術の質問だが、実は請求の問題だ」という文脈を理解した判断は難しいですね。このようなケースではSwarmが適しています。

実装例3: バックトラック

最後に、Swarmの特徴である バックトラック(前のステップに戻る) の例を紹介します。

ユースケース

「要件定義 → 実装 → レビュー」という流れで、レビュー時に「要件が不明確」と判明した場合、要件定義へ戻るケースです。

strands-agents-swarm-autonomous-agent-collaboration_3.png

エージェントの定義

https://github.com/TAKEDA-Takashi/study-for-strands-agents/blob/main/03-swarm/03_backtrack_swarm.py#L23-L79

レビューエージェントのシステムプロンプトで、問題の種類に応じたhandoff先を指示しています。軽微な修正であれば実装担当に、要件レベルの問題であれば要件定義に戻ります。

Swarmの構築(バックトラック対応)

https://github.com/TAKEDA-Takashi/study-for-strands-agents/blob/main/03-swarm/03_backtrack_swarm.py#L81-L88

バックトラックを考慮して max_handoffs=10 と多めに設定しています。タイムアウトも長めにしています。

ポイント

  • reviewerが「要件が不明確」と判断
  • 自らrequirements_analystにhandoff
  • LLMが「前のステップに戻るべき」と自律的に判断

Graphでもループは実装できますが、条件関数で「前のステップに戻るべきか」を明示的にコードで定義する必要があります。Swarmでは、エージェント自身が状況を判断して柔軟に対応します。

このパターンが向いているケース

文脈に応じた柔軟な判断や、会話の中で状況が変化しうる場合に向いています。カスタマーサポートでの動的振り分けや、複雑なプロジェクトでの専門家間協調がいい例ですね。

逆に、フローを明示的に制御して予測可能な動作を求めるならGraphです。単純な専門家への委譲だけならAgents as Tools、固定フローを再利用可能なツールとして定義したいならWorkflowがいいでしょう。

注意点とベストプラクティス

意図しない動きの可能性

LLM判断ですので、予期しないhandoffが起きることもあります。対策としては、システムプロンプトを明確にし、handoffの条件を適切に示唆することが重要です。

上限設定の重要性

swarm = Swarm(
    nodes=[...],
    entry_point=entry_agent,
    max_handoffs=10,          # handoff回数の上限
    max_iterations=15,        # イテレーション上限
    execution_timeout=600.0,  # タイムアウト(秒)
)

無限ループを防ぐために、これらの設定は必須です。公式ドキュメントでも安全機構として明記されています。

反復的なhandoffの検出

公式ドキュメントでは、同じエージェント間で繰り返しhandoffが発生するパターンを検出する機能も紹介されています。

swarm = Swarm(
    ...,
    repetitive_handoff_detection_window=3,  # 3回の履歴で反復を検出
)

Graphとの比較

SwarmとGraphはどちらも複数のエージェントが協調するパターンですが、ルーティングの決定方法が根本的に異なります。

観点 Swarm Graph
ルーティング決定 LLM判断 条件関数(コード)
予測可能性 低い 高い
柔軟性 高い 低い
デバッグ 困難 容易
コンテキスト共有 自動(共有作業メモリ) 明示的(GraphState経由)

公式ドキュメントでは、この違いを次のように説明しています。

The critical distinction is how execution paths are determined

「実行パスがどう決定されるか」が重要な違いです。Swarmではエージェント(LLM)が文脈を理解してルーティングを判断し、Graphでは開発者がコードで条件を定義して予測可能なルーティングを実現します。

どちらを選ぶか

状況 推奨
条件が明確に定義できる Graph
文脈に応じた柔軟な判断が必要 Swarm
デバッグの容易さ重視 Graph
人間のような判断が必要 Swarm

まとめ

Swarmは、Strands Agentsで エージェントが自律的に協調する ためのパターンです。handoff_to_agent ツールで制御を引き継ぎ、共有コンテキストで情報を共有します。

「LLMが判断する」というのは、明示的なif文を書くのではなく、エージェント自身が文脈を理解して適切な引き継ぎ先を決めるということです。これにより、会話の中で状況が変化するような動的なケースにも柔軟に対応できます。

公式ドキュメントでは「創発的知能(Emergent Intelligence)」というコンセプトで説明されています。予測可能な動作よりも柔軟な対応を重視する場合に適したパターンですね。どなたかの参考になれば幸いです。

参考リンク

この記事をシェアする

FacebookHatena blogX

関連記事