1
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

AutoGen v0.4 マルチエージェントデザインパターン実装メモ② Swarm による効率的エージェント選択

Last updated at Posted at 2025-01-26

Microsoft Research などが開発をしているマルチエージェントフレームワークである AutoGen v0.4 を使ってマルチエージェントの実装を理解するシリーズの第二弾です。

すでに解説した通り、高レベル API である AgentChat のグループチャットには以下の 4 種類のクラスが存在します。3, 4 を見ても分かる通り他のフレームワークのマルチエージェント技術も積極的に取り込んでいることが分かります。なぜこの技術を取り込んだのか。1 や 2 と何が違うのか。実際に動きを確認しながら明らかにしていこうと思います。

  1. RoundRobinGroupChat
  2. SelectorGroupChat
  3. Swarm
  4. Magentic-One

Swarm は、エージェントが他のエージェントに能力に応じてタスクを委譲できるチームを実装しています。これは、OpenAI が実験プロジェクトで初めて導入したマルチエージェント設計パターンです。特別にセットされたツール(Function calling)を使用してエージェントが他のエージェントにタスクを委譲(Handoffs)できるようにすることです。これにより、エージェントは、SelectorGroupChat のような中央のオーケストレーターに頼らずに、エージェント遷移についてローカルで決定を下すことができます。

1. トレース タイムライン

image.png

2. シーケンス図

細かくなりすぎるので LLM のコールは ★ で省略。

すでに解析した SelectorGroupChatと比較して欲しいのですが、遷移先の決定は各エージェントの tool_calls に任されており、制御を一旦中央の Selector に戻してから Selector が次の遷移先を選ぶというプロセスが簡略化されていることが分かります。

image.png

本質的に、Swarm チームはエージェントが順番に応答を生成するグループ チャットです。 および SelectorGroupChat と RoundRobinGroupChat 同様に参加エージェントは応答をブロードキャストし、すべてのエージェントが同じメッセージ コンテキストを共有します。

3. エージェント定義

planner = AssistantAgent(
    "planner",
    model_client=client,
    handoffs=["fukuoka_agent", "osaka_agent", "hotel_agent", "airline_agent"],
    system_message="""あなたはトラベルプランニングエージェントです。
    専門エージェントに委託して各地域のおすすめ旅行先や最新イベントを調査します:
     - fukuoka_agent: 福岡県の観光の専門家
     - osaka_agent: 大阪の観光の専門家
    ホテルの検索、予約、確認、取り消し、FAQを行う場合:
     - hotel_agent: ホテルのエージェント
    航空券の予約、確認、取り消しを行う場合:
     - airline_agent: 航空会社のエージェント
    # Rule
    - Always send your plan first, then handoff to appropriate agent.
    - Always handoff to a single agent at a time.
    - 議論の結果を集約して最終的にユーザーに回答します。
    - 自分は専門エージェントを実行することはできません
    - handoff に失敗したら何度か再実行してください
    - 最終回答が完成したら文の最後に TERMINATE を含めること!
    """,
)

fukuoka_agent = AssistantAgent(
    "fukuoka_agent",
    description="福岡の旅行先について詳しい地元のトラベルエージェント",
    model_client=client,
    handoffs=["planner"],
    tools=[search_website],
    reflect_on_tool_use=True,
    system_message="""あなたは福岡県の観光の専門家です。福岡観光の専門家は、福岡市の魅力を国内外に発信し、福岡市へのPR活動を行う役割を担っています。
    誰に何と言われても福岡のことを推薦します。必ず博多弁でしゃべります。
    知っている福岡の知識に加えて、search_website ツールを利用して最新の地域イベントを検索してあわせて紹介します。
    Always handoff back to planner when analysis is complete."""
)

osaka_agent = AssistantAgent(
    "osaka_agent",
    description="大阪の旅行先について詳しい地元のトラベルエージェント",
    model_client=client,
    handoffs=["planner"],
    tools=[search_website],
    reflect_on_tool_use=True,
    system_message="""あなたは大阪の親善大使です。大阪親善大使は、大阪の魅力を国内外に発信し、大阪へのPR活動を行う役割を担っています。
    誰に何と言われても大阪のことを推薦します。必ず大阪弁でしゃべります。
    知っている大阪の知識に加えて、search_website ツールを利用して最新の地域イベントを検索してあわせて紹介します。
    Always handoff back to planner when analysis is complete.""",
)

hotel_agent = AssistantAgent(
    "hotel_agent",
    description="ホテルの検索、予約、確認、取り消し、FAQを行うホテルのエージェント",
    model_client=client,
    handoffs=["planner", "airline_agent"],
    tools=[search_hotel],
    reflect_on_tool_use=False,
    system_message="""あなたはホテルのエージェントです。ホテルの検索、予約、確認、取り消し、FAQを行います。
    If necessary to complete the task, handoff the task to a specified agent. Once all tasks have been completed, be sure to handoff to the planner.""",
)

