Closed6

OpenAI「Agents SDK」⑤モデル

kun432kun432

モデル

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

まず当然ながらOpenAIモデルは標準サポートされており、2つのAPIで利用ができる。

そういえば、ここまで試してきた中ではあまり意識はしてなかったけども、トレーシングを見るとデフォルトだと

  • API: Responses API
  • モデル: gpt-4o

が使用されていた。

非OpenAIモデル

これに加えて、OpenAI以外の他のモデルも利用できる。これは LiteLLM を使って行われるらしい。これを有効にするにはSDKインストール時にextrasで指定する。

uv add "openai-agents[litellm]"

LiteLLM経由でOpenAI以外のモデルを使用する場合は、モデル指定時にlitellm/プレフィクスを指定すればよいらしい。

claude_agent = Agent(model="litellm/anthropic/claude-3-5-sonnet-20240620", ...)
gemini_agent = Agent(model="litellm/gemini/gemini-2.5-flash-preview-04-17", ...)

なお、OpenAI以外で Responses API に対応しているプロバイダーはほとんどないと思うので、ChatCompletions APIを使うことになる。

非 OpenAI モデルを使用するその他の方法

OpenAI以外のモデルを使用する場合、3通りの方法がある。それぞれのサンプルを見てみる。

1. set_default_openai_client

これは、以下の条件の場合にOpenAI SDKのAsyncOpenAIをグローバルに使うことができる。

  • LLMが、OpenAI 互換の API エンドポイントを持っていて、base_urlapi_key を設定できる場合

つまり、llama.cpp、Ollama、LM Studioなどはこれでいけるはずだし、LiteLLM ですでにOpenAI互換プロキシを立てているようなケースでも使えるはず。

以下にコード例がある。

https://github.com/openai/openai-agents-python/tree/main/examples/model_providers/custom_example_global.py

import asyncio
import os

from openai import AsyncOpenAI

from agents import (
    Agent,
    Runner,
    function_tool,
    set_default_openai_api,
    set_default_openai_client,
    set_tracing_disabled,
)

BASE_URL = os.getenv("EXAMPLE_BASE_URL") or ""
API_KEY = os.getenv("EXAMPLE_API_KEY") or ""
MODEL_NAME = os.getenv("EXAMPLE_MODEL_NAME") or ""

if not BASE_URL or not API_KEY or not MODEL_NAME:
    raise ValueError(
        "環境変数 EXAMPLE_BASE_URL, EXAMPLE_API_KEY, EXAMPLE_MODEL_NAME を設定してください。"
    )
""" この例では、デフォルトですべてのリクエストにカスタムプロバイダーを使用している。以下の3つの手順を実行する:
1. カスタムクライアントを作成。
2. それをデフォルトのOpenAIクライアントとして設定し、トレースには使用しないようにする。
3. デフォルトのAPIをChat Completionsに設定。これは、ほとんどのLLMプロバイダーがまだResponses APIをサポートしていないため。

なお、このサンプルでは、platform.openai.com から API キーを取得していないことを前提に、トレースを無効化している。
API キーがある場合は、`OPENAI_API_KEY` 環境変数を設定するか
set_tracing_export_api_key() を呼び出してトレース専用のキーを設定できる。
"""

client = AsyncOpenAI(
    base_url=BASE_URL,
    api_key=API_KEY,
)
set_default_openai_client(client=client, use_for_tracing=False)
set_default_openai_api("chat_completions")
set_tracing_disabled(disabled=True)


@function_tool
def get_weather(city: str):
    print(f"[debug] getting weather for {city}")
    return f"{city} の天気は「晴れ」です。"


async def main():
    agent = Agent(
        name="Assistant",
        instructions="常に俳句形式で返してください。",
        model=MODEL_NAME,
        tools=[get_weather],
    )

    result = await Runner.run(agent, "東京の天気について教えて。")
    print(result.final_output)


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

手元のLM Studioで動いているgpt-oss-20bを使ってみる。環境変数をセット。

export EXAMPLE_BASE_URL="http://localhost:1234/v1"
export EXAMPLE_API_KEY="dummy"
export EXAMPLE_MODEL_NAME="openai/gpt-oss-20b"

スクリプト実行結果。

出力
[debug] getting weather for 東京
朝光照らし、  
東京空は晴れ。  
風が笑う春。

2. ModelProvider

Runner.run レベルでモデルを指定すると、「この実行で全ての エージェント にカスタムのモデルプロバイダーを使う」という指定になる。

コード例は以下

https://github.com/openai/openai-agents-python/tree/main/examples/model_providers/custom_example_provider.py

from __future__ import annotations

import asyncio
import os

from openai import AsyncOpenAI

from agents import (
    Agent,
    Model,
    ModelProvider,
    OpenAIChatCompletionsModel,
    RunConfig,
    Runner,
    function_tool,
    set_tracing_disabled,
)

