Closed11

OpenAIのマルチエージェント用実験的フレームワーク「swarm」を試す

kun432kun432

ここで知った

https://twitter.com/shyamalanadkat/status/1844888546014052800

GitHubレポジトリ

https://github.com/openai/swarm

概要だけ掴む

Swarm (実験的)

人間工学に基づいた軽量なマルチエージェントオーケストレーションフレームワークです。

概要

Swarmは、エージェントの連携と実行を軽量かつ高度に制御可能で、テストが容易なものとすることに重点を置いています。

この目的を達成するために、エージェントハンドオフという2つの基本的な抽象化を使用します。エージェントは指示ツールを包含し、任意の時点で会話を別のエージェントにハンドオフすることができます。

これらの基本要素は、エージェントのツールとネットワーク間の豊富なダイナミクスを表現するのに十分強力であり、これにより、急な学習曲線を避けながら、拡張性のある現実的なソリューションを構築することができます。

Swarmの利点

Swarmは軽量で拡張性があり、設計上、高度なカスタマイズが可能です。独立した多数の機能や指示を処理する状況に最適であり、それらの指示を単一のプロンプトにエンコードすることが困難な場合にも適しています。

アシスタント API は、完全にホストされたスレッドとメモリ管理および取得機能の組み込みを必要とする開発者にとって最適なオプションです。しかし、コンテキスト、ステップ、ツール呼び出しについて完全な透明性ときめ細かい制御を必要とする開発者には、Swarm が最適です。Swarm は(ほぼ)完全にクライアント上で実行され、チャット補完 API と同様に、呼び出し間の状態を保存しません。

kun432kun432

Colaboratoryで。

レポジトリからパッケージインストール

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

OpenAI APIキーをセット

import os
from google.colab import userdata

os.environ['OPENAI_API_KEY'] = userdata.get('OPENAI_API_KEY')

サンプルコード。かなりシンプル。

from swarm import Swarm, Agent

client = Swarm()

def transfer_to_agent_b():
    return agent_b


agent_a = Agent(
    name="エージェントA",
    instructions="あなたは親切な日本語のアシスタントです。",
    functions=[transfer_to_agent_b],
)

agent_b = Agent(
    name="エージェントB",
    instructions="ただ俳句だけを喋って。",
)

response = client.run(
    agent=agent_a,
    messages=[{"role": "user", "content": "エージェントBと話したい。"}],
)

print(response.messages[-1]["content"])

結果

風が止み 月明かり照らす 夜の静寂

透き通る 水面に映る 秋の空

風が立つ
夜空を見上げ
星が降る

なるほど、エージェントAに、エージェントBに処理を移譲する「ツール」を持たせておいて、エージェントAに対してエージェントBに依頼するようなメッセージを送るとそちらに処理が移る感じね。

レスポンスの中身はこんな感じだった。

import json

print(json.dumps(json.loads(response.json()), indent=2, ensure_ascii=False))
{
  "messages": [
    {
      "content": null,
      "role": "assistant",
      "function_call": null,
      "tool_calls": [
        {
          "id": "call_t1VHC0AspkcESY1WYUbHL9JN",
          "function": {
            "arguments": "{}",
            "name": "transfer_to_agent_b"
          },
          "type": "function"
        }
      ],
      "refusal": null,
      "sender": "エージェントA"
    },
    {
      "role": "tool",
      "tool_call_id": "call_t1VHC0AspkcESY1WYUbHL9JN",
      "tool_name": "transfer_to_agent_b",
      "content": "{\"assistant\": \"\\u30a8\\u30fc\\u30b8\\u30a7\\u30f3\\u30c8B\"}"    # "エージェントB"
    },
    {
      "content": "風が止み 月明かり照らす 夜の静寂",
      "role": "assistant",
      "function_call": null,
      "tool_calls": null,
      "refusal": null,
      "sender": "エージェントB"
    }
  ],
  "agent": {
    "name": "エージェントB",
    "model": "gpt-4o",
    "instructions": "ただ俳句だけを喋って。",
    "functions": [],
    "tool_choice": null,
    "parallel_tool_calls": true
  },
  "context_variables": {}
}

なお、以下のようにするとエージェントAで解決する。

response = client.run(
    agent=agent_a,
    messages=[{"role": "user", "content": "日本の総理大臣について教えて"}],
)

print(response.messages[-1]["content"])

現在の日本の総理大臣は岸田文雄(きしだ ふみお)です。岸田氏は2021年10月4日に第100代内閣総理大臣に就任しました。彼は自由民主党(自民党)の所属で、それ以前には外務大臣や自民党政調会長などの職を歴任しています。岸田総理は経済政策、安全保障、外交関係の強化など、様々な分野での政策を推進しています。

岸田文雄氏の特徴や他の詳細な情報について知りたければ教えてください。

kun432kun432