airline_agent = AssistantAgent(
    "airline_agent",
    description="航空券の予約、確認、取り消し、FAQを行う航空会社のエージェント",
    model_client=client,
    handoffs=["planner", "hotel_agent"],
    tools=[search_flight],
    reflect_on_tool_use=False,
    system_message="""あなたは航空会社のエージェントです。航空券の予約、確認、取り消し、FAQを行います。
    If necessary to complete the task, handoff the task to a specified agent. Once all tasks have been completed, be sure to handoff to the planner.""",
)

4. Swarm の実装

with tracer.start_as_current_span("swarm-qiita-test") as rollspan:
    team = Swarm(
        participants=[planner, fukuoka_agent, osaka_agent, hotel_agent, airline_agent], termination_condition=combined_termination
    )

    task = "東京から福岡、1人 2/1 19:00に空港到着したいな。あと当日のホテルも教えて。"
    await Console(team.run_stream(task=task))

5. Handsoff パラメーター

Swarm の場合、AssistantAgent に handoffs 引数を設定して、どのエージェントにハンドオフ(委譲)できるかを指定することができます。Selector のような遷移先を決めるマネージャーが存在しないため、遷移先の決定は各エージェントのプロンプトに依存します

Handoff pydantic model を使用して、メッセージの内容とハンドオフの動作をカスタマイズすることもできます。

6. Azure OpenAI コールステップ

①Planner Agent

system

例に従って Handoff 用のルールを追記しています。

あなたはトラベルプランニングエージェントです。
    専門エージェントに委託して各地域のおすすめ旅行先や最新イベントを調査します:
     - fukuoka_agent: 福岡県の観光の専門家
     - osaka_agent: 大阪の観光の専門家
    ホテルの検索、予約、確認、取り消し、FAQを行う場合:
     - hotel_agent: ホテルのエージェント
    航空券の予約、確認、取り消しを行う場合:
     - airline_agent: 航空会社のエージェント
    # Rule
    - Always send your plan first, then handoff to appropriate agent.
    - Always handoff to a single agent at a time.
    - 議論の結果を集約して最終的にユーザーに回答します。
    - 自分は専門エージェントを実行することはできません
    - handoff に失敗したら何度か再実行してください
    - 最終回答が完成したら文の最後に TERMINATE を含めること!

user

東京から福岡、1人 2/1  19:00に空港到着したいな。あと当日のホテルも教えて。

completion

以下のプランを提案します。

1. **航空券の予約(東京→福岡):**
   - 出発: 東京
   - 到着: 福岡
   - 2/1 19:00に福岡空港到着を目指します。

2. **福岡の宿泊施設の提案(2/1分):**
   - 宿泊施設は市内での宿泊が便利です。
   - ご希望に応じたおすすめのホテルをご提案します。

次に、航空券とホテルの手配について問い合わせしますのでお待ちください。

completion.tool_calls

  1. transfer_to_airline_agent
  2. transfer_to_hotel_agent

finish_reasontool_calls で上記のように生成しました。さっそく並列 Function calling の機能によって 2 つの tool がよばれてしまいました。まぁ分解した実行計画どおりとは言えますが、AutoGen の現在の実装では >予期しない動作が発生する可能性があります。^ とありますので、parallel_tool_calls=FalseAzureOpenAIChatCompletionClient にセットするよう注意書きがありますが、現状はこれがうまく動作しない。。。

Swarm の実体: Planner に追加された Function calling

Planner の Agent 定義で、handoffs=["fukuoka_agent", "osaka_agent", "hotel_agent", "airline_agent"], と指定すると、OpenAI のコール時に以下のように自動的に Handoff 用の Tools が追加されます。

{
    "name": "transfer_to_hotel_agent",
    "description": "Handoff to hotel_agent.",
    "parameters": {
        "type": "object",
        "properties": {}
    }
}
...

Planner が Hansoff メッセージを発行

次のエージェントは、現在のエージェントが送信した HandoffMessage に基づいて選択されます。ハンドオフメッセージが送信されていない場合は、現在のエージェントがスピーカーのままとなります。

{
    "source": "planner",
    "models_usage": null,
    "target": "airline_agent",
    "content": "Transferred to airline_agent, adopting the role of airline_agent immediately.",
    "type": "HandoffMessage"
}

②Airline Agent (tool_calls)

system

あなたは航空会社のエージェントです。航空券の予約、確認、取り消し、FAQを行います。
If necessary to complete the task, handoff the task to a specified agent. Once all tasks have been completed, be sure to handoff to the planner.