BASE_URL = os.getenv("EXAMPLE_BASE_URL") or ""
API_KEY = os.getenv("EXAMPLE_API_KEY") or ""
MODEL_NAME = os.getenv("EXAMPLE_MODEL_NAME") or ""

if not BASE_URL or not API_KEY or not MODEL_NAME:
    raise ValueError(
        "環境変数 EXAMPLE_BASE_URL, EXAMPLE_API_KEY, EXAMPLE_MODEL_NAME を設定してください。"
    )


"""
この例では、Runner.run() への一部の呼び出しにカスタムプロバイダーを使用し、他の呼び出しには OpenAI に直接アクセスしている。
手順:
1. カスタム OpenAI クライアントを作成。
2. カスタムクライアントを使用する ModelProvider を作成。
3. Runner.run() への呼び出しで ModelProvider を使用し、カスタム LLM プロバイダーを使用したい場合のみに限定。

この例では、platform.openai.com から API キーを取得していないことを前提に、トレースを無効化している。
API キーがある場合は、`OPENAI_API_KEY` 環境変数を設定するか
set_tracing_export_api_key() を呼び出してトレース専用のキーを設定できる。
"""
client = AsyncOpenAI(base_url=BASE_URL, api_key=API_KEY)
set_tracing_disabled(disabled=True)


class CustomModelProvider(ModelProvider):
    def get_model(self, model_name: str | None) -> Model:
        return OpenAIChatCompletionsModel(model=model_name or MODEL_NAME, openai_client=client)


CUSTOM_MODEL_PROVIDER = CustomModelProvider()


@function_tool
def get_weather(city: str):
    print(f"[debug] getting weather for {city}")
    return f"{city} の天気は「晴れ」です。"


async def main():
    agent = Agent(
        name="Assistant",
        instructions="常に俳句形式で返してください。",
        tools=[get_weather]
    )

    # ここではカスタムモデルプロバイダを使う
    result = await Runner.run(
        agent,
        "東京の天気について教えて。",
        run_config=RunConfig(model_provider=CUSTOM_MODEL_PROVIDER),
    )
    print(result.final_output)

    print("-" * 20)

    # ここではカスタムモデルプロバイダを使わず、OpenAIを直接使う
    result = await Runner.run(
        agent,
        "神戸の天気について教えて。",
    )
    print(result.final_output)


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

一つ前と同様に環境変数をセット、あと、OpenAIも使うようにしたのでOpenAI APIキーもセット。

export EXAMPLE_BASE_URL="http://localhost:1234/v1"
export EXAMPLE_API_KEY="dummy"
export EXAMPLE_MODEL_NAME="openai/gpt-oss-20b"
export OPENAI_API_KEY="XXXXXXXXXX"

実行結果

出力
[debug] getting weather for Tokyo
東京の空  
朝風がさざめく  
晴れ渡る街よ
--------------------
[debug] getting weather for Kobe
澄んだ空  
神戸の街に  
光満ち

3. Agent.model

Agent.modelを使うと、特定の Agent インスタンスに対して、モデルを指定できる。

こちらもサンプルコードが以下にある。

https://github.com/openai/openai-agents-python/blob/main/examples/model_providers/custom_example_agent.py

import asyncio
import os

from openai import AsyncOpenAI

from agents import Agent, OpenAIChatCompletionsModel, Runner, function_tool, set_tracing_disabled

BASE_URL = os.getenv("EXAMPLE_BASE_URL") or ""
API_KEY = os.getenv("EXAMPLE_API_KEY") or ""
MODEL_NAME = os.getenv("EXAMPLE_MODEL_NAME") or ""

if not BASE_URL or not API_KEY or not MODEL_NAME:
    raise ValueError(
        "環境変数 EXAMPLE_BASE_URL, EXAMPLE_API_KEY, EXAMPLE_MODEL_NAMEを設定してください。"
    )

"""この例では、特定のエージェントにカスタムプロバイダーを使用する。手順:
1. カスタム OpenAI クライアントを作成。
2. カスタムクライアントを使用する `Model` を作成。
3. `model` をエージェントに設定。

この例では、platform.openai.com から API キーを取得していないことを前提に、トレースを無効化している。
APIがある場合は、`OPENAI_API_KEY` 環境変数を設定するか
set_tracing_export_api_key() を呼び出してトレース専用のキーを設定できる。
"""
client = AsyncOpenAI(base_url=BASE_URL, api_key=API_KEY)
set_tracing_disabled(disabled=True)

# もう一つのアプローチとして以下も可能:
# PROVIDER = OpenAIProvider(openai_client=client)
# agent = Agent(..., model="some-custom-model")
# Runner.run(agent, ..., run_config=RunConfig(model_provider=PROVIDER))


