OpenAI Agents SDK 0.3 : エージェント & ツール使用の強制

OpenAI Agents SDK のコア・ビルディングブロック – エージェントの機能の説明です。エージェントは指示とツールで構成された、大規模言語モデル (LLM) です。

OpenAI Agents SDK 0.3 : エージェント

作成 : クラスキャット・セールスインフォメーション
作成日時 : 10/15/2025
バージョン : v0.3.3

* 本記事は以下のページを参考にしています :

* サンプルコードの動作確認はしておりますが、必要な場合には適宜、追加改変しています。
* ご自由にリンクを張って頂いてかまいませんが、sales-info@classcat.com までご一報いただけると嬉しいです。

 

 

OpenAI Agents SDK 0.3 : エージェント

エージェントはアプリケーションのはコア・ビルディングブロックです。エージェントは指示 (instructions) とツールで構成された、大規模言語モデル (LLM) です。

 

基本的な構成設定

構成設定するエージェントの最も一般的なプロパティは以下です :

  • name : エージェントを識別する必須の文字列。

  • instructions: 開発者メッセージやシステムプロンプトとも呼ばれます。

  • model: どの LLM を使用するか、そして temperature, top_p のようなモデル調整パラメータを設定するオプションの model_settings。

  • tools: エージェントがタスクを遂行するために使用できるツール。
from agents import Agent, ModelSettings, function_tool

@function_tool
def get_weather(city: str) -> str:
    """returns weather info for the specified city."""
    return f"The weather in {city} is sunny"

agent = Agent(
    name="Haiku agent",
    instructions="Always respond in haiku form",
    model="gpt-5-nano",
    tools=[get_weather],
)

 

コンテキスト

エージェントはコンテキスト型について汎用的 (generic) です (i.e. 型パラメータ化されています)。またコンテキストは依存性注入 (dependency-injection) ツールです : それはユーザが作成して Runner.run() に渡すオブジェクトで、すべてのエージェント、ツール、ハンドオフ等に渡され、そしてエージェント実行の依存性と状態の詰め合わせ (grab bag) として機能します。任意の Python オブジェクトをコンテキストとして提供できます。

@dataclass
class UserContext:
    name: str
    uid: str
    is_pro_user: bool

    async def fetch_purchases() -> list[Purchase]:
        return ...

agent = Agent[UserContext](
    ...,
)

 

出力タイプ

デフォルトでは、エージェントは plain テキスト (i.e. str) 出力を生成します。エージェントに特定のタイプの出力を生成することを望む場合、output_type パラメータを使用できます。一般的な選択は Pydantic オブジェクトを使用することですが、Pydantic TypeAdapter – dataclasses, lists, TypedDict 等でラップできる任意のタイプをサポートします。

from pydantic import BaseModel
from agents import Agent


class CalendarEvent(BaseModel):
    name: str
    date: str
    participants: list[str]

agent = Agent(
    name="Calendar extractor",
    instructions="Extract calendar events from text",
    output_type=CalendarEvent,
)

Note : output_type を渡す場合、通常の plain テキスト応答ではなく、構造化出力 を使用するようにモデルに指示します。

 

マルチエージェントシステム・デザインパターン

マルチエージェントシステムの設計方法は数多くありますが、一般的には広く適用可能な 2 つのパターンがあります :

  1. マネージャ (ツールとしてのエージェント) : 中心的なマネージャ/オーケストレーターが専門のサブエージェントをツールとして呼び出し、会話の制御を維持します。

  2. ハンドオフ : peer エージェントが会話を引き継ぐ専門エージェントに制御をハンドオフします。これは分散型 (decentralized) です。

See our practical guide to building agents for more details.

 

マネージャ (ツールとしてのエージェント)

customer_facing_agent はすべてのユーザ・インタラクションを処理し、ツールとして公開されている、専門のサブエージェントをツールとして呼び出します。Read more in the tools documentation.

from agents import Agent

booking_agent = Agent(...)
refund_agent = Agent(...)

customer_facing_agent = Agent(
    name="Customer-facing agent",
    instructions=(
        "Handle all direct user communication. "
        "Call the relevant tools when specialized expertise is needed."
    ),
    tools=[
        booking_agent.as_tool(
            tool_name="booking_expert",
            tool_description="Handles booking questions and requests.",
        ),
        refund_agent.as_tool(
            tool_name="refund_expert",
            tool_description="Handles refund questions and requests.",
        )
    ],
)

 

ハンドオフ

ハンドオフはエージェントが委任できるサブエージェントです。ハンドオフが発生すると、委任されたエージェントは会話履歴を受け取り、会話を引き継ぎます。このパターンは、単一のタスクに優れた、モジュール型の専門エージェントの実現を可能にします。Read more in the handoffs documentation.

from agents import Agent

booking_agent = Agent(...)
refund_agent = Agent(...)

triage_agent = Agent(
    name="Triage agent",
    instructions=(
        "Help the user with their questions. "
        "If they ask about booking, hand off to the booking agent. "
        "If they ask about refunds, hand off to the refund agent."
    ),
    handoffs=[booking_agent, refund_agent],
)

 

動的な指示 (instructions)

殆どの場合、エージェントを作成するときに指示を提供できます。但し関数を通して動的な指示を提供することもできます。関数はエージェントとコンテキストを受け取り、プロンプトを返す必要があります。通常の関数と async 関数の両方が受け入れられます。

