Closed6

OpenAIの「Agents SDK」を試す

kun432kun432

公式の記事。以前試したSwarmをベースにエージェント専用SDKとしてリリースされたという感じ。

https://openai.com/ja-JP/index/new-tools-for-building-agents/

公式ドキュメント

https://platform.openai.com/docs/guides/agents

Agents

OpenAI API を使用してエージェントを構築する方法を学びます。
エージェントとは、単純なワークフローの実行から複雑で幅広い目的の追求まで、知的にタスクを遂行するシステムを指します。

OpenAI は、エージェント構築を可能にする豊富なコンポーザブルプリミティブを提供しています。このガイドでは、それらのプリミティブと、それらがどのように結合して堅牢なエージェントプラットフォームを形成するかについて説明します。

概要

エージェントの構築は、モデル、ツール、知識とメモリ、オーディオとスピーチ、ガードレール、およびオーケストレーションなど、複数のドメインにまたがるコンポーネントの組み合わせを含みます。OpenAI は各ドメインに対してコンポーザブルプリミティブを提供しています。

ドメイン 説明 OpenAIの基本構成要素
モデル 推論、意思決定、およびさまざまなモダリティの処理が可能な中核的な知能。 o1, o3-mini, GPT-4.5, GPT-4o, GPT-4o-mini
ツール 世界とのインターフェース、環境との相互作用、関数呼び出し、内蔵ツールなど。 Function calling, Web検索, ファイル検索, Computer use
知識とメモリ エージェントに外部かつ永続的な知識を拡張します。 ベクトルストア, ファイル検索, Embeddings
音声とスピーチ オーディオを理解し、自然言語で応答できるエージェントを作成します。 オーディオ生成, リアルタイム, オーディオエージェント
ガードレール 不適切、有害、または望ましくない行動を防止します。 モデレーション, 指示のヒエラルキー
オーケストレーション エージェントの開発、展開、監視、および改善を行います。 Agents SDK, トレーシング, 評価, ファインチューニング
音声エージェント オーディオを理解し、自然言語で応答できるエージェントを作成します。 Realtime API, Agents SDKの音声サポート

モデル

モデル エージェントとしての強み
o1 and o3-mini 長期計画、困難なタスク、および推論に最適。
GPT-4.5 エージェント実行に最適。
GPT-4o エージェント能力と待機時間のバランスが良好。
GPT-4o-mini 低待機時間に最適。

大規模言語モデル(LLMs)は、多くのエージェントシステムの中核を担っており、意思決定や世界との相互作用を担当します。OpenAI のモデルは、以下の幅広い機能をサポートしています:

詳細なモデル比較については、モデルページをご覧ください。

ツール

ツールは、エージェントが世界と相互作用することを可能にします。OpenAI は、あなたのコードと接続するためのfunction callingと、ウェブ検索やデータ取得などの一般的なタスク向けのビルトイン・ツールをサポートしています。

Tool Description
Function calling 開発者が定義したコードと対話します。
Web検索 ウェブから最新の情報を取得します。
ファイル検索 ドキュメント全体で意味的検索を実行します。
Computer use コンピュータまたはブラウザを理解し、制御します。

知識とメモリ

知識とメモリは、エージェントが初期のトレーニングデータを超えた情報を保存、取得、および利用するのに役立ちます。Vector stores により、エージェントはドキュメントを意味的に検索し、実行時に関連情報を取得することができます。一方、embeddings は、迅速な取得を可能にするためにデータを効率的に表現し、動的な知識ソリューションおよび長期のエージェントメモリを強化します。OpenAI の ベクトルストア および Embeddings API を使用して、あなたのデータを統合することができます。

ガードレール

ガードレールは、エージェントが安全かつ一貫して、意図した範囲内で動作することを保証します。これは本番環境での展開において重要です。OpenAI の無料 モデレーションAPI を使用して、不安全なコンテンツを自動的にフィルタリングします。さらに、開発者が定義したプロンプトを優先して、望ましくないエージェントの行動を軽減する指示のヒエラルキー を活用することで、エージェントの行動を制御できます。

オーケストレーション

エージェントの構築はプロセスです。OpenAI は、エージェントシステムの構築、展開、監視、評価、および改善を効果的に行うためのツールを提供しています。


referred from https://platform.openai.com/docs/guides/agents