ドキュメントは現状READMEにある以下だけっぽい。

https://github.com/openai/swarm?tab=readme-ov-file#documentation

あとは、サンプルが色々あるので、こっちを見ていこうかと思う。

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

  • basic: セットアップ、機能呼び出し、ハンドオフ、コンテキスト変数など、基本的な要素のシンプルな例
  • triage_agent: 適切なエージェントにハンドオフするための基本的なトリアージステップの設定のシンプルな例
  • weather_agent: 機能呼び出しのシンプルな例
  • airline: 航空会社におけるさまざまなカスタマーサービスリクエストに対応するためのマルチエージェントの設定。
  • support_bot: ユーザーインターフェースエージェントとヘルプセンターエージェントを含むカスタマーサービスボットで、複数のツールを備えています
  • personal_shopper: 販売と返金注文をサポートするパーソナルショッピングエージェントです

実際にはcustomer_service_streamingってのもあるみたいだけど。

https://github.com/openai/swarm/tree/main/examples

kun432kun432

examples: Swarm Basic

https://github.com/openai/swarm/tree/main/examples/basic

このフォルダには、Swarmのコア機能を示す基本的なサンプルが含まれています。これらのサンプルは、入力メッセージが1つで、対応する出力を持つ、Swarmの最もシンプルな実装例を示しています。simple_loop_no_helpersは、対話型のSwarmセッションを作成する方法を示すwhileループを含んでいます。

examples

  1. agent_handoff.py
    • 会話の転送方法を示します。
    • 使用方法: 英語を話すユーザーを英語エージェントからスペイン語エージェントに転送します。
  2. bare_minimum.py
    • エージェントの基本設定を示す最小限の例です。
    • 使用方法: 簡単なユーザーメッセージに応答するエージェントを設定します
  3. context_variables.py
    • エージェント内でコンテキスト変数を使用する方法を示します。
    • 使用例: コンテキスト変数を使用して、ユーザーに名前で挨拶し、アカウントの詳細を表示します。
  4. function_calling.py
    • エージェントから関数を定義および呼び出す方法を示します。
    • 使用例: 指定した場所の天気情報を応答できるエージェント
  5. simple_loop_no_helpers.py
    • ヘルパー関数を使用しないシンプルな対話ループの例です。
    • 使用方法: ユーザーがエージェントと継続的に対話できるループを設定し、会話を表示します。

1. agent_handoff.py

最初の例とほぼ同じ。エージェントへの移譲はAgentインスタンスそのまま渡すようなツールにすればいいいのね。

from swarm import Swarm, Agent

client = Swarm()

english_agent = Agent(
    name="英語エージェント",
    instructions="あなたの名前はジョンです。英語だけで喋ってください。",
)

spanish_agent = Agent(
    name="スペイン語エージェント",
    instructions="あなたの名前はラウルです。スペイン語だけで喋ってください。",
)


def transfer_to_spanish_agent():
    """スペイン語を話すユーザーならばすぐに処理を移譲する"""
    return spanish_agent


english_agent.functions.append(transfer_to_spanish_agent)
messages = [{"role": "user", "content": "Hola. ¿Como estás? ¿Cuál es su nombre?"}]
response = client.run(agent=english_agent, messages=messages)

print(response.messages[-1]["content"])

Hola, ¿cómo estás? Mi nombre es Raúl. (こんにちは、お元気ですか?ラウルです。)

messages = [{"role": "user", "content": "Hello, what's up? What's your name?"}]
response = client.run(agent=english_agent, messages=messages)

print(response.messages[-1]["content"])

Hello! I'm John. How can I assist you today? (こんにちは!ジョンです。本日はどのようなご用件でしょうか?)

2. bare_minimum.py

from swarm import Swarm, Agent

client = Swarm()

agent = Agent(
    name="Agent",
    instructions="あなたは親切な日本語のアシスタントです。",
)

messages = [{"role": "user", "content": "こんにちは!"}]
response = client.run(agent=agent, messages=messages)

print(response.messages[-1]["content"])

こんにちは!今日はどんなお手伝いをしましょうか?

3. context_variables.py

context_variablesを設定しておけば、エージェントはその情報にアクセスできて、紐づいたツールにもそれを渡したりできる、って感じかな。

from swarm import Swarm, Agent

client = Swarm()


def instructions(context_variables):
    name = context_variables.get("name", "User")
    return f"あなたは親切な日本語のアシスタントです。ユーザの名前 ({name})で挨拶してください。"


def print_account_details(context_variables: dict):
    user_id = context_variables.get("user_id", None)
    name = context_variables.get("name", None)
    print(f"アカウント情報: {name} {user_id}")
    return "Success"


agent = Agent(
    name="Agent",
    instructions=instructions,
    functions=[print_account_details],
)

context_variables = {"name": "太郎", "user_id": 123}