@function_tool
def get_weather(city: str):
    print(f"[debug] getting weather for {city}")
    return f"{city}の天気は「晴れ」です。"


async def main():
    # This agent will use the custom LLM provider
    agent = Agent(
        name="Assistant",
        instructions="常に俳句形式で返してください。",
        model=OpenAIChatCompletionsModel(model=MODEL_NAME, openai_client=client),
        tools=[get_weather],
    )

    result = await Runner.run(agent, "東京の天気について教えて。")
    print(result.final_output)


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

こちらも同様に環境変数をセット。

export EXAMPLE_BASE_URL="http://localhost:1234/v1"
export EXAMPLE_API_KEY="dummy"
export EXAMPLE_MODEL_NAME="openai/gpt-oss-20b"

実行結果

出力
[debug] getting weather for Tokyo
東京の空  
青く広がる風  
今日も晴れやかに

なお、注意書きや上記の例でも設定してあるが、基本的にトレーシングはデフォルトで有効、かつ、OpenAIプラットフォームのものを使用するようになっている様子。OpenAI以外のモデルを使用する(かつOpenAIを一切使わない)場合は

  • set_tracing_disabled()でOpenAIプラットフォームへのトレーシングを無効化
  • 他のトレーシング連携を使用する

ことになる。

kun432kun432

ところで、上記の例は全てAsyncOpenAIを使用して、OpenAI互換API(自分の場合はLM Studio)へアクセスしていたが、LiteLLMを使うならば他のプロバイダを使ってみたい。

そのあたりのサンプルが以下にあった。

https://github.com/openai/openai-agents-python/tree/main/examples/model_providers/litellm_auto.py

https://github.com/openai/openai-agents-python/tree/main/examples/model_providers/litellm_provider.py

上記2つのサンプルの違いは以下。

  • 前者は、モデル名のプレフィクスにlitellm/をつけて指定、つまりAgents SDKの内部でLiteLLMを使用する
  • 後者は、LitellmModelというLiteLLMモデル専用クラスを明示的に使う

前者でGemini APIを試してみる。サンプルはCLIでモデルを引数指定できるようになっているが、そこは除外した例。

import asyncio
from agents import Agent, Runner, function_tool, set_tracing_disabled

set_tracing_disabled(disabled=True)

@function_tool
def get_weather(city: str):
    print(f"[debug] getting weather for {city}")
    return f"{city} の天気は「晴れ」です。"


async def main():
    agent = Agent(
        name="Assistant",
        instructions="常に俳句形式で返してください。",
        # "litellm/" プレフィクスをつけてLiteLLMを使用
        model="litellm/gemini/gemini-2.5-flash-lite",
        tools=[get_weather],
    )

    result = await Runner.run(agent, "東京の天気について教えて。")
    print(result.final_output)


if __name__ == "__main__":
    import os

    if os.getenv("GEMINI_API_KEY") is None:
        raise ValueError(
            "環境変数 GEMINI_API_KEY が設定されていません。"
        )

    asyncio.run(main())

GEMINI_API_KEYをセット

export GEMINI_API_KEY=XXXXXXXXXX

実行結果

出力
東京の
空は晴れやかに
風そよぐ
kun432kun432

モデルの組み合わせ

単一のワークフロー内でエージェントごとにモデルを使用する。以下のような使い方が可能となる。

  • 振り分けは軽量・高速なモデルを使用
  • 複雑なタスクには大型で高機能なモデルを使用

この場合、Agentsにモデルを渡すことになるが、モデルの渡し方は以下の3通り。

  1. モデル名を直接渡す
  2. 任意のモデル名+その名前をModelインスタンスにマッピングできるModelProviderを渡す
  3. Model実装を直接渡す

なお、注意書きには、

この SDK は OpenAIResponsesModel と OpenAIChatCompletionsModel の両方の形をサポートしていますが、各ワークフローでは 1 つのモデル形状に統一することをおすすめします。両者はサポートする機能やツールが異なるためです。もしワークフローでモデル形状の組み合わせが必要な場合は、使用する全機能が両方で利用可能であることを確認してください。

とあるので、特にOpenAI以外のモデルプロバイダを使う場合には注意が必要。

上記3通りをそれぞれ書いてみた。

from agents import Agent, Runner, RunConfig, ModelProvider, Model, AsyncOpenAI, OpenAIChatCompletionsModel
import asyncio

# モデル名を渡す場合
japanese_agent = Agent(
    name="Japanese agent",
    instructions="あなたは日本語だけを話す。",
    model="gpt-4o", 
)

# ModelProviderを渡す場合 
class CustomModelProvider(ModelProvider):
    def get_model(self, model_name: str | None) -> Model:
        # カスタムなモデルプロバイダーの設定を行う
        return OpenAIChatCompletionsModel(model=model_name, openai_client=AsyncOpenAI())