フェーズ 説明 OpenAIの基本構成要素
構築とデプロイ Agents SDK を使用してエージェントを迅速に構築し、ガードレールを適用し、対話フローを処理します。 Agents SDK
モニタリング エージェントの動作をリアルタイムで観察し、問題のデバッグとトレーシングによる洞察を得ます。 トレーシング
評価と改善 エージェントのパフォーマンスを測定し、改善すべき点を特定し、エージェントを洗練させます。 評価, ファインチューニング

始めよう

OpenAI Agents SDK for Pythonをインストールして開始してください:

pip install openai-agents

詳細については、リポジトリドキュメントを参照してください。

kun432kun432

GitHubレポジトリ

https://github.com/openai/openai-agents-python

OpenAI Agents SDK

OpenAI Agents SDK は、マルチエージェントのワークフローを構築するための、軽量かつ強力なフレームワークです。

コアコンセプト

  1. Agents: 指示、ツール、ガードレール、およびハンドオフで構成された LLM
  2. Handoffs: エージェント間で制御を移譲するために Agents SDK専用のツール呼び出し
  3. Guardrails: 入出力の検証のための設定可能な安全チェック
  4. Tracing: エージェントの実行を内蔵で追跡し、ワークフローの表示、デバッグ、最適化を可能にする

examples ディレクトリを参照して SDK の動作例を確認し、詳細は documentation をご覧ください。

特に、我々の SDK は OpenAI Chat Completions API 形式をサポートする任意のモデルプロバイダーと 互換性があります

基本的には以前やったSwarmと概念などは似ていると思う。

https://zenn.dev/kun432/scraps/30a5c55db75fb9

なのだが、SDKのドキュメントを見ると

https://openai.github.io/openai-agents-python/

  • Model context protocol (MCP)
  • トレーシング
  • ガードレール
  • 可視化
  • 音声エージェント

など以前にはなかった概念があるし、個人的には音声エージェントに非常に興味があるので、一通り進めようかと思う。

kun432kun432

ちょっと時間が経ってしまったけど、改めて。

kun432kun432

Quickstart

公式ドキュメントに従って進める。日本語版が用意されているのはありがたい。

https://openai.github.io/openai-agents-python/ja/quickstart/

uvでプロジェクト作成

uv init -p 3.12 agents-sdk-work && cd $_

パッケージインストール

uv add openai-agents
出力
(snip)
 + openai==1.99.9
 + openai-agents==0.2.8
(snip)

OpenAI APIキーを環境変数にセット

export OPENAI_API_KEY=XXXXXXXXXX

シンプルな数学の家庭教師エージェントのサンプル。エージェントを定義して、ワークフロー(Runner)で実行する。

sample_math_agent.py
from agents import Agent, Runner
import asyncio

agent = Agent(
    name="数学の家庭教師",
    instructions=(
        "あなたは数学の問題解決を支援します。"
        "各ステップでの考え方を、例を挙げて説明してください。"
    )
)

async def main():
    result = await Runner.run(agent, "5x - 7 = 18 は?")
    print(result.final_output)

if __name__ == "__main__":
    asyncio.run(main())
出力
この方程式を解くには、変数 \( x \) を求める必要があります。以下のステップで解いていきましょう。

### ステップ 1: 方程式をシンプルにする

まず、方程式は次のようになっています。

\[ 5x - 7 = 18 \]

両辺に 7 を加えて、\( x \) の項を残します。

\[ 5x - 7 + 7 = 18 + 7 \]

この結果、方程式は次のようになります。

\[ 5x = 25 \]

### ステップ 2: \( x \) を求める

次に、\( 5x = 25 \) なので、両辺を 5 で割って \( x \) を求めます。

\[ x = \frac{25}{5} \]

これにより、

\[ x = 5 \]

### ステップ 3: 解を確認する

解を元の方程式に代入して確認します。

元の方程式:

\[ 5x - 7 = 18 \]

\( x = 5 \) を代入すると:

\[ 5(5) - 7 = 25 - 7 = 18 \]

これは元の方程式と一致するので、解は正しいです。

したがって、\( x = 5 \) になります。

マルチエージェントの例。質問を受け取るエージェントが、内容に応じて最適なエージェントを選択して、質問を「ハンドオフ」する。

sample_multi_agent.py
from agents import Agent, Runner
import asyncio

math_tutor_agent = Agent(
    name="数学の家庭教師",
    instructions=(
        "あなたは数学の問題解決を支援します。"
        "各ステップでの考え方を、例を挙げて説明してください。"
    )
)

history_tutor_agent = Agent(
    name="歴史の家庭教師",
    instructions=(
        "あなたは歴史の問題解決を支援します。"
        "重要な出来事や背景を明確に説明します。"
    )
)