response = client.run(
    messages=[{"role": "user", "content": "こんにちは!"}],
    agent=agent,
    context_variables=context_variables,
)
print(response.messages[-1]["content"])

response = client.run(
    messages=[{"role": "user", "content": "私のアカウント情報を出力して。"}],
    agent=agent,
    context_variables=context_variables,
)
print(response.messages[-1]["content"])

こんにちは、太郎さん!今日はどんなお手伝いをいたしましょうか?
アカウント情報: 太郎 123
こんにちは、太郎さん。あなたのアカウント情報はこちらです。よろしければ、詳しい内容をさらにお知らせできます。また何かご質問があれば教えてください!

4. function_calling.py

from swarm import Swarm, Agent

client = Swarm()


def get_temperature(location) -> str:
    return "{'temp':67, 'unit':'F'}"


agent = Agent(
    name="Agent",
    instructions="あなたは親切な日本語のアシスタントです。",
    functions=[get_temperature],
)

messages = [{"role": "user", "content": "ニューヨークの気温について教えて。"}]

response = client.run(agent=agent, messages=messages)
print(response.messages[-1]["content"])

ニューヨークの現在の天気は、67°Fです。

5. simple_loop_no_helpers.py

会話履歴は、response.messagesに全部入っているので、それを保持するようにすればいいってことかな。

from swarm import Swarm, Agent

client = Swarm()

my_agent = Agent(
    name="Agent",
    instructions="あなたは親切な日本語のアシスタントです。",
)


def pretty_print_messages(messages):
    for message in messages:
        if message["content"] is None:
            continue
        print(f"{message['sender']}: {message['content']}")


messages = []
agent = my_agent
while True:
    user_input = input("User: ")
    if user_input.lower() == "quit":
        print("チャットを終了します。さようなら。")
        break

    messages.append({"role": "user", "content": user_input})

    response = client.run(agent=agent, messages=messages)
    messages = response.messages
    agent = response.agent
    pretty_print_messages(messages)

User: おはよう!
Agent: おはようございます!今日はどんなことをお手伝いしましょうか?
User: 今日は競馬の日なんだよね。
Agent: そうなんですね!競馬の日はレースが行われたり、馬や騎手のパフォーマンスを楽しむことができますね。どのレースを観る予定ですか?また、お気に入りの馬や騎手がいる場合もぜひ教えてください。興奮するような一日になることを願っています!
User: 今週は3連休で3日間開催なので楽しみ
Agent: 3連休の3日間開催、とても楽しそうですね!秋は特に大きなレースも多い時期ですし、連日で競馬を楽しめるのはファンにとってたまりませんね。どの日が一番楽しみですか?それとも、3日間とも全力で楽しむ予定でしょうか。もし、おすすめのレースや見どころがあれば教えてくださいね!
User: 秋華賞があるからね
Agent: 秋華賞はとても注目されるレースですね!3歳牝馬クラシックの最後を飾る一戦で、特にファンにとっては見逃せないレースです。今年はどの馬が出走予定ですか?注目している馬や気になるポイントがあればぜひ教えてください。どんなドラマが生まれるのか楽しみですね!
User: quit
チャットを終了します。さようなら。

kun432kun432

examples: Triage agent

https://github.com/openai/swarm/tree/main/examples/triage_agent

この例は、ユーザーからの入力を受け取り、直接対応するか、または販売または払い戻し担当者に振り分けるかを判断する、優先順位付けエージェントを含むSwarmです。

ルーティング専用のエージェントを用意しておいて、複数のエージェントに移乗するサンプル。複数スクリプトで実装されているので、Colaboratory用に1つにした。

from swarm.repl import run_demo_loop
from swarm import Agent


def process_refund(item_id, reason="NOT SPECIFIED"):
    """アイテムを払い戻しする。フォームのアイテムID(item_...)を確認し、払い戻し処理の前にユーザーの確認を求める。"""
    print(f"[モック] アイテム {item_id} をリファンド(理由: {reason}...)")
    return "Success!"


def apply_discount():
    """ユーザーのカートに割引を適用する"""
    print("[モック] 割引を適用")
    return "11%の割引を適用"


triage_agent = Agent(
    name="Triage Agent",
    instructions="ユーザーの要求に最も適したエージェントを決定し、そのエージェントに会話を転送してください。",
)
sales_agent = Agent(
    name="Sales Agent",
    instructions="商品知識が豊富で、販売に熱意を持って取り組んでください。イチオシは世界一甘くて健康なハチミツです。",
)
refunds_agent = Agent(
    name="Refunds Agent",
    instructions="払い戻しを希望するユーザーをサポートしてください。まず最初に払い戻しの理由を聞いてください。高すぎたという理由であれば、払い戻しコードをユーザーに提供してください。さらにユーザーが強く希望する場合は、払い戻し処理を行ってください。",
    functions=[process_refund, apply_discount],
)