spanish_agent = Agent(
    name="Spanish agent",
    instructions="あなたはスペイン語だけを話す。",
    model=CustomModelProvider().get_model("gpt-4o-mini")
)

# Model実装を直接渡す場合
english_agent = Agent(
    name="English agent",
    instructions="あなたは英語だけを話す。",
    model=OpenAIChatCompletionsModel( 
        model="gpt-4.1-nano",
        openai_client=AsyncOpenAI()
    ),
)

triage_agent = Agent(
    name="Triage agent",
    instructions="リクエストの言語に基づいて、適切なエージェントにハンドオフする。",
    handoffs=[japanese_agent, english_agent, spanish_agent],
    model="gpt-4.1",
)

async def main():
    for input in ["Hello!", "こんにちは", "¡Hola!"]:
        result = await Runner.run(triage_agent, input=input)
        print(f"{result.last_agent.name}: {result.final_output}")
        print("-" * 20)

if __name__ == "__main__":
    asyncio.run(main())
出力
English agent: Hello! How can I assist you today?
--------------------
Japanese agent: こんにちは!今日はどんなお手伝いができるでしょうか?
--------------------
Spanish agent: ¡Hola! ¿Cómo puedo ayudarte hoy?
--------------------

モデルの設定を細かく制御したい場合、例えばtemperatureなどを指定したい場合はModelSettingsを渡す。

from agents import Agent, Runner, ModelSettings
import asyncio

agent = Agent(
    name="Haiku agent",
    instructions="常に俳句形式で返す。",
    model="gpt-4o", 
    model_settings=ModelSettings(
        temperature=0.7,
    )
)

async def main():
    result = await Runner.run(agent, input="競馬の魅力を教えて。")
    print(result.final_output)

if __name__ == "__main__":
    asyncio.run(main())
出力
速さ競い  
馬と人の絆  
夢を追う

Responses API固有のパラメータの場合、トップレベルで指定できないものがあるらしい。その場合はextra_argsで渡す。

from agents import Agent, Runner, ModelSettings
import asyncio

agent = Agent(
    name="Haiku agent",
    instructions="常に俳句形式で返す。",
    model="gpt-4o", 
    model_settings=ModelSettings(
        temperature=0.7,
        extra_args={"user": "user_123"},
    )
)

async def main():
    result = await Runner.run(agent, input="競馬の魅力を教えて。")
    print(result.final_output)

if __name__ == "__main__":
    asyncio.run(main())
出力
蹄の響き  
風を切る速さ  
夢の駆け引き
kun432kun432

他社 LLM プロバイダー利用時のよくある問題

Agents SDKは当然ながらOpenAIが基本となっているため、デフォルトの仕様や設定が他のプロバイダモデルと噛み合わない場合があるので注意が必要。

  1. トレーシングのクライアントエラー401
    • デフォルトだとOpenAIプラットフォームにトレーシングが送信されるため、OpenAI APIキーが必須になる。他のモデルプロバイダを使う場合、この点を踏まえて以下の対応が必要。
      1. set_tracing_disabled(True) で、OpenAIプラットフォームへのトレーシングを無効化
      2. set_tracing_export_api_key(...)で、トレーシング用途のみにOpenAI APIキーをセット
      3. 他のトレーシングを使用
  2. Responses APIサポート
    • Agents SDKはデフォルトで、Responses API を使用する。他のほとんどのモデルプロバイダはResponses APIをサポートしていないため、以下の対応が必要。
      1. set_default_openai_api("chat_completions") で、Chat Completions APIを使用する。ただし、OPENAI_API_KEYOPENAI_BASE_URL を指定している場合のみ
      - つまりOpenAI互換APIの場合のみ。
      2. OpenAIChatCompletionsModelを使う。
  3. Structured outputsのサポート
    • モデルプロバイダによっては Structured outputs をサポートしていない。その場合にはエラーが発生する。
    • これについては改善中だが、JSON schema 出力をサポートするプロバイダーの使用を推奨

プロバイダーをまたぐモデルの組み合わせ

モデルプロバイダごとに提供している機能には当然違いがある。この違いによってはエラーが発生する場合がある。

例えば、OpenAIでは以下が提供されているが、他のプロバイダではサポートされていない場合がある。

  • structured outputs
  • マルチモーダル入力
  • ホスト型の ファイル検索 / Web 検索、など

当然ながらこれらを使ったコードは他のモデルプロバイダでは動作しないため、以下に注意

  • プロバイダが対応していないツールを送信しない
  • テキスト専用モデルの場合は、送信前にマルチモーダル入力を除去
  • structured JSON 出力をサポートしないプロバイダーは、無効な JSON を生成する可能性があるため、それに対応したプロバイダを選択する
kun432kun432

注意すべき点は当然ながらあるが、ある程度はいろいろなモデルに対して汎用的に使えそうな雰囲気はある。

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