triage_agent = Agent(
    name="受付エージェント",
    instructions="ユーザから与えられた宿題の質問内容に応じて、使用する家庭教師エージェントを選択します。",
    handoffs=[math_tutor_agent, history_tutor_agent]
)

async def main():
    result = await Runner.run(triage_agent, "5x - 7 = 18 は?")
    print(result.final_output)

if __name__ == "__main__":
    asyncio.run(main())
出力
この方程式を解くには、まず \(5x - 7 = 18\) を解きます。

1. 両辺に 7 を加えて、定数項を移行します。
   \[
   5x - 7 + 7 = 18 + 7
   \]
   \[
   5x = 25
   \]

2. 両辺を 5 で割って、\(x\) の値を求めます。
   \[
   x = \frac{25}{5}
   \]
   \[
   x = 5
   \]

したがって、解は \(x = 5\) です。

質問を変えてみる。

(snip)
    result = await Runner.run(triage_agent, "墾田永年私財法とは?")
(snip)
出力
墾田永年私財法(こんでんえいねんしざいほう)は、743年に日本で施行された法令です。これは、新しく開墾した土地を恒久的に私有地として認めるというものでした。背景には、奈良時代に律令国家が運営する荘園制度が行き詰まりを見せていたことがあります。

### 背景
- **律令制度**: 国家がすべての土地を所有し、人民に口分田として貸し与える制度でしたが、次第に運用が難しくなっていました。
- **人口増加と土地不足**: 人口増加に伴い、分配するべき土地が不足する問題が発生していました。
- **財政問題**: 政府の財政難を背景に新たな開墾を奨励し、税収を確保する意図がありました。

### 影響
- **土地の私有化**: 新たに開墾した土地が永続的に私有として認められることで、貴族や大寺社が積極的に土地を開発するようになりました。
- **荘園の発展**: この法の施行がきっかけで、私有地としての荘園が急速に広がり、地方権力者や寺社が経済力を強化することにつながりました。
- **律令制の衰退**: 律令制度に基づく国家統制が弱まり、地方豪族の力が増しくるきっかけとなりました。

墾田永年私財法は、日本の土地制度と経済構造に長期的な影響を与える重要な転換点となりました。

入出力に対してガードレールを追加する。最初のシンプルなエージェントの例に対して設定してみる。

sample_math_agent.py
from agents import Agent, Runner, GuardrailFunctionOutput, InputGuardrail 
import asyncio
from pydantic import BaseModel
from agents.exceptions import InputGuardrailTripwireTriggered

# 出力の定義
class HomeworkOutput(BaseModel):
    is_homework: bool
    reasoning: str

# 数学の宿題に関するかどうかをチェックするガードレールエージェントの定義
guardrail_agent = Agent(
    name="ガードレールチェック",
    instructions="ユーザの質問が数学の宿題に関するものかどうかをチェックする。",
    output_type=HomeworkOutput,
)

# ガードレール関数
async def homework_guardrail(ctx, agent, input_data):
    result = await Runner.run(guardrail_agent, input_data, context=ctx.context)
    final_output = result.final_output_as(HomeworkOutput)
    return GuardrailFunctionOutput(
        output_info=final_output,
        tripwire_triggered=not final_output.is_homework,
    )

agent = Agent(
    name="数学の家庭教師",
    instructions=(
        "あなたは数学の問題解決を支援します。"
        "各ステップでの考え方を、例を挙げて説明してください。"
    ),
    # 入力に対してガードレールを適用する
    input_guardrails=[
        InputGuardrail(guardrail_function=homework_guardrail),
    ],
)

async def main():
    try:
        result = await Runner.run(agent, "5x - 7 = 18 は?")
        print(result.final_output)
    except InputGuardrailTripwireTriggered as e:
        # ガードレールがブロックした場合
        print("ガードレールでブロックされました:", e)

if __name__ == "__main__":
    asyncio.run(main())
出力
この方程式を解くには、次のステップに従います。

### ステップ 1: 方程式を整理する
まず、方程式は \(5x - 7 = 18\) です。

### ステップ 2: 片方に定数を移動
定数項である \(-7\) を方程式の右側に移動します。そのために、両辺に \(7\) を足します。

\[ 5x - 7 + 7 = 18 + 7 \]

\[ 5x = 25 \]

### ステップ 3: \(x\) の値を求める
次に、\(x\) の係数を解消するために、両辺を \(5\) で割ります。

\[ \frac{5x}{5} = \frac{25}{5} \]

\[ x = 5 \]