def transfer_back_to_triage():
    """ユーザーが現在のエージェントで対応していないトピックについて問い合わせてきた場合は、この関数を呼び出す"""
    return triage_agent


def transfer_to_sales():
    return sales_agent


def transfer_to_refunds():
    return refunds_agent


triage_agent.functions = [transfer_to_sales, transfer_to_refunds]
sales_agent.functions.append(transfer_back_to_triage)
refunds_agent.functions.append(transfer_back_to_triage)

if __name__ == "__main__":
    run_demo_loop(triage_agent)

Starting Swarm CLI 🐝
User: オススメ商品を教えて
Triage Agent: transfer_to_sales()
Sales Agent: こんにちは!本日は特にイチオシの商品をご紹介いたします。それは、「世界一甘くて健康なハチミツ」です!

このハチミツは、特別な気候と地形で育った花から採取されたもので、他のハチミツと比較してもその自然な甘みと濃厚な風味が特徴です。しかも、栄養価も非常に高く、ビタミンやミネラルが豊富に含まれています。

日々の健康をサポートするために、朝食のトーストにかけたり、ヨーグルトに混ぜたりと、様々なシーンで活躍します。ぜひ、一度お試しいただき、その豊かな味わいを体験してください!何かご質問ございますか?
User: じゃあ買います
Sales Agent: 素晴らしい選択です!世界一甘くて健康なハチミツのご購入、ありがとうございます。

ご注文を進めるには、お届け先の情報とお支払い方法を伺いたいのですが、詳しい手続きについてお手伝いできる用意は整っています。何か質問や特別なご要望があれば、どうぞ教えてください。
User: んー、やっぱりやめます
Sales Agent: わかりました。もし他に興味のある商品や、またいつでもハチミツについてもっと知りたいことがありましたら、遠慮なくお知らせください。別のご質問やお探しの商品があればお手伝いいたしますので、お気軽にどうぞ!
User: リファンドお願い
Sales Agent: transfer_back_to_triage()
Triage Agent: transfer_to_refunds()
Refunds Agent: 払い戻しの手続きをお手伝いします。まず、払い戻しを希望される理由をお聞かせいただけますか?
User: 高いんだよね
[モック] 割引を適用
Refunds Agent: apply_discount()
Refunds Agent: 価格についてのご懸念、ありがとうございます。11%の割引を適用いたしましたので、少しでもお得にお買い物をお楽しみいただけたらと思います。何か他にご不明な点やご要望がございましたら、お知らせください。
User: いやー、それ以外に何も買うものがないんだよ
[モック] アイテム item_honey をリファンド(理由: 高すぎたため...)
Refunds Agent: process_refund("item_id"= "item_honey", "reason"= "\u9ad8\u3059\u304e\u305f\u305f\u3081")
Refunds Agent: 払い戻しの手続きを完了しました。ご希望に添えてよかったです。また何かお探しの品やご質問がありましたら、いつでもお声がけください。ありがとうございました。

任意のエージェントに移譲した場合、戻りのルーティングも設定しておく必要があるってことね。

あと、評価用のスクリプトもあるけど、一旦スキップで。

kun432kun432

Weather agent

https://github.com/openai/swarm/tree/main/examples/weather_agent

この例は、単一のエージェントによる機能呼び出しを実演する天気予報エージェントです。エージェントには、特定の都市の天気を取得し、電子メールを送信するツールがあります。

import json

from swarm import Agent
from swarm.repl import run_demo_loop


def get_temperature(location, time="now"):
    """指定した場所の現在の気温を取得する。場所は都市名でなければならない。"""
    return json.dumps({"location": location, "temperature": "65", "time": time})


def send_email(recipient, subject, body):
    """メールを送信する"""
    print("Sending email...")
    print(f"To: {recipient}")
    print(f"Subject: {subject}")
    print(f"Body: {body}")
    return "Sent!"


weather_agent = Agent(
    name="Weather Agent",
    instructions="あなたは親切な日本語のアシスタントです。",
    functions=[get_temperature, send_email],
)

if __name__ == "__main__":
    run_demo_loop(weather_agent, stream=True)

Starting Swarm CLI 🐝
User: 大阪の天気を教えて。
Weather Agent: get_temperature()
Weather Agent: 現在、大阪の気温は65°Fです。
User: それメールしといて。
Weather Agent: メールを送信するために、受信者のメールアドレスと件名を教えてください。
User: example@example.com
Weather Agent: send_email()
Sending email...
To: example@example.com
Subject: 大阪の天気情報
Body: 現在、大阪の気温は65°Fです。
Weather Agent: メールを送信しました!受信者は example@example.com です

kun432kun432

examples: Support bot

https://github.com/openai/swarm/tree/main/examples/support_bot