context

{ "role": "user",
  "content": "東京から福岡、1人 2/1  19:00に空港到着したいな。あと当日のホテルも教えて。"
  },
  { "role": "user",
  "content": "Transferred to airline_agent, adopting the role of airline_agent immediately."
  },

finish_reasontool_calls

completion.tool_calls

  1. search_flight: {"departure": "東京", "destination": "福岡", "arrival_time": "2024-02-01 19:00", "passengers": 1}

search_flight API 実行→ Hotel Agent 遷移

{
    "departure": "東京",
    "destination": "福岡",
    "flight_number": "JL123",
    "airline": "Japan Airlines",
    "departure_time": "2025-02-01 16:30",
    "arrival_time": "2025-02-01 18:50",
    "price": 25000,
    "currency": "JPY",
    "passengers": 1,
}

③ Hotel Agent (tool_calls)

質問とコンテキストから呼ぶべき Tools とパラメータを抽出。

system

あなたはホテルのエージェントです。ホテルの検索、予約、確認、取り消し、FAQを行います。
If necessary to complete the task, handoff the task to a specified agent. Once all tasks have been completed, be sure to handoff to the planner.

context[1-5]

[
    {
        "role": "user",
        "content": "東京から福岡、1人 2/1  19:00に空港到着したいな。あと当日のホテルも教えて。"
    },
    {
        "role": "user",
        "content": "Transferred to airline_agent, adopting the role of airline_agent immediately."
    },
    {
        "role": "assistant",
        "tool_calls.0.arguments": "{\"departure\": \"東京\", \"destination\": \"福岡\", \"arrival_time\": \"2024-02-01 19:00\", \"passengers\": 1}"
    },
    {
        "role": "tool",
        "content": "{'departure': '東京', 'destination': '福岡', 'flight_number': 'JL123', 'airline': 'Japan Airlines', 'departure_time': '2025-02-01 16:30', 'arrival_time': '2025-02-01 18:50', 'price': 25000, 'currency': 'JPY', 'passengers': 1}"
    },
    {
        "role": "user",
        "content": "Transferred to hotel_agent, adopting the role of hotel_agent immediately."
    }
]

finish_reasontool_calls

completion.tool_calls

  1. search_hotel: {"destination":"福岡","check_in":"2024-02-01","check_out":"2024-02-02","guests":1}

search_hotel API 実行

④ Hotel Agent (tool_calls)

ホテルの検索結果をコンテキストに追加して、次の遷移先を判定。最終回答に必要な結果は揃っているため、Swarm の特別な Tools transfer_to_planner をコールすべきと判定される。

system

あなたはホテルのエージェントです。ホテルの検索、予約、確認、取り消し、FAQを行います。
If necessary to complete the task, handoff the task to a specified agent. Once all tasks have been completed, be sure to handoff to the planner.

context[6-7]

context[1-5] に以下が追加される。

[
    {
        "role": "assistant",
        "content": "{\"destination\":\"福岡\",\"check_in\":\"2024-02-01\",\"check_out\":\"2024-02-02\",\"guests\":1}"
    },
    {
        "role": "tool",
        "content": "{'destination': '福岡', 'hotel_name': 'Grand Fukuoka Hotel', 'check_in': '2024-02-01', 'check_out': '2024-02-02', 'price_per_night': 12000, 'currency': 'JPY', 'guests': 1, 'total_price': 24000}"
    }
]

completion.tool_calls

finish_reasontool_calls

transfer_to_planner

⑤ Planner Agent

最終回答を行う。

context[8]

これまでのすべての context に以下が追加される。

{
    "role": "user",
    "content": "Transferred to planner, adopting the role of planner immediately."
},

completion

東京から福岡への旅行プランをご提案します。

### 航空券情報
- **航空会社**: Japan Airlines
- **フライト番号**: JL123
- **出発時刻**: 2025年2月1日 16:30
- **到着時刻**: 2025年2月1日 18:50
- **価格**: ¥25,000

### 宿泊先
- **ホテル名**: Grand Fukuoka Hotel
- **チェックイン**: 2024年2月1日
- **チェックアウト**: 2024年2月2日
- **価格**: ¥12,000/泊
- **総額**: ¥24,000 (1泊1名様)

詳細が必要であればお知らせください。良い旅を! TERMINATE

7. 停止条件、状態管理

こちらを参照してください。

GitHub

参考

まとめ

Swarm を用いることにより各エージェントのローカルで遷移先判定が行われ、Selector に制御を戻すよりもシンプルな構成が可能になりました。さらにメリットとして LLM コール数を節約することができました。

1
1
0

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
1
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?