### 結論
したがって、方程式 \(5x - 7 = 18\) の解は \(x = 5\) です。

別の問題にしてみる。

(snip)
        result = await Runner.run(agent, "5x - 7 = 18 は?")
(snip)

数学の問題ではないのでブロックされる。

出力
ガードレールでブロックされました: Guardrail InputGuardrail triggered tripwire

ではマルチエージェントでも。

sample_multi_agent_with_guardrail.py
from agents import Agent, Runner, GuardrailFunctionOutput, InputGuardrail
import asyncio
from pydantic import BaseModel
from agents.exceptions import InputGuardrailTripwireTriggered

class HomeworkOutput(BaseModel):
    is_homework: bool
    reasoning: str

guardrail_agent = Agent(
    name="ガードレールチェック",
    instructions="ユーザの質問が宿題に関するものかどうかをチェックする。",
    output_type=HomeworkOutput,
)

async def homework_guardrail(ctx, agent, input_data):
    result = await Runner.run(guardrail_agent, input_data, context=ctx.context)
    final_output = result.final_output_as(HomeworkOutput)
    return GuardrailFunctionOutput(
        output_info=final_output,
        tripwire_triggered=not final_output.is_homework,
    )

math_tutor_agent = Agent(
    name="数学の家庭教師",
    instructions=(
        "あなたは数学の問題解決を支援します。"
        "各ステップでの考え方を、例を挙げて説明してください。"
    )
)

history_tutor_agent = Agent(
    name="歴史の家庭教師",
    instructions=(
        "あなたは歴史の問題解決を支援します。"
        "重要な出来事や背景を明確に説明します。"
    )
)

triage_agent = Agent(
    name="受付エージェント",
    instructions="ユーザから与えられた宿題の質問内容に応じて、使用する家庭教師エージェントを選択します。",
    handoffs=[math_tutor_agent, history_tutor_agent],
    input_guardrails=[
        InputGuardrail(guardrail_function=homework_guardrail),
    ],
)

async def main():
    try:
        result = await Runner.run(triage_agent, "5x - 7 = 18 は?")
        print(result.final_output)
    except InputGuardrailTripwireTriggered as e:
        # ガードレールがブロックした場合
        print("ガードレールでブロックされました:", e)

    print("-" * 20)

    try:
        result = await Runner.run(triage_agent, "墾田永年私財法とは?")
        print(result.final_output)
    except InputGuardrailTripwireTriggered as e:
        # ガードレールがブロックした場合
        print("ガードレールでブロックされました:", e)

    print("-" * 20)

    try:
        result = await Runner.run(triage_agent, "人生の意味とは?")
        print(result.final_output)
    except InputGuardrailTripwireTriggered as e:
        # ガードレールがブロックした場合
        print("ガードレールでブロックされました:", e)

if __name__ == "__main__":
    asyncio.run(main())

結果。数学・歴史の質問に対しては回答されるが、それ以外の質問についてはガードレールでブロックされている。

出力
この方程式を解くには、まず \(x\) を求めます。

1. 方程式の両辺に 7 を足します。
   \[
   5x - 7 + 7 = 18 + 7
   \]
   \[
   5x = 25
   \]

2. 両辺を 5 で割ります。
   \[
   x = \frac{25}{5}
   \]
   \[
   x = 5
   \]

解は \(x = 5\) です。
--------------------
墾田永年私財法は、日本の奈良時代において、743年に施行された法律です。この法律の目的は、新しい農地の開墾を奨励することにありました。

### 背景
- **人口増加と食糧事情**: 奈良時代、日本の人口は徐々に増加し、それに伴って食糧生産の増大が必要となっていました。
- **税収確保**: 政府は税収増加を期待して政策を打ち出しました。

### 内容
- **永年私有の許可**: 新しく開墾した土地については、その土地を開拓した者が永年にわたって私有できるとしました。これにより、開墾に対する意欲を高めようとしました。

### 影響
- **貴族や大寺院の力の増大**: 大規模に開墾を行うことができた貴族や大寺院が多くの土地を所有するようになり、その影響力が増しました。
- **荘園の形成**: この法律を契機に、荘園と呼ばれる私有地の成立が進み、後の土地制度にも影響を与えました。

墾田永年私財法は、日本の土地制度の転換点となり、社会構造に大きな変化をもたらしました。
--------------------
ガードレールでブロックされました: Guardrail InputGuardrail triggered tripwire

OpenAIのダッシュボードでトレース情報が確認できる。

モデルはgpt-4oがデフォルトみたい。あと、適切なエージェントへのハンドオフができていなかったり(歴史の家庭教師エージェントが数学の質問にも答えてる)など、もわかるね。