def dynamic_instructions(
    context: RunContextWrapper[UserContext], agent: Agent[UserContext]
) -> str:
    return f"The user's name is {context.context.name}. Help them with their questions."


agent = Agent[UserContext](
    name="Triage agent",
    instructions=dynamic_instructions,
)

 

ライフサイクル・イベント (フック)

エージェントのライフサイクルを観察したい場合があります。例えば、イベントをログ記録したり、特定のイベントが発生するときデータを事前取得したい場合があるかもしれません。hooks プロパティを使用してエージェントのライフサイクルをフックできます。AgentHooks クラスをサブクラス化して、関心のあるメソッドをオーバライドします。

 

ガードレール

ガードレールは、エージェントの実行と並行して、ユーザ入力と (生成後に) エージェントの出力をチェック/検証を実行することを可能にします。例えば、関連性の観点からユーザの入力とエージェントの出力をスクリーニングできるでしょう。Read more in the guardrails documentation.

 

エージェントのクローニング (複製) /コピー

エージェントの clone() メソッドを使用して、エージェントを複製し、オプションで好みのプロパティを変更することができます。

pirate_agent = Agent(
    name="Pirate",
    instructions="Write like a pirate",
    model="gpt-4.1",
)

robot_agent = pirate_agent.clone(
    name="Robot",
    instructions="Write like a robot",
)

 

ツール使用の強制

ツールのリストの供給は、LLM がツールを使用することを意味しているとは限りません。ModelSettings.tool_choice を設定することで、ツール使用を強制できます。有効な値は :

  1. auto, LLM がツールを使用するか否か決定することができます。

  2. required, LLM がツールを使用することを必須にします (ただしどのツールを使用するかはインテリジェントに決定できます)。

  3. none, LLM がツールを使用しないことを必須にします。

  4. 特定の文字列 e.g. my_tool を設定すると、 LLM がその特定のツールを使用することを必須にします。
from agents import Agent, Runner, function_tool, ModelSettings

@function_tool
def get_weather(city: str) -> str:
    """Returns weather info for the specified city."""
    return f"The weather in {city} is sunny"

agent = Agent(
    name="Weather Agent",
    instructions="Retrieve weather details.",
    tools=[get_weather],
    model_settings=ModelSettings(tool_choice="get_weather")
)

 

ツール使用時の動作

エージェント設定の tool_use_behavior パラメータはツール出力の処理方法を制御します :

  • “run_llm_again”: デフォルト。ツールが実行され、LLM は結果を処理して最終的な応答を生成します。

  • “stop_on_first_tool”: 最初のツール呼び出しの出力が最終的な応答として使用され、それ以上の LLM により処理は行われません。

    from agents import Agent, Runner, function_tool, ModelSettings
    
    @function_tool
    def get_weather(city: str) -> str:
        """Returns weather info for the specified city."""
        return f"The weather in {city} is sunny"
    
    agent = Agent(
        name="Weather Agent",
        instructions="Retrieve weather details.",
        tools=[get_weather],
        tool_use_behavior="stop_on_first_tool"
    )
    

  • StopAtTools(stop_at_tool_names=[…]): 指定したツールが呼び出された場合には停止し、その出力を最終的な応答として使用します。

    from agents import Agent, Runner, function_tool
    from agents.agent import StopAtTools
    
    @function_tool
    def get_weather(city: str) -> str:
        """Returns weather info for the specified city."""
        return f"The weather in {city} is sunny"
    
    @function_tool
    def sum_numbers(a: int, b: int) -> int:
        """Adds two numbers."""
        return a + b
    
    agent = Agent(
        name="Stop At Stock Agent",
        instructions="Get weather or sum numbers.",
        tools=[get_weather, sum_numbers],
        tool_use_behavior=StopAtTools(stop_at_tool_names=["get_weather"])
    )
    

  • ToolsToFinalOutputFunction: ツールの結果を処理して、LLM を停止するか続行するかを決定するカスタム関数。

    from agents import Agent, Runner, function_tool, FunctionToolResult, RunContextWrapper
    from agents.agent import ToolsToFinalOutputResult
    from typing import List, Any
    
    @function_tool
    def get_weather(city: str) -> str:
        """Returns weather info for the specified city."""
        return f"The weather in {city} is sunny"
    
    def custom_tool_handler(
        context: RunContextWrapper[Any],
        tool_results: List[FunctionToolResult]
    ) -> ToolsToFinalOutputResult:
        """Processes tool results to decide final output."""
        for result in tool_results:
            if result.output and "sunny" in result.output:
                return ToolsToFinalOutputResult(
                    is_final_output=True,
                    final_output=f"Final weather: {result.output}"
                )
        return ToolsToFinalOutputResult(
            is_final_output=False,
            final_output=None
        )
    
    agent = Agent(
        name="Weather Agent",
        instructions="Retrieve weather details.",
        tools=[get_weather],
        tool_use_behavior=custom_tool_handler
    )
    

Note : 無限ループを防ぐために、フレームワークはツール呼び出し後に tool_choice を “auto” に自動的にリセットします。この動作は agent.reset_tool_choice で設定可能です。無限ループが発生するのは、ツールの結果が LLM に送信され、これが tool_choice ゆえに別のツール呼び出しを無限に生成するためです。

 

以上