🐶

Swarm (実験的サンプル)

2024/10/13に公開

エルゴノミックで軽量なマルチエージェントオーケストレーションフレームワーク

[!WARNING]
Swarmは現在、マルチエージェントシステムのエルゴノミックなインターフェースを探求するための実験的なサンプルフレームワークです。本番環境での使用を意図しておらず、公式サポートもありません。(そのため、PRやIssueのレビューも行いません!)

Swarmの主な目的は、Orchestrating Agents: Handoffs & Routinesクックブックで探求されているハンドオフとルーチンのパターンを紹介することです。スタンドアロンのライブラリとしてではなく、主に教育目的で提供されています。

インストール

Python 3.10以上が必要です

pip install git+ssh://git@github.com/openai/swarm.git

または

pip install git+https://github.com/openai/swarm.git

使用方法

from swarm import Swarm, Agent

client = Swarm()

def transfer_to_agent_b():
    return agent_b

agent_a = Agent(
    name="Agent A",
    instructions="あなたは役立つエージェントです。",
    functions=[transfer_to_agent_b],
)

agent_b = Agent(
    name="Agent B",
    instructions="俳句でのみ話してください。",
)

response = client.run(
    agent=agent_a,
    messages=[{"role": "user", "content": "Agent Bと話したいです。"}],
)

print(response.messages[-1]["content"])
希望の光
新しい道交わる
何をお手伝い

目次

概要

Swarmは、エージェントの調整実行を軽量で、高度に制御可能、そして簡単にテスト可能にすることに焦点を当てています。

これは、Agentハンドオフという2つの基本的な抽象化を通じて実現されています。Agentinstructionstoolsを包含し、いつでも会話を別のAgentにハンドオフすることができます。

これらのプリミティブは、ツールとエージェントのネットワーク間の豊かな動的関係を表現するのに十分な力を持っており、急峻な学習曲線を避けながら、スケーラブルで実世界のソリューションを構築することができます。

[!NOTE]
SwarmのエージェントはAssistants APIのAssistantsとは関係ありません。便宜上似た名前がついていますが、それ以外は全く無関係です。SwarmはChat Completions APIのみを使用しており、そのため呼び出し間でステートレスです。

なぜSwarmなのか

Swarmは設計上、軽量で、スケーラブル、そして高度にカスタマイズ可能です。単一のプロンプトにエンコードすることが難しい、多数の独立した機能と指示を扱う状況に最適です。

Assistants APIは、完全にホストされたスレッドと組み込みのメモリ管理および検索機能を求める開発者にとって素晴らしいオプションです。一方、Swarmは、コンテキスト、ステップ、ツール呼び出しに対する完全な透明性と細かい制御を求める開発者に最適です。Swarmは(ほぼ)完全にクライアント上で動作し、Chat Completions APIと同様に、呼び出し間で状態を保存しません。

インスピレーションを得るために/examplesをチェックしてください!各例の詳細はそのREADMEをご覧ください。

  • basic: セットアップ、関数呼び出し、ハンドオフ、コンテキスト変数など、基本的な要素の簡単な例
  • triage_agent: 適切なエージェントにハンドオフするための基本的なトリアージステップを設定する簡単な例
  • weather_agent: 関数呼び出しの簡単な例
  • airline: 航空会社のコンテキストで異なる顧客サービスリクエストを処理するマルチエージェントセットアップ
  • support_bot: ユーザーインターフェースエージェントと複数のツールを持つヘルプセンターエージェントを含む顧客サービスボット
  • personal_shopper: 販売や注文の払い戻しを支援できるパーソナルショッピングエージェント

ドキュメント

Swarm Diagram

Swarmの実行

まず、Swarmクライアントをインスタンス化します(内部的には単にOpenAIクライアントをインスタンス化します)。

from swarm import Swarm

client = Swarm()

client.run()

Swarmのrun()関数は、Chat Completions APIのchat.completions.create()関数に類似しています - messagesを受け取り、messagesを返し、呼び出し間で状態を保存しません。ただし、重要な点として、エージェントの関数実行、ハンドオフ、コンテキスト変数の参照を処理し、ユーザーに戻る前に複数のターンを取ることができます。

本質的に、Swarmのclient.run()は以下のループを実装しています:

  1. 現在のエージェントから完了を取得
  2. ツール呼び出しを実行し、結果を追加
  3. 必要に応じてエージェントを切り替え
  4. 必要に応じてコンテキスト変数を更新
  5. 新しい関数呼び出しがなければ、返却