kun432kun432

まとめ

以前におそらくこれのベースとなった「Swarm」はひと通り試していたけど、概ね考え方のようなものは同じではないかという気がする。なので比較的わかりやすいというか理解しやすいのではなかろうか。

あとは適宜各コンポーネントやトピックについて見ていくこととする。

次はこちら

https://zenn.dev/kun432/scraps/ced02ed77be7cd

kun432kun432

余談だが、マルチエージェントの際に、適切なエージェントへのハンドオフがなされない・違うエージェントにハンドオフされる、ということがあったが、どうやらエージェントの名前は英語にし他方が良いみたい。

ハンドオフのドキュメントを見ると、どうやらエージェント名はツール名に変換されるらしい。

https://openai.github.io/openai-agents-python/ja/handoffs/

こんな感じで英語にしてみる。

from agents import Agent, Runner
import asyncio

math_tutor_agent = Agent(
    name="math tutor agent",
    instructions=(
        "あなたは「数学」に関する質問の問題解決を支援します。数学以外の質問は対応できません。"
        "最初に、必ず自己紹介してください。"
        "その後、質問に関して、各ステップでの考え方を例を挙げながら説明してください。"
    )
)

history_tutor_agent = Agent(
    name="history tutor agent",
    instructions=(
        "あなたは「歴史」に関する質問の問題解決を支援します。歴史以外の質問は対応できません。"
        "最初に、必ず自己紹介してください。"
        "その後、質問に関して、重要な出来事や背景などを明確に説明してください。"
    )
)

triage_agent = Agent(
    name="triage agent",
    instructions=(
        "ユーザの宿題に関する質問に対して、適切なエージェントを選択してハンドオフしてください。\n"
        "- 数学の質問は、math tutor agentにハンドオフしてください。\n"
        "- 歴史の質問は、history tutor agentにハンドオフしてください。\n"
    ),
    handoffs=[math_tutor_agent, history_tutor_agent],
)

async def main():
    result = await Runner.run(triage_agent, "5x - 7 = 18 は?")
    print(result.final_output)

    print("-" * 20)

    result = await Runner.run(triage_agent, "墾田永年私財法とは?")
    print(result.final_output)

if __name__ == "__main__":
    asyncio.run(main())

出力
こんにちは!数学の問題を解くお手伝いをします。

5x - 7 = 18 の方程式を解いてみましょう。

**ステップ1: 両辺に7を足す**

まず、xを含む項を分離するために、両辺に7を足します。

\[ 5x - 7 + 7 = 18 + 7 \]

これにより、方程式は次のようになります。

\[ 5x = 25 \]

**ステップ2: 両辺を5で割る**

次に、xの係数が1になるように、両辺を5で割ります。

\[ \frac{5x}{5} = \frac{25}{5} \]

これにより、方程式は次のようになります。

\[ x = 5 \]

したがって、方程式の解は \( x = 5 \) です。何か質問がありますか?
--------------------
こんにちは、歴史に関する質問をお手伝いします。墾田永年私財法について説明しますね。

**墾田永年私財法**は、743年に日本の奈良時代に出された法律です。この法令は、開墾した土地を永世にわたって私有地とすることを認めたものでした。

### 背景
- **律令制と公地公民制**: 律令制下では、土地と人民は国家のものとされていました。しかし、人口増加や農業技術の進歩で新たな土地開発の機運が高まっていました。
- **農業生産の促進**: 国内の政治や経済を安定させるためには、農業生産の向上が重要とされ、この法令が出されました。
- **土地不足**: 都市や中央の貴族の間で土地取得の競争が激化し、土地不足が深刻になっていたことも背景としてあります。

### 影響と結果
- **私有地の拡大**: この法律により、豪族や寺社が多くの土地を開墾し、自らのものとしました。
- **荘園の発展**: 私有地の増加は荘園制の発達につながり、後の時代の社会構造に大きな影響を与えました。
- **公地公民制の弱体化**: 徐々に律令制の根幹であった公地公民制が弱まり、国家による土地支配は崩れていきました。

この法律によって私有地が増えたことは、日本の古代社会から中世社会への変遷に大きな影響を与えました。質問やさらに知りたいことがあれば、お知らせください。

OpenAIのダッシュボードでトレースを見ると、エージェント名が英語の場合は正しいツール名になっているが、日本語の場合だとうまく処理されずにおそらくツールを見分けれないのだろうと思われる。

このスクラップは21日前にクローズされました