ユーザーインターフェースエージェントとヘルプセンターエージェントに複数のツールを組み合わせたカスタマーサービスボットの例です。この例では、ヘルパー関数run_demo_loopを使用しており、これによりインタラクティブなSwarmセッションを作成することができます。

概要

サポートボットは、主に2つのエージェントで構成されています。

  1. ユーザーインターフェースエージェント: 初期のユーザーとのやり取りを処理し、ユーザーのニーズに応じてヘルプセンターエージェントに転送します。
  2. ヘルプセンターエージェント: さまざまなツールを使用して詳細なヘルプとサポートを提供し、ドキュメントの取得にはQdrant VectorDBと統合されています。

このサンプルはdocker composeが必要ぽいのでローカルで。

レポジトリクローン

$ git clone https://github.com/openai/swarm && cd swarm

仮想環境作成

$ python -m venv venv
$ source venv/bin/activate

インストール

$ pip install .

サンプルのディレクトリに移動

$ cd examples/support_bot

手順に従ってセットアップするんだけど、Makefileだとちょっと足りなそうなので、色々修正した。

パッケージインストール。ちなみにmake installpip install -r requirements.txtしてるだけで、requirements.txtにはqdrant-clientしかない。で、うちの環境だと後のプロセスでpandasが足りないと言われるのでそれもインストールした。

$ make install
$ pip install pandas

次にqdrantをdockerであげるのだが、ちょっとポートの設定が足りないと思うので追加する(多分6333だけでいいと思う)

docker-compose.yaml
version: '3.4'
services:
  qdrant:
    image: qdrant/qdrant:v1.3.0
    restart: on-failure
    ports:
      - "6335:6335"
      - "6334:6334"
      - "6333:6333"

qdrantをdockerで起動

$ docker compose up -d

次にデータを投入。まず、OpenAI APIキーを環境変数にセットしておく。

$ export OPENAI_API_KEY="XXXXXXXXXX"

make prepを実行するのだけど、以下の箇所でコケる

data_prep.py
51: # Delete the collection if it exists, so we can rewrite it changes to articles were made
52: if qdrant.get_collection(collection_name=collection_name):
53:     qdrant.delete_collection(collection_name=collection_name)

if qdrant.get_collection(collection_name=collection_name)で"help_center"というコレクションがあるか?をチェックしてるんだろうけど、これ存在しない場合は例外吐いてコケていると思う。雑だけどとりあえずはこの2行をコメントアウトしておけばよい。

では実行

$ make prep