引数

引数 説明 デフォルト
agent Agent (初期の)呼び出されるエージェント。 (必須)
messages List メッセージオブジェクトのリスト。Chat Completions messagesと同一。 (必須)
context_variables dict 関数とエージェントの指示で利用可能な追加のコンテキスト変数の辞書。 {}
max_turns int 許可される会話のターンの最大数。 float("inf")
model_override str エージェントが使用するモデルをオーバーライドするためのオプションの文字列。 None
execute_tools bool Falseの場合、エージェントが関数を呼び出そうとしたときに実行を中断し、即座にtool_callsメッセージを返します。 True
stream bool Trueの場合、ストリーミングレスポンスを有効にします。 False
debug bool Trueの場合、デバッグログを有効にします。 False

client.run()が終了すると(潜在的に複数のエージェントとツールの呼び出しの後)、関連するすべての更新された状態を含むResponseを返します。具体的には、新しいmessages、最後に呼び出されたAgent、最新のcontext_variablesが含まれます。これらの値(および新しいユーザーメッセージ)を次のclient.run()実行に渡すことで、中断したところから対話を継続できます - chat.completions.create()と同様に。(run_demo_loop関数は、/swarm/repl/repl.pyで完全な実行ループの例を実装しています。)

Response フィールド

フィールド 説明
messages List 会話中に生成されたメッセージオブジェクトのリスト。Chat Completions messagesと非常に似ていますが、メッセージの発信元のAgentを示すsenderフィールドがあります。
agent Agent メッセージを最後に処理したエージェント。
context_variables dict 入力変数と同じですが、変更がある場合はそれも含みます。

エージェント

Agentは単に一連のinstructionsと一連のfunctions(および以下の追加設定)をカプセル化し、実行を別のAgentにハンドオフする能力を持っています。

Agentを「Xを行う誰か」として擬人化したくなりますが、instructionsfunctionsによって定義される非常に特定のワークフローまたはステップ(例:一連のステップ、複雑な検索、単一のデータ変換ステップなど)を表すこともできます。これにより、Agentを「エージェント」、「ワークフロー」、「タスク」のネットワークに構成することができ、すべて同じプリミティブで表現されます。

Agent フィールド

フィールド 説明 デフォルト
name str エージェントの名前。 "Agent"
model str エージェントが使用するモデル。 "gpt-4o"
instructions str または func() -> str エージェントの指示。文字列または文字列を返す呼び出し可能オブジェクト。 "You are a helpful agent."
functions List エージェントが呼び出せる関数のリスト。 []
tool_choice str エージェントのツール選択(ある場合)。 None

指示

Agentinstructionsは直接会話のsystemプロンプトに変換されます(最初のメッセージとして)。アクティブなAgentinstructionsのみが常に存在します(例:Agentのハンドオフがある場合、systemプロンプトは変更されますが、チャット履歴は変更されません)。

agent = Agent(
   instructions="あなたは役立つエージェントです。"
)

instructionsは通常のstr、またはstrを返す関数のいずれかです。関数はオプションでcontext_variablesパラメータを受け取ることができ、これはclient.run()に渡されたcontext_variablesによって埋められます。

def instructions(context_variables):
   user_name = context_variables["user_name"]
   return f"{user_name}さんの要望を何でも手伝ってください。"

agent = Agent(
   instructions=instructions
)
response = client.run(
   agent=agent,
   messages=[{"role":"user", "content": "こんにちは!"}],
   context_variables={"user_name":"太郎"}
)
print(response.messages[-1]["content"])
こんにちは、太郎さん!今日はどのようなお手伝いができますか?

関数

  • Swarm AgentはPython関数を直接呼び出すことができます。
  • 関数は通常strを返すべきです(値はstrとしてキャストされようとします)。
  • 関数がAgentを返す場合、実行はそのAgentに転送されます。
  • 関数がcontext_variablesパラメータを定義している場合、client.run()に渡されたcontext_variablesによって埋められます。
def greet(context_variables, language):
   user_name = context_variables["user_name"]
   greeting = "こんにちは" if language.lower() == "japanese" else "Hello"
   print(f"{greeting}, {user_name}さん!")
   return "完了"

agent = Agent(
   functions=[greet]
)