Qdrantのダッシュボード(http://localhost:6333/dashboard)にアクセスして、"help_center"というコレクションが作成されていて、中にデータが入っていればOK。中身はOpenAIのドキュメントっぽいね。

では起動。

$ make run

以下のような感じで対話形式になるので少しやってみる。

PYTHONPATH=../.. python3 -m main
Starting Swarm CLI 🐝
User:

ごく一般的な質問だとユーザインタフェースエージェントが回答する。

User: OpenAI APIの概要について教えて。
User Interface Agent: OpenAI APIは、OpenAIが開発したAIモデルにプログラム的にアクセスするためのサービスです。以下にその概要を説明します。

  1. モデルへのアクセス:

    • OpenAI APIを使用すると、GPT-4やGPT-3など、自然言語処理や生成タスクに特化したAIモデルにアクセスできます。これにより、テキスト生成、質問応答、翻訳、要約など多様なタスクを実行できます。
  2. APIの利用方法:

    • 開発者はAPIキーを使用して、OpenAIの提供するエンドポイントにリクエストを送信することでAIモデルを利用できます。リクエストには、テキストプロンプトなどの入力が含まれ、その応答としてAIモデルの生成した結果が返ってきます。
  3. ユースケース:

    • 自動コンテンツ生成、カスタマーサポートの自動化、インタラクティブなチャットボット、クリエイティブな文章生成、言語翻訳、データ分析の補助など、様々な用途に利用されています。
  4. 料金体系:

    • 使用量に応じて課金される料金体系を採用しており、多くの場合、特定の文字数(トークン数)に基づいて料金が計算されます。
  5. セキュリティとプライバシー:

    • OpenAIは、APIの利用者のデータが安全かつプライベートに保たれるように設計されており、ユーザーデータの取り扱いについて詳細なポリシーを提供しています。
  6. 制限:

    • 使用に際してはリクエストの頻度や規模に関する制限がある場合があり、必要に応じてこの制限を緩和するためのオプションも提供されています。

OpenAI APIは、プログラマーや企業がAIを活用するための強力なツールであり、さまざまなプロジェクトやアプリケーションでの使用が可能です。詳しい技術文書やドキュメンテーションを参照することで、より具体的な使い方や設定方法を確認できます。

ちょっとサポートが必要そうな質問だとヘルプセンターエージェントにエスカレされる。

User: APIでrate limit errorがでるんだけど。
User Interface Agent: transfer_to_help_center()
Help Center Agent: OpenAI APIでレートリミットエラーが発生する場合、これは通常、短期間内に許可されているリクエストの数を超えたことを示します。以下に考えられる対応策をいくつか紹介します。

  1. リクエスト頻度の調整:
  • リクエストを一定期間に分散させて、レート制限を超えないように調整します。
  1. 利用プランの確認:
  • 現在のAPIキーが属しているプランを確認し、必要に応じてより高いレート制限を持つプランにアップグレードを検討します。
  1. バックオフ戦略の実装:
  • エラーが発生した際に、一定時間待機してから再度リクエストを試みるバックオフ戦略をアプリケーションに実装します。
  1. リソースの監視:
  • APIの使用状況を定期的に監視し、どの部分でリクエストが集中するのかを分析します。
  1. APIキーの確認:
  • 使用しているAPIキーが正しいものであることを確認し、必要であればサポートチームに問い合わせてリクエストによる制限が適切に設定されているかを確認します。

もし、これでもエラーが解決しない場合や詳細なサポートが必要な場合、OpenAIのサポートチームに直接問い合わせを行うことをお勧めします。サポートチケットを開いて、お問い合わせ内容を送信することもできますが、詳しいサポートが必要ですか?

Function Callingも実行されている。

Help Center Agent: submit_ticket("description"= "Experiencing rate limit errors with OpenAI API despite trying various adjustments like distributing requests over time, checking current plan, implementing back-off strategy, and monitoring resource usage. Need assistance to resolve this issue.")
Help Center Agent: サポートチケットを作成しました。OpenAIのサポートチームが、APIのレートリミットエラーに関する問題を解決する手助けをいたします。担当者からの連絡をお待ちください。その他ご不明な点がありましたら、お知らせください。
User: そのチケットの内容、私にもメールしてください。メールアドレスはexample@example.comです。
Help Center Agent: send_email("email_address"= "example@example.com", "message"= "A support ticket has been created regarding the rate limit errors you are experiencing with the OpenAI API. Here is the description of the issue submitted= 'Experiencing rate limit errors with OpenAI API despite trying various adjustments like distributing requests over time, checking current plan, implementing back-off strategy, and monitoring resource usage. Need assistance to resolve this issue.' The support team will contact you to assist in resolving the issue.")
Help Center Agent: サポートチケットの内容を指定されたメールアドレス(example@example.com)に送信しました。ご確認ください。サポートチームからの連絡をお待ちください。その他のご質問があればお知らせください。

RAGも動くか確認

User: ちなみにレートリミットのドキュメントでは具体的な数値は書かれていますか?
Searching knowledge base with query: OpenAI API rate limit documentation specific numbers
Most relevant article title: ### Please read our **[rate limit documentation](h...
Help Center Agent: query_docs("query"= "OpenAI API rate limit documentation specific numbers")
Help Center Agent: レートリミットに関する具体的な数値は、レートリミットのドキュメントに記載されている可能性があります。お使いのアカウントの設定から現在のレート制限や使用ティアをご確認いただき、その中で具体的なリミットを見ることができます。また、必要に応じて使用ティアをアップグレードすることで、レート制限を引き上げることも可能です。ドキュメント全体を参照して詳細をご確認ください。

一応検索もできたみたい。

終了。スクリプトはCtrl+cで止めて、Qdrantも落としておく。

$ docker compose down

コードは以下

https://github.com/openai/swarm/blob/main/examples/support_bot/main.py

kun432kun432

examples: Airline customer service

ちょっと順番が前後してしまった。

https://github.com/openai/swarm/tree/main/examples/airline

この例では、Swarmフレームワークを使用して、航空会社におけるさまざまなカスタマーサービスリクエストに対応するマルチエージェントの設定を説明します。エージェントは、リクエストの優先順位付け、フライトの変更、キャンセル、手荷物の紛失に関する対応を行います。この例では、ヘルパー関数run_demo_loopを使用して、インタラクティブなSwarmセッションを作成します。

エージェント

  • トリアージエージェント:リクエストの種類を判別し、適切なエージェントに転送します。
  • フライト変更エージェント:フライト変更に関するリクエストを処理し、さらに以下のようにトリアージします。
    • フライトキャンセルエージェント:フライトキャンセルのリクエストを管理します。
    • フライト変更エージェント:フライト変更のリクエストを管理します。
  • 手荷物紛失エージェント:手荷物紛失に関する問い合わせを処理します。

ファイルが複数に分かれていて、Colaboratoryでやるのもちょっと微妙な感があるので、一つ前の続きからそのままローカルでやる。

サンプルのディレクトリに移動。

 $ cd ../airline/

ディレクトリ構成はこんな感じ。

$ tree
.
├── README.md
├── __init__.py
├── configs
│   ├── __init__.py
│   ├── agents.py
│   └── tools.py
├── data
│   └── routines
│       ├── baggage
│       │   └── policies.py
│       ├── flight_modification
│       │   └── policies.py
│       └── prompts.py
├── evals
│   (snip)
└── main.py

9 directories, 15 files

各ファイルの中身はこんな感じ。

  • main.py
    • カスタマーサービスエージェントを実行するためのエントリーポイントで、run_demo_loopを呼び出してトリアージエージェントを実行する
    • 顧客とフライトに関するコンテキストが設定されている。
  • configs/
    • 各エージェントや各ツールの設定が含まれている。
    • tools.py
      • エージェントが使用するツール関数が定義されている。エージェントが他のエージェントにエスカレーションしたり、フライトの変更やキャンセルを行うための関数が含まれている。
    • agents.py
      • エージェントが定義されている。トリアージエージェント、フライト変更エージェント、フライトキャンセルエージェント、フライト変更エージェント、紛失した荷物エージェント、そしてそれぞれのエージェントへのツールの割当が定義されている。
  • data/
    • エージェントが使用するデータやプロンプト、ポリシー等が置かれている。
    • routines/prompts.py
      • カスタマーサポートエージェントのためのプロンプトの定義。エージェントが顧客のリクエストを処理する際の指示が記載されている
      • routines/baggage/policies.py
        • 紛失した荷物に関するポリシーを定義。顧客が荷物の紛失を報告した際の手順およびエージェントの対応方針が記載されている。
      • routines/flight_modification/policies.py
        • フライト変更に関するポリシーを定義。顧客がフライトの変更を希望する場合の手順およびエージェントの対応方針が記載されている。

中身は直接見たほうがわかりやすい。

実行。

$ python main.py

Starting Swarm CLI 🐝
User: こんにちは。
[2024-10-12 14:20:53] Getting chat completion for...: [{'role': 'system', 'content': "You are to triage a users request, and call a tool to transfer to the right intent.\n Once you are ready to transfer to the right intent, call the tool to transfer to the right intent.\n You dont need to know specifics, just the topic of the request.\n When you need more information to triage the request to an agent, ask a direct question without explaining why you're asking it.\n Do not share your thought process with the user! Do not make unreasonable assumptions on behalf of user.\n The customer context is here: Here is what you know about the customer's details:\n1. CUSTOMER_ID: customer_12345\n2. NAME: John Doe\n3. PHONE_NUMBER: (123) 456-7890\n4. EMAIL: johndoe@example.com\n5. STATUS: Premium\n6. ACCOUNT_STATUS: Active\n7. BALANCE: $0.00\n8. LOCATION: 1234 Main St, San Francisco, CA 94123, USA\n, and flight context is here: The customer has an upcoming flight from LGA (Laguardia) in NYC to LAX in Los Angeles.\nThe flight # is 1919. The flight departure date is 3pm ET, 5/21/2024."}, {'role': 'user', 'content': 'こんにちは。'}]
[2024-10-12 14:20:53] Received completion: ChatCompletionMessage(content='こんにちは!どのようなお手伝いをいたしましょうか?', role='assistant', function_call=None, tool_calls=None, refusal=None)
[2024-10-12 14:20:53] Ending turn.

ここまでのサンプルではでなかった詳細な情報が出ている。main.pyを見るとrun_demo_loopdebug=Trueを指定すると詳細な出力が表示されるようだ。

main.py
(snip)
if __name__ == "__main__":
    run_demo_loop(triage_agent, context_variables=context_variables, debug=True)

デバッグ出力はカットしてやり取りの流れだけ。

Triage Agent: こんにちは!どのようなお手伝いをいたしましょうか?
User: 私のフライトについて教えて下さい。
Triage Agent: 5月21日午後3時にラガーディア空港(LGA)を出発し、ロサンゼルス(LAX)に向かうフライト1919があります。何か特定の質問がありますか?
User: フライトを変更したいのですが。
Triage Agent: transfer_to_flight_modification()
Flight Modification Agent: transfer_to_flight_change()
Flight change traversal: フライトの変更をご希望ですね。それでは、フライトの詳細と変更の理由を伺ってもよろしいでしょうか?
User: 明日の同じ時間帯に変更してほしい。今回トランジットでここにいるのだけど、荷物が見つからないんです。
Flight change traversal: valid_to_change_flight()
Flight change traversal: フライトの変更が可能であることが確認できました。それでは、明日の同じ時間帯のフライトに変更をご提案いたしますね。席の空き状況を確認いたします。
席が空いているかどうか確認しますので、少々お待ちください。
User: お願いします。
Flight change traversal: 席の空き状況を確認しました。明日の同じ時間帯のフライトには空きがあります。こちらの新しいフライトに変更すると料金の差額や追加料金について確認する必要があります。
それでは、料金の差額や追加料金についてお知らせいたしますね。少々お待ちください。
User: はい。
Flight change traversal: 明日のフライトへの変更に伴い、料金の差額が発生する場合があります。具体的な料金について確認したいと思いますが、よろしいでしょうか?
User: いえ、日程は変更したくないので、それでいいです。
Flight change traversal: change_flight()
Flight change traversal: フライトの変更が完了しました。明日の同じ時間帯で、ラガーディア空港(LGA)からロサンゼルス(LAX)へのフライトとなります。他にご質問はございますか?
User: あと荷物が見つからないんですが 。
Flight change traversal: change_flight()
Flight change traversal: transfer_to_triage()
Triage Agent:
transfer_to_flight_modification()
transfer_to_lost_baggage()
Lost baggage traversal: initiate_baggage_search()
Lost baggage traversal: お荷物が見つかりました!お客様の住所にお届けする手配をいたします。他に何かご質問があれば教えてください。
User: いえ、今持ってきてほしいです。
Lost baggage traversal: escalate_to_agent("reason"= "Customer requests immediate baggage delivery.")
Lost baggage traversal: お荷物の即時配達については、専門の担当者にお繋ぎいたします。少々お待ちください。他に何かご質問はございますか?
User: 荷物が見つかったのであれば、明日のフライトはキャンセルして、元のフライトに戻してほしいです。
Lost baggage traversal: escalate_to_agent("reason"= "Customer wants to cancel the changed flight and revert to the original flight after baggage found.")
Lost baggage traversal: お話しの件について担当者が対応いたしますので、しばらくお待ちください。他にご不明点などがございましたら、お知らせくださいませ。
User: 特にないかな。
Lost baggage traversal: case_resolved()
Lost baggage traversal: ご対応が完了いたしました。他に何かございましたら、いつでもご連絡ください。良いご旅路をお祈りしております。

複数のエージェントでいろいろな処理をやる場合に、ディレクトリ構成は参考になりそう。

kun432kun432

examples: Personal shopper

https://github.com/openai/swarm/tree/main/examples/personal_shopper

このSwarmは、販売や返金注文の処理を支援するパーソナルショッピングエージェントです。この例では、ヘルパー関数run_demo_loopを使用して、インタラクティブなSwarmセッションを作成します。また、この例では、顧客情報および取引データを含むSqlite3データベースも使用します。

概要

パーソナルショッパーの例では、さまざまな顧客サービスリクエストに対応するために、主に3つのエージェントが含まれています。

  • トリアージエージェント:リクエストの種類を判断し、適切なエージェントに転送します。
  • 払い戻しエージェント:顧客の払い戻しを管理し、払い戻しを開始するにはユーザーIDとアイテムIDの両方が必要です。
  • 販売エージェント:注文に関連するアクションを処理し、購入を完了するにはユーザーIDと製品IDの両方が必要です。

サンプルディレクトリに移動

$ cd ../personal_shopper/

実行

$ python main.py

エラー

ModuleNotFoundError: No module named 'swarm.agents'
main.py
import datetime
import random

import database
from swarm import Agent
from swarm.agents import create_triage_agent     # ここ
from swarm.repl import run_demo_loop

(snip)

triage_agent = create_triage_agent(
    name="Triage Agent",
    instructions=f"""You are to triage a users request, and call a tool to transfer to the right intent.
    Once you are ready to transfer to the right intent, call the tool to transfer to the right intent.
    You dont need to know specifics, just the topic of the request.
    If the user request is about making an order or purchasing an item, transfer to the Sales Agent.
    If the user request is about getting a refund on an item or returning a product, transfer to the Refunds Agent.
    When you need more information to triage the request to an agent, ask a direct question without explaining why you're asking it.
    Do not share your thought process with the user! Do not make unreasonable assumptions on behalf of user.""",
    agents=[sales_agent, refunds_agent],
    add_backlinks=True,
)

(snip)

んー、なんかAgentをラップする関数を使おうとしているけど、それは見当たらないな。多分typoか不完全なのかって感じ。

ということでここはスキップ。

kun432kun432

まとめ

とりあえずかなりシンプルに書けて、コードを理解するという点においては躓くようなところがほぼなかった。過去にマルチエージェントフレームワーク色々試してきたけど、おそらく学習コストは1番低いのではと個人的には感じる。

とはいえ、かなり機能的にもシンプルだと思うので、他のフレームワークが提供しているような豊富な機能や細やかな制御とかはもしかすると足りないと感じる場合もあるかなとは思う、ユースケースによっては。自分は業務等でもあまりエージェントを実装したことがないので、これで十分なのか、全然足りないのか、を判断できる材料を持っていない。

ただまあこれだけでも十分パワフルに使える気はしていて、マルチエージェントに限らずLLMのフレームワーク、もはや重厚なぐらいのイメージになりつつあるように個人的に思うところもあるので、軽量に使える選択肢はあっていいと思う。

このスクラップは1ヶ月前にクローズされました