client.run(
   agent=agent,
   messages=[{"role": "user", "content": "greet()を日本語で使ってください。"}],
   context_variables={"user_name": "太郎"}
)
こんにちは、太郎さん!
  • Agentの関数呼び出しにエラーがある場合(関数の欠落、引数の誤り、エラー)、エラーレスポンスがチャットに追加され、Agentが適切に回復できるようにします。
  • Agentによって複数の関数が呼び出された場合、それらはその順序で実行されます。

ハンドオフとコンテキスト変数の更新

Agentfunctionで別のAgentを返すことで、ハンドオフを行うことができます。

sales_agent = Agent(name="営業担当エージェント")

def transfer_to_sales():
   return sales_agent

agent = Agent(functions=[transfer_to_sales])

response = client.run(agent, [{"role":"user", "content":"営業部門に転送してください。"}])
print(response.agent.name)
営業担当エージェント

また、より完全なResultオブジェクトを返すことで、context_variablesを更新することもできます。これにはvalueagentも含めることができ、単一の関数で値を返し、エージェントを更新し、コンテキスト変数を更新する(またはその3つの任意の組み合わせ)ことができます。

sales_agent = Agent(name="営業担当エージェント")

def talk_to_sales():
   print("こんにちは、世界!")
   return Result(
       value="完了",
       agent=sales_agent,
       context_variables={"department": "sales"}
   )

agent = Agent(functions=[talk_to_sales])

response = client.run(
   agent=agent,
   messages=[{"role": "user", "content": "営業部門に転送してください"}],
   context_variables={"user_name": "太郎"}
)
print(response.agent.name)
print(response.context_variables)
営業担当エージェント
{'department': 'sales', 'user_name': '太郎'}

[!NOTE]
Agentが複数の関数を呼び出してAgentにハンドオフする場合、最後のハンドオフ関数のみが使用されます。

関数スキーマ

Swarmは自動的に関数をChat Completions toolsに渡されるJSONスキーマに変換します。

  • ドキュメント文字列は関数のdescriptionになります。
  • デフォルト値のないパラメータはrequiredに設定されます。
  • 型ヒントはパラメータのtypeにマッピングされます(デフォルトはstringです)。
  • パラメータごとの説明は明示的にサポートされていませんが、ドキュメント文字列に追加すれば同様に機能するはずです。(将来的にはドキュメント文字列の引数解析が追加される可能性があります。)
def greet(name, age: int, location: str = "東京"):
   """ユーザーに挨拶します。呼び出す前に必ず名前と年齢を取得してください。

   Args:
      name: ユーザーの名前。
      age: ユーザーの年齢。
      location: 最高の場所。
   """
   print(f"こんにちは{name}さん、{location}{age}歳とは素晴らしいですね!")
{
   "type": "function",
   "function": {
      "name": "greet",
      "description": "ユーザーに挨拶します。呼び出す前に必ず名前と年齢を取得してください。\n\nArgs:\n   name: ユーザーの名前。\n   age: ユーザーの年齢。\n   location: 最高の場所。",
      "parameters": {
         "type": "object",
         "properties": {
            "name": {"type": "string"},
            "age": {"type": "integer"},
            "location": {"type": "string"}
         },
         "required": ["name", "age"]
      }
   }
}

ストリーミング

stream = client.run(agent, messages, stream=True)
for chunk in stream:
   print(chunk)

Chat Completions APIのストリーミングと同じイベントを使用します。例として/swarm/repl/repl.pyprocess_and_print_streaming_responseをご覧ください。

2つの新しいイベントタイプが追加されています:

  • {"delim":"start"}{"delim":"start"}は、Agentが単一のメッセージ(レスポンスまたは関数呼び出し)を処理するたびに信号を送ります。これはAgent間の切り替えを識別するのに役立ちます。
  • {"response": Response}は、便宜上、ストリームの最後に集計された(完全な)レスポンスを含むResponseオブジェクトを返します。

評価

評価は任意のプロジェクトにとって重要であり、開発者が自身のswarmのパフォーマンスをテストするための独自の評価スイートを持ってくることを推奨します。参考として、airlineweather_agenttriage_agentのクイックスタート例にswarmを評価する方法のいくつかの例があります。詳細はそれぞれのREADMEをご覧ください。

ユーティリティ

run_demo_loopを使用してswarmをテストしてください!これはコマンドラインでREPLを実行します。ストリーミングをサポートしています。

from swarm.repl import run_demo_loop
...
run_demo_loop(agent, stream=True)

主要な貢献者

Discussion