chore: import upstream snapshot with attribution
This commit is contained in:
@@ -0,0 +1,428 @@
|
||||
---
|
||||
search:
|
||||
exclude: true
|
||||
---
|
||||
# エージェント
|
||||
|
||||
エージェントは、アプリの中核となる構成要素です。エージェントとは、instructions、ツール、およびハンドオフ、ガードレール、structured outputs などのオプションの実行時動作を設定した大規模言語モデル(LLM)です。
|
||||
|
||||
単一の標準的な `Agent` を定義またはカスタマイズする場合は、このページを参照してください。複数のエージェントをどのように連携させるかを検討している場合は、[エージェントオーケストレーション](multi_agent.md)を参照してください。マニフェストで定義されたファイルとサンドボックスネイティブの機能を備えた分離ワークスペース内でエージェントを実行する場合は、[サンドボックスエージェントの概念](sandbox/guide.md)を参照してください。
|
||||
|
||||
SDK は、OpenAI モデルに対してデフォルトで Responses API を使用しますが、ここでの違いはオーケストレーションにあります。`Agent` と `Runner` を組み合わせることで、SDK がターン、ツール、ガードレール、ハンドオフ、セッションを管理します。このループを自分で管理したい場合は、代わりに Responses API を直接使用してください。
|
||||
|
||||
## 次のガイドの選択
|
||||
|
||||
このページをエージェント定義のハブとして使用してください。次に行う必要がある判断に合った関連ガイドに進んでください。
|
||||
|
||||
| 目的 | 次に読むガイド |
|
||||
| --- | --- |
|
||||
| モデルまたはプロバイダーの設定を選択する | [モデル](models/index.md) |
|
||||
| エージェントに機能を追加する | [ツール](tools.md) |
|
||||
| 実際のリポジトリ、ドキュメント一式、または分離ワークスペースを対象にエージェントを実行する | [サンドボックスエージェントのクイックスタート](sandbox_agents.md) |
|
||||
| マネージャー形式のオーケストレーションとハンドオフのどちらを使用するか決定する | [エージェントオーケストレーション](multi_agent.md) |
|
||||
| ハンドオフの動作を設定する | [ハンドオフ](handoffs.md) |
|
||||
| ターンの実行、イベントのストリーミング、または会話状態の管理を行う | [エージェントの実行](running_agents.md) |
|
||||
| 最終出力、実行項目、または再開可能な状態を確認する | [実行結果](results.md) |
|
||||
| ローカル依存関係と実行時状態を共有する | [コンテキスト管理](context.md) |
|
||||
|
||||
## 基本設定
|
||||
|
||||
エージェントで最も一般的なプロパティは次のとおりです。
|
||||
|
||||
| プロパティ | 必須 | 説明 |
|
||||
| --- | --- | --- |
|
||||
| `name` | はい | 人が理解しやすいエージェント名です。 |
|
||||
| `instructions` | いいえ | システムプロンプトまたは動的 instructions コールバックです。使用を強く推奨します。[動的 instructions](#dynamic-instructions)を参照してください。 |
|
||||
| `prompt` | いいえ | OpenAI Responses API のプロンプト設定です。静的なプロンプトオブジェクトまたは関数を受け取ります。[プロンプトテンプレート](#prompt-templates)を参照してください。 |
|
||||
| `handoff_description` | いいえ | このエージェントがハンドオフ先として提示される際に公開される短い説明です。 |
|
||||
| `handoffs` | いいえ | 会話を専門エージェントに委任します。[ハンドオフ](handoffs.md)を参照してください。 |
|
||||
| `model` | いいえ | 使用する LLM です。[モデル](models/index.md)を参照してください。 |
|
||||
| `model_settings` | いいえ | `temperature`、`top_p`、`tool_choice` などのモデル調整パラメーターです。 |
|
||||
| `tools` | いいえ | エージェントが呼び出せるツールです。[ツール](tools.md)を参照してください。 |
|
||||
| `mcp_servers` | いいえ | エージェント向けの MCP ベースのツールです。[MCP ガイド](mcp.md)を参照してください。 |
|
||||
| `mcp_config` | いいえ | 厳密なスキーマ変換や MCP エラー形式など、MCP ツールの準備方法を詳細に調整します。[MCP ガイド](mcp.md#agent-level-mcp-configuration)を参照してください。 |
|
||||
| `input_guardrails` | いいえ | このエージェントチェーンへの最初のユーザー入力に対して実行されるガードレールです。[ガードレール](guardrails.md)を参照してください。 |
|
||||
| `output_guardrails` | いいえ | このエージェントの最終出力に対して実行されるガードレールです。[ガードレール](guardrails.md)を参照してください。 |
|
||||
| `output_type` | いいえ | プレーンテキストの代わりに使用する構造化出力型です。[出力型](#output-types)を参照してください。 |
|
||||
| `hooks` | いいえ | エージェントスコープのライフサイクルコールバックです。[ライフサイクルイベント(フック)](#lifecycle-events-hooks)を参照してください。 |
|
||||
| `tool_use_behavior` | いいえ | ツールの実行結果をモデルに戻すか、実行を終了するかを制御します。[ツール使用時の動作](#tool-use-behavior)を参照してください。 |
|
||||
| `reset_tool_choice` | いいえ | ツール使用ループを回避するため、ツール呼び出し後に `tool_choice` をリセットします(デフォルト:`True`)。[ツール使用の強制](#forcing-tool-use)を参照してください。 |
|
||||
|
||||
```python
|
||||
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],
|
||||
)
|
||||
```
|
||||
|
||||
このセクションの内容はすべて `Agent` に適用されます。`SandboxAgent` は同じ概念を基盤とし、さらにワークスペーススコープの実行向けに `default_manifest`、`base_instructions`、`capabilities`、`run_as` を追加します。[サンドボックスエージェントの概念](sandbox/guide.md)を参照してください。
|
||||
|
||||
## プロンプトテンプレート
|
||||
|
||||
`prompt` を設定すると、OpenAI プラットフォームで作成したプロンプトテンプレートを参照できます。これは、Responses API を使用する OpenAI モデルで機能します。
|
||||
|
||||
使用するには、次の手順に従ってください。
|
||||
|
||||
1. https://platform.openai.com/playground/prompts に移動します。
|
||||
2. 新しいプロンプト変数 `poem_style` を作成します。
|
||||
3. 次の内容でシステムプロンプトを作成します。
|
||||
|
||||
```
|
||||
Write a poem in {{poem_style}}
|
||||
```
|
||||
|
||||
4. `--prompt-id` フラグを指定してコード例を実行します。
|
||||
|
||||
```python
|
||||
from agents import Agent
|
||||
|
||||
agent = Agent(
|
||||
name="Prompted assistant",
|
||||
prompt={
|
||||
"id": "pmpt_123",
|
||||
"version": "1",
|
||||
"variables": {"poem_style": "haiku"},
|
||||
},
|
||||
)
|
||||
```
|
||||
|
||||
実行時にプロンプトを動的に生成することもできます。
|
||||
|
||||
```python
|
||||
from dataclasses import dataclass
|
||||
|
||||
from agents import Agent, GenerateDynamicPromptData, Runner
|
||||
|
||||
@dataclass
|
||||
class PromptContext:
|
||||
prompt_id: str
|
||||
poem_style: str
|
||||
|
||||
|
||||
async def build_prompt(data: GenerateDynamicPromptData):
|
||||
ctx: PromptContext = data.context.context
|
||||
return {
|
||||
"id": ctx.prompt_id,
|
||||
"version": "1",
|
||||
"variables": {"poem_style": ctx.poem_style},
|
||||
}
|
||||
|
||||
|
||||
agent = Agent(name="Prompted assistant", prompt=build_prompt)
|
||||
result = await Runner.run(
|
||||
agent,
|
||||
"Say hello",
|
||||
context=PromptContext(prompt_id="pmpt_123", poem_style="limerick"),
|
||||
)
|
||||
```
|
||||
|
||||
## コンテキスト
|
||||
|
||||
エージェントは `context` 型に対してジェネリックです。コンテキストは依存性注入のためのツールです。これは、作成して `Runner.run()` に渡すオブジェクトであり、すべてのエージェント、ツール、ハンドオフなどに渡され、エージェント実行に必要な依存関係と状態をまとめて保持します。任意の Python オブジェクトをコンテキストとして指定できます。
|
||||
|
||||
`RunContextWrapper` の全機能、共有使用量の追跡、ネストされた `tool_input`、およびシリアライズ時の注意事項については、[コンテキストガイド](context.md)を参照してください。
|
||||
|
||||
```python
|
||||
@dataclass
|
||||
class UserContext:
|
||||
name: str
|
||||
uid: str
|
||||
is_pro_user: bool
|
||||
|
||||
async def fetch_purchases() -> list[Purchase]:
|
||||
return ...
|
||||
|
||||
agent = Agent[UserContext](
|
||||
...,
|
||||
)
|
||||
```
|
||||
|
||||
## 出力型
|
||||
|
||||
デフォルトでは、エージェントはプレーンテキスト(つまり `str`)の出力を生成します。エージェントに特定の型の出力を生成させる場合は、`output_type` パラメーターを使用できます。一般的には [Pydantic](https://docs.pydantic.dev/) オブジェクトを使用しますが、Pydantic の [TypeAdapter](https://docs.pydantic.dev/latest/api/type_adapter/) でラップできる任意の型(データクラス、リスト、TypedDict など)をサポートしています。
|
||||
|
||||
```python
|
||||
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` を渡すと、通常のプレーンテキスト応答の代わりに [structured outputs](https://platform.openai.com/docs/guides/structured-outputs) を使用するようモデルに指示します。
|
||||
|
||||
## マルチエージェントシステムの設計パターン
|
||||
|
||||
マルチエージェントシステムにはさまざまな設計方法がありますが、一般的に広く適用できる次の 2 つのパターンが使用されます。
|
||||
|
||||
1. マネージャー(agents as tools):中央のマネージャー/オーケストレーターが、専門化されたサブエージェントをツールとして呼び出し、会話の制御を維持します。
|
||||
2. ハンドオフ:対等なエージェントが、会話を引き継ぐ専門エージェントに制御をハンドオフします。これは分散型のパターンです。
|
||||
|
||||
詳細については、[エージェント構築の実践ガイド](https://cdn.openai.com/business-guides-and-resources/a-practical-guide-to-building-agents.pdf)を参照してください。
|
||||
|
||||
### マネージャー(agents as tools)
|
||||
|
||||
`customer_facing_agent` はすべてのユーザー対応を処理し、ツールとして公開された専門化されたサブエージェントを呼び出します。詳細については、[ツール](tools.md#agents-as-tools)のドキュメントを参照してください。
|
||||
|
||||
```python
|
||||
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.",
|
||||
)
|
||||
],
|
||||
)
|
||||
```
|
||||
|
||||
### ハンドオフ
|
||||
|
||||
ハンドオフは、エージェントが処理を委任できるサブエージェントです。ハンドオフが発生すると、委任先のエージェントが会話履歴を受け取り、会話を引き継ぎます。このパターンにより、単一のタスクに特化したモジュール式の専門エージェントを実現できます。詳細については、[ハンドオフ](handoffs.md)のドキュメントを参照してください。
|
||||
|
||||
```python
|
||||
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
|
||||
|
||||
ほとんどの場合、エージェントの作成時に instructions を指定できます。ただし、関数を介して動的な instructions を指定することもできます。この関数はエージェントとコンテキストを受け取り、プロンプトを返す必要があります。通常の関数と `async` 関数の両方を使用できます。
|
||||
|
||||
```python
|
||||
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,
|
||||
)
|
||||
```
|
||||
|
||||
## ライフサイクルイベント(フック)
|
||||
|
||||
エージェントのライフサイクルを監視したい場合があります。たとえば、特定のイベントが発生した際に、イベントのログ記録、データの事前取得、または使用量の記録を行う場合があります。
|
||||
|
||||
フックには次の 2 つのスコープがあります。
|
||||
|
||||
- [`RunHooks`][agents.lifecycle.RunHooks] は、他のエージェントへのハンドオフを含む `Runner.run(...)` 呼び出し全体を監視します。
|
||||
- [`AgentHooks`][agents.lifecycle.AgentHooks] は、`agent.hooks` を介して特定のエージェントインスタンスにアタッチされます。
|
||||
|
||||
コールバックのコンテキストも、イベントによって異なります。
|
||||
|
||||
- エージェントの開始/終了フックは [`AgentHookContext`][agents.run_context.AgentHookContext] を受け取ります。これは元のコンテキストをラップし、共有される実行使用量の状態を保持します。
|
||||
- LLM、ツール、ハンドオフのフックは [`RunContextWrapper`][agents.run_context.RunContextWrapper] を受け取ります。
|
||||
|
||||
一般的なフックのタイミングは次のとおりです。
|
||||
|
||||
- `on_agent_start` / `on_agent_end`:特定のエージェントが最終出力の生成を開始または完了したとき。
|
||||
- `on_llm_start` / `on_llm_end`:各モデル呼び出しの直前と直後。
|
||||
- `on_tool_start` / `on_tool_end`:各ローカルツール呼び出しの前後。関数ツールの場合、フックの `context` は通常 `ToolContext` であるため、`tool_call_id` などのツール呼び出しメタデータを確認できます。
|
||||
- `on_handoff`:制御があるエージェントから別のエージェントに移るとき。
|
||||
|
||||
ワークフロー全体を単一のオブザーバーで監視する場合は `RunHooks` を使用し、1 つのエージェントにカスタムの副作用が必要な場合は `AgentHooks` を使用してください。
|
||||
|
||||
```python
|
||||
from agents import Agent, RunHooks, Runner
|
||||
|
||||
|
||||
class LoggingHooks(RunHooks):
|
||||
async def on_agent_start(self, context, agent):
|
||||
print(f"Starting {agent.name}")
|
||||
|
||||
async def on_llm_end(self, context, agent, response):
|
||||
print(f"{agent.name} produced {len(response.output)} output items")
|
||||
|
||||
async def on_agent_end(self, context, agent, output):
|
||||
print(f"{agent.name} finished with usage: {context.usage}")
|
||||
|
||||
|
||||
agent = Agent(name="Assistant", instructions="Be concise.")
|
||||
result = await Runner.run(agent, "Explain quines", hooks=LoggingHooks())
|
||||
print(result.final_output)
|
||||
```
|
||||
|
||||
コールバックの全機能については、[ライフサイクル API リファレンス](ref/lifecycle.md)を参照してください。
|
||||
|
||||
## ガードレール
|
||||
|
||||
ガードレールを使用すると、エージェントの実行と並行してユーザー入力に対するチェック/検証を行い、エージェントの出力が生成された後にその出力をチェックできます。たとえば、ユーザー入力とエージェント出力が関連性のある内容かどうかを検査できます。詳細については、[ガードレール](guardrails.md)のドキュメントを参照してください。
|
||||
|
||||
## エージェントのクローン作成/コピー
|
||||
|
||||
エージェントの `clone()` メソッドを使用すると、Agent を複製し、必要に応じて任意のプロパティを変更できます。
|
||||
|
||||
```python
|
||||
pirate_agent = Agent(
|
||||
name="Pirate",
|
||||
instructions="Write like a pirate",
|
||||
model="gpt-5.6-sol",
|
||||
)
|
||||
|
||||
robot_agent = pirate_agent.clone(
|
||||
name="Robot",
|
||||
instructions="Write like a robot",
|
||||
)
|
||||
```
|
||||
|
||||
## ツール使用の強制
|
||||
|
||||
ツールのリストを指定しても、LLM が必ずツールを使用するとは限りません。[`ModelSettings.tool_choice`][agents.model_settings.ModelSettings.tool_choice] を設定すると、ツールの使用を強制できます。有効な値は次のとおりです。
|
||||
|
||||
1. `auto`:ツールを使用するかどうかを LLM が判断できます。
|
||||
2. `required`:LLM にツールの使用を要求します。ただし、どのツールを使用するかは LLM が適切に判断できます。
|
||||
3. `none`:LLM にツールを _使用しない_ よう要求します。
|
||||
4. `my_tool` などの特定の文字列:LLM にその特定のツールを使用するよう要求します。
|
||||
|
||||
OpenAI Responses のツール検索を使用する場合、名前付きツールの選択にはさらに制限があります。`tool_choice` では、単独の名前空間名や遅延専用ツールを指定できず、`tool_choice="tool_search"` で [`ToolSearchTool`][agents.tool.ToolSearchTool] を指定することもできません。このような場合は、`auto` または `required` を使用してください。Responses 固有の制約については、[ホスト型ツール検索](tools.md#hosted-tool-search)を参照してください。
|
||||
|
||||
```python
|
||||
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")
|
||||
)
|
||||
```
|
||||
|
||||
## ツール使用時の動作
|
||||
|
||||
`Agent` 設定の `tool_use_behavior` パラメーターは、ツール出力の処理方法を制御します。
|
||||
|
||||
- `"run_llm_again"`:デフォルトです。ツールが実行され、その実行結果を LLM が処理して最終応答を生成します。
|
||||
- `"stop_on_first_tool"`:最初のツール呼び出しの出力を、それ以降の LLM 処理を行わずに最終応答として使用します。
|
||||
|
||||
```python
|
||||
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=[...])`:指定したツールのいずれかが呼び出された場合に停止し、その出力を最終応答として使用します。
|
||||
|
||||
```python
|
||||
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 での処理を続けるかを判断するカスタム関数です。
|
||||
|
||||
```python
|
||||
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`][agents.agent.Agent.reset_tool_choice] で設定できます。無限ループが発生するのは、ツールの実行結果が LLM に送信され、その後 `tool_choice` によって LLM が再びツール呼び出しを生成し、この処理が際限なく繰り返されるためです。
|
||||
@@ -0,0 +1,205 @@
|
||||
---
|
||||
search:
|
||||
exclude: true
|
||||
---
|
||||
# 設定
|
||||
|
||||
このページでは、デフォルトの OpenAI キーまたはクライアント、デフォルトの OpenAI API の形式、トレーシングエクスポートのデフォルト、ログ動作など、通常はアプリケーションの起動時に一度だけ設定する SDK 全体のデフォルトについて説明します。
|
||||
|
||||
これらのデフォルトはサンドボックスベースのワークフローにも引き続き適用されますが、サンドボックスワークスペース、サンドボックスクライアント、セッションの再利用は別途設定します。
|
||||
|
||||
代わりに特定のエージェントまたは実行を設定する必要がある場合は、まず次を参照してください:
|
||||
|
||||
- [エージェント](agents.md): 通常の `Agent` の instructions、tools、出力タイプ、ハンドオフ、ガードレールについて。
|
||||
- [エージェントの実行](running_agents.md): `RunConfig`、セッション、会話状態オプションについて。
|
||||
- [サンドボックスエージェント](sandbox/guide.md): `SandboxRunConfig`、マニフェスト、ケイパビリティ、サンドボックスクライアント固有のワークスペース設定について。
|
||||
- [モデル](models/index.md): モデル選択とプロバイダー設定について。
|
||||
- [トレーシング](tracing.md): 実行ごとのトレーシングメタデータとカスタムトレースプロセッサーについて。
|
||||
|
||||
## API キーとクライアント
|
||||
|
||||
デフォルトでは、SDK は LLM リクエストとトレーシングに `OPENAI_API_KEY` 環境変数を使用します。このキーは、SDK が初めて OpenAI クライアントを作成するときに解決されます(遅延初期化)。そのため、最初のモデル呼び出しの前に環境変数を設定してください。アプリの起動前にその環境変数を設定できない場合は、[set_default_openai_key()][agents.set_default_openai_key] 関数を使用してキーを設定できます。
|
||||
|
||||
```python
|
||||
from agents import set_default_openai_key
|
||||
|
||||
set_default_openai_key("sk-...")
|
||||
```
|
||||
|
||||
また、使用する OpenAI クライアントを設定することもできます。デフォルトでは、SDK は環境変数の API キー、または上で設定したデフォルトキーを使用して、`AsyncOpenAI` インスタンスを作成します。これは [set_default_openai_client()][agents.set_default_openai_client] 関数を使用して変更できます。
|
||||
|
||||
```python
|
||||
from openai import AsyncOpenAI
|
||||
from agents import set_default_openai_client
|
||||
|
||||
custom_client = AsyncOpenAI(base_url="...", api_key="...")
|
||||
set_default_openai_client(custom_client)
|
||||
```
|
||||
|
||||
環境変数ベースのエンドポイント設定を使用したい場合、デフォルトの OpenAI プロバイダーは `OPENAI_BASE_URL` も読み取ります。Responses WebSocket トランスポートを有効にすると、WebSocket の `/responses` エンドポイント用に `OPENAI_WEBSOCKET_BASE_URL` も読み取ります。
|
||||
|
||||
```bash
|
||||
export OPENAI_BASE_URL="https://your-openai-compatible-endpoint.example/v1"
|
||||
export OPENAI_WEBSOCKET_BASE_URL="wss://your-openai-compatible-endpoint.example/v1"
|
||||
```
|
||||
|
||||
最後に、使用される OpenAI API もカスタマイズできます。デフォルトでは OpenAI Responses API を使用します。[set_default_openai_api()][agents.set_default_openai_api] 関数を使用すると、これを上書きして Chat Completions API を使用できます。
|
||||
|
||||
```python
|
||||
from agents import set_default_openai_api
|
||||
|
||||
set_default_openai_api("chat_completions")
|
||||
```
|
||||
|
||||
## OpenAI プロバイダーのデフォルト
|
||||
|
||||
OpenAI を基盤とするプロバイダーは、モデル名を解決するときにも SDK 全体のデフォルトを読み取ります。OpenAI Responses モデルがデフォルトで WebSocket トランスポートを使用するようにするには、[`set_default_openai_responses_transport()`][agents.set_default_openai_responses_transport] を使用します:
|
||||
|
||||
```python
|
||||
from agents import set_default_openai_responses_transport
|
||||
|
||||
set_default_openai_responses_transport("websocket")
|
||||
```
|
||||
|
||||
これは、デフォルトの OpenAI プロバイダーによって解決される OpenAI Responses モデルに影響します。プロバイダーレベルのセットアップ、接続の再利用、キープアライブオプション、カスタム WebSocket エンドポイントについては、[Responses WebSocket トランスポート](models/index.md#responses-websocket-transport) を参照してください。
|
||||
|
||||
OpenAI セットアップでプロバイダーレベルのエージェント登録メタデータが必要な場合は、起動時にデフォルトのハーネス ID を一度設定してください:
|
||||
|
||||
```python
|
||||
from agents import set_default_openai_harness
|
||||
|
||||
set_default_openai_harness("your-harness-id")
|
||||
```
|
||||
|
||||
完全な登録オブジェクトを渡すこともできます:
|
||||
|
||||
```python
|
||||
from agents import OpenAIAgentRegistrationConfig, set_default_openai_agent_registration
|
||||
|
||||
set_default_openai_agent_registration(
|
||||
OpenAIAgentRegistrationConfig(harness_id="your-harness-id")
|
||||
)
|
||||
```
|
||||
|
||||
SDK のデフォルトが設定されていない場合、OpenAI を基盤とするプロバイダーは `OPENAI_AGENT_HARNESS_ID` 環境変数にフォールバックします。ハーネス ID が設定されている場合、`agent_harness_id` が `RunConfig.trace_metadata` にすでに存在する場合を除き、SDK はそれを `agent_harness_id` としてトレースメタデータに追加します。
|
||||
|
||||
## トレーシング
|
||||
|
||||
トレーシングはデフォルトで有効です。デフォルトでは、上のセクションで説明したモデルリクエストと同じ OpenAI API キー(つまり、環境変数または設定したデフォルトキー)を使用します。トレーシングに使用する API キーは、[`set_tracing_export_api_key`][agents.set_tracing_export_api_key] 関数を使用して個別に設定できます。
|
||||
|
||||
```python
|
||||
from agents import set_tracing_export_api_key
|
||||
|
||||
set_tracing_export_api_key("sk-...")
|
||||
```
|
||||
|
||||
モデルのトラフィックではあるキーまたはクライアントを使用し、トレーシングでは別の OpenAI キーを使用したい場合は、デフォルトのキーまたはクライアントを設定するときに `use_for_tracing=False` を渡し、そのうえでトレーシングを個別に設定してください。カスタムクライアントを使用していない場合は、同じパターンを [`set_default_openai_key()`][agents.set_default_openai_key] にも適用できます。
|
||||
|
||||
```python
|
||||
from openai import AsyncOpenAI
|
||||
from agents import (
|
||||
set_default_openai_client,
|
||||
set_tracing_export_api_key,
|
||||
)
|
||||
|
||||
custom_client = AsyncOpenAI(base_url="https://your-openai-compatible-endpoint.example/v1", api_key="provider-key")
|
||||
set_default_openai_client(custom_client, use_for_tracing=False)
|
||||
|
||||
set_tracing_export_api_key("sk-tracing")
|
||||
```
|
||||
|
||||
デフォルトエクスポーターを使用するときに、トレースを特定の組織またはプロジェクトに関連付ける必要がある場合は、アプリの起動前に次の環境変数を設定してください:
|
||||
|
||||
```bash
|
||||
export OPENAI_ORG_ID="org_..."
|
||||
export OPENAI_PROJECT_ID="proj_..."
|
||||
```
|
||||
|
||||
グローバルエクスポーターを変更せずに、実行ごとにトレーシング API キーを設定することもできます。
|
||||
|
||||
```python
|
||||
from agents import Runner, RunConfig
|
||||
|
||||
await Runner.run(
|
||||
agent,
|
||||
input="Hello",
|
||||
run_config=RunConfig(tracing={"api_key": "sk-tracing-123"}),
|
||||
)
|
||||
```
|
||||
|
||||
[`set_tracing_disabled()`][agents.set_tracing_disabled] 関数を使用して、トレーシングを完全に無効化することもできます。
|
||||
|
||||
```python
|
||||
from agents import set_tracing_disabled
|
||||
|
||||
set_tracing_disabled(True)
|
||||
```
|
||||
|
||||
トレーシングを有効のままにしつつ、機微情報を含む可能性のある入力/出力をトレースペイロードから除外したい場合は、[`RunConfig.trace_include_sensitive_data`][agents.run.RunConfig.trace_include_sensitive_data] を `False` に設定してください:
|
||||
|
||||
```python
|
||||
from agents import Runner, RunConfig
|
||||
|
||||
await Runner.run(
|
||||
agent,
|
||||
input="Hello",
|
||||
run_config=RunConfig(trace_include_sensitive_data=False),
|
||||
)
|
||||
```
|
||||
|
||||
コードを使わずにデフォルトを変更することもできます。アプリの起動前にこの環境変数を設定してください:
|
||||
|
||||
```bash
|
||||
export OPENAI_AGENTS_TRACE_INCLUDE_SENSITIVE_DATA=0
|
||||
```
|
||||
|
||||
トレーシング制御の詳細については、[トレーシングガイド](tracing.md) を参照してください。
|
||||
|
||||
## デバッグログ
|
||||
|
||||
SDK は 2 つの Python ロガー(`openai.agents` と `openai.agents.tracing`)を定義しており、デフォルトではハンドラーをアタッチしません。ログは、アプリケーションの Python ロギング設定に従います。
|
||||
|
||||
詳細ログを有効にするには、[`enable_verbose_stdout_logging()`][agents.enable_verbose_stdout_logging] 関数を使用します。
|
||||
|
||||
```python
|
||||
from agents import enable_verbose_stdout_logging
|
||||
|
||||
enable_verbose_stdout_logging()
|
||||
```
|
||||
|
||||
また、ハンドラー、フィルター、フォーマッターなどを追加してログをカスタマイズすることもできます。詳しくは [Python ロギングガイド](https://docs.python.org/3/howto/logging.html) を参照してください。
|
||||
|
||||
```python
|
||||
import logging
|
||||
|
||||
logger = logging.getLogger("openai.agents") # or openai.agents.tracing for the Tracing logger
|
||||
|
||||
# To make all logs show up
|
||||
logger.setLevel(logging.DEBUG)
|
||||
# To make info and above show up
|
||||
logger.setLevel(logging.INFO)
|
||||
# To make warning and above show up
|
||||
logger.setLevel(logging.WARNING)
|
||||
# etc
|
||||
|
||||
# You can customize this as needed, but this will output to `stderr` by default
|
||||
logger.addHandler(logging.StreamHandler())
|
||||
```
|
||||
|
||||
### ログ内の機微データ
|
||||
|
||||
一部のログには、機微データ(たとえば、ユーザーデータ)が含まれる場合があります。
|
||||
|
||||
デフォルトでは、SDK は LLM の入力/出力やツールの入力/出力を **ログに記録しません** 。これらの保護は次の項目で制御されます:
|
||||
|
||||
```bash
|
||||
OPENAI_AGENTS_DONT_LOG_MODEL_DATA=1
|
||||
OPENAI_AGENTS_DONT_LOG_TOOL_DATA=1
|
||||
```
|
||||
|
||||
デバッグのためにこのデータを一時的に含める必要がある場合は、アプリの起動前にいずれかの変数を `0`(または `false`)に設定してください:
|
||||
|
||||
```bash
|
||||
export OPENAI_AGENTS_DONT_LOG_MODEL_DATA=0
|
||||
export OPENAI_AGENTS_DONT_LOG_TOOL_DATA=0
|
||||
```
|
||||
@@ -0,0 +1,148 @@
|
||||
---
|
||||
search:
|
||||
exclude: true
|
||||
---
|
||||
# コンテキスト管理
|
||||
|
||||
コンテキストは多義的な用語です。考慮すべきコンテキストには、主に 2 つの種類があります:
|
||||
|
||||
1. コードからローカルに利用できるコンテキスト: これは、ツール関数の実行時、`on_handoff` のようなコールバック内、ライフサイクルフック内などで必要になる可能性のあるデータや依存関係です。
|
||||
2. LLM が利用できるコンテキスト: これは、LLM が応答を生成するときに参照するデータです。
|
||||
|
||||
## ローカルコンテキスト
|
||||
|
||||
これは [`RunContextWrapper`][agents.run_context.RunContextWrapper] クラス、およびその中の [`context`][agents.run_context.RunContextWrapper.context] プロパティで表現されます。仕組みは次のとおりです:
|
||||
|
||||
1. 任意の Python オブジェクトを作成します。一般的なパターンは dataclass や Pydantic オブジェクトを使用することです。
|
||||
2. そのオブジェクトを各種実行メソッドに渡します (例: `Runner.run(..., context=whatever)`)。
|
||||
3. すべてのツール呼び出し、ライフサイクルフックなどには、ラッパーオブジェクト `RunContextWrapper[T]` が渡されます。ここで `T` はコンテキストオブジェクトの型を表し、`wrapper.context` を通じてアクセスできます。
|
||||
|
||||
一部のランタイム固有のコールバックでは、SDK はより特殊化された `RunContextWrapper[T]` のサブクラスを渡す場合があります。たとえば、関数ツールのライフサイクルフックは通常 `ToolContext` を受け取り、これは `tool_call_id`、`tool_name`、`tool_arguments` などのツール呼び出しメタデータも公開します。
|
||||
|
||||
認識すべき **最も重要な** 点は、あるエージェント実行におけるすべてのエージェント、ツール関数、ライフサイクルなどが、同じ _型_ のコンテキストを使用しなければならないということです。
|
||||
|
||||
コンテキストは、たとえば次の用途に使用できます:
|
||||
|
||||
- 実行時のコンテキストデータ (例: ユーザー名 / uid や、ユーザーに関するその他の情報)
|
||||
- 依存関係 (例: ロガーオブジェクト、データ取得器など)
|
||||
- ヘルパー関数
|
||||
|
||||
!!! danger "注記"
|
||||
|
||||
コンテキストオブジェクトは LLM に **送信されません**。これは完全にローカルなオブジェクトであり、読み取り、書き込み、メソッドの呼び出しができます。
|
||||
|
||||
1 回の実行内では、派生したラッパーは同じ基盤となるアプリコンテキスト、承認状態、使用状況の追跡を共有します。ネストされた [`Agent.as_tool()`][agents.agent.Agent.as_tool] の実行では異なる `tool_input` を付加する場合がありますが、デフォルトではアプリ状態の分離コピーは取得しません。
|
||||
|
||||
### `RunContextWrapper` の公開内容
|
||||
|
||||
[`RunContextWrapper`][agents.run_context.RunContextWrapper] は、アプリで定義したコンテキストオブジェクトを包むラッパーです。実際には、ほとんどの場合、次のものを使用します:
|
||||
|
||||
- [`wrapper.context`][agents.run_context.RunContextWrapper.context]: 独自の可変なアプリ状態と依存関係に使用します。
|
||||
- [`wrapper.usage`][agents.run_context.RunContextWrapper.usage]: 現在の実行全体で集計されたリクエストおよびトークン使用量に使用します。
|
||||
- [`wrapper.tool_input`][agents.run_context.RunContextWrapper.tool_input]: 現在の実行が [`Agent.as_tool()`][agents.agent.Agent.as_tool] の内部で実行されている場合の構造化入力に使用します。
|
||||
- [`wrapper.approve_tool(...)`][agents.run_context.RunContextWrapper.approve_tool] / [`wrapper.reject_tool(...)`][agents.run_context.RunContextWrapper.reject_tool]: 承認状態をプログラムで更新する必要がある場合に使用します。
|
||||
|
||||
アプリで定義したオブジェクトは `wrapper.context` のみです。その他のフィールドは SDK が管理するランタイムメタデータです。
|
||||
|
||||
後で human-in-the-loop や耐久ジョブワークフローのために [`RunState`][agents.run_state.RunState] をシリアライズする場合、そのランタイムメタデータは状態とともに保存されます。シリアライズされた状態を永続化または送信する予定がある場合、[`RunContextWrapper.context`][agents.run_context.RunContextWrapper.context] にシークレットを入れないでください。
|
||||
|
||||
会話状態は別の関心事です。ターンをどのように引き継ぐかに応じて、`result.to_input_list()`、`session`、`conversation_id`、または `previous_response_id` を使用してください。その判断については、[実行結果](results.md)、[エージェントの実行](running_agents.md)、[セッション](sessions/index.md) を参照してください。
|
||||
|
||||
```python
|
||||
import asyncio
|
||||
from dataclasses import dataclass
|
||||
|
||||
from agents import Agent, RunContextWrapper, Runner, function_tool
|
||||
|
||||
@dataclass
|
||||
class UserInfo: # (1)!
|
||||
name: str
|
||||
uid: int
|
||||
|
||||
@function_tool
|
||||
async def fetch_user_age(wrapper: RunContextWrapper[UserInfo]) -> str: # (2)!
|
||||
"""Fetch the age of the user. Call this function to get user's age information."""
|
||||
return f"The user {wrapper.context.name} is 47 years old"
|
||||
|
||||
async def main():
|
||||
user_info = UserInfo(name="John", uid=123)
|
||||
|
||||
agent = Agent[UserInfo]( # (3)!
|
||||
name="Assistant",
|
||||
tools=[fetch_user_age],
|
||||
)
|
||||
|
||||
result = await Runner.run( # (4)!
|
||||
starting_agent=agent,
|
||||
input="What is the age of the user?",
|
||||
context=user_info,
|
||||
)
|
||||
|
||||
print(result.final_output) # (5)!
|
||||
# The user John is 47 years old.
|
||||
|
||||
if __name__ == "__main__":
|
||||
asyncio.run(main())
|
||||
```
|
||||
|
||||
1. これがコンテキストオブジェクトです。ここでは dataclass を使用していますが、任意の型を使用できます。
|
||||
2. これはツールです。`RunContextWrapper[UserInfo]` を受け取っていることがわかります。ツール実装はコンテキストから読み取ります。
|
||||
3. 型チェッカーがエラーを検出できるように、エージェントにジェネリック `UserInfo` を指定します (たとえば、異なるコンテキスト型を受け取るツールを渡そうとした場合)。
|
||||
4. コンテキストは `run` 関数に渡されます。
|
||||
5. エージェントは正しくツールを呼び出し、年齢を取得します。
|
||||
|
||||
---
|
||||
|
||||
### 高度な内容: `ToolContext`
|
||||
|
||||
場合によっては、実行中のツールに関する追加メタデータ (名前、呼び出し ID、生の引数文字列など) にアクセスしたいことがあります。
|
||||
この場合、`RunContextWrapper` を拡張する [`ToolContext`][agents.tool_context.ToolContext] クラスを使用できます。
|
||||
|
||||
```python
|
||||
from typing import Annotated
|
||||
from pydantic import BaseModel, Field
|
||||
from agents import Agent, Runner, function_tool
|
||||
from agents.tool_context import ToolContext
|
||||
|
||||
class WeatherContext(BaseModel):
|
||||
user_id: str
|
||||
|
||||
class Weather(BaseModel):
|
||||
city: str = Field(description="The city name")
|
||||
temperature_range: str = Field(description="The temperature range in Celsius")
|
||||
conditions: str = Field(description="The weather conditions")
|
||||
|
||||
@function_tool
|
||||
def get_weather(ctx: ToolContext[WeatherContext], city: Annotated[str, "The city to get the weather for"]) -> Weather:
|
||||
print(f"[debug] Tool context: (name: {ctx.tool_name}, call_id: {ctx.tool_call_id}, args: {ctx.tool_arguments})")
|
||||
return Weather(city=city, temperature_range="14-20C", conditions="Sunny with wind.")
|
||||
|
||||
agent = Agent(
|
||||
name="Weather Agent",
|
||||
instructions="You are a helpful agent that can tell the weather of a given city.",
|
||||
tools=[get_weather],
|
||||
)
|
||||
```
|
||||
|
||||
`ToolContext` は `RunContextWrapper` と同じ `.context` プロパティを提供し、
|
||||
現在のツール呼び出しに固有の追加フィールドも提供します:
|
||||
|
||||
- `tool_name` – 呼び出されているツールの名前
|
||||
- `tool_call_id` – このツール呼び出しの一意の識別子
|
||||
- `tool_arguments` – ツールに渡された生の引数文字列
|
||||
- `tool_namespace` – ツールが `tool_namespace()` または別の名前空間付きサーフェスを通じて読み込まれた場合の、ツール呼び出しに対する Responses 名前空間
|
||||
- `qualified_tool_name` – 名前空間が利用できる場合に、その名前空間で修飾されたツール名
|
||||
|
||||
実行中にツールレベルのメタデータが必要な場合は、`ToolContext` を使用してください。
|
||||
エージェントとツール間で一般的なコンテキスト共有を行うには、`RunContextWrapper` のままで十分です。`ToolContext` は `RunContextWrapper` を拡張しているため、ネストされた `Agent.as_tool()` 実行が構造化入力を提供した場合には `.tool_input` も公開できます。
|
||||
|
||||
---
|
||||
|
||||
## エージェント / LLM コンテキスト
|
||||
|
||||
LLM が呼び出されるとき、その LLM が参照できる **唯一の** データは会話履歴に含まれるものです。つまり、新しいデータを LLM に利用可能にしたい場合は、その履歴内で利用可能になるような方法で行う必要があります。これにはいくつかの方法があります:
|
||||
|
||||
1. エージェントの `instructions` に追加できます。これは「システムプロンプト」または「開発者メッセージ」とも呼ばれます。システムプロンプトは静的文字列にも、コンテキストを受け取って文字列を出力する動的関数にもできます。これは、常に役立つ情報 (たとえば、ユーザーの名前や現在の日付) に対する一般的な手法です。
|
||||
2. `Runner.run` 関数を呼び出すときに `input` に追加します。これは `instructions` の手法に似ていますが、[指揮系統](https://cdn.openai.com/spec/model-spec-2024-05-08.html#follow-the-chain-of-command) においてより下位のメッセージにできます。
|
||||
3. 関数ツールを介して公開します。これは _オンデマンド_ のコンテキストに便利です。LLM がデータを必要とするタイミングを判断し、そのデータを取得するためにツールを呼び出せます。
|
||||
4. リトリーバルまたは Web 検索を使用します。これらは、ファイルやデータベースから関連データを取得する (リトリーバル)、または Web から取得する (Web 検索) ことができる特殊なツールです。これは、関連するコンテキストデータに基づいて応答を「グラウンディング」するのに便利です。
|
||||
@@ -0,0 +1,136 @@
|
||||
---
|
||||
search:
|
||||
exclude: true
|
||||
---
|
||||
# コード例
|
||||
|
||||
[リポジトリ](https://github.com/openai/openai-agents-python/tree/main/examples) のコード例セクションで、SDK のさまざまな実装サンプルをご覧ください。コード例は複数のカテゴリーに整理され、それぞれ異なるパターンと機能を示します。
|
||||
|
||||
## カテゴリー
|
||||
|
||||
- **[agent_patterns](https://github.com/openai/openai-agents-python/tree/main/examples/agent_patterns):** このカテゴリーのコード例では、次のような一般的なエージェント設計パターンを示します。
|
||||
|
||||
- 決定論的ワークフロー
|
||||
- Agents as tools
|
||||
- ストリーミングイベントを使用する Agents as tools (`examples/agent_patterns/agents_as_tools_streaming.py`)
|
||||
- 構造化入力パラメーターを使用する Agents as tools (`examples/agent_patterns/agents_as_tools_structured.py`)
|
||||
- エージェントの並列実行
|
||||
- 条件付きのツール使用
|
||||
- 異なる動作でのツール使用の強制 (`examples/agent_patterns/forcing_tool_use.py`)
|
||||
- 入出力ガードレール
|
||||
- 判定役としての LLM
|
||||
- ルーティング
|
||||
- ストリーミングガードレール
|
||||
- ツール承認と状態のシリアル化を伴う人間参加型フロー (`examples/agent_patterns/human_in_the_loop.py`)
|
||||
- ストリーミングを伴う人間参加型フロー (`examples/agent_patterns/human_in_the_loop_stream.py`)
|
||||
- 承認フロー向けのカスタム拒否メッセージ (`examples/agent_patterns/human_in_the_loop_custom_rejection.py`)
|
||||
|
||||
- **[basic](https://github.com/openai/openai-agents-python/tree/main/examples/basic):** これらのコード例では、次のような SDK の基本機能を紹介します。
|
||||
|
||||
- Hello world のコード例(デフォルトモデル、GPT-5、オープンウェイトモデル)
|
||||
- エージェントのライフサイクル管理
|
||||
- 実行フックとエージェントフックのライフサイクルのコード例 (`examples/basic/lifecycle_example.py`)
|
||||
- 動的システムプロンプト
|
||||
- 基本的なツールの使用 (`examples/basic/tools.py`)
|
||||
- ツールの入出力ガードレール (`examples/basic/tool_guardrails.py`)
|
||||
- 画像形式のツール出力 (`examples/basic/image_tool_output.py`)
|
||||
- ストリーミング出力(テキスト、アイテム、関数呼び出しの引数)
|
||||
- ターン間で共有されるセッションヘルパーを使用する Responses WebSocket トランスポート (`examples/basic/stream_ws.py`)
|
||||
- プロンプトテンプレート
|
||||
- ファイル処理(ローカルおよびリモート、画像および PDF)
|
||||
- 使用量の追跡
|
||||
- Runner が管理する再試行設定 (`examples/basic/retry.py`)
|
||||
- サードパーティー製アダプターを介して Runner が管理する再試行 (`examples/basic/retry_litellm.py`)
|
||||
- 厳密でない出力型
|
||||
- 以前のレスポンス ID の使用
|
||||
|
||||
- **[customer_service](https://github.com/openai/openai-agents-python/tree/main/examples/customer_service):** 航空会社向けカスタマーサービスシステムのコード例です。
|
||||
|
||||
- **[financial_research_agent](https://github.com/openai/openai-agents-python/tree/main/examples/financial_research_agent):** エージェントとツールを使用した、金融データ分析向けの構造化された調査ワークフローを示す金融調査エージェントです。
|
||||
|
||||
- **[handoffs](https://github.com/openai/openai-agents-python/tree/main/examples/handoffs):** メッセージフィルタリングを伴うエージェントのハンドオフの実践的なコード例です。以下が含まれます。
|
||||
|
||||
- メッセージフィルターのコード例 (`examples/handoffs/message_filter.py`)
|
||||
- ストリーミングを伴うメッセージフィルター (`examples/handoffs/message_filter_streaming.py`)
|
||||
|
||||
- **[hosted_mcp](https://github.com/openai/openai-agents-python/tree/main/examples/hosted_mcp):** OpenAI Responses API でホスト型 MCP (Model Context Protocol) を使用する方法を示すコード例です。以下が含まれます。
|
||||
|
||||
- 承認不要のシンプルなホスト型 MCP (`examples/hosted_mcp/simple.py`)
|
||||
- Google Calendar などの MCP コネクター (`examples/hosted_mcp/connectors.py`)
|
||||
- 中断ベースの承認を使用する人間参加型フロー (`examples/hosted_mcp/human_in_the_loop.py`)
|
||||
- MCP ツール呼び出しの承認時コールバック (`examples/hosted_mcp/on_approval.py`)
|
||||
|
||||
- **[mcp](https://github.com/openai/openai-agents-python/tree/main/examples/mcp):** MCP (Model Context Protocol) を使用してエージェントを構築する方法を学びます。以下が含まれます。
|
||||
|
||||
- ファイルシステムのコード例
|
||||
- Git のコード例
|
||||
- MCP プロンプトサーバーのコード例
|
||||
- SSE (Server-Sent Events) のコード例
|
||||
- SSE リモートサーバー接続 (`examples/mcp/sse_remote_example`)
|
||||
- Streamable HTTP のコード例
|
||||
- Streamable HTTP リモート接続 (`examples/mcp/streamable_http_remote_example`)
|
||||
- Streamable HTTP 向けのカスタム HTTP クライアントファクトリー (`examples/mcp/streamablehttp_custom_client_example`)
|
||||
- `MCPUtil.get_all_function_tools` を使用したすべての MCP ツールの事前取得 (`examples/mcp/get_all_mcp_tools_example`)
|
||||
- FastAPI と組み合わせた MCPServerManager (`examples/mcp/manager_example`)
|
||||
- MCP ツールのフィルタリング (`examples/mcp/tool_filter_example`)
|
||||
|
||||
- **[memory](https://github.com/openai/openai-agents-python/tree/main/examples/memory):** エージェント向けのさまざまなメモリ実装のコード例です。以下が含まれます。
|
||||
|
||||
- SQLite セッションストレージ
|
||||
- 高度な SQLite セッションストレージ
|
||||
- Redis セッションストレージ
|
||||
- SQLAlchemy セッションストレージ
|
||||
- Dapr ステートストアのセッションストレージ
|
||||
- 暗号化されたセッションストレージ
|
||||
- OpenAI Conversations セッションストレージ
|
||||
- Responses 圧縮セッションストレージ
|
||||
- `ModelSettings(store=False)` を使用したステートレスな Responses 圧縮 (`examples/memory/compaction_session_stateless_example.py`)
|
||||
- ファイルベースのセッションストレージ (`examples/memory/file_session.py`)
|
||||
- 人間参加型フローを伴うファイルベースのセッション (`examples/memory/file_hitl_example.py`)
|
||||
- 人間参加型フローを伴う SQLite インメモリセッション (`examples/memory/memory_session_hitl_example.py`)
|
||||
- 人間参加型フローを伴う OpenAI Conversations セッション (`examples/memory/openai_session_hitl_example.py`)
|
||||
- セッションをまたぐ HITL の承認/拒否シナリオ (`examples/memory/hitl_session_scenario.py`)
|
||||
|
||||
- **[model_providers](https://github.com/openai/openai-agents-python/tree/main/examples/model_providers):** カスタムプロバイダーやサードパーティー製アダプターなど、OpenAI 以外のモデルを SDK で使用する方法を紹介します。
|
||||
|
||||
- **[realtime](https://github.com/openai/openai-agents-python/tree/main/examples/realtime):** SDK を使用してリアルタイム体験を構築する方法を示すコード例です。以下が含まれます。
|
||||
|
||||
- 構造化されたテキストメッセージと画像メッセージを使用する Web アプリケーションパターン
|
||||
- コマンドラインでの音声ループと再生処理
|
||||
- WebSocket を介した Twilio Media Streams 統合
|
||||
- Realtime Calls API のアタッチフローを使用した Twilio SIP 統合
|
||||
|
||||
- **[reasoning_content](https://github.com/openai/openai-agents-python/tree/main/examples/reasoning_content):** 推論コンテンツの扱い方を示すコード例です。以下が含まれます。
|
||||
|
||||
- Runner API を使用した推論コンテンツ、ストリーミングおよび非ストリーミング (`examples/reasoning_content/runner_example.py`)
|
||||
- OpenRouter 経由の OSS モデルを使用した推論コンテンツ (`examples/reasoning_content/gpt_oss_stream.py`)
|
||||
- 基本的な推論コンテンツのコード例 (`examples/reasoning_content/main.py`)
|
||||
|
||||
- **[research_bot](https://github.com/openai/openai-agents-python/tree/main/examples/research_bot):** 複雑なマルチエージェント調査ワークフローを示す、シンプルなディープリサーチのクローンです。
|
||||
|
||||
- **[sandbox](https://github.com/openai/openai-agents-python/tree/main/examples/sandbox):** 分離されたワークスペースでエージェントを実行するためのコード例です。以下が含まれます。
|
||||
|
||||
- 基本的なサンドボックスエージェントのセットアップ (`examples/sandbox/basic.py`)
|
||||
- Unix ローカルおよび Docker サンドボックスのライフサイクルのコード例
|
||||
- サンドボックスを利用したハンドオフ (`examples/sandbox/handoffs.py`)
|
||||
- サンドボックスのメモリとスナップショットからの再開 (`examples/sandbox/memory.py`)
|
||||
- ツールとして公開されるサンドボックスエージェント (`examples/sandbox/sandbox_agents_as_tools.py`)
|
||||
|
||||
- **[tools](https://github.com/openai/openai-agents-python/tree/main/examples/tools):** OpenAI がホストするツールや実験的な Codex ツール機能の実装方法を学びます。以下が含まれます。
|
||||
|
||||
- Web 検索、およびフィルター付き Web 検索
|
||||
- ファイル検索
|
||||
- Code interpreter
|
||||
- ファイル編集と承認を伴うパッチ適用ツール (`examples/tools/apply_patch.py`)
|
||||
- 承認コールバックを伴うシェルツールの実行 (`examples/tools/shell.py`)
|
||||
- 中断ベースの人間参加型承認を伴うシェルツール (`examples/tools/shell_human_in_the_loop.py`)
|
||||
- インラインスキルを備えたホスト型コンテナシェル (`examples/tools/container_shell_inline_skill.py`)
|
||||
- スキル参照を備えたホスト型コンテナシェル (`examples/tools/container_shell_skill_reference.py`)
|
||||
- ローカルスキルを備えたローカルシェル (`examples/tools/local_shell_skill.py`)
|
||||
- 名前空間と遅延ツールを使用したツール検索 (`examples/tools/tool_search.py`)
|
||||
- コンピュータ操作
|
||||
- 画像生成
|
||||
- 実験的な Codex ツールワークフロー (`examples/tools/codex.py`)
|
||||
- 実験的な Codex の同一スレッドワークフロー (`examples/tools/codex_same_thread.py`)
|
||||
|
||||
- **[voice](https://github.com/openai/openai-agents-python/tree/main/examples/voice):** TTS および STT モデルを使用した音声エージェントのコード例をご覧ください。ストリーミング音声のコード例も含まれます。
|
||||
@@ -0,0 +1,234 @@
|
||||
---
|
||||
search:
|
||||
exclude: true
|
||||
---
|
||||
# ガードレール
|
||||
|
||||
ガードレールを使用すると、ユーザー入力とエージェント出力のチェックおよび検証を行えます。たとえば、顧客からのリクエストを支援するために非常に賢い(そのため低速で高コストな)モデルを使用するエージェントがあるとします。悪意のあるユーザーに、そのモデルへ数学の宿題を手伝わせたくはないはずです。そこで、高速 / 低コストなモデルでガードレールを実行できます。ガードレールが悪意のある使用を検出した場合、即座にエラーを送出して高価なモデルの実行を防ぎ、時間と費用を節約できます( **ブロッキングガードレールを使用する場合に限ります。並列ガードレールでは、ガードレールが完了する前に、高価なモデルがすでに実行を開始している可能性があります。詳細は下記の「実行モード」を参照してください** )。
|
||||
|
||||
ガードレールには 2 種類あります。
|
||||
|
||||
1. 入力ガードレールは、最初のユーザー入力に対して実行されます。
|
||||
2. 出力ガードレールは、最終的なエージェント出力に対して実行されます。
|
||||
|
||||
## ワークフローの境界
|
||||
|
||||
ガードレールはエージェントとツールにアタッチされますが、すべてがワークフロー内の同じ時点で実行されるわけではありません。
|
||||
|
||||
- **入力ガードレール** は、チェーン内の最初のエージェントに対してのみ実行されます。
|
||||
- **出力ガードレール** は、最終出力を生成するエージェントに対してのみ実行されます。
|
||||
- **ツールガードレール** は、すべてのカスタム関数ツール呼び出しで実行され、実行前に入力ガードレール、実行後に出力ガードレールが実行されます。
|
||||
|
||||
マネージャー、ハンドオフ、または委任先の専門家を含むワークフローで、各カスタム関数ツール呼び出しの前後にチェックが必要な場合は、エージェントレベルの入力 / 出力ガードレールだけに頼るのではなく、ツールガードレールを使用してください。
|
||||
|
||||
## 入力ガードレール
|
||||
|
||||
入力ガードレールは 3 ステップで実行されます。
|
||||
|
||||
1. まず、ガードレールはエージェントに渡されたものと同じ入力を受け取ります。
|
||||
2. 次に、ガードレール関数が実行され、 [`GuardrailFunctionOutput`][agents.guardrail.GuardrailFunctionOutput] が生成されます。これはその後 [`InputGuardrailResult`][agents.guardrail.InputGuardrailResult] にラップされます。
|
||||
3. 最後に、 [`.tripwire_triggered`][agents.guardrail.GuardrailFunctionOutput.tripwire_triggered] が true かどうかを確認します。true の場合、 [`InputGuardrailTripwireTriggered`][agents.exceptions.InputGuardrailTripwireTriggered] 例外が送出されるため、ユーザーに適切に応答したり、例外を処理したりできます。
|
||||
|
||||
!!! Note
|
||||
|
||||
入力ガードレールはユーザー入力に対して実行されることを想定しているため、エージェントのガードレールは、そのエージェントが *最初の* エージェントである場合にのみ実行されます。なぜ `guardrails` プロパティが `Runner.run` に渡されるのではなく、エージェント上にあるのか疑問に思うかもしれません。これは、ガードレールが実際のエージェントに関連していることが多いためです。エージェントごとに異なるガードレールを実行するため、コードを同じ場所に配置しておくと可読性の面で役立ちます。
|
||||
|
||||
### 実行モード
|
||||
|
||||
入力ガードレールは 2 つの実行モードをサポートします。
|
||||
|
||||
- **並列実行** (デフォルト、 `run_in_parallel=True` ): ガードレールはエージェントの実行と並行して実行されます。両方が同時に開始されるため、レイテンシが最も良くなります。ただし、ガードレールが失敗した場合、キャンセルされる前にエージェントがすでにトークンを消費し、ツールを実行している可能性があります。
|
||||
|
||||
- **ブロッキング実行** ( `run_in_parallel=False` ): ガードレールはエージェントが開始する *前に* 実行され、完了します。ガードレールのトリップワイヤーが発火した場合、エージェントは一切実行されないため、トークン消費とツール実行を防げます。これは、コスト最適化や、ツール呼び出しによる潜在的な副作用を避けたい場合に最適です。
|
||||
|
||||
## 出力ガードレール
|
||||
|
||||
出力ガードレールは 3 ステップで実行されます。
|
||||
|
||||
1. まず、ガードレールはエージェントによって生成された出力を受け取ります。
|
||||
2. 次に、ガードレール関数が実行され、 [`GuardrailFunctionOutput`][agents.guardrail.GuardrailFunctionOutput] が生成されます。これはその後 [`OutputGuardrailResult`][agents.guardrail.OutputGuardrailResult] にラップされます。
|
||||
3. 最後に、 [`.tripwire_triggered`][agents.guardrail.GuardrailFunctionOutput.tripwire_triggered] が true かどうかを確認します。true の場合、 [`OutputGuardrailTripwireTriggered`][agents.exceptions.OutputGuardrailTripwireTriggered] 例外が送出されるため、ユーザーに適切に応答したり、例外を処理したりできます。
|
||||
|
||||
!!! Note
|
||||
|
||||
出力ガードレールは最終的なエージェント出力に対して実行されることを想定しているため、エージェントのガードレールは、そのエージェントが *最後の* エージェントである場合にのみ実行されます。入力ガードレールと同様に、これはガードレールが実際のエージェントに関連していることが多いためです。エージェントごとに異なるガードレールを実行するため、コードを同じ場所に配置しておくと可読性の面で役立ちます。
|
||||
|
||||
出力ガードレールは必ずエージェントの完了後に実行されるため、 `run_in_parallel` パラメーターはサポートしません。
|
||||
|
||||
## ツールガードレール
|
||||
|
||||
ツールガードレールは **関数ツール** をラップし、実行の前後でツール呼び出しを検証またはブロックできるようにします。これはツール自体に設定され、そのツールが呼び出されるたびに実行されます。
|
||||
|
||||
- 入力ツールガードレールはツール実行前に実行され、呼び出しをスキップしたり、出力をメッセージに置き換えたり、トリップワイヤーを送出したりできます。
|
||||
- 出力ツールガードレールはツール実行後に実行され、出力を置き換えたり、トリップワイヤーを送出したりできます。
|
||||
- 関数ツールに承認が必要な場合、入力ツールガードレールは通常、承認後かつ実行直前に実行されます。保留中の承認割り込みが発行される前にこれらの入力チェックを実行したい場合は、 [`RunConfig.tool_execution`][agents.run.RunConfig.tool_execution] を [`ToolExecutionConfig(pre_approval_tool_input_guardrails=True)`][agents.run.ToolExecutionConfig] に設定してください。この承認前チェックに合格した呼び出しも、ツールが実行される前に、承認後に再度チェックされます。
|
||||
- ツールガードレールは、 [`function_tool`][agents.tool.function_tool] で作成された関数ツールにのみ適用されます。ハンドオフは通常の関数ツールパイプラインではなく、 SDK のハンドオフパイプラインを通じて実行されるため、ツールガードレールはハンドオフ呼び出し自体には適用されません。ホスト型ツール( `WebSearchTool` 、 `FileSearchTool` 、 `HostedMCPTool` 、 `CodeInterpreterTool` 、 `ImageGenerationTool` )と組み込み実行ツール( `ComputerTool` 、 `ShellTool` 、 `ApplyPatchTool` 、 `LocalShellTool` )もこのガードレールパイプラインを使用しません。また、 [`Agent.as_tool()`][agents.agent.Agent.as_tool] は現在、ツールガードレールのオプションを直接公開していません。
|
||||
|
||||
詳細は、下記のコードスニペットを参照してください。
|
||||
|
||||
## トリップワイヤー
|
||||
|
||||
入力または出力がガードレールに合格しなかった場合、ガードレールはトリップワイヤーでこれを知らせることができます。トリップワイヤーが発火したガードレールを検出した時点で、即座に `{Input,Output}GuardrailTripwireTriggered` 例外を送出し、エージェントの実行を停止します。
|
||||
|
||||
## ガードレールの実装
|
||||
|
||||
入力を受け取り、 [`GuardrailFunctionOutput`][agents.guardrail.GuardrailFunctionOutput] を返す関数を用意する必要があります。この例では、内部でエージェントを実行することでこれを行います。
|
||||
|
||||
```python
|
||||
from pydantic import BaseModel
|
||||
from agents import (
|
||||
Agent,
|
||||
GuardrailFunctionOutput,
|
||||
InputGuardrailTripwireTriggered,
|
||||
RunContextWrapper,
|
||||
Runner,
|
||||
TResponseInputItem,
|
||||
input_guardrail,
|
||||
)
|
||||
|
||||
class MathHomeworkOutput(BaseModel):
|
||||
is_math_homework: bool
|
||||
reasoning: str
|
||||
|
||||
guardrail_agent = Agent( # (1)!
|
||||
name="Guardrail check",
|
||||
instructions="Check if the user is asking you to do their math homework.",
|
||||
output_type=MathHomeworkOutput,
|
||||
)
|
||||
|
||||
|
||||
@input_guardrail
|
||||
async def math_guardrail( # (2)!
|
||||
ctx: RunContextWrapper[None], agent: Agent, input: str | list[TResponseInputItem]
|
||||
) -> GuardrailFunctionOutput:
|
||||
result = await Runner.run(guardrail_agent, input, context=ctx.context)
|
||||
|
||||
return GuardrailFunctionOutput(
|
||||
output_info=result.final_output, # (3)!
|
||||
tripwire_triggered=result.final_output.is_math_homework,
|
||||
)
|
||||
|
||||
|
||||
agent = Agent( # (4)!
|
||||
name="Customer support agent",
|
||||
instructions="You are a customer support agent. You help customers with their questions.",
|
||||
input_guardrails=[math_guardrail],
|
||||
)
|
||||
|
||||
async def main():
|
||||
# This should trip the guardrail
|
||||
try:
|
||||
await Runner.run(agent, "Hello, can you help me solve for x: 2x + 3 = 11?")
|
||||
print("Guardrail didn't trip - this is unexpected")
|
||||
|
||||
except InputGuardrailTripwireTriggered:
|
||||
print("Math homework guardrail tripped")
|
||||
```
|
||||
|
||||
1. このエージェントをガードレール関数で使用します。
|
||||
2. これは、エージェントの入力 / コンテキストを受け取り、実行結果を返すガードレール関数です。
|
||||
3. ガードレールの実行結果に追加情報を含めることができます。
|
||||
4. これは、ワークフローを定義する実際のエージェントです。
|
||||
|
||||
出力ガードレールも同様です。
|
||||
|
||||
```python
|
||||
from pydantic import BaseModel
|
||||
from agents import (
|
||||
Agent,
|
||||
GuardrailFunctionOutput,
|
||||
OutputGuardrailTripwireTriggered,
|
||||
RunContextWrapper,
|
||||
Runner,
|
||||
output_guardrail,
|
||||
)
|
||||
class MessageOutput(BaseModel): # (1)!
|
||||
response: str
|
||||
|
||||
class MathOutput(BaseModel): # (2)!
|
||||
reasoning: str
|
||||
is_math: bool
|
||||
|
||||
guardrail_agent = Agent(
|
||||
name="Guardrail check",
|
||||
instructions="Check if the output includes any math.",
|
||||
output_type=MathOutput,
|
||||
)
|
||||
|
||||
@output_guardrail
|
||||
async def math_guardrail( # (3)!
|
||||
ctx: RunContextWrapper, agent: Agent, output: MessageOutput
|
||||
) -> GuardrailFunctionOutput:
|
||||
result = await Runner.run(guardrail_agent, output.response, context=ctx.context)
|
||||
|
||||
return GuardrailFunctionOutput(
|
||||
output_info=result.final_output,
|
||||
tripwire_triggered=result.final_output.is_math,
|
||||
)
|
||||
|
||||
agent = Agent( # (4)!
|
||||
name="Customer support agent",
|
||||
instructions="You are a customer support agent. You help customers with their questions.",
|
||||
output_guardrails=[math_guardrail],
|
||||
output_type=MessageOutput,
|
||||
)
|
||||
|
||||
async def main():
|
||||
# This should trip the guardrail
|
||||
try:
|
||||
await Runner.run(agent, "Hello, can you help me solve for x: 2x + 3 = 11?")
|
||||
print("Guardrail didn't trip - this is unexpected")
|
||||
|
||||
except OutputGuardrailTripwireTriggered:
|
||||
print("Math output guardrail tripped")
|
||||
```
|
||||
|
||||
1. これは、実際のエージェントの出力型です。
|
||||
2. これは、ガードレールの出力型です。
|
||||
3. これは、エージェントの出力を受け取り、実行結果を返すガードレール関数です。
|
||||
4. これは、ワークフローを定義する実際のエージェントです。
|
||||
|
||||
最後に、ツールガードレールのコード例を示します。
|
||||
|
||||
```python
|
||||
import json
|
||||
from agents import (
|
||||
Agent,
|
||||
Runner,
|
||||
ToolGuardrailFunctionOutput,
|
||||
function_tool,
|
||||
tool_input_guardrail,
|
||||
tool_output_guardrail,
|
||||
)
|
||||
|
||||
@tool_input_guardrail
|
||||
def block_secrets(data):
|
||||
args = json.loads(data.context.tool_arguments or "{}")
|
||||
if "sk-" in json.dumps(args):
|
||||
return ToolGuardrailFunctionOutput.reject_content(
|
||||
"Remove secrets before calling this tool."
|
||||
)
|
||||
return ToolGuardrailFunctionOutput.allow()
|
||||
|
||||
|
||||
@tool_output_guardrail
|
||||
def redact_output(data):
|
||||
text = str(data.output or "")
|
||||
if "sk-" in text:
|
||||
return ToolGuardrailFunctionOutput.reject_content("Output contained sensitive data.")
|
||||
return ToolGuardrailFunctionOutput.allow()
|
||||
|
||||
|
||||
@function_tool(
|
||||
tool_input_guardrails=[block_secrets],
|
||||
tool_output_guardrails=[redact_output],
|
||||
)
|
||||
def classify_text(text: str) -> str:
|
||||
"""Classify text for internal routing."""
|
||||
return f"length:{len(text)}"
|
||||
|
||||
|
||||
agent = Agent(name="Classifier", tools=[classify_text])
|
||||
result = Runner.run_sync(agent, "hello world")
|
||||
print(result.final_output)
|
||||
```
|
||||
@@ -0,0 +1,156 @@
|
||||
---
|
||||
search:
|
||||
exclude: true
|
||||
---
|
||||
# ハンドオフ
|
||||
|
||||
ハンドオフにより、エージェントはタスクを別のエージェントに委任できます。これは、異なるエージェントがそれぞれ別の領域を専門とするシナリオで特に役立ちます。たとえば、カスタマーサポートアプリには、注文ステータス、返金、 FAQ などのタスクをそれぞれ専門に扱うエージェントがあるかもしれません。
|
||||
|
||||
ハンドオフは LLM に対してツールとして表現されます。そのため、 `Refund Agent` という名前のエージェントへのハンドオフがある場合、そのツールは `transfer_to_refund_agent` と呼ばれます。
|
||||
|
||||
## ハンドオフの作成
|
||||
|
||||
すべてのエージェントには [`handoffs`][agents.agent.Agent.handoffs] パラメーターがあり、 `Agent` を直接受け取ることも、ハンドオフをカスタマイズする `Handoff` オブジェクトを受け取ることもできます。
|
||||
|
||||
通常の `Agent` インスタンスを渡す場合、その [`handoff_description`][agents.agent.Agent.handoff_description] (設定されている場合)がデフォルトのツール説明に追加されます。完全な `handoff()` オブジェクトを書かずに、そのハンドオフをモデルが選ぶべきタイミングを示唆するために使用してください。
|
||||
|
||||
Agents SDK が提供する [`handoff()`][agents.handoffs.handoff] 関数を使用してハンドオフを作成できます。この関数では、必要に応じた上書きや入力フィルターとともに、引き渡し先のエージェントを指定できます。
|
||||
|
||||
### 基本的な使用法
|
||||
|
||||
シンプルなハンドオフを作成する方法は次のとおりです。
|
||||
|
||||
```python
|
||||
from agents import Agent, handoff
|
||||
|
||||
billing_agent = Agent(name="Billing agent")
|
||||
refund_agent = Agent(name="Refund agent")
|
||||
|
||||
# (1)!
|
||||
triage_agent = Agent(name="Triage agent", handoffs=[billing_agent, handoff(refund_agent)])
|
||||
```
|
||||
|
||||
1. エージェントを直接使用することも( `billing_agent` のように)、 `handoff()` 関数を使用することもできます。
|
||||
|
||||
### `handoff()` 関数によるハンドオフのカスタマイズ
|
||||
|
||||
[`handoff()`][agents.handoffs.handoff] 関数を使用すると、さまざまな項目をカスタマイズできます。
|
||||
|
||||
- `agent`: 処理を引き渡す先のエージェントです。
|
||||
- `tool_name_override`: デフォルトでは `Handoff.default_tool_name()` 関数が使用され、 `transfer_to_<agent_name>` に解決されます。これは上書きできます。
|
||||
- `tool_description_override`: `Handoff.default_tool_description()` から得られるデフォルトのツール説明を上書きします。
|
||||
- `on_handoff`: ハンドオフが呼び出されたときに実行されるコールバック関数です。ハンドオフが呼び出されることが分かった時点ですぐにデータ取得を開始する、といった用途に便利です。この関数はエージェントコンテキストを受け取り、任意で LLM が生成した入力も受け取れます。入力データは `input_type` パラメーターによって制御されます。
|
||||
- `input_type`: ハンドオフツール呼び出し引数のスキーマです。設定されている場合、解析されたペイロードが `on_handoff` に渡されます。
|
||||
- `input_filter`: これにより、次のエージェントが受け取る入力をフィルタリングできます。詳細は以下を参照してください。
|
||||
- `is_enabled`: ハンドオフが有効かどうかです。これはブール値、またはブール値を返す関数にでき、実行時にハンドオフを動的に有効化または無効化できます。
|
||||
- `nest_handoff_history`: RunConfig レベルの `nest_handoff_history` 設定に対する、呼び出しごとの任意の上書きです。 `None` の場合は、アクティブな実行設定で定義された値が代わりに使用されます。
|
||||
|
||||
[`handoff()`][agents.handoffs.handoff] ヘルパーは、渡された特定の `agent` に常に制御を移します。複数の宛先候補がある場合は、宛先ごとに 1 つのハンドオフを登録し、モデルにその中から選ばせてください。独自のハンドオフコードが呼び出し時にどのエージェントを返すかを決定する必要がある場合にのみ、カスタム [`Handoff`][agents.handoffs.Handoff] を使用してください。
|
||||
|
||||
```python
|
||||
from agents import Agent, handoff, RunContextWrapper
|
||||
|
||||
def on_handoff(ctx: RunContextWrapper[None]):
|
||||
print("Handoff called")
|
||||
|
||||
agent = Agent(name="My agent")
|
||||
|
||||
handoff_obj = handoff(
|
||||
agent=agent,
|
||||
on_handoff=on_handoff,
|
||||
tool_name_override="custom_handoff_tool",
|
||||
tool_description_override="Custom description",
|
||||
)
|
||||
```
|
||||
|
||||
## ハンドオフ入力
|
||||
|
||||
状況によっては、 LLM がハンドオフを呼び出すときに何らかのデータを提供してほしい場合があります。たとえば、「エスカレーションエージェント」へのハンドオフを想像してみてください。ログに記録できるように、モデルに理由を提供してほしい場合があります。
|
||||
|
||||
```python
|
||||
from pydantic import BaseModel
|
||||
|
||||
from agents import Agent, handoff, RunContextWrapper
|
||||
|
||||
class EscalationData(BaseModel):
|
||||
reason: str
|
||||
|
||||
async def on_handoff(ctx: RunContextWrapper[None], input_data: EscalationData):
|
||||
print(f"Escalation agent called with reason: {input_data.reason}")
|
||||
|
||||
agent = Agent(name="Escalation agent")
|
||||
|
||||
handoff_obj = handoff(
|
||||
agent=agent,
|
||||
on_handoff=on_handoff,
|
||||
input_type=EscalationData,
|
||||
)
|
||||
```
|
||||
|
||||
`input_type` は、ハンドオフツール呼び出し自体の引数を表します。 SDK はそのスキーマをハンドオフツールの `parameters` としてモデルに公開し、返された JSON をローカルで検証して、解析済みの値を `on_handoff` に渡します。
|
||||
|
||||
これは次のエージェントのメイン入力を置き換えるものではなく、別の宛先を選択するものでもありません。 [`handoff()`][agents.handoffs.handoff] ヘルパーは引き続き、ラップした特定のエージェントへ転送し、受け取り側のエージェントは [`input_filter`][agents.handoffs.Handoff.input_filter] またはネストされたハンドオフ履歴設定で変更しない限り、引き続き会話履歴を参照します。
|
||||
|
||||
`input_type` は [`RunContextWrapper.context`][agents.run_context.RunContextWrapper.context] とも別のものです。ローカルにすでにあるアプリケーション状態や依存関係ではなく、ハンドオフ時にモデルが決定するメタデータには `input_type` を使用してください。
|
||||
|
||||
### `input_type` の使用タイミング
|
||||
|
||||
ハンドオフに `reason` 、 `language` 、 `priority` 、 `summary` など、モデルが生成する小さなメタデータが必要な場合に `input_type` を使用してください。たとえば、トリアージエージェントは `{ "reason": "duplicate_charge", "priority": "high" }` とともに返金エージェントへハンドオフでき、返金エージェントが引き継ぐ前に `on_handoff` でそのメタデータをログに記録したり永続化したりできます。
|
||||
|
||||
目的が異なる場合は、別の仕組みを選んでください。
|
||||
|
||||
- 既存のアプリケーション状態と依存関係は [`RunContextWrapper.context`][agents.run_context.RunContextWrapper.context] に置いてください。[コンテキストガイド](context.md)を参照してください。
|
||||
- 受け取り側のエージェントが参照する履歴を変更したい場合は、 [`input_filter`][agents.handoffs.Handoff.input_filter] 、 [`RunConfig.nest_handoff_history`][agents.run.RunConfig.nest_handoff_history] 、または [`RunConfig.handoff_history_mapper`][agents.run.RunConfig.handoff_history_mapper] を使用してください。
|
||||
- 複数の専門エージェント候補がある場合は、宛先ごとに 1 つのハンドオフを登録してください。 `input_type` は選択されたハンドオフにメタデータを追加できますが、宛先間の振り分けは行いません。
|
||||
- 会話を引き渡さずに、ネストされた専門エージェントに構造化入力を渡したい場合は、 [`Agent.as_tool(parameters=...)`][agents.agent.Agent.as_tool] を優先してください。[ツール](tools.md#structured-input-for-tool-agents)を参照してください。
|
||||
|
||||
## 入力フィルター
|
||||
|
||||
ハンドオフが発生すると、新しいエージェントが会話を引き継ぎ、以前の会話履歴全体を参照できるようになります。これを変更したい場合は、 [`input_filter`][agents.handoffs.Handoff.input_filter] を設定できます。入力フィルターは、 [`HandoffInputData`][agents.handoffs.HandoffInputData] を通じて既存の入力を受け取り、新しい `HandoffInputData` を返す必要がある関数です。
|
||||
|
||||
[`HandoffInputData`][agents.handoffs.HandoffInputData] には次が含まれます。
|
||||
|
||||
- `input_history`: `Runner.run(...)` が開始する前の入力履歴です。
|
||||
- `pre_handoff_items`: ハンドオフが呼び出されたエージェントターンより前に生成されたアイテムです。
|
||||
- `new_items`: ハンドオフ呼び出しとハンドオフ出力アイテムを含む、現在のターン中に生成されたアイテムです。
|
||||
- `input_items`: セッション履歴用に `new_items` をそのまま保ちながらモデル入力をフィルタリングできるよう、 `new_items` の代わりに次のエージェントへ転送する任意のアイテムです。
|
||||
- `run_context`: ハンドオフが呼び出された時点でアクティブな [`RunContextWrapper`][agents.run_context.RunContextWrapper] です。
|
||||
|
||||
ネストされたハンドオフはオプトインのベータとして利用でき、安定化が進むまではデフォルトで無効です。 [`RunConfig.nest_handoff_history`][agents.run.RunConfig.nest_handoff_history] を有効にすると、ランナーは以前の会話記録を 1 つの assistant 要約メッセージにまとめ、それを `<CONVERSATION HISTORY>` ブロックで包みます。このブロックには、同じ実行中に複数のハンドオフが発生した場合に新しいターンが追加され続けます。 [`RunConfig.handoff_history_mapper`][agents.run.RunConfig.handoff_history_mapper] を通じて独自のマッピング関数を提供し、完全な `input_filter` を書くことなく、生成されたメッセージを置き換えることができます。このオプトインは、ハンドオフと実行のどちらも明示的な `input_filter` を指定していない場合にのみ適用されます。そのため、ペイロードをすでにカスタマイズしている既存のコード(このリポジトリ内のコード例を含む)は、変更なしで現在の動作を維持します。単一のハンドオフに対してネスト動作を上書きするには、 [`handoff(...)`][agents.handoffs.handoff] に `nest_handoff_history=True` または `False` を渡します。これにより [`Handoff.nest_handoff_history`][agents.handoffs.Handoff.nest_handoff_history] が設定されます。生成された要約のラッパーテキストだけを変更したい場合は、エージェントを実行する前に [`set_conversation_history_wrappers`][agents.handoffs.set_conversation_history_wrappers] を呼び出してください(必要に応じて [`reset_conversation_history_wrappers`][agents.handoffs.reset_conversation_history_wrappers] も呼び出せます)。
|
||||
|
||||
ハンドオフとアクティブな [`RunConfig.handoff_input_filter`][agents.run.RunConfig.handoff_input_filter] の両方がフィルターを定義している場合、その特定のハンドオフではハンドオフごとの [`input_filter`][agents.handoffs.Handoff.input_filter] が優先されます。
|
||||
|
||||
!!! note
|
||||
|
||||
ハンドオフは単一の実行内にとどまります。入力ガードレールは引き続きチェーン内の最初のエージェントにのみ適用され、出力ガードレールは最終出力を生成するエージェントにのみ適用されます。ワークフロー内の各カスタム関数ツール呼び出しの周囲でチェックが必要な場合は、ツールガードレールを使用してください。
|
||||
|
||||
一般的なパターン(たとえば、履歴からすべてのツール呼び出しを削除するなど)がいくつかあり、 [`agents.extensions.handoff_filters`][] に実装されています。
|
||||
|
||||
```python
|
||||
from agents import Agent, handoff
|
||||
from agents.extensions import handoff_filters
|
||||
|
||||
agent = Agent(name="FAQ agent")
|
||||
|
||||
handoff_obj = handoff(
|
||||
agent=agent,
|
||||
input_filter=handoff_filters.remove_all_tools, # (1)!
|
||||
)
|
||||
```
|
||||
|
||||
1. これにより、 `FAQ agent` が呼び出されたときに、履歴からすべてのツールが自動的に削除されます。
|
||||
|
||||
## 推奨プロンプト
|
||||
|
||||
LLM がハンドオフを適切に理解できるように、エージェントにハンドオフに関する情報を含めることを推奨します。推奨されるプレフィックスを [`agents.extensions.handoff_prompt.RECOMMENDED_PROMPT_PREFIX`][] に用意しています。または、 [`agents.extensions.handoff_prompt.prompt_with_handoff_instructions`][] を呼び出して、推奨データをプロンプトに自動的に追加できます。
|
||||
|
||||
```python
|
||||
from agents import Agent
|
||||
from agents.extensions.handoff_prompt import RECOMMENDED_PROMPT_PREFIX
|
||||
|
||||
billing_agent = Agent(
|
||||
name="Billing agent",
|
||||
instructions=f"""{RECOMMENDED_PROMPT_PREFIX}
|
||||
<Fill in the rest of your prompt here>.""",
|
||||
)
|
||||
```
|
||||
@@ -0,0 +1,201 @@
|
||||
---
|
||||
search:
|
||||
exclude: true
|
||||
---
|
||||
# ヒューマンインザループ
|
||||
|
||||
ヒューマンインザループ (HITL) フローを使用すると、人が慎重な扱いが必要なツール呼び出しを承認または拒否するまで、エージェントの実行を一時停止できます。ツールは承認が必要なタイミングを宣言し、実行結果は保留中の承認を中断として提示し、`RunState` によって判定後に実行をシリアライズして再開できます。
|
||||
|
||||
その承認の提示先は実行全体であり、現在のトップレベルのエージェントに限定されません。同じパターンは、ツールが現在のエージェントに属する場合、ハンドオフを通じて到達したエージェントに属する場合、またはネストされた [`Agent.as_tool()`][agents.agent.Agent.as_tool] 実行に属する場合にも適用されます。ネストされた `Agent.as_tool()` の場合でも、中断は外側の実行に提示されるため、外側の `RunState` で承認または拒否し、元のトップレベルの実行を再開します。
|
||||
|
||||
`Agent.as_tool()` では、承認が 2 つの異なるレイヤーで発生する可能性があります。エージェントツール自体が `Agent.as_tool(..., needs_approval=...)` によって承認を要求でき、ネストされたエージェント内のツールも、ネストされた実行が開始した後に独自の承認を要求できます。どちらも同じ外側の実行の中断フローを通じて処理されます。
|
||||
|
||||
このページでは、`interruptions` を介した手動承認フローに焦点を当てます。アプリがコード内で判定できる場合、一部のツールタイプはプログラムによる承認コールバックにも対応しているため、実行を一時停止せずに続行できます。
|
||||
|
||||
## 承認が必要なツールの指定
|
||||
|
||||
常に承認を要求するには `needs_approval` を `True` に設定するか、呼び出しごとに判定する async 関数を指定します。この呼び出し可能オブジェクトは、実行コンテキスト、解析済みのツールパラメーター、ツール呼び出し ID を受け取ります。
|
||||
|
||||
```python
|
||||
from agents import Agent, Runner, function_tool
|
||||
|
||||
|
||||
@function_tool(needs_approval=True)
|
||||
async def cancel_order(order_id: int) -> str:
|
||||
return f"Cancelled order {order_id}"
|
||||
|
||||
|
||||
async def requires_review(_ctx, params, _call_id) -> bool:
|
||||
return "refund" in params.get("subject", "").lower()
|
||||
|
||||
|
||||
@function_tool(needs_approval=requires_review)
|
||||
async def send_email(subject: str, body: str) -> str:
|
||||
return f"Sent '{subject}'"
|
||||
|
||||
|
||||
agent = Agent(
|
||||
name="Support agent",
|
||||
instructions="Handle tickets and ask for approval when needed.",
|
||||
tools=[cancel_order, send_email],
|
||||
)
|
||||
```
|
||||
|
||||
`needs_approval` は、[`function_tool`][agents.tool.function_tool]、[`Agent.as_tool`][agents.agent.Agent.as_tool]、[`ShellTool`][agents.tool.ShellTool]、[`ApplyPatchTool`][agents.tool.ApplyPatchTool] で利用できます。ローカル MCP サーバーも、[`MCPServerStdio`][agents.mcp.server.MCPServerStdio]、[`MCPServerSse`][agents.mcp.server.MCPServerSse]、[`MCPServerStreamableHttp`][agents.mcp.server.MCPServerStreamableHttp] の `require_approval` を通じて承認に対応しています。ホスト型 MCP サーバーは、`tool_config={"require_approval": "always"}` と任意の `on_approval_request` コールバックを設定した [`HostedMCPTool`][agents.tool.HostedMCPTool] によって承認に対応します。Shell と apply_patch ツールは、中断を提示せずに自動承認または自動拒否したい場合に `on_approval` コールバックを受け付けます。
|
||||
|
||||
## 承認フローの仕組み
|
||||
|
||||
1. モデルがツール呼び出しを出力すると、ランナーはその承認ルール (`needs_approval`、`require_approval`、またはホスト型 MCP の同等機能) を評価します。
|
||||
2. そのツール呼び出しの承認判定がすでに [`RunContextWrapper`][agents.run_context.RunContextWrapper] に保存されている場合、ランナーは確認を求めずに処理を続行します。呼び出しごとの承認は特定の呼び出し ID にスコープされます。そのツールに対する今後の呼び出しに、実行の残りの間同じ判定を保持するには、`always_approve=True` または `always_reject=True` を渡します。
|
||||
3. それ以外の場合、実行は一時停止し、`RunResult.interruptions` (または `RunResultStreaming.interruptions`) に、`agent.name`、`tool_name`、`arguments` などの詳細を含む [`ToolApprovalItem`][agents.items.ToolApprovalItem] エントリが入ります。これには、ハンドオフ後やネストされた `Agent.as_tool()` 実行内で発生した承認も含まれます。
|
||||
4. 実行結果を `result.to_state()` で `RunState` に変換し、`state.approve(...)` または `state.reject(...)` を呼び出してから、`Runner.run(agent, state)` または `Runner.run_streamed(agent, state)` で再開します。ここで `agent` は、その実行における元のトップレベルのエージェントです。
|
||||
5. 再開された実行は中断した場所から続行し、新しい承認が必要になった場合はこのフローに再び入ります。
|
||||
|
||||
`always_approve=True` または `always_reject=True` で作成された固定判定は実行状態に保存されるため、後で同じ一時停止中の実行を再開するときに `state.to_string()` / `RunState.from_string(...)` および `state.to_json()` / `RunState.from_json(...)` を使っても保持されます。
|
||||
|
||||
すべての保留中承認を同じ 1 回の処理で解決する必要はありません。`interruptions` には、通常の関数ツール、ホスト型 MCP の承認、ネストされた `Agent.as_tool()` の承認が混在する場合があります。一部の項目だけを承認または拒否した後に再実行すると、解決済みの呼び出しは続行でき、未解決のものは `interruptions` に残って実行を再び一時停止します。
|
||||
|
||||
## カスタム拒否メッセージ
|
||||
|
||||
既定では、拒否されたツール呼び出しは SDK 標準の拒否テキストを実行内に返します。このメッセージは 2 つのレイヤーでカスタマイズできます。
|
||||
|
||||
- 実行全体のフォールバック: 実行全体で承認拒否に対するモデルに見える既定メッセージを制御するには、[`RunConfig.tool_error_formatter`][agents.run.RunConfig.tool_error_formatter] を設定します。
|
||||
- 呼び出しごとのオーバーライド: 特定の拒否されたツール呼び出しだけに異なるメッセージを提示したい場合は、`state.reject(...)` に `rejection_message=...` を渡します。
|
||||
|
||||
両方が指定されている場合、呼び出しごとの `rejection_message` が実行全体のフォーマッターより優先されます。
|
||||
|
||||
```python
|
||||
from agents import RunConfig, ToolErrorFormatterArgs
|
||||
|
||||
|
||||
def format_rejection(args: ToolErrorFormatterArgs[None]) -> str | None:
|
||||
if args.kind != "approval_rejected":
|
||||
return None
|
||||
return "Publish action was canceled because approval was rejected."
|
||||
|
||||
|
||||
run_config = RunConfig(tool_error_formatter=format_rejection)
|
||||
|
||||
# Later, while resolving a specific interruption:
|
||||
state.reject(
|
||||
interruption,
|
||||
rejection_message="Publish action was canceled because the reviewer denied approval.",
|
||||
)
|
||||
```
|
||||
|
||||
両方のレイヤーをまとめて示す完全なコード例については、[`examples/agent_patterns/human_in_the_loop_custom_rejection.py`](https://github.com/openai/openai-agents-python/tree/main/examples/agent_patterns/human_in_the_loop_custom_rejection.py) を参照してください。
|
||||
|
||||
## 自動承認判定
|
||||
|
||||
手動の `interruptions` は最も汎用的なパターンですが、唯一の方法ではありません。
|
||||
|
||||
- ローカルの [`ShellTool`][agents.tool.ShellTool] と [`ApplyPatchTool`][agents.tool.ApplyPatchTool] は、`on_approval` を使用してコード内で即座に承認または拒否できます。
|
||||
- [`HostedMCPTool`][agents.tool.HostedMCPTool] は、`tool_config={"require_approval": "always"}` と `on_approval_request` を組み合わせて、同じ種類のプログラムによる判定を行えます。
|
||||
- 通常の [`function_tool`][agents.tool.function_tool] ツールと [`Agent.as_tool()`][agents.agent.Agent.as_tool] は、このページの手動中断フローを使用します。
|
||||
|
||||
これらのコールバックが判定を返すと、人間の応答を待って一時停止することなく実行が続行されます。Realtime および音声セッション API については、[Realtime ガイド](realtime/guide.md) の承認フローを参照してください。
|
||||
|
||||
## ストリーミングとセッション
|
||||
|
||||
同じ中断フローはストリーミング実行でも機能します。ストリーミング実行が一時停止した後は、イテレーターが終了するまで [`RunResultStreaming.stream_events()`][agents.result.RunResultStreaming.stream_events] を消費し続け、[`RunResultStreaming.interruptions`][agents.result.RunResultStreaming.interruptions] を確認して解決し、再開後の出力もストリーミングし続けたい場合は [`Runner.run_streamed(...)`][agents.run.Runner.run_streamed] で再開します。このパターンのストリーミング版については、[ストリーミング](streaming.md) を参照してください。
|
||||
|
||||
セッションも使用している場合は、`RunState` から再開するときに同じセッションインスタンスを渡し続けるか、同じバッキングストアを指す別のセッションオブジェクトを渡します。これにより、再開されたターンは同じ保存済み会話履歴に追加されます。セッションのライフサイクル詳細については、[セッション](sessions/index.md) を参照してください。
|
||||
|
||||
## 例: 一時停止・承認・再開
|
||||
|
||||
以下のスニペットは JavaScript の HITL ガイドと同じ流れです。ツールに承認が必要な場合に一時停止し、状態をディスクに永続化して再読み込みし、判定を収集した後に再開します。
|
||||
|
||||
```python
|
||||
import asyncio
|
||||
import json
|
||||
from pathlib import Path
|
||||
|
||||
from agents import Agent, Runner, RunState, function_tool
|
||||
|
||||
|
||||
async def needs_oakland_approval(_ctx, params, _call_id) -> bool:
|
||||
return "Oakland" in params.get("city", "")
|
||||
|
||||
|
||||
@function_tool(needs_approval=needs_oakland_approval)
|
||||
async def get_temperature(city: str) -> str:
|
||||
return f"The temperature in {city} is 20° Celsius"
|
||||
|
||||
|
||||
agent = Agent(
|
||||
name="Weather assistant",
|
||||
instructions="Answer weather questions with the provided tools.",
|
||||
tools=[get_temperature],
|
||||
)
|
||||
|
||||
STATE_PATH = Path(".cache/hitl_state.json")
|
||||
|
||||
|
||||
def prompt_approval(tool_name: str, arguments: str | None) -> bool:
|
||||
answer = input(f"Approve {tool_name} with {arguments}? [y/N]: ").strip().lower()
|
||||
return answer in {"y", "yes"}
|
||||
|
||||
|
||||
async def main() -> None:
|
||||
result = await Runner.run(agent, "What is the temperature in Oakland?")
|
||||
|
||||
while result.interruptions:
|
||||
# Persist the paused state.
|
||||
state = result.to_state()
|
||||
STATE_PATH.parent.mkdir(parents=True, exist_ok=True)
|
||||
STATE_PATH.write_text(state.to_string())
|
||||
|
||||
# Load the state later (could be a different process).
|
||||
stored = json.loads(STATE_PATH.read_text())
|
||||
state = await RunState.from_json(agent, stored)
|
||||
|
||||
for interruption in result.interruptions:
|
||||
approved = await asyncio.get_running_loop().run_in_executor(
|
||||
None, prompt_approval, interruption.name or "unknown_tool", interruption.arguments
|
||||
)
|
||||
if approved:
|
||||
state.approve(interruption, always_approve=False)
|
||||
else:
|
||||
state.reject(interruption)
|
||||
|
||||
result = await Runner.run(agent, state)
|
||||
|
||||
print(result.final_output)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
asyncio.run(main())
|
||||
```
|
||||
|
||||
この例では、`prompt_approval` は `input()` を使用し、`run_in_executor(...)` で実行されるため同期的です。承認の取得元がすでに非同期である場合 (たとえば、HTTP リクエストや非同期データベースクエリ)、代わりに `async def` 関数を使用して直接 `await` できます。
|
||||
|
||||
承認を待つ間に出力をストリーミングするには、`Runner.run_streamed` を呼び出し、完了するまで `result.stream_events()` を消費してから、上記と同じ `result.to_state()` と再開手順に従います。
|
||||
|
||||
## リポジトリのパターンとコード例
|
||||
|
||||
- **ストリーミング承認**: `examples/agent_patterns/human_in_the_loop_stream.py` は、`stream_events()` を最後まで読み出し、その後 `Runner.run_streamed(agent, state)` で再開する前に保留中のツール呼び出しを承認する方法を示します。
|
||||
- **カスタム拒否テキスト**: `examples/agent_patterns/human_in_the_loop_custom_rejection.py` は、承認が拒否された場合に、実行レベルの `tool_error_formatter` と呼び出しごとの `rejection_message` オーバーライドを組み合わせる方法を示します。
|
||||
- **ツールとしてのエージェントの承認**: `Agent.as_tool(..., needs_approval=...)` は、委譲されたエージェントタスクにレビューが必要な場合に同じ中断フローを適用します。ネストされた中断も外側の実行に提示されるため、ネストされたエージェントではなく元のトップレベルのエージェントを再開してください。
|
||||
- **ローカル shell と apply_patch ツール**: `ShellTool` と `ApplyPatchTool` も `needs_approval` に対応しています。将来の呼び出しに備えて判定をキャッシュするには、`state.approve(interruption, always_approve=True)` または `state.reject(..., always_reject=True)` を使用します。自動判定には `on_approval` を指定します (`examples/tools/shell.py` を参照)。手動判定には中断を処理します (`examples/tools/shell_human_in_the_loop.py` を参照)。ホスト型 shell 環境は `needs_approval` または `on_approval` に対応していません。[ツールガイド](tools.md) を参照してください。
|
||||
- **ローカル MCP サーバー**: MCP ツール呼び出しを制御するには、`MCPServerStdio` / `MCPServerSse` / `MCPServerStreamableHttp` の `require_approval` を使用します (`examples/mcp/get_all_mcp_tools_example/main.py` と `examples/mcp/tool_filter_example/main.py` を参照)。
|
||||
- **ホスト型 MCP サーバー**: HITL を強制するには、`HostedMCPTool` で `require_approval` を `"always"` に設定し、必要に応じて自動承認または拒否のために `on_approval_request` を指定します (`examples/hosted_mcp/human_in_the_loop.py` と `examples/hosted_mcp/on_approval.py` を参照)。信頼済みサーバーには `"never"` を使用します (`examples/hosted_mcp/simple.py`)。
|
||||
- **セッションとメモリ**: セッションを `Runner.run` に渡すと、承認と会話履歴が複数ターンにわたって保持されます。SQLite と OpenAI Conversations のセッション版は、`examples/memory/memory_session_hitl_example.py` と `examples/memory/openai_session_hitl_example.py` にあります。
|
||||
- **Realtime エージェント**: Realtime デモでは、`RealtimeSession` の `approve_tool_call` / `reject_tool_call` を介してツール呼び出しを承認または拒否する WebSocket メッセージを公開しています (サーバー側ハンドラーについては `examples/realtime/app/server.py`、API サーフェスについては [Realtime ガイド](realtime/guide.md#tool-approvals) を参照)。
|
||||
|
||||
## 長時間にわたる承認
|
||||
|
||||
`RunState` は耐久性を持つように設計されています。`state.to_json()` または `state.to_string()` を使用して保留中の作業をデータベースまたはキューに保存し、後で `RunState.from_json(...)` または `RunState.from_string(...)` で再作成します。
|
||||
|
||||
便利なシリアライズオプション:
|
||||
|
||||
- `context_serializer`: 非マッピングのコンテキストオブジェクトのシリアライズ方法をカスタマイズします。
|
||||
- `context_deserializer`: `RunState.from_json(...)` または `RunState.from_string(...)` で状態を読み込むときに、非マッピングのコンテキストオブジェクトを再構築します。
|
||||
- `strict_context=True`: コンテキストがすでにマッピングであるか、適切なシリアライザー / デシリアライザーを指定している場合を除き、シリアライズまたはデシリアライズを失敗させます。
|
||||
- `context_override`: 状態を読み込むときに、シリアライズされたコンテキストを置き換えます。これは、元のコンテキストオブジェクトを復元したくない場合に便利ですが、すでにシリアライズ済みのペイロードからそのコンテキストを削除するわけではありません。
|
||||
- `include_tracing_api_key=True`: 再開された作業で同じ認証情報を使ってトレースのエクスポートを継続する必要がある場合、シリアライズされたトレースペイロードにトレーシング API キーを含めます。
|
||||
|
||||
シリアライズされた実行状態には、アプリのコンテキストに加えて、承認、使用量、シリアライズ済みの `tool_input`、ネストされた agent-as-tool の再開情報、トレースメタデータ、サーバー管理の会話設定など、SDK 管理のランタイムメタデータが含まれます。シリアライズされた状態を保存または送信する予定がある場合は、`RunContextWrapper.context` を永続化データとして扱い、状態と一緒に移動させる意図がある場合を除き、そこにシークレットを置かないでください。
|
||||
|
||||
## 保留中タスクのバージョニング
|
||||
|
||||
承認がしばらく保留される可能性がある場合は、エージェント定義または SDK のバージョンマーカーを、シリアライズされた状態と一緒に保存してください。これにより、モデル、プロンプト、ツール定義が変更された場合の非互換性を避けるために、対応するコードパスへデシリアライズ処理を振り分けられます。
|
||||
@@ -0,0 +1,101 @@
|
||||
---
|
||||
search:
|
||||
exclude: true
|
||||
---
|
||||
# OpenAI Agents SDK
|
||||
|
||||
[OpenAI Agents SDK](https://github.com/openai/openai-agents-python) は、抽象化をほとんど持たない軽量で使いやすいパッケージで、エージェント型 AI アプリを構築できるようにします。これは、以前のエージェント向け実験プロジェクトである [Swarm](https://github.com/openai/swarm/tree/main) を本番環境対応に発展させたものです。Agents SDK は、非常に少数の基本コンポーネントで構成されています:
|
||||
|
||||
- **エージェント**: 指示とツールを備えた LLM です
|
||||
- **Agents as tools / ハンドオフ**: エージェントが特定のタスクを他のエージェントに委任できるようにします
|
||||
- **ガードレール**: エージェントの入力と出力の検証を可能にします
|
||||
|
||||
Python と組み合わせることで、これらの基本コンポーネントは、ツールとエージェント間の複雑な関係を表現するのに十分強力であり、習得のハードルを高くすることなく実世界のアプリケーションを構築できます。さらに、SDK には組み込みの **トレーシング** が含まれており、エージェント型フローの可視化とデバッグ、評価、さらにはアプリケーション向けのモデルのファインチューニングも可能です。
|
||||
|
||||
## Agents SDK の利用理由
|
||||
|
||||
SDK の設計を支える原則は 2 つあります:
|
||||
|
||||
1. 使用する価値がある十分な機能を備えつつ、すばやく学べるだけの少数の基本コンポーネントに抑えること。
|
||||
2. そのままでも優れた動作をしつつ、何が起こるかを正確にカスタマイズできること。
|
||||
|
||||
SDK の主な機能は次のとおりです:
|
||||
|
||||
- **エージェントループ**: ツール呼び出しを処理し、結果を LLM に送り返し、タスクが完了するまで継続する組み込みのエージェントループです。
|
||||
- **Python ファースト**: 新しい抽象化を学ぶ必要なく、組み込みの言語機能を使ってエージェントをオーケストレーションし、連鎖させます。
|
||||
- **Agents as tools / ハンドオフ**: 複数のエージェント間で作業を調整し、委任するための強力な仕組みです。
|
||||
- **Sandbox エージェント**: マニフェストで定義されたファイル、Sandbox クライアントの選択、再開可能なサンドボックスセッションを備えた、実際の隔離ワークスペース内で専門エージェントを実行します。
|
||||
- **ガードレール**: エージェント実行と並行して入力検証と安全性チェックを実行し、チェックに通らない場合は即座に失敗として終了します。
|
||||
- **関数ツール**: スキーマの自動生成と Pydantic によるバリデーションにより、任意の Python 関数をツールに変換します。
|
||||
- **MCP サーバーのツール呼び出し**: 関数ツールと同じように動作する、組み込みの MCP サーバーツール統合です。
|
||||
- **セッション**: エージェントループ内で作業コンテキストを維持するための永続的なメモリレイヤーです。
|
||||
- **ヒューマンインザループ**: エージェント実行の各所に人間を関与させるための組み込みの仕組みです。
|
||||
- **トレーシング**: ワークフローを可視化、デバッグ、監視するための組み込みのトレーシングで、OpenAI の評価、ファインチューニング、蒸留ツール群をサポートします。
|
||||
- **Realtime エージェント**: `gpt-realtime-2.1` を使い、自動割り込み検出、コンテキスト管理、ガードレールなどを備えた強力な音声エージェントを構築します。
|
||||
|
||||
## Agents SDK と Responses API の選択
|
||||
|
||||
SDK は OpenAI モデルに対してデフォルトで Responses API を使用しますが、モデル呼び出しの周りに高レベルのランタイムを追加します。
|
||||
|
||||
次の場合は Responses API を直接使用します:
|
||||
|
||||
- ループ、ツールのディスパッチ、状態処理を自分で管理したい場合
|
||||
- ワークフローが短期間で、主にモデルの応答を返すことが目的の場合
|
||||
|
||||
次の場合は Agents SDK を使用します:
|
||||
|
||||
- ランタイムにターン、ツール実行、ガードレール、ハンドオフ、またはセッションを管理させたい場合
|
||||
- エージェントが成果物を生成する、または複数の協調したステップにわたって動作する必要がある場合
|
||||
- 実際のワークスペース、または [Sandbox エージェント](sandbox_agents.md) による再開可能な実行が必要な場合
|
||||
|
||||
アプリケーション全体でどちらか一方を選ぶ必要はありません。多くのアプリケーションでは、管理されたワークフローには SDK を使用し、低レベルの処理経路では Responses API を直接呼び出します。
|
||||
|
||||
## インストール
|
||||
|
||||
```bash
|
||||
pip install openai-agents
|
||||
```
|
||||
|
||||
## Hello world の例
|
||||
|
||||
```python
|
||||
from agents import Agent, Runner
|
||||
|
||||
agent = Agent(name="Assistant", instructions="You are a helpful assistant")
|
||||
|
||||
result = Runner.run_sync(agent, "Write a haiku about recursion in programming.")
|
||||
print(result.final_output)
|
||||
|
||||
# Code within the code,
|
||||
# Functions calling themselves,
|
||||
# Infinite loop's dance.
|
||||
```
|
||||
|
||||
(_これを実行する場合は、 `OPENAI_API_KEY` 環境変数を設定していることを確認してください_)
|
||||
|
||||
```bash
|
||||
export OPENAI_API_KEY=sk-...
|
||||
```
|
||||
|
||||
## 開始ポイント
|
||||
|
||||
- [クイックスタート](quickstart.md) で、最初のテキストベースのエージェントを構築します。
|
||||
- 次に、[エージェントの実行](running_agents.md#choose-a-memory-strategy) で、ターン間で状態をどのように引き継ぐかを決定します。
|
||||
- タスクが実際のファイル、リポジトリ、またはエージェントごとに隔離されたワークスペース状態に依存する場合は、[Sandbox エージェントのクイックスタート](sandbox_agents.md) を参照してください。
|
||||
- ハンドオフとマネージャースタイルのオーケストレーションのどちらにするかを決める場合は、[エージェントオーケストレーション](multi_agent.md) を参照してください。
|
||||
|
||||
## パスの選択
|
||||
|
||||
実行したい作業は分かっているものの、どのページで説明されているか分からない場合は、この表を使用してください。
|
||||
|
||||
| 目的 | 参照先 |
|
||||
| --- | --- |
|
||||
| 最初のテキストエージェントを構築し、完全な 1 回の実行を確認する | [クイックスタート](quickstart.md) |
|
||||
| 関数ツール、OpenAI がホストするツール、または agents as tools を追加する | [ツール](tools.md) |
|
||||
| 実際の隔離ワークスペース内で、コーディング、レビュー、またはドキュメント処理のエージェントを実行する | [Sandbox エージェントのクイックスタート](sandbox_agents.md) and [Sandbox クライアント](sandbox/clients.md) |
|
||||
| ハンドオフとマネージャースタイルのオーケストレーションのどちらを使うか決める | [エージェントオーケストレーション](multi_agent.md) |
|
||||
| ターン間でメモリを保持する | [エージェントの実行](running_agents.md#choose-a-memory-strategy) and [セッション](sessions/index.md) |
|
||||
| OpenAI モデル、WebSocket トランスポート、または OpenAI 以外のプロバイダーを使用する | [モデル](models/index.md) |
|
||||
| 出力、実行アイテム、割り込み、再開状態を確認する | [実行結果](results.md) |
|
||||
| `gpt-realtime-2.1` を使って低レイテンシの音声エージェントを構築する | [Realtime エージェントのクイックスタート](realtime/quickstart.md) and [Realtime トランスポート](realtime/transport.md) |
|
||||
| 音声認識 / エージェント / 音声合成のパイプラインを構築する | [音声パイプラインのクイックスタート](voice/quickstart.md) |
|
||||
+466
@@ -0,0 +1,466 @@
|
||||
---
|
||||
search:
|
||||
exclude: true
|
||||
---
|
||||
# Model context protocol (MCP)
|
||||
|
||||
[Model context protocol](https://modelcontextprotocol.io/introduction) (MCP) は、アプリケーションがツールや
|
||||
コンテキストを言語モデルに公開する方法を標準化します。公式ドキュメントより:
|
||||
|
||||
> MCP は、アプリケーションが LLM にコンテキストを提供する方法を標準化するオープンプロトコルです。MCP は、AI
|
||||
> アプリケーションにおける USB-C ポートのようなものだと考えてください。USB-C がデバイスをさまざまな周辺機器やアクセサリに接続する標準化された方法を提供するのと同様に、MCP
|
||||
> は AI モデルをさまざまなデータソースやツールに接続する標準化された方法を提供します。
|
||||
|
||||
Agents Python SDK は複数の MCP トランスポートに対応しています。これにより、既存の MCP サーバーを再利用したり、独自に構築して、ファイルシステム、HTTP、またはコネクターをバックエンドとするツールをエージェントに公開できます。
|
||||
|
||||
## MCP 統合の選択
|
||||
|
||||
MCP サーバーをエージェントに組み込む前に、ツール呼び出しをどこで実行すべきか、どのトランスポートに到達できるかを決めてください。次の表は、Python SDK がサポートする選択肢の概要です。
|
||||
|
||||
| 必要なこと | 推奨オプション |
|
||||
| ------------------------------------------------------------------------------------ | ----------------------------------------------------- |
|
||||
| OpenAI の Responses API に、モデルに代わって公開到達可能な MCP サーバーを呼び出させる| **ホスト型 MCP サーバーツール** ([`HostedMCPTool`][agents.tool.HostedMCPTool] 経由) |
|
||||
| ローカルまたはリモートで実行している Streamable HTTP サーバーに接続する | **Streamable HTTP MCP サーバー** ([`MCPServerStreamableHttp`][agents.mcp.server.MCPServerStreamableHttp] 経由) |
|
||||
| Server-Sent Events を用いた HTTP を実装しているサーバーと通信する | **SSE を用いた HTTP MCP サーバー** ([`MCPServerSse`][agents.mcp.server.MCPServerSse] 経由) |
|
||||
| ローカルプロセスを起動し、stdin/stdout 経由で通信する | **stdio MCP サーバー** ([`MCPServerStdio`][agents.mcp.server.MCPServerStdio] 経由) |
|
||||
|
||||
以降のセクションでは、各オプション、その設定方法、あるトランスポートを別のトランスポートより優先すべきタイミングについて説明します。
|
||||
|
||||
## エージェントレベルの MCP 設定
|
||||
|
||||
トランスポートの選択に加えて、`Agent.mcp_config` を設定することで MCP ツールの準備方法を調整できます。
|
||||
|
||||
```python
|
||||
from agents import Agent
|
||||
|
||||
agent = Agent(
|
||||
name="Assistant",
|
||||
mcp_servers=[server],
|
||||
mcp_config={
|
||||
# Try to convert MCP tool schemas to strict JSON schema.
|
||||
"convert_schemas_to_strict": True,
|
||||
# If None, MCP tool failures are raised as exceptions instead of
|
||||
# returning model-visible error text.
|
||||
"failure_error_function": None,
|
||||
# Prefix local MCP tool names with their server name.
|
||||
"include_server_in_tool_names": True,
|
||||
},
|
||||
)
|
||||
```
|
||||
|
||||
注:
|
||||
|
||||
- `convert_schemas_to_strict` はベストエフォートです。スキーマを変換できない場合は、元のスキーマが使用されます。
|
||||
- `failure_error_function` は、MCP ツール呼び出しの失敗をモデルにどのように提示するかを制御します。
|
||||
- `failure_error_function` が未設定の場合、SDK はデフォルトのツールエラーフォーマッターを使用します。
|
||||
- サーバーレベルの `failure_error_function` は、そのサーバーについて `Agent.mcp_config["failure_error_function"]` を上書きします。
|
||||
- `include_server_in_tool_names` はオプトインです。有効にすると、各ローカル MCP ツールは、決定論的なサーバー接頭辞付きの名前でモデルに公開されます。これにより、複数の MCP サーバーが同じ名前のツールを公開する場合の衝突を避けやすくなります。生成される名前は ASCII セーフで、関数ツール名の長さ制限内に収まり、同じエージェント上の既存のローカル関数ツール名および有効化されたハンドオフ名を避けます。それでも SDK は元のサーバー上で元の MCP ツール名を呼び出します。
|
||||
|
||||
## トランスポート共通のパターン
|
||||
|
||||
トランスポートを選択した後、多くの統合では同じ追加判断が必要になります。
|
||||
|
||||
- ツールのサブセットのみを公開する方法([ツールフィルタリング](#tool-filtering))。
|
||||
- サーバーが再利用可能なプロンプトも提供するかどうか([プロンプト](#prompts))。
|
||||
- `list_tools()` をキャッシュすべきかどうか([キャッシュ](#caching))。
|
||||
- MCP アクティビティがトレースにどのように表示されるか([トレーシング](#tracing))。
|
||||
|
||||
ローカル MCP サーバー(`MCPServerStdio`、`MCPServerSse`、`MCPServerStreamableHttp`)では、承認ポリシーと呼び出しごとの `_meta` ペイロードも共通の概念です。Streamable HTTP セクションでは最も完全な例を示しており、同じパターンは他のローカルトランスポートにも適用されます。
|
||||
|
||||
## 1. ホスト型 MCP サーバーツール
|
||||
|
||||
ホスト型ツールでは、ツールのラウンドトリップ全体を OpenAI のインフラに委ねます。ツールの一覧取得と呼び出しをコード側で行う代わりに、[`HostedMCPTool`][agents.tool.HostedMCPTool] がサーバーラベル(および任意のコネクターメタデータ)を Responses API に転送します。モデルはリモートサーバーのツールを一覧表示し、Python プロセスへの追加のコールバックなしにそれらを呼び出します。現在、ホスト型ツールは Responses API のホスト型 MCP 統合をサポートする OpenAI モデルで動作します。
|
||||
|
||||
### 基本的なホスト型 MCP ツール
|
||||
|
||||
エージェントの `tools` リストに [`HostedMCPTool`][agents.tool.HostedMCPTool] を追加してホスト型ツールを作成します。`tool_config` 辞書は REST API に送信する JSON と同じ構造です:
|
||||
|
||||
```python
|
||||
import asyncio
|
||||
|
||||
from agents import Agent, HostedMCPTool, Runner
|
||||
|
||||
async def main() -> None:
|
||||
agent = Agent(
|
||||
name="Assistant",
|
||||
instructions="Use the DeepWiki hosted MCP server to inspect openai/openai-agents-python.",
|
||||
tools=[
|
||||
HostedMCPTool(
|
||||
tool_config={
|
||||
"type": "mcp",
|
||||
"server_label": "deepwiki",
|
||||
"server_url": "https://mcp.deepwiki.com/mcp",
|
||||
"require_approval": "never",
|
||||
}
|
||||
)
|
||||
],
|
||||
)
|
||||
|
||||
result = await Runner.run(
|
||||
agent,
|
||||
"Which language is the repository openai/openai-agents-python written in?",
|
||||
)
|
||||
print(result.final_output)
|
||||
|
||||
asyncio.run(main())
|
||||
```
|
||||
|
||||
ホスト型サーバーはツールを自動的に公開します。`mcp_servers` に追加する必要はありません。
|
||||
|
||||
ホスト型ツール検索にホスト型 MCP サーバーを遅延読み込みさせたい場合は、`tool_config["defer_loading"] = True` を設定し、エージェントに [`ToolSearchTool`][agents.tool.ToolSearchTool] を追加します。これは OpenAI Responses モデルでのみサポートされます。ツール検索の完全な設定と制約については、[ツール](tools.md#hosted-tool-search) を参照してください。
|
||||
|
||||
### ホスト型 MCP の結果のストリーミング
|
||||
|
||||
ホスト型ツールは、関数ツールとまったく同じ方法で結果のストリーミングをサポートします。モデルがまだ処理中でも、`Runner.run_streamed` を使用して
|
||||
増分的な MCP 出力を受け取れます:
|
||||
|
||||
```python
|
||||
result = Runner.run_streamed(agent, "Summarise this repository's top languages")
|
||||
async for event in result.stream_events():
|
||||
if event.type == "run_item_stream_event":
|
||||
print(f"Received: {event.item}")
|
||||
print(result.final_output)
|
||||
```
|
||||
|
||||
### 任意の承認フロー
|
||||
|
||||
サーバーが機密性の高い操作を実行できる場合、各ツール実行の前に人間またはプログラムによる承認を必須にできます。`tool_config` で `require_approval` を、単一のポリシー(`"always"`、`"never"`)またはツール名をポリシーにマッピングする辞書として設定します。Python 内で判断するには、`on_approval_request` コールバックを指定します。
|
||||
|
||||
```python
|
||||
from agents import MCPToolApprovalFunctionResult, MCPToolApprovalRequest
|
||||
|
||||
SAFE_TOOLS = {"read_wiki_structure", "read_wiki_contents", "ask_question"}
|
||||
|
||||
def approve_tool(request: MCPToolApprovalRequest) -> MCPToolApprovalFunctionResult:
|
||||
if request.data.name in SAFE_TOOLS:
|
||||
return {"approve": True}
|
||||
return {"approve": False, "reason": "Escalate to a human reviewer"}
|
||||
|
||||
agent = Agent(
|
||||
name="Assistant",
|
||||
tools=[
|
||||
HostedMCPTool(
|
||||
tool_config={
|
||||
"type": "mcp",
|
||||
"server_label": "deepwiki",
|
||||
"server_url": "https://mcp.deepwiki.com/mcp",
|
||||
"require_approval": "always",
|
||||
},
|
||||
on_approval_request=approve_tool,
|
||||
)
|
||||
],
|
||||
)
|
||||
```
|
||||
|
||||
このコールバックは同期または非同期にでき、モデルが実行を継続するための承認データを必要とするたびに呼び出されます。
|
||||
|
||||
### コネクター対応のホスト型サーバー
|
||||
|
||||
ホスト型 MCP は OpenAI コネクターにも対応しています。`server_url` を指定する代わりに、`connector_id` とアクセストークンを指定します。Responses API が認証を処理し、ホスト型サーバーがコネクターのツールを公開します。
|
||||
|
||||
```python
|
||||
import os
|
||||
|
||||
HostedMCPTool(
|
||||
tool_config={
|
||||
"type": "mcp",
|
||||
"server_label": "google_calendar",
|
||||
"connector_id": "connector_googlecalendar",
|
||||
"authorization": os.environ["GOOGLE_CALENDAR_AUTHORIZATION"],
|
||||
"require_approval": "never",
|
||||
}
|
||||
)
|
||||
```
|
||||
|
||||
完全に動作するホスト型ツールのサンプル(ストリーミング、承認、コネクターを含む)は [`examples/hosted_mcp`](https://github.com/openai/openai-agents-python/tree/main/examples/hosted_mcp) にあります。
|
||||
|
||||
## 2. Streamable HTTP MCP サーバー
|
||||
|
||||
ネットワーク接続を自分で管理したい場合は、[`MCPServerStreamableHttp`][agents.mcp.server.MCPServerStreamableHttp] を使用します。Streamable HTTP サーバーは、トランスポートを制御したい場合や、レイテンシを低く保ちながら自分のインフラ内でサーバーを実行したい場合に最適です。
|
||||
|
||||
```python
|
||||
import asyncio
|
||||
import os
|
||||
|
||||
from agents import Agent, Runner
|
||||
from agents.mcp import MCPServerStreamableHttp
|
||||
from agents.model_settings import ModelSettings
|
||||
|
||||
async def main() -> None:
|
||||
token = os.environ["MCP_SERVER_TOKEN"]
|
||||
async with MCPServerStreamableHttp(
|
||||
name="Streamable HTTP Python Server",
|
||||
params={
|
||||
"url": "http://localhost:8000/mcp",
|
||||
"headers": {"Authorization": f"Bearer {token}"},
|
||||
"timeout": 10,
|
||||
},
|
||||
cache_tools_list=True,
|
||||
max_retry_attempts=3,
|
||||
) as server:
|
||||
agent = Agent(
|
||||
name="Assistant",
|
||||
instructions="Use the MCP tools to answer the questions.",
|
||||
mcp_servers=[server],
|
||||
model_settings=ModelSettings(tool_choice="required"),
|
||||
)
|
||||
|
||||
result = await Runner.run(agent, "Add 7 and 22.")
|
||||
print(result.final_output)
|
||||
|
||||
asyncio.run(main())
|
||||
```
|
||||
|
||||
コンストラクターは追加オプションを受け取ります。
|
||||
|
||||
- `client_session_timeout_seconds` は HTTP 読み取りタイムアウトを制御します。
|
||||
- `use_structured_content` は、`tool_result.structured_content` をテキスト出力より優先するかどうかを切り替えます。
|
||||
- `max_retry_attempts` と `retry_backoff_seconds_base` は、`list_tools()` と `call_tool()` に自動リトライを追加します。
|
||||
- `tool_filter` は、ツールのサブセットのみを公開できるようにします([ツールフィルタリング](#tool-filtering) を参照)。
|
||||
- `require_approval` は、ローカル MCP ツールでヒューマンインザループの承認ポリシーを有効にします。
|
||||
- `failure_error_function` は、モデルに表示される MCP ツール失敗メッセージをカスタマイズします。`None` に設定すると、代わりにエラーを送出します。
|
||||
- `tool_meta_resolver` は、呼び出しごとの MCP `_meta` ペイロードを `call_tool()` の前に注入します。
|
||||
|
||||
### ローカル MCP サーバーの承認ポリシー
|
||||
|
||||
`MCPServerStdio`、`MCPServerSse`、`MCPServerStreamableHttp` はいずれも `require_approval` を受け取ります。
|
||||
|
||||
サポートされる形式:
|
||||
|
||||
- すべてのツールに対する `"always"` または `"never"`。
|
||||
- `True` / `False`(always/never と同等)。
|
||||
- ツールごとのマップ。例: `{"delete_file": "always", "read_file": "never"}`。
|
||||
- グループ化されたオブジェクト: `{"always": {"tool_names": [...]}, "never": {"tool_names": [...]}}`。
|
||||
|
||||
```python
|
||||
async with MCPServerStreamableHttp(
|
||||
name="Filesystem MCP",
|
||||
params={"url": "http://localhost:8000/mcp"},
|
||||
require_approval={"always": {"tool_names": ["delete_file"]}},
|
||||
) as server:
|
||||
...
|
||||
```
|
||||
|
||||
完全な一時停止 / 再開フローについては、[ヒューマンインザループ](human_in_the_loop.md) と `examples/mcp/get_all_mcp_tools_example/main.py` を参照してください。
|
||||
|
||||
### `tool_meta_resolver` による呼び出しごとのメタデータ
|
||||
|
||||
MCP サーバーが `_meta` にリクエストメタデータ(たとえばテナント ID やトレースコンテキスト)を期待する場合は、`tool_meta_resolver` を使用します。下の例では、`Runner.run(...)` に `context` として `dict` を渡すことを前提としています。
|
||||
|
||||
```python
|
||||
from agents.mcp import MCPServerStreamableHttp, MCPToolMetaContext
|
||||
|
||||
|
||||
def resolve_meta(context: MCPToolMetaContext) -> dict[str, str] | None:
|
||||
run_context_data = context.run_context.context or {}
|
||||
tenant_id = run_context_data.get("tenant_id")
|
||||
if tenant_id is None:
|
||||
return None
|
||||
return {"tenant_id": str(tenant_id), "source": "agents-sdk"}
|
||||
|
||||
|
||||
server = MCPServerStreamableHttp(
|
||||
name="Metadata-aware MCP",
|
||||
params={"url": "http://localhost:8000/mcp"},
|
||||
tool_meta_resolver=resolve_meta,
|
||||
)
|
||||
```
|
||||
|
||||
実行コンテキストが Pydantic モデル、データクラス、またはカスタムクラスの場合は、属性アクセスでテナント ID を読み取ってください。
|
||||
|
||||
### MCP ツール出力: テキストと画像
|
||||
|
||||
MCP ツールが画像コンテンツを返すと、SDK はそれを画像ツール出力エントリーに自動的にマッピングします。テキスト / 画像の混在レスポンスは出力項目のリストとして転送されるため、エージェントは通常の関数ツールからの画像出力を扱うのと同じ方法で MCP の画像結果を扱えます。
|
||||
|
||||
## 3. SSE を用いた HTTP MCP サーバー
|
||||
|
||||
!!! warning
|
||||
|
||||
MCP プロジェクトでは Server-Sent Events トランスポートが非推奨になりました。新しい統合では Streamable HTTP または stdio を優先し、SSE はレガシーサーバーにのみ使用してください。
|
||||
|
||||
MCP サーバーが SSE を用いた HTTP トランスポートを実装している場合は、[`MCPServerSse`][agents.mcp.server.MCPServerSse] をインスタンス化します。トランスポート以外は、API は Streamable HTTP サーバーと同一です。
|
||||
|
||||
```python
|
||||
|
||||
from agents import Agent, Runner
|
||||
from agents.model_settings import ModelSettings
|
||||
from agents.mcp import MCPServerSse
|
||||
|
||||
workspace_id = "demo-workspace"
|
||||
|
||||
async with MCPServerSse(
|
||||
name="SSE Python Server",
|
||||
params={
|
||||
"url": "http://localhost:8000/sse",
|
||||
"headers": {"X-Workspace": workspace_id},
|
||||
},
|
||||
cache_tools_list=True,
|
||||
) as server:
|
||||
agent = Agent(
|
||||
name="Assistant",
|
||||
mcp_servers=[server],
|
||||
model_settings=ModelSettings(tool_choice="required"),
|
||||
)
|
||||
result = await Runner.run(agent, "What's the weather in Tokyo?")
|
||||
print(result.final_output)
|
||||
```
|
||||
|
||||
## 4. stdio MCP サーバー
|
||||
|
||||
ローカルサブプロセスとして実行される MCP サーバーには、[`MCPServerStdio`][agents.mcp.server.MCPServerStdio] を使用します。SDK はプロセスを起動し、パイプを開いたままにし、コンテキストマネージャーを抜けると自動的に閉じます。このオプションは、簡単な概念実証や、サーバーがコマンドラインエントリーポイントのみを公開する場合に役立ちます。
|
||||
|
||||
```python
|
||||
from pathlib import Path
|
||||
from agents import Agent, Runner
|
||||
from agents.mcp import MCPServerStdio
|
||||
|
||||
current_dir = Path(__file__).parent
|
||||
samples_dir = current_dir / "sample_files"
|
||||
|
||||
async with MCPServerStdio(
|
||||
name="Filesystem Server via npx",
|
||||
params={
|
||||
"command": "npx",
|
||||
"args": ["-y", "@modelcontextprotocol/server-filesystem", str(samples_dir)],
|
||||
},
|
||||
) as server:
|
||||
agent = Agent(
|
||||
name="Assistant",
|
||||
instructions="Use the files in the sample directory to answer questions.",
|
||||
mcp_servers=[server],
|
||||
)
|
||||
result = await Runner.run(agent, "List the files available to you.")
|
||||
print(result.final_output)
|
||||
```
|
||||
|
||||
## 5. MCP サーバーマネージャー
|
||||
|
||||
複数の MCP サーバーがある場合は、`MCPServerManager` を使用して事前に接続し、接続済みのサブセットをエージェントに公開します。コンストラクターオプションと再接続の動作については、[MCPServerManager API リファレンス](ref/mcp/manager.md) を参照してください。
|
||||
|
||||
```python
|
||||
from agents import Agent, Runner
|
||||
from agents.mcp import MCPServerManager, MCPServerStreamableHttp
|
||||
|
||||
servers = [
|
||||
MCPServerStreamableHttp(name="calendar", params={"url": "http://localhost:8000/mcp"}),
|
||||
MCPServerStreamableHttp(name="docs", params={"url": "http://localhost:8001/mcp"}),
|
||||
]
|
||||
|
||||
async with MCPServerManager(servers) as manager:
|
||||
agent = Agent(
|
||||
name="Assistant",
|
||||
instructions="Use MCP tools when they help.",
|
||||
mcp_servers=manager.active_servers,
|
||||
)
|
||||
result = await Runner.run(agent, "Which MCP tools are available?")
|
||||
print(result.final_output)
|
||||
```
|
||||
|
||||
主な動作:
|
||||
|
||||
- `active_servers` には、`drop_failed_servers=True`(デフォルト)の場合、正常に接続されたサーバーのみが含まれます。
|
||||
- 失敗は `failed_servers` と `errors` で追跡されます。
|
||||
- `strict=True` を設定すると、最初の接続失敗時にエラーを送出します。
|
||||
- `reconnect(failed_only=True)` を呼び出すと失敗したサーバーを再試行し、`reconnect(failed_only=False)` を呼び出すとすべてのサーバーを再起動します。
|
||||
- `connect_timeout_seconds`、`cleanup_timeout_seconds`、`connect_in_parallel` を使用してライフサイクル動作を調整します。
|
||||
|
||||
## 共通のサーバー機能
|
||||
|
||||
以下のセクションは MCP サーバートランスポート全体に適用されます(正確な API の範囲はサーバークラスによって異なります)。
|
||||
|
||||
## ツールフィルタリング
|
||||
|
||||
各 MCP サーバーはツールフィルターに対応しているため、エージェントに必要な関数だけを公開できます。フィルタリングは構築時に行うことも、実行ごとに動的に行うこともできます。
|
||||
|
||||
### 静的なツールフィルタリング
|
||||
|
||||
[`create_static_tool_filter`][agents.mcp.create_static_tool_filter] を使用して、シンプルな許可 / ブロックリストを設定します:
|
||||
|
||||
```python
|
||||
from pathlib import Path
|
||||
|
||||
from agents.mcp import MCPServerStdio, create_static_tool_filter
|
||||
|
||||
samples_dir = Path("/path/to/files")
|
||||
|
||||
filesystem_server = MCPServerStdio(
|
||||
params={
|
||||
"command": "npx",
|
||||
"args": ["-y", "@modelcontextprotocol/server-filesystem", str(samples_dir)],
|
||||
},
|
||||
tool_filter=create_static_tool_filter(allowed_tool_names=["read_file", "write_file"]),
|
||||
)
|
||||
```
|
||||
|
||||
`allowed_tool_names` と `blocked_tool_names` の両方が指定された場合、SDK はまず許可リストを適用し、その後、残ったセットからブロックされたツールを削除します。
|
||||
|
||||
### 動的なツールフィルタリング
|
||||
|
||||
より高度なロジックには、[`ToolFilterContext`][agents.mcp.ToolFilterContext] を受け取るコール可能オブジェクトを渡します。このコール可能オブジェクトは同期または非同期にでき、ツールを公開すべき場合に `True` を返します。
|
||||
|
||||
```python
|
||||
from pathlib import Path
|
||||
|
||||
from agents.mcp import MCPServerStdio, ToolFilterContext
|
||||
|
||||
samples_dir = Path("/path/to/files")
|
||||
|
||||
async def context_aware_filter(context: ToolFilterContext, tool) -> bool:
|
||||
if context.agent.name == "Code Reviewer" and tool.name.startswith("danger_"):
|
||||
return False
|
||||
return True
|
||||
|
||||
async with MCPServerStdio(
|
||||
params={
|
||||
"command": "npx",
|
||||
"args": ["-y", "@modelcontextprotocol/server-filesystem", str(samples_dir)],
|
||||
},
|
||||
tool_filter=context_aware_filter,
|
||||
) as server:
|
||||
...
|
||||
```
|
||||
|
||||
フィルターコンテキストは、アクティブな `run_context`、ツールを要求している `agent`、および `server_name` を公開します。
|
||||
|
||||
## プロンプト
|
||||
|
||||
MCP サーバーは、エージェントの指示を動的に生成するプロンプトも提供できます。プロンプトに対応するサーバーは 2 つの
|
||||
メソッドを公開します:
|
||||
|
||||
- `list_prompts()` は利用可能なプロンプトテンプレートを列挙します。
|
||||
- `get_prompt(name, arguments)` は具体的なプロンプトを取得します。任意でパラメーターを指定できます。
|
||||
|
||||
```python
|
||||
from agents import Agent
|
||||
|
||||
prompt_result = await server.get_prompt(
|
||||
"generate_code_review_instructions",
|
||||
{"focus": "security vulnerabilities", "language": "python"},
|
||||
)
|
||||
instructions = prompt_result.messages[0].content.text
|
||||
|
||||
agent = Agent(
|
||||
name="Code Reviewer",
|
||||
instructions=instructions,
|
||||
mcp_servers=[server],
|
||||
)
|
||||
```
|
||||
|
||||
## キャッシュ
|
||||
|
||||
エージェントを実行するたびに、各 MCP サーバーで `list_tools()` が呼び出されます。リモートサーバーでは目に見えるレイテンシが発生する可能性があるため、すべての MCP サーバークラスは `cache_tools_list` オプションを公開しています。ツール定義が頻繁に変更されないと確信できる場合にのみ、`True` に設定してください。後で最新のリストを強制的に取得するには、サーバーインスタンスで `invalidate_tools_cache()` を呼び出します。
|
||||
|
||||
## トレーシング
|
||||
|
||||
[トレーシング](./tracing.md) は、次を含む MCP アクティビティを自動的にキャプチャします。
|
||||
|
||||
1. ツールを一覧表示するための MCP サーバーへの呼び出し。
|
||||
2. ツール呼び出し上の MCP 関連情報。
|
||||
|
||||

|
||||
|
||||
## 参考情報
|
||||
|
||||
- [Model Context Protocol](https://modelcontextprotocol.io/) – 仕様と設計ガイド。
|
||||
- [examples/mcp](https://github.com/openai/openai-agents-python/tree/main/examples/mcp) – 実行可能な stdio、SSE、Streamable HTTP のサンプル。
|
||||
- [examples/hosted_mcp](https://github.com/openai/openai-agents-python/tree/main/examples/hosted_mcp) – 承認とコネクターを含む、完全なホスト型 MCP デモ。
|
||||
@@ -0,0 +1,674 @@
|
||||
---
|
||||
search:
|
||||
exclude: true
|
||||
---
|
||||
# モデル
|
||||
|
||||
Agents SDKには、すぐに利用できる OpenAIモデルのサポートが 2 種類用意されています。
|
||||
|
||||
- **推奨**: 新しい [Responses API](https://platform.openai.com/docs/api-reference/responses) を使用して OpenAI API を呼び出す [`OpenAIResponsesModel`][agents.models.openai_responses.OpenAIResponsesModel]。
|
||||
- [Chat Completions API](https://platform.openai.com/docs/api-reference/chat) を使用して OpenAI API を呼び出す [`OpenAIChatCompletionsModel`][agents.models.openai_chatcompletions.OpenAIChatCompletionsModel]。
|
||||
|
||||
## モデル設定の選択
|
||||
|
||||
設定に適した最もシンプルな方法から始めてください。
|
||||
|
||||
| 実現したいこと | 推奨される方法 | 詳細 |
|
||||
| --- | --- | --- |
|
||||
| OpenAIモデルのみを使用する | Responses モデルパスでデフォルトの OpenAIプロバイダーを使用する | [OpenAIモデル](#openai-models) |
|
||||
| WebSocket トランスポート経由で OpenAI Responses API を使用する | Responses モデルパスを維持し、WebSocket トランスポートを有効にする | [Responses WebSocket トランスポート](#responses-websocket-transport) |
|
||||
| OpenAIがホストするサブエージェントを使用する | 試験的なホスト型マルチエージェントモデルを使用する | [ホスト型マルチエージェント](#hosted-multi-agent-experimental) |
|
||||
| OpenAI以外のプロバイダーを 1 つ使用する | 組み込みのプロバイダー統合ポイントから始める | [OpenAI以外のモデル](#non-openai-models) |
|
||||
| エージェント間でモデルまたはプロバイダーを組み合わせる | 実行ごと、またはエージェントごとにプロバイダーを選択し、機能の違いを確認する | [単一ワークフローでのモデルの組み合わせ](#mixing-models-in-one-workflow)および[プロバイダー間でのモデルの組み合わせ](#mixing-models-across-providers) |
|
||||
| OpenAI Responses の高度なリクエスト設定を調整する | OpenAI Responses パスで `ModelSettings` を使用する | [OpenAI Responses の高度な設定](#advanced-openai-responses-settings) |
|
||||
| OpenAI以外のプロバイダー、または複数プロバイダーのルーティングにサードパーティ製アダプターを使用する | サポートされているベータ版アダプターを比較し、リリース予定のプロバイダーパスを検証する | [サードパーティ製アダプター](#third-party-adapters) |
|
||||
|
||||
## OpenAIモデル
|
||||
|
||||
OpenAIのみを使用するほとんどのアプリでは、デフォルトの OpenAIプロバイダーで文字列のモデル名を使用し、Responses モデルパスを維持する方法を推奨します。
|
||||
|
||||
`Agent` の初期化時にモデルを指定しない場合、デフォルトモデルが使用されます。現在のデフォルトは、低レイテンシーのエージェントワークフロー向けに `reasoning.effort="none"` と `verbosity="low"` を設定した [`gpt-5.4-mini`](https://developers.openai.com/api/docs/models/gpt-5.4-mini) です。利用できる場合は、明示的な `model_settings` を維持しながら、より高い品質を得るためにエージェントを `gpt-5.6-sol` に設定することを推奨します。
|
||||
|
||||
`gpt-5.6-sol` などの別のモデルに切り替える場合、エージェントを設定する方法は 2 つあります。
|
||||
|
||||
### デフォルトモデル
|
||||
|
||||
まず、カスタムモデルを設定していないすべてのエージェントで特定のモデルを一貫して使用するには、エージェントを実行する前に `OPENAI_DEFAULT_MODEL` 環境変数を設定します。
|
||||
|
||||
```bash
|
||||
export OPENAI_DEFAULT_MODEL=gpt-5.6-sol
|
||||
python3 my_awesome_agent.py
|
||||
```
|
||||
|
||||
次に、`RunConfig` を使用して実行のデフォルトモデルを設定できます。エージェントにモデルを設定していない場合、この実行のモデルが使用されます。
|
||||
|
||||
```python
|
||||
from agents import Agent, RunConfig, Runner
|
||||
|
||||
agent = Agent(
|
||||
name="Assistant",
|
||||
instructions="You're a helpful agent.",
|
||||
)
|
||||
|
||||
result = await Runner.run(
|
||||
agent,
|
||||
"Hello",
|
||||
run_config=RunConfig(model="gpt-5.6-sol"),
|
||||
)
|
||||
```
|
||||
|
||||
#### GPT-5 モデル
|
||||
|
||||
この方法で `gpt-5.6-sol` などの GPT-5 モデルを使用すると、SDK はデフォルトの `ModelSettings` を適用します。ほとんどのユースケースに最適な設定が使用されます。デフォルトモデルの推論エフォートを調整するには、独自の `ModelSettings` を渡します。
|
||||
|
||||
```python
|
||||
from openai.types.shared import Reasoning
|
||||
from agents import Agent, ModelSettings
|
||||
|
||||
my_agent = Agent(
|
||||
name="My Agent",
|
||||
instructions="You're a helpful agent.",
|
||||
# If OPENAI_DEFAULT_MODEL=gpt-5.6-sol is set, passing only model_settings works.
|
||||
# It's also fine to pass a GPT-5 model name explicitly:
|
||||
model="gpt-5.6-sol",
|
||||
model_settings=ModelSettings(reasoning=Reasoning(effort="high"), verbosity="low")
|
||||
)
|
||||
```
|
||||
|
||||
レイテンシーを低減するには、GPT-5 モデルで `reasoning.effort="none"` を使用することを推奨します。
|
||||
|
||||
GPT-5.6 は、既存の `reasoning` 設定を通じて、推論モード、永続化された推論コンテキスト、および `"max"` エフォートレベルもサポートします。これらの制御は Responses API パスで利用できます。
|
||||
|
||||
```python
|
||||
from openai.types.shared import Reasoning
|
||||
from agents import Agent, ModelSettings
|
||||
|
||||
agent = Agent(
|
||||
name="Deep research agent",
|
||||
model="gpt-5.6-sol",
|
||||
model_settings=ModelSettings(
|
||||
reasoning=Reasoning(
|
||||
mode="pro",
|
||||
effort="max",
|
||||
context="all_turns",
|
||||
),
|
||||
),
|
||||
)
|
||||
```
|
||||
|
||||
`reasoning.mode` と `reasoning.context` は Responses 専用の設定です。Chat Completions では `reasoning.effort` のみが使用され、サポートされるエフォートレベルはモデルと API サーフェスによって異なります。GPT-5.6 の `"max"` エフォートには Responses API を使用してください。Chat Completions アダプターは警告を出してモードとコンテキストを無視します。その警告をエラーにするには、OpenAIプロバイダーで `strict_feature_validation=True` を設定します。
|
||||
|
||||
`context="all_turns"` を使用する場合は、`previous_response_id`、サーバー側の会話、または以前の推論項目の再現によって会話を保持してください。ステートレスな `store=False` 呼び出しでは、レスポンスに `reasoning.encrypted_content` を含め、次のリクエストでそれらの推論項目を再現してください。
|
||||
|
||||
#### ComputerTool のモデル選択
|
||||
|
||||
エージェントに [`ComputerTool`][agents.tool.ComputerTool] が含まれている場合、実際の Responses リクエストにおける実効モデルによって、SDK が送信するコンピューターツールのペイロードが決まります。明示的な `gpt-5.5` リクエストでは、GA の組み込み `computer` ツールが使用されます。一方、明示的な `computer-use-preview` リクエストでは、従来の `computer_use_preview` ペイロードが維持されます。
|
||||
|
||||
プロンプト管理の呼び出しが主な例外です。プロンプトテンプレートがモデルを所有し、SDK がリクエストから `model` を省略する場合、プロンプトが固定しているモデルを SDK が推測しないように、プレビュー互換のコンピューターペイロードがデフォルトで使用されます。このフローで GA パスを維持するには、リクエストで `model="gpt-5.5"` を明示するか、`ModelSettings(tool_choice="computer")` または `ModelSettings(tool_choice="computer_use")` で GA セレクターを強制します。
|
||||
|
||||
[`ComputerTool`][agents.tool.ComputerTool] が登録されている場合、`tool_choice="computer"`、`"computer_use"`、`"computer_use_preview"` は、実効リクエストモデルに一致する組み込みセレクターへ正規化されます。`ComputerTool` が登録されていない場合、これらの文字列は引き続き通常の関数名として動作します。
|
||||
|
||||
プレビュー互換のリクエストでは、`environment` と表示サイズを事前にシリアライズする必要があります。そのため、[`ComputerProvider`][agents.tool.ComputerProvider] ファクトリーを使用するプロンプト管理フローでは、具体的な `Computer` または `AsyncComputer` インスタンスを渡すか、リクエスト送信前に GA セレクターを強制する必要があります。移行の詳細については、[ツール](../tools.md#computertool-and-the-responses-computer-tool)を参照してください。
|
||||
|
||||
#### GPT-5 以外のモデル
|
||||
|
||||
カスタム `model_settings` を指定せずに GPT-5 以外のモデル名を渡すと、SDK はすべてのモデルと互換性のある汎用的な `ModelSettings` に戻ります。
|
||||
|
||||
### Responses 専用のツール検索機能
|
||||
|
||||
次のツール機能は、OpenAI Responses モデルでのみサポートされます。
|
||||
|
||||
- [`ToolSearchTool`][agents.tool.ToolSearchTool]
|
||||
- [`tool_namespace()`][agents.tool.tool_namespace]
|
||||
- `@function_tool(defer_loading=True)` およびその他の遅延読み込み対応 Responses ツールサーフェス
|
||||
|
||||
これらの機能は、Chat Completions モデルおよび Responses 以外のバックエンドでは拒否されます。遅延読み込みツールを使用する場合は、エージェントに `ToolSearchTool()` を追加し、修飾されていない名前空間名や遅延読み込み専用の関数名を強制する代わりに、`auto` または `required` のツール選択を通じてモデルにツールを読み込ませます。設定の詳細と現在の制約については、[ツール](../tools.md#hosted-tool-search)を参照してください。
|
||||
|
||||
### Responses WebSocket トランスポート
|
||||
|
||||
デフォルトでは、OpenAI Responses API リクエストは HTTP トランスポートを使用します。OpenAIを基盤とするモデルを使用する場合は、WebSocket トランスポートを有効にできます。
|
||||
|
||||
#### 基本設定
|
||||
|
||||
```python
|
||||
from agents import set_default_openai_responses_transport
|
||||
|
||||
set_default_openai_responses_transport("websocket")
|
||||
```
|
||||
|
||||
これは、デフォルトの OpenAIプロバイダーによって解決される OpenAI Responses モデルに影響します。これには `"gpt-5.6-sol"` などの文字列モデル名も含まれます。
|
||||
|
||||
トランスポートの選択は、SDK がモデル名をモデルインスタンスへ解決するときに行われます。具体的な [`Model`][agents.models.interface.Model] オブジェクトを渡す場合、そのトランスポートはすでに固定されています。[`OpenAIResponsesWSModel`][agents.models.openai_responses.OpenAIResponsesWSModel] は WebSocket、[`OpenAIResponsesModel`][agents.models.openai_responses.OpenAIResponsesModel] は HTTP を使用し、[`OpenAIChatCompletionsModel`][agents.models.openai_chatcompletions.OpenAIChatCompletionsModel] は Chat Completions のままです。`RunConfig(model_provider=...)` を渡す場合、グローバルなデフォルトではなく、そのプロバイダーがトランスポートの選択を制御します。
|
||||
|
||||
#### プロバイダー単位または実行単位の設定
|
||||
|
||||
プロバイダーごと、または実行ごとに WebSocket トランスポートを設定することもできます。
|
||||
|
||||
```python
|
||||
from agents import Agent, OpenAIProvider, RunConfig, Runner
|
||||
|
||||
provider = OpenAIProvider(
|
||||
use_responses_websocket=True,
|
||||
# Optional; if omitted, OPENAI_WEBSOCKET_BASE_URL is used when set.
|
||||
websocket_base_url="wss://your-proxy.example/v1",
|
||||
# Optional low-level websocket keepalive settings.
|
||||
responses_websocket_options={"ping_interval": 20.0, "ping_timeout": 60.0},
|
||||
)
|
||||
|
||||
agent = Agent(name="Assistant")
|
||||
result = await Runner.run(
|
||||
agent,
|
||||
"Hello",
|
||||
run_config=RunConfig(model_provider=provider),
|
||||
)
|
||||
```
|
||||
|
||||
OpenAIを基盤とするプロバイダーでは、任意のエージェント登録設定も受け付けます。これは、ハーネス ID など、プロバイダー単位の登録メタデータを OpenAI設定が必要とする場合の高度なオプションです。
|
||||
|
||||
```python
|
||||
from agents import (
|
||||
Agent,
|
||||
OpenAIAgentRegistrationConfig,
|
||||
OpenAIProvider,
|
||||
RunConfig,
|
||||
Runner,
|
||||
)
|
||||
|
||||
provider = OpenAIProvider(
|
||||
use_responses_websocket=True,
|
||||
agent_registration=OpenAIAgentRegistrationConfig(harness_id="your-harness-id"),
|
||||
)
|
||||
|
||||
agent = Agent(name="Assistant")
|
||||
result = await Runner.run(
|
||||
agent,
|
||||
"Hello",
|
||||
run_config=RunConfig(model_provider=provider),
|
||||
)
|
||||
```
|
||||
|
||||
#### `MultiProvider` を使用した高度なルーティング
|
||||
|
||||
プレフィックスに基づくモデルルーティングが必要な場合、たとえば 1 回の実行で `openai/...` と `any-llm/...` のモデル名を組み合わせる場合は、[`MultiProvider`][agents.MultiProvider] を使用し、そこで `openai_use_responses_websocket=True` を設定します。
|
||||
|
||||
`MultiProvider` は、従来からの 2 つのデフォルト動作を維持します。
|
||||
|
||||
- `openai/...` は OpenAIプロバイダーのエイリアスとして扱われるため、`openai/gpt-4.1` はモデル `gpt-4.1` としてルーティングされます。
|
||||
- 不明なプレフィックスは、そのまま渡されるのではなく `UserError` を発生させます。
|
||||
|
||||
OpenAI互換エンドポイントが、名前空間付きのモデル ID を文字どおり受け取ることを想定している場合は、パススルー動作を明示的に有効にしてください。WebSocket を有効にした設定では、`MultiProvider` にも `openai_use_responses_websocket=True` を設定したままにします。
|
||||
|
||||
```python
|
||||
from agents import Agent, MultiProvider, RunConfig, Runner
|
||||
|
||||
provider = MultiProvider(
|
||||
openai_base_url="https://openrouter.ai/api/v1",
|
||||
openai_api_key="...",
|
||||
openai_use_responses_websocket=True,
|
||||
openai_prefix_mode="model_id",
|
||||
unknown_prefix_mode="model_id",
|
||||
)
|
||||
|
||||
agent = Agent(
|
||||
name="Assistant",
|
||||
instructions="Be concise.",
|
||||
model="openai/gpt-4.1",
|
||||
)
|
||||
|
||||
result = await Runner.run(
|
||||
agent,
|
||||
"Hello",
|
||||
run_config=RunConfig(model_provider=provider),
|
||||
)
|
||||
```
|
||||
|
||||
バックエンドが文字どおりの `openai/...` 文字列を想定している場合は、`openai_prefix_mode="model_id"` を使用します。バックエンドが `openrouter/openai/gpt-4.1-mini` など、その他の名前空間付きモデル ID を想定している場合は、`unknown_prefix_mode="model_id"` を使用します。これらのオプションは、WebSocket トランスポート以外の `MultiProvider` でも機能します。この例で WebSocket が有効になっているのは、このセクションで説明しているトランスポート設定の一部であるためです。同じオプションは [`responses_websocket_session()`][agents.responses_websocket_session] でも利用できます。
|
||||
|
||||
`MultiProvider` を介してルーティングする際に同じプロバイダー単位の登録メタデータが必要な場合は、`openai_agent_registration=OpenAIAgentRegistrationConfig(...)` を渡します。これは基盤となる OpenAIプロバイダーへ転送されます。
|
||||
|
||||
カスタムの OpenAI互換エンドポイントまたはプロキシを使用する場合、WebSocket トランスポートには互換性のある WebSocket `/responses` エンドポイントも必要です。そのような設定では、`websocket_base_url` を明示的に設定する必要がある場合があります。
|
||||
|
||||
#### 注意事項
|
||||
|
||||
- これは WebSocket トランスポート経由の Responses API であり、[Realtime API](../realtime/guide.md)ではありません。Chat Completions、および Responses WebSocket `/responses` エンドポイントをサポートしていない OpenAI以外のプロバイダーには適用されません。
|
||||
- 環境にまだ存在しない場合は、`websockets` パッケージをインストールしてください。
|
||||
- WebSocket トランスポートを有効にした後、[`Runner.run_streamed()`][agents.run.Runner.run_streamed] を直接使用できます。複数ターンのワークフローで、ターン間およびネストされた agent-as-tool 呼び出し間で同じ WebSocket 接続を再利用する場合は、[`responses_websocket_session()`][agents.responses_websocket_session] ヘルパーを推奨します。[エージェントの実行](../running_agents.md)ガイドおよび [`examples/basic/stream_ws.py`](https://github.com/openai/openai-agents-python/tree/main/examples/basic/stream_ws.py) を参照してください。
|
||||
- 長時間の推論ターンやレイテンシーが急増するネットワークでは、`responses_websocket_options` を使用して WebSocket のキープアライブ動作をカスタマイズします。遅延した pong フレームを許容するには `ping_timeout` を増やすか、ping を有効にしたままハートビートのタイムアウトを無効にするには `ping_timeout=None` を設定します。WebSocket のレイテンシーより信頼性が重要な場合は、HTTP/SSE トランスポートを優先してください。
|
||||
- デフォルトでは、SDK は受信メッセージのサイズ制限を無効にします(`max_size=None`)。プロキシの背後で長期間実行されるエージェントプロセスや、メモリ制約のあるコンテナでは、`responses_websocket_options={"max_size": 8 * 1024 * 1024}` を設定して、メッセージごとのメモリ使用量に上限を設けます。
|
||||
|
||||
### ホスト型マルチエージェント(試験的)
|
||||
|
||||
OpenAI Responses API のホスト型マルチエージェントベータでは、GPT-5.6 のルートモデルがサーバー上でホストされるサブエージェントを作成し、調整できます。Agents SDKは通常の `Runner` を引き続き使用できます。ホスト型オーケストレーションはサービス上で行われ、開発者が定義した関数ツールはアプリケーション内で実行されます。
|
||||
|
||||
この統合は試験的であり、ローカル関数の出力を `response.inject` を使用してアクティブなホスト型エージェントへ返せるように、Responses WebSocket トランスポートを使用します。`client.beta.responses.connect` を公開するベータビルドを含む `openai[realtime]>=2.45.0` が必要です。インターフェースとベータ項目のスキーマは、一般提供までに変更される可能性があります。
|
||||
|
||||
#### モデルの設定
|
||||
|
||||
試験的モジュールからモデルをインポートし、SDK の `Agent` に割り当てます。
|
||||
|
||||
```python
|
||||
from agents import Agent
|
||||
from agents.extensions.experimental.hosted_multi_agent import OpenAIHostedMultiAgentModel
|
||||
|
||||
agent = Agent(
|
||||
name="Research coordinator",
|
||||
instructions="Delegate independent research tasks, then synthesize the findings.",
|
||||
model=OpenAIHostedMultiAgentModel(model="gpt-5.6-sol", config={"max_concurrent_subagents": 3}),
|
||||
)
|
||||
```
|
||||
|
||||
`OpenAIHostedMultiAgentModel` を構築すると、`multi_agent.enabled` が有効になり、`OpenAI-Beta: responses_multi_agent=v1` WebSocket ヘッダーが送信されます。`openai_client` が指定されていない場合、モデルはデフォルトの OpenAIクライアントを使用します。`max_concurrent_subagents` を省略すると、サービスのデフォルト値が使用されます。
|
||||
|
||||
#### ローカル関数ツール
|
||||
|
||||
すべてのホスト型エージェントは、リクエストに設定されたモデルとツールを共有します。どのホスト型エージェントが関数を呼び出すかは、Responses API が決定します。通常の SDK Runner は関数をローカルで実行し、同じ呼び出し ID を持つ `function_call_output` をアクティブな WebSocket レスポンスへ注入します。これにより、サービスは元のホスト型呼び出し元を再開できます。関数の実行には、引き続き Runner の通常のガードレール、フック、失敗変換が適用されます。SDK のツール承認による中断はサポートされません。`needs_approval` 設定が `False` ではない関数ツールは、リクエスト送信前に拒否されます。
|
||||
|
||||
ツールで呼び出し元を認識したロギングまたは認可が必要な場合は、`get_hosted_agent_metadata()` を使用します。
|
||||
|
||||
```python
|
||||
from typing import Any
|
||||
|
||||
from agents import function_tool
|
||||
from agents.extensions.experimental.hosted_multi_agent import get_hosted_agent_metadata
|
||||
from agents.tool_context import ToolContext
|
||||
|
||||
@function_tool
|
||||
def lookup_document(ctx: ToolContext[Any], section: str) -> str:
|
||||
metadata = get_hosted_agent_metadata(ctx)
|
||||
caller = metadata.agent_name if metadata else "unknown"
|
||||
print(f"tool caller: {caller}; call ID: {ctx.tool_call_id}")
|
||||
return f"Contents for {section}"
|
||||
```
|
||||
|
||||
ホスト型エージェントの名前は観測用メタデータであり、ローカルルーティングの仕組みではありません。SDK が提供する呼び出し ID を使用して出力をルーティングしてください。副作用を伴うツールでは、その呼び出し ID を冪等性キーとして使用し、ツールの実行前または実行中に、必要な認可をアプリケーションコードで適用してください。このモデルでは `needs_approval` を使用しないでください。ツールの引数と出力は Responses API の境界を越えます。
|
||||
|
||||
#### 出力とストリーミングの動作
|
||||
|
||||
フェーズが `final_answer` であり、`/root` に帰属するメッセージのみが通常の最終メッセージになります。試験的アダプターは、サブエージェントのメッセージとホスト型オーケストレーションのレコードを高レベルの `RunResult` から除外します。SDK がそれらのレコードをローカル関数として実行することはありません。
|
||||
|
||||
raw ストリーミングでは、ホスト型出力項目や `response.inject.created` 確認応答を含むベータ版 Responses イベントが引き続き公開されます。アダプターは、関数呼び出しの準備が整うと、1 つのアクティブなプロバイダーレスポンスを SDK から見える論理的なモデルターンに分割します。その後、Runner が出力を生成すると、同じプロバイダーレスポンスを再開します。帰属情報を確認するには、raw のホスト型項目または `ToolContext` とともに `get_hosted_agent_metadata()` を使用します。
|
||||
|
||||
#### SDK オーケストレーションとの関係
|
||||
|
||||
ホスト型マルチエージェントは、SDK のハンドオフおよび agents-as-tools とは別のものです。
|
||||
|
||||
- ホスト型マルチエージェントは、OpenAIサービス上でサブエージェントを作成します。アプリケーションがそれらのサブエージェントを作成またはスケジュールすることはありません。
|
||||
- SDK のハンドオフは、アクティブなローカル SDK `Agent` を変更します。この試験的モデルを使用している場合、すべてのホスト型エージェントが同じハンドオフツールを受け取り、所有権の競合が発生するため、ハンドオフは拒否されます。
|
||||
- Agents-as-tools は引き続き利用できますが、使用するとクライアント側とサーバー側のオーケストレーションがネストされます。追加のレイテンシー、コスト、ツールの公開範囲を慎重に評価してください。
|
||||
|
||||
#### 現在の制限事項
|
||||
|
||||
試験的モデルは、`reasoning.summary`、`max_tool_calls`、および呼び出し元が指定する `multi_agent` または `betas` のオーバーライドを拒否します。Responses の `/compact` エンドポイントはベータ版でサポートされていません。ただし、サービスが各ホスト型エージェントのコンテキストを個別に自動圧縮するため、明示的な `context_management.compact_threshold` は使用できます。
|
||||
|
||||
1 つの `OpenAIHostedMultiAgentModel` インスタンスが同時に保持できるアクティブなホスト型レスポンスは、最大 1 つです。ローカル関数の出力を待機している間に実行が放棄された場合は、`await model.close()` を呼び出して WebSocket を解放してください。実行中のホスト型レスポンスを別のプロセスまたはイベントループで復元することは、現在サポートされていません。
|
||||
|
||||
基盤となる Responses API ベータの動作については、[OpenAI マルチエージェントガイド](https://developers.openai.com/api/docs/guides/tools-multi-agent)を参照してください。非ストリーミングおよびストリーミングでの SDK の使用方法については、[`examples/agent_patterns/hosted_multi_agent_beta.py`](https://github.com/openai/openai-agents-python/tree/main/examples/agent_patterns/hosted_multi_agent_beta.py) を参照してください。
|
||||
|
||||
## OpenAI以外のモデル
|
||||
|
||||
OpenAI以外のプロバイダーが必要な場合は、SDK の組み込みプロバイダー統合ポイントから始めてください。多くの設定では、サードパーティ製アダプターを追加しなくても、これで十分です。各パターンのコード例は、[examples/model_providers](https://github.com/openai/openai-agents-python/tree/main/examples/model_providers/) にあります。
|
||||
|
||||
### OpenAI以外のプロバイダーの統合方法
|
||||
|
||||
| アプローチ | 使用する場合 | 適用範囲 |
|
||||
| --- | --- | --- |
|
||||
| [`set_default_openai_client`][agents.set_default_openai_client] | 1 つの OpenAI互換エンドポイントを、ほとんどまたはすべてのエージェントのデフォルトにする場合 | グローバルデフォルト |
|
||||
| [`ModelProvider`][agents.models.interface.ModelProvider] | 1 つのカスタムプロバイダーを単一の実行に適用する場合 | 実行単位 |
|
||||
| [`Agent.model`][agents.agent.Agent.model] | エージェントごとに異なるプロバイダーまたは具体的なモデルオブジェクトが必要な場合 | エージェント単位 |
|
||||
| サードパーティ製アダプター | 組み込みの方法では提供されない、アダプター管理のプロバイダーカバレッジまたはルーティングが必要な場合 | [サードパーティ製アダプター](#third-party-adapters)を参照 |
|
||||
|
||||
次の組み込み方法を使用して、他の LLM プロバイダーを統合できます。
|
||||
|
||||
1. [`set_default_openai_client`][agents.set_default_openai_client] は、`AsyncOpenAI` のインスタンスを LLM クライアントとしてグローバルに使用する場合に役立ちます。これは、LLM プロバイダーが OpenAI互換 API エンドポイントを持ち、`base_url` と `api_key` を設定できる場合に使用します。設定可能なコード例については、[examples/model_providers/custom_example_global.py](https://github.com/openai/openai-agents-python/tree/main/examples/model_providers/custom_example_global.py) を参照してください。
|
||||
2. [`ModelProvider`][agents.models.interface.ModelProvider] は `Runner.run` レベルで使用します。これにより、「この実行内のすべてのエージェントでカスタムモデルプロバイダーを使用する」と指定できます。設定可能なコード例については、[examples/model_providers/custom_example_provider.py](https://github.com/openai/openai-agents-python/tree/main/examples/model_providers/custom_example_provider.py) を参照してください。
|
||||
3. [`Agent.model`][agents.agent.Agent.model] を使用すると、特定の Agent インスタンスにモデルを指定できます。これにより、エージェントごとに異なるプロバイダーを組み合わせて使用できます。設定可能なコード例については、[examples/model_providers/custom_example_agent.py](https://github.com/openai/openai-agents-python/tree/main/examples/model_providers/custom_example_agent.py) を参照してください。
|
||||
|
||||
`platform.openai.com` の API キーを持っていない場合は、`set_tracing_disabled()` を使用してトレーシングを無効にするか、[別のトレーシングプロセッサー](../tracing.md)を設定することを推奨します。
|
||||
|
||||
``` python
|
||||
from agents import Agent, AsyncOpenAI, OpenAIChatCompletionsModel, set_tracing_disabled
|
||||
|
||||
set_tracing_disabled(disabled=True)
|
||||
|
||||
client = AsyncOpenAI(api_key="Api_Key", base_url="Base URL of Provider")
|
||||
model = OpenAIChatCompletionsModel(model="Model_Name", openai_client=client)
|
||||
|
||||
agent= Agent(name="Helping Agent", instructions="You are a Helping Agent", model=model)
|
||||
```
|
||||
|
||||
!!! note
|
||||
|
||||
これらのコード例では、多くの LLM プロバイダーがまだ Responses API をサポートしていないため、Chat Completions API/モデルを使用しています。LLM プロバイダーが Responses API をサポートしている場合は、Responses の使用を推奨します。
|
||||
|
||||
## 単一ワークフローでのモデルの組み合わせ
|
||||
|
||||
単一のワークフロー内で、エージェントごとに異なるモデルを使用したい場合があります。たとえば、トリアージには小型で高速なモデルを使用し、複雑なタスクには大型で高性能なモデルを使用できます。[`Agent`][agents.Agent] を設定する場合、次のいずれかの方法で特定のモデルを選択できます。
|
||||
|
||||
1. モデル名を渡します。
|
||||
2. 任意のモデル名と、その名前を Model インスタンスにマッピングできる [`ModelProvider`][agents.models.interface.ModelProvider] を渡します。
|
||||
3. [`Model`][agents.models.interface.Model] の実装を直接指定します。
|
||||
|
||||
!!! note
|
||||
|
||||
SDK は [`OpenAIResponsesModel`][agents.models.openai_responses.OpenAIResponsesModel] と [`OpenAIChatCompletionsModel`][agents.models.openai_chatcompletions.OpenAIChatCompletionsModel] の両方の形式をサポートしていますが、2 つの形式でサポートされる機能とツールのセットが異なるため、ワークフローごとに 1 つのモデル形式を使用することを推奨します。ワークフローで複数のモデル形式を組み合わせる必要がある場合は、使用するすべての機能が両方で利用できることを確認してください。
|
||||
|
||||
```python
|
||||
from agents import Agent, Runner, AsyncOpenAI, OpenAIChatCompletionsModel
|
||||
import asyncio
|
||||
|
||||
spanish_agent = Agent(
|
||||
name="Spanish agent",
|
||||
instructions="You only speak Spanish.",
|
||||
model="gpt-5-mini", # (1)!
|
||||
)
|
||||
|
||||
english_agent = Agent(
|
||||
name="English agent",
|
||||
instructions="You only speak English",
|
||||
model=OpenAIChatCompletionsModel( # (2)!
|
||||
model="gpt-5-nano",
|
||||
openai_client=AsyncOpenAI()
|
||||
),
|
||||
)
|
||||
|
||||
triage_agent = Agent(
|
||||
name="Triage agent",
|
||||
instructions="Handoff to the appropriate agent based on the language of the request.",
|
||||
handoffs=[spanish_agent, english_agent],
|
||||
model="gpt-5.6-sol",
|
||||
)
|
||||
|
||||
async def main():
|
||||
result = await Runner.run(triage_agent, input="Hola, ¿cómo estás?")
|
||||
print(result.final_output)
|
||||
```
|
||||
|
||||
1. OpenAIモデルの名前を直接設定します。
|
||||
2. [`Model`][agents.models.interface.Model] の実装を指定します。
|
||||
|
||||
エージェントで使用するモデルをさらに設定する場合は、temperature などの任意のモデル設定パラメーターを提供する [`ModelSettings`][agents.models.interface.ModelSettings] を渡せます。
|
||||
|
||||
```python
|
||||
from agents import Agent, ModelSettings
|
||||
|
||||
english_agent = Agent(
|
||||
name="English agent",
|
||||
instructions="You only speak English",
|
||||
model="gpt-4.1",
|
||||
model_settings=ModelSettings(temperature=0.1),
|
||||
)
|
||||
```
|
||||
|
||||
## OpenAI Responses の高度な設定
|
||||
|
||||
OpenAI Responses パスを使用していて、より詳細な制御が必要な場合は、`ModelSettings` から始めてください。
|
||||
|
||||
### 一般的な高度な `ModelSettings` オプション
|
||||
|
||||
OpenAI Responses API を使用する場合、いくつかのリクエストフィールドにはすでに対応する `ModelSettings` フィールドが用意されているため、それらに `extra_args` を使用する必要はありません。
|
||||
|
||||
- `parallel_tool_calls`: 同じターンで複数のツール呼び出しを許可または禁止します。
|
||||
- `truncation`: コンテキストが上限を超える場合に失敗する代わりに、Responses API が最も古い会話項目を削除できるようにするには、`"auto"` を設定します。
|
||||
- `store`: 生成されたレスポンスを、後で取得できるようにサーバー側へ保存するかどうかを制御します。これは、レスポンス ID に依存する後続ワークフローや、`store=False` の場合にローカル入力へのフォールバックが必要になる可能性があるセッション圧縮フローに関係します。
|
||||
- `context_management`: `compact_threshold` を使用した Responses 圧縮など、サーバー側のコンテキスト処理を設定します。
|
||||
- `prompt_cache_retention`: 以前のモデルファミリー向けに、たとえば
|
||||
`"24h"` を使用して保持期間の延長を設定します。
|
||||
- `prompt_cache_options`: 暗黙的または明示的なプロンプトキャッシュを選択し、GPT-5.6 では `"30m"` のキャッシュ TTL を設定します。
|
||||
- `response_include`: `web_search_call.action.sources`、`file_search_call.results`、`reasoning.encrypted_content` など、より詳細なレスポンスペイロードをリクエストします。
|
||||
- `top_logprobs`: 出力テキストについて、上位トークンの logprobs をリクエストします。SDK は `message.output_text.logprobs` も自動的に追加します。
|
||||
- `retry`: モデル呼び出しに対して Runner 管理の再試行設定を有効にします。[Runner 管理の再試行](#runner-managed-retries)を参照してください。
|
||||
|
||||
```python
|
||||
from agents import Agent, ModelSettings
|
||||
|
||||
research_agent = Agent(
|
||||
name="Research agent",
|
||||
model="gpt-5.6-sol",
|
||||
model_settings=ModelSettings(
|
||||
parallel_tool_calls=False,
|
||||
truncation="auto",
|
||||
store=True,
|
||||
context_management=[{"type": "compaction", "compact_threshold": 200000}],
|
||||
prompt_cache_options={"mode": "explicit", "ttl": "30m"},
|
||||
response_include=["web_search_call.action.sources"],
|
||||
top_logprobs=5,
|
||||
),
|
||||
)
|
||||
```
|
||||
|
||||
明示的なプロンプトキャッシュでは、再利用可能なプレフィックスの末尾にあるコンテンツ部分へブレークポイントを追加します。同じ `ModelSettings.prompt_cache_options` フィールドが Responses と Chat Completions のリクエストに渡され、Chat Completions コンバーターは、テキスト、画像、音声、ファイルのコンテンツ部分にあるブレークポイントを保持します。
|
||||
|
||||
```python
|
||||
from agents import Runner
|
||||
|
||||
result = await Runner.run(
|
||||
research_agent,
|
||||
[
|
||||
{
|
||||
"role": "user",
|
||||
"content": [
|
||||
{
|
||||
"type": "input_text",
|
||||
"text": "Reusable background material...",
|
||||
"prompt_cache_breakpoint": {"mode": "explicit"},
|
||||
},
|
||||
{
|
||||
"type": "input_text",
|
||||
"text": "Analyze the latest question.",
|
||||
},
|
||||
],
|
||||
}
|
||||
],
|
||||
)
|
||||
```
|
||||
|
||||
`prompt_cache_retention` は、従来の保持制御を使用する以前のモデルファミリーでも引き続き
|
||||
利用できます。直接指定する `ModelSettings` フィールドと同じキーを
|
||||
`extra_args` に含めないでください。
|
||||
|
||||
`store=False` を設定すると、Responses API はそのレスポンスを後でサーバー側から取得できる状態で保持しません。これはステートレスまたはゼロデータ保持形式のフローに役立ちますが、通常であればレスポンス ID を再利用する機能が、代わりにローカルで管理された状態へ依存する必要があることも意味します。たとえば、最後のレスポンスが保存されていない場合、[`OpenAIResponsesCompactionSession`][agents.memory.openai_responses_compaction_session.OpenAIResponsesCompactionSession] は、デフォルトの `"auto"` 圧縮パスを入力ベースの圧縮へ切り替えます。[セッションガイド](../sessions/index.md#openai-responses-compaction-sessions)を参照してください。
|
||||
|
||||
サーバー側の圧縮は、[`OpenAIResponsesCompactionSession`][agents.memory.openai_responses_compaction_session.OpenAIResponsesCompactionSession] とは異なります。`context_management=[{"type": "compaction", "compact_threshold": ...}]` は Responses API リクエストごとに送信され、レンダリングされたコンテキストがしきい値を超えると、API はレスポンスの一部として圧縮項目を出力できます。`OpenAIResponsesCompactionSession` は、ターン間で独立した `responses.compact` エンドポイントを呼び出し、ローカルのセッション履歴を書き換えます。
|
||||
|
||||
### `extra_args` の受け渡し
|
||||
|
||||
SDK がまだトップレベルで直接公開していない、プロバイダー固有または新しいリクエストフィールドが必要な場合は、`extra_args` を使用します。
|
||||
|
||||
また、OpenAIの Responses API を使用する場合、[他にもいくつかの任意パラメーターがあります](https://platform.openai.com/docs/api-reference/responses/create)(たとえば `user`、`service_tier` など)。トップレベルで利用できない場合は、`extra_args` を使用して渡すこともできます。同じリクエストフィールドを、直接指定する `ModelSettings` フィールドでも設定しないでください。
|
||||
|
||||
```python
|
||||
from agents import Agent, ModelSettings
|
||||
|
||||
english_agent = Agent(
|
||||
name="English agent",
|
||||
instructions="You only speak English",
|
||||
model="gpt-4.1",
|
||||
model_settings=ModelSettings(
|
||||
temperature=0.1,
|
||||
extra_args={"service_tier": "flex", "user": "user_12345"},
|
||||
),
|
||||
)
|
||||
```
|
||||
|
||||
## Runner 管理の再試行
|
||||
|
||||
再試行は実行時のみ有効で、オプトイン方式です。`ModelSettings(retry=...)` を設定し、再試行ポリシーが再試行を選択しない限り、SDK は一般的なモデルリクエストを再試行しません。
|
||||
|
||||
```python
|
||||
from agents import Agent, ModelRetrySettings, ModelSettings, retry_policies
|
||||
|
||||
agent = Agent(
|
||||
name="Assistant",
|
||||
model="gpt-5.6-sol",
|
||||
model_settings=ModelSettings(
|
||||
retry=ModelRetrySettings(
|
||||
max_retries=4,
|
||||
backoff={
|
||||
"initial_delay": 0.5,
|
||||
"max_delay": 5.0,
|
||||
"multiplier": 2.0,
|
||||
"jitter": True,
|
||||
},
|
||||
policy=retry_policies.any(
|
||||
retry_policies.provider_suggested(),
|
||||
retry_policies.retry_after(),
|
||||
retry_policies.network_error(),
|
||||
retry_policies.http_status([408, 409, 429, 500, 502, 503, 504]),
|
||||
),
|
||||
)
|
||||
),
|
||||
)
|
||||
```
|
||||
|
||||
`ModelRetrySettings` には 3 つのフィールドがあります。
|
||||
|
||||
<div class="field-table" markdown="1">
|
||||
|
||||
| フィールド | 型 | 注記 |
|
||||
| --- | --- | --- |
|
||||
| `max_retries` | `int | None` | 最初のリクエスト後に許可される再試行回数です。 |
|
||||
| `backoff` | `ModelRetryBackoffSettings | dict | None` | ポリシーが明示的な遅延を返さずに再試行する場合の、デフォルトの遅延戦略です。`backoff.max_delay` は、計算されたこのバックオフ遅延のみに上限を設定します。ポリシーが返す明示的な遅延や retry-after ヒントには上限を設定しません。 |
|
||||
| `policy` | `RetryPolicy | None` | 再試行するかどうかを決定するコールバックです。このフィールドは実行時のみ有効で、シリアライズされません。 |
|
||||
|
||||
</div>
|
||||
|
||||
再試行ポリシーは、次の情報を持つ [`RetryPolicyContext`][agents.retry.RetryPolicyContext] を受け取ります。
|
||||
|
||||
- `attempt` と `max_retries`: 試行回数を考慮した判断に使用できます。
|
||||
- `stream`: ストリーミング動作と非ストリーミング動作を分岐できます。
|
||||
- `error`: raw の内容を調べるために使用します。
|
||||
- `normalized`: `status_code`、`retry_after`、`error_code`、`is_network_error`、`is_timeout`、`is_abort` などの正規化された情報です。
|
||||
- `provider_advice`: 基盤となるモデルアダプターが再試行に関するガイダンスを提供できる場合に設定されます。
|
||||
|
||||
ポリシーは、次のいずれかを返せます。
|
||||
|
||||
- 単純な再試行判断を行う場合は、`True` / `False`。
|
||||
- 遅延を上書きするか、診断用の理由を付加する場合は、[`RetryDecision`][agents.retry.RetryDecision]。
|
||||
|
||||
SDK は、`retry_policies` でそのまま利用できるヘルパーを公開しています。
|
||||
|
||||
| ヘルパー | 動作 |
|
||||
| --- | --- |
|
||||
| `retry_policies.never()` | 常に再試行を行いません。 |
|
||||
| `retry_policies.provider_suggested()` | 利用可能な場合、プロバイダーの再試行アドバイスに従います。 |
|
||||
| `retry_policies.network_error()` | 一時的なトランスポート障害およびタイムアウト障害に一致します。 |
|
||||
| `retry_policies.http_status([...])` | 選択された HTTP ステータスコードに一致します。 |
|
||||
| `retry_policies.retry_after()` | retry-after ヒントが利用可能な場合にのみ、その遅延を使用して再試行します。このヘルパーは retry-after 値を明示的なポリシー遅延として扱うため、`backoff.max_delay` による上限は適用されません。 |
|
||||
| `retry_policies.any(...)` | ネストされたポリシーのいずれかが再試行を選択した場合に再試行します。 |
|
||||
| `retry_policies.all(...)` | ネストされたすべてのポリシーが再試行を選択した場合にのみ再試行します。 |
|
||||
|
||||
ポリシーを組み合わせる場合、プロバイダーが再実行の安全性を区別できるときに、プロバイダーによる拒否と再実行の安全性に関する承認を維持できるため、`provider_suggested()` が最も安全な最初の基本要素です。
|
||||
|
||||
##### 安全性の境界
|
||||
|
||||
一部の失敗は自動的に再試行されません。
|
||||
|
||||
- 中止エラー。
|
||||
- プロバイダーのアドバイスにより、再実行が安全ではないと示されたリクエスト。
|
||||
- 出力がすでに開始され、再実行が安全でなくなる状態になったストリーミング実行。
|
||||
|
||||
`previous_response_id` または `conversation_id` を使用するステートフルな後続リクエストも、より保守的に扱われます。これらのリクエストでは、`network_error()` や `http_status([500])` など、プロバイダー由来ではない条件だけでは不十分です。再試行ポリシーには、通常 `retry_policies.provider_suggested()` を通じて、プロバイダーから再実行が安全であることの承認を含める必要があります。
|
||||
|
||||
##### Runner とエージェントのマージ動作
|
||||
|
||||
`retry` は、Runner レベルとエージェントレベルの `ModelSettings` の間でディープマージされます。
|
||||
|
||||
- エージェントは `retry.max_retries` のみを上書きし、Runner の `policy` を継承できます。
|
||||
- エージェントは `retry.backoff` の一部のみを上書きし、Runner の他のバックオフフィールドを維持できます。
|
||||
- `policy` は実行時のみ有効であるため、シリアライズされた `ModelSettings` には `max_retries` と `backoff` が保持されますが、コールバック自体は含まれません。
|
||||
|
||||
より詳しいコード例については、[`examples/basic/retry.py`](https://github.com/openai/openai-agents-python/tree/main/examples/basic/retry.py) および[アダプターを使用した再試行のコード例](https://github.com/openai/openai-agents-python/tree/main/examples/basic/retry_litellm.py)を参照してください。
|
||||
|
||||
## OpenAI以外のプロバイダーのトラブルシューティング
|
||||
|
||||
### トレーシングクライアントの 401 エラー
|
||||
|
||||
トレーシングに関連するエラーが発生する場合、トレースが OpenAIサーバーへアップロードされる一方で、OpenAI API キーがないことが原因です。解決方法は 3 つあります。
|
||||
|
||||
1. トレーシングを完全に無効にします: [`set_tracing_disabled(True)`][agents.set_tracing_disabled]。
|
||||
2. トレーシング用の OpenAIキーを設定します: [`set_tracing_export_api_key(...)`][agents.set_tracing_export_api_key]。この API キーはトレースのアップロードにのみ使用され、[platform.openai.com](https://platform.openai.com/) から取得したものである必要があります。
|
||||
3. OpenAI以外のトレースプロセッサーを使用します。[トレーシングのドキュメント](../tracing.md#custom-tracing-processors)を参照してください。
|
||||
|
||||
### Responses API のサポート
|
||||
|
||||
SDK はデフォルトで Responses API を使用しますが、他の多くの LLM プロバイダーはまだサポートしていません。その結果、404 または同様の問題が発生する場合があります。解決方法は 2 つあります。
|
||||
|
||||
1. [`set_default_openai_api("chat_completions")`][agents.set_default_openai_api] を呼び出します。これは、環境変数を通じて `OPENAI_API_KEY` と `OPENAI_BASE_URL` を設定している場合に機能します。
|
||||
2. [`OpenAIChatCompletionsModel`][agents.models.openai_chatcompletions.OpenAIChatCompletionsModel] を使用します。コード例は[こちら](https://github.com/openai/openai-agents-python/tree/main/examples/model_providers/)にあります。
|
||||
|
||||
### Chat Completions の互換性オプション
|
||||
|
||||
Chat Completions を介してルーティングする場合、SDK は、`previous_response_id`、`conversation_id`、プロンプト、テキスト以外を含むツール出力など、Chat Completions では送信できない Responses 専用フィールドを暗黙的に削除することで互換性を維持します。開発中にこれらの不一致を早期にエラーにしたい場合は、OpenAIプロバイダーで厳密な機能検証を有効にします。
|
||||
|
||||
```python
|
||||
from agents import Agent, OpenAIProvider, RunConfig, Runner
|
||||
|
||||
provider = OpenAIProvider(
|
||||
use_responses=False,
|
||||
strict_feature_validation=True,
|
||||
)
|
||||
|
||||
agent = Agent(name="Assistant")
|
||||
result = await Runner.run(
|
||||
agent,
|
||||
"Hello",
|
||||
run_config=RunConfig(model_provider=provider),
|
||||
)
|
||||
```
|
||||
|
||||
[`MultiProvider`][agents.MultiProvider] を使用する場合は、代わりに `openai_strict_feature_validation=True` を渡します。
|
||||
|
||||
一部の OpenAI互換 Chat Completions プロバイダーは、SDK が増分処理するには十分な信頼性がないチャンク形式で、ツール呼び出しの差分をストリーミングします。その場合は、ストリーミングされたツール呼び出しのバッファリングを有効にし、プロバイダーのストリームが終了した後にのみ SDK がツール呼び出しを出力するようにします。
|
||||
|
||||
```python
|
||||
from agents import OpenAIProvider
|
||||
|
||||
provider = OpenAIProvider(
|
||||
use_responses=False,
|
||||
buffer_streamed_tool_calls=True,
|
||||
)
|
||||
```
|
||||
|
||||
[`MultiProvider`][agents.MultiProvider] では、`openai_buffer_streamed_tool_calls=True` を使用します。
|
||||
|
||||
### structured outputs のサポート
|
||||
|
||||
一部のモデルプロバイダーは、[structured outputs](https://platform.openai.com/docs/guides/structured-outputs)をサポートしていません。その結果、次のようなエラーが発生することがあります。
|
||||
|
||||
```
|
||||
|
||||
BadRequestError: Error code: 400 - {'error': {'message': "'response_format.type' : value is not one of the allowed values ['text','json_object']", 'type': 'invalid_request_error'}}
|
||||
|
||||
```
|
||||
|
||||
これは一部のモデルプロバイダーの制約です。JSON 出力には対応していますが、出力に使用する `json_schema` を指定できません。この問題の修正に取り組んでいますが、JSON スキーマ出力をサポートするプロバイダーを利用することを推奨します。そうしないと、不正な形式の JSON によってアプリが頻繁に動作しなくなる可能性があります。
|
||||
|
||||
## プロバイダー間でのモデルの組み合わせ
|
||||
|
||||
モデルプロバイダー間の機能差を把握しておく必要があります。そうしないと、エラーが発生する可能性があります。たとえば、OpenAIは structured outputs、マルチモーダル入力、ホスト型のファイル検索と Web 検索をサポートしていますが、他の多くのプロバイダーはこれらの機能をサポートしていません。次の制限に注意してください。
|
||||
|
||||
- サポートされていない `tools` を、それらを解釈できないプロバイダーへ送信しないでください
|
||||
- テキスト専用モデルを呼び出す前に、マルチモーダル入力を除外してください
|
||||
- 構造化された JSON 出力をサポートしていないプロバイダーでは、無効な JSON が生成される場合があることに注意してください。
|
||||
|
||||
## サードパーティ製アダプター
|
||||
|
||||
SDK の組み込みプロバイダー統合ポイントでは不十分な場合にのみ、サードパーティ製アダプターを使用してください。この SDK で OpenAIモデルのみを使用する場合は、Any-LLM や LiteLLM ではなく、組み込みの [`OpenAIResponsesModel`][agents.models.openai_responses.OpenAIResponsesModel] パスを優先してください。サードパーティ製アダプターは、OpenAIモデルと OpenAI以外のプロバイダーを組み合わせる必要がある場合、または組み込みの方法では提供されない、アダプター管理のプロバイダーカバレッジやルーティングが必要な場合に使用します。アダプターは SDK と上流のモデルプロバイダーの間に互換性レイヤーを追加するため、機能のサポートとリクエストのセマンティクスはプロバイダーによって異なる場合があります。SDK には現在、ベストエフォート方式のベータ版アダプター統合として Any-LLM と LiteLLM が含まれています。
|
||||
|
||||
### Any-LLM
|
||||
|
||||
Any-LLM のサポートは、Any-LLM が管理するプロバイダーカバレッジまたはルーティングが必要な場合に向けて、ベストエフォート方式のベータ版として含まれています。
|
||||
|
||||
上流のプロバイダーパスに応じて、Any-LLM は Responses API、Chat Completions 互換 API、またはプロバイダー固有の互換性レイヤーを使用する場合があります。
|
||||
|
||||
Any-LLM が必要な場合は、`openai-agents[any-llm]` をインストールし、[`examples/model_providers/any_llm_auto.py`](https://github.com/openai/openai-agents-python/tree/main/examples/model_providers/any_llm_auto.py) または [`examples/model_providers/any_llm_provider.py`](https://github.com/openai/openai-agents-python/tree/main/examples/model_providers/any_llm_provider.py) から始めてください。[`MultiProvider`][agents.MultiProvider] で `any-llm/...` モデル名を使用するか、`AnyLLMModel` を直接インスタンス化するか、実行スコープで `AnyLLMProvider` を使用できます。モデルサーフェスを明示的に固定する必要がある場合は、`AnyLLMModel` の構築時に `api="responses"` または `api="chat_completions"` を渡します。
|
||||
|
||||
Any-LLM は引き続きサードパーティ製アダプターレイヤーであるため、プロバイダーの依存関係と機能差は SDK ではなく、上流の Any-LLM によって定義されます。上流のプロバイダーが使用量指標を返す場合、それらは自動的に伝播されます。ただし、ストリーミング対応の Chat Completions バックエンドでは、使用量チャンクを出力する前に `ModelSettings(include_usage=True)` が必要になる場合があります。structured outputs、ツール呼び出し、使用量レポート、または Responses 固有の動作に依存する場合は、デプロイ予定の正確なプロバイダーバックエンドを検証してください。
|
||||
|
||||
### LiteLLM
|
||||
|
||||
LiteLLM のサポートは、LiteLLM 固有のプロバイダーカバレッジまたはルーティングが必要な場合に向けて、ベストエフォート方式のベータ版として含まれています。
|
||||
|
||||
LiteLLM が必要な場合は、`openai-agents[litellm]` をインストールし、[`examples/model_providers/litellm_auto.py`](https://github.com/openai/openai-agents-python/tree/main/examples/model_providers/litellm_auto.py) または [`examples/model_providers/litellm_provider.py`](https://github.com/openai/openai-agents-python/tree/main/examples/model_providers/litellm_provider.py) から始めてください。`litellm/...` モデル名を使用するか、[`LitellmModel`][agents.extensions.models.litellm_model.LitellmModel] を直接インスタンス化できます。
|
||||
|
||||
LiteLLM を基盤とする一部のプロバイダーは、デフォルトでは SDK の使用量指標を設定しません。使用量レポートが必要な場合は、`ModelSettings(include_usage=True)` を渡してください。また、structured outputs、ツール呼び出し、使用量レポート、またはアダプター固有のルーティング動作に依存する場合は、デプロイ予定の正確なプロバイダーバックエンドを検証してください。
|
||||
@@ -0,0 +1,13 @@
|
||||
---
|
||||
search:
|
||||
exclude: true
|
||||
---
|
||||
# LiteLLM
|
||||
|
||||
<script>
|
||||
window.location.replace("../#third-party-adapters");
|
||||
</script>
|
||||
|
||||
このページは [Models のサードパーティアダプターセクション](index.md#third-party-adapters) に移動しました。
|
||||
|
||||
自動的にリダイレクトされない場合は、上記のリンクを使用してください。
|
||||
@@ -0,0 +1,64 @@
|
||||
---
|
||||
search:
|
||||
exclude: true
|
||||
---
|
||||
# エージェントオーケストレーション
|
||||
|
||||
オーケストレーションとは、アプリ内でのエージェントの流れを指します。どのエージェントを、どの順序で実行し、次に何が起こるかをどのように決定するか、ということです。エージェントをオーケストレーションする主な方法は 2 つあります:
|
||||
|
||||
1. LLM に判断を任せる:LLM の知能を使って計画と推論を行い、それに基づいて取る手順を決定します。
|
||||
2. コードによるオーケストレーション:コードでエージェントの流れを決定します。
|
||||
|
||||
これらのパターンは組み合わせることができます。それぞれにトレードオフがあり、以下で説明します。
|
||||
|
||||
## LLM によるオーケストレーション
|
||||
|
||||
エージェントとは、instructions、tools、ハンドオフを備えた LLM です。つまり、自由度の高いタスクが与えられた場合、LLM は、tools を使ってアクションを実行しデータを取得し、ハンドオフを使ってサブエージェントにタスクを委任しながら、そのタスクへの取り組み方を自律的に計画できます。たとえば、リサーチエージェントには次のようなツールを備えられます:
|
||||
|
||||
- オンラインで情報を見つけるための Web 検索
|
||||
- 独自データや接続先を検索するためのファイル検索と取得
|
||||
- コンピューター上でアクションを実行するためのコンピュータ操作
|
||||
- データ分析を行うためのコード実行
|
||||
- 計画、レポート作成などに優れた専門エージェントへのハンドオフ。
|
||||
|
||||
### コア SDK パターン
|
||||
|
||||
Python SDK では、次の 2 つのオーケストレーションパターンが最もよく登場します:
|
||||
|
||||
| パターン | 仕組み | 最適な場合 |
|
||||
| --- | --- | --- |
|
||||
| Agents as tools | マネージャーエージェントが会話の制御を維持し、`Agent.as_tool()` を通じて専門エージェントを呼び出します。 | 1 つのエージェントに最終回答を担わせたい場合、複数の専門エージェントからの出力を統合したい場合、または共通のガードレールを 1 か所で適用したい場合。 |
|
||||
| ハンドオフ | トリアージエージェントが会話を専門エージェントにルーティングし、その専門エージェントがそのターンの残りでアクティブなエージェントになります。 | 専門エージェントに直接応答させたい場合、プロンプトを焦点の絞られた状態に保ちたい場合、またはマネージャーが結果を説明することなく instructions を切り替えたい場合。 |
|
||||
|
||||
専門エージェントが範囲の限定されたサブタスクを支援するべきだが、ユーザー向けの会話を引き継ぐべきではない場合は、 **agents as tools** を使用します。ルーティング自体がワークフローの一部であり、選ばれた専門エージェントにインタラクションの次の部分を担わせたい場合は、 **ハンドオフ** を使用します。
|
||||
|
||||
この 2 つを組み合わせることもできます。トリアージエージェントが専門エージェントにハンドオフし、その専門エージェントがさらに狭いサブタスクのために他のエージェントをツールとして呼び出すこともできます。
|
||||
|
||||
このパターンは、タスクの自由度が高く、LLM の知能に頼りたい場合に最適です。ここで最も重要な戦術は次のとおりです:
|
||||
|
||||
1. 優れたプロンプトに投資します。利用できるツール、その使い方、そしてエージェントが従うべきパラメーターを明確にします。
|
||||
2. アプリを監視し、反復改善します。どこで問題が起こるかを確認し、プロンプトを改善します。
|
||||
3. エージェントが内省して改善できるようにします。たとえば、ループ内で実行して自己批評させる、またはエラーメッセージを提供して改善させます。
|
||||
4. 何でも得意であることを期待される汎用エージェントではなく、1 つのタスクに秀でた専門エージェントを用意します。
|
||||
5. [evals](https://platform.openai.com/docs/guides/evals) に投資します。これにより、エージェントをトレーニングして改善し、タスクの遂行能力を高めることができます。
|
||||
|
||||
このスタイルのオーケストレーションを支えるコア SDK の基本コンポーネントを知りたい場合は、[ツール](tools.md)、[ハンドオフ](handoffs.md)、[エージェントの実行](running_agents.md) から始めてください。
|
||||
|
||||
## コードによるオーケストレーション
|
||||
|
||||
LLM によるオーケストレーションは強力ですが、コードによるオーケストレーションは、速度、コスト、パフォーマンスの観点でタスクをより決定論的で予測可能にします。ここでの一般的なパターンは次のとおりです:
|
||||
|
||||
- [structured outputs](https://platform.openai.com/docs/guides/structured-outputs) を使って、コードで検査できる適切な形式のデータを生成します。たとえば、エージェントにタスクをいくつかのカテゴリーに分類させ、そのカテゴリーに基づいて次のエージェントを選択できます。
|
||||
- 複数のエージェントをチェーンし、あるエージェントの出力を次のエージェントの入力に変換します。ブログ記事を書くようなタスクを一連のステップに分解できます - リサーチする、アウトラインを書く、ブログ記事を書く、批評し、それから改善します。
|
||||
- タスクを実行するエージェントを `while` ループ内で、評価してフィードバックを提供するエージェントと一緒に実行し、評価者が出力が特定の基準を満たしたと言うまで続けます。
|
||||
- 複数のエージェントを並列に実行します。たとえば、`asyncio.gather` のような Python の基本コンポーネントを使います。これは、互いに依存しない複数のタスクがある場合に高速化に役立ちます。
|
||||
|
||||
[`examples/agent_patterns`](https://github.com/openai/openai-agents-python/tree/main/examples/agent_patterns) には多数のコード例があります。
|
||||
|
||||
## 関連ガイド
|
||||
|
||||
- 構成パターンとエージェント設定については、[エージェント](agents.md) を参照してください。
|
||||
- `Agent.as_tool()` とマネージャースタイルのオーケストレーションについては、[ツール](tools.md#agents-as-tools) を参照してください。
|
||||
- 専門エージェント間の委任については、[ハンドオフ](handoffs.md) を参照してください。
|
||||
- 実行ごとのオーケストレーション制御と会話状態については、[エージェントの実行](running_agents.md) を参照してください。
|
||||
- 最小限のエンドツーエンドのハンドオフ例については、[クイックスタート](quickstart.md) を参照してください。
|
||||
@@ -0,0 +1,225 @@
|
||||
---
|
||||
search:
|
||||
exclude: true
|
||||
---
|
||||
# クイックスタート
|
||||
|
||||
## プロジェクトと仮想環境の作成
|
||||
|
||||
これは一度だけ行えば十分です。
|
||||
|
||||
```bash
|
||||
mkdir my_project
|
||||
cd my_project
|
||||
python -m venv .venv
|
||||
```
|
||||
|
||||
### 仮想環境の有効化
|
||||
|
||||
新しいターミナルセッションを開始するたびに行ってください。
|
||||
|
||||
macOS または Linux の場合:
|
||||
|
||||
```bash
|
||||
source .venv/bin/activate
|
||||
```
|
||||
|
||||
Windows の場合:
|
||||
|
||||
```cmd
|
||||
.venv\Scripts\activate
|
||||
```
|
||||
|
||||
### Agents SDK のインストール
|
||||
|
||||
```bash
|
||||
pip install openai-agents # or `uv add openai-agents`, etc
|
||||
```
|
||||
|
||||
### OpenAI API キーの設定
|
||||
|
||||
まだ持っていない場合は、[こちらの手順](https://platform.openai.com/docs/quickstart#create-and-export-an-api-key)に従って OpenAI API キーを作成してください。
|
||||
|
||||
以下のコマンドは、現在のターミナルセッションにキーを設定します。
|
||||
|
||||
macOS または Linux の場合:
|
||||
|
||||
```bash
|
||||
export OPENAI_API_KEY=sk-...
|
||||
```
|
||||
|
||||
Windows PowerShell の場合:
|
||||
|
||||
```powershell
|
||||
$env:OPENAI_API_KEY = "sk-..."
|
||||
```
|
||||
|
||||
Windows コマンドプロンプトの場合:
|
||||
|
||||
```cmd
|
||||
set "OPENAI_API_KEY=sk-..."
|
||||
```
|
||||
|
||||
## 最初のエージェントの作成
|
||||
|
||||
エージェントは、instructions、名前、および特定のモデルなどの任意の設定で定義します。
|
||||
|
||||
```python
|
||||
from agents import Agent
|
||||
|
||||
agent = Agent(
|
||||
name="History Tutor",
|
||||
instructions="You answer history questions clearly and concisely.",
|
||||
)
|
||||
```
|
||||
|
||||
## 最初のエージェントの実行
|
||||
|
||||
[`Runner`][agents.run.Runner] を使用してエージェントを実行し、[`RunResult`][agents.result.RunResult] を取得します。
|
||||
|
||||
```python
|
||||
import asyncio
|
||||
from agents import Agent, Runner
|
||||
|
||||
agent = Agent(
|
||||
name="History Tutor",
|
||||
instructions="You answer history questions clearly and concisely.",
|
||||
)
|
||||
|
||||
async def main():
|
||||
result = await Runner.run(agent, "When did the Roman Empire fall?")
|
||||
print(result.final_output)
|
||||
|
||||
if __name__ == "__main__":
|
||||
asyncio.run(main())
|
||||
```
|
||||
|
||||
2 回目のターンでは、`result.to_input_list()` を `Runner.run(...)` に戻して渡すか、[セッション](sessions/index.md)をアタッチするか、`conversation_id` / `previous_response_id` で OpenAI によりサーバー側で管理される状態を再利用できます。[エージェントの実行](running_agents.md)ガイドでは、これらのアプローチを比較しています。
|
||||
|
||||
次の目安を使ってください:
|
||||
|
||||
| 実現したいこと... | まず使うもの... |
|
||||
| --- | --- |
|
||||
| 完全な手動制御とプロバイダー非依存の履歴 | `result.to_input_list()` |
|
||||
| SDK に履歴の読み込みと保存を任せる | [`session=...`](sessions/index.md) |
|
||||
| OpenAI 管理のサーバー側継続 | `previous_response_id` または `conversation_id` |
|
||||
|
||||
トレードオフと正確な挙動については、[エージェントの実行](running_agents.md#choose-a-memory-strategy)を参照してください。
|
||||
|
||||
タスクが主にプロンプト、ツール、会話状態で完結する場合は、シンプルな `Agent` と `Runner` を使います。エージェントが分離されたワークスペース内の実ファイルを検査または変更する必要がある場合は、[Sandbox エージェントのクイックスタート](sandbox_agents.md)に進んでください。
|
||||
|
||||
## エージェントへのツールの付与
|
||||
|
||||
エージェントにツールを与えることで、情報を調べたりアクションを実行したりできます。
|
||||
|
||||
```python
|
||||
import asyncio
|
||||
from agents import Agent, Runner, function_tool
|
||||
|
||||
|
||||
@function_tool
|
||||
def history_fun_fact() -> str:
|
||||
"""Return a short history fact."""
|
||||
return "Sharks are older than trees."
|
||||
|
||||
|
||||
agent = Agent(
|
||||
name="History Tutor",
|
||||
instructions="Answer history questions clearly. Use history_fun_fact when it helps.",
|
||||
tools=[history_fun_fact],
|
||||
)
|
||||
|
||||
|
||||
async def main():
|
||||
result = await Runner.run(
|
||||
agent,
|
||||
"Tell me something surprising about ancient life on Earth.",
|
||||
)
|
||||
print(result.final_output)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
asyncio.run(main())
|
||||
```
|
||||
|
||||
## さらにいくつかのエージェントの追加
|
||||
|
||||
マルチエージェントパターンを選ぶ前に、最終回答の主導権を誰が持つべきかを決めてください。
|
||||
|
||||
- **ハンドオフ**: スペシャリストが、そのターンの該当部分について会話を引き継ぎます。
|
||||
- **Agents as tools**: オーケストレーターが制御を維持し、スペシャリストをツールとして呼び出します。
|
||||
|
||||
このクイックスタートでは、最初の例として最も短いため、 **ハンドオフ** で続けます。マネージャースタイルのパターンについては、[エージェントオーケストレーション](multi_agent.md)と[ツール: agents as tools](tools.md#agents-as-tools)を参照してください。
|
||||
|
||||
追加のエージェントも同じ方法で定義できます。`handoff_description` は、いつ委譲すべきかについて、ルーティングエージェントに追加のコンテキストを提供します。
|
||||
|
||||
```python
|
||||
from agents import Agent
|
||||
|
||||
history_tutor_agent = Agent(
|
||||
name="History Tutor",
|
||||
handoff_description="Specialist agent for historical questions",
|
||||
instructions="You answer history questions clearly and concisely.",
|
||||
)
|
||||
|
||||
math_tutor_agent = Agent(
|
||||
name="Math Tutor",
|
||||
handoff_description="Specialist agent for math questions",
|
||||
instructions="You explain math step by step and include worked examples.",
|
||||
)
|
||||
```
|
||||
|
||||
## ハンドオフの定義
|
||||
|
||||
エージェントには、タスクを解決する際に選択できるハンドオフ先の選択肢の一覧を定義できます。
|
||||
|
||||
```python
|
||||
triage_agent = Agent(
|
||||
name="Triage Agent",
|
||||
instructions="Route each homework question to the right specialist.",
|
||||
handoffs=[history_tutor_agent, math_tutor_agent],
|
||||
)
|
||||
```
|
||||
|
||||
## エージェントオーケストレーションの実行
|
||||
|
||||
ランナーは、個々のエージェントの実行、すべてのハンドオフ、すべてのツール呼び出しを処理します。
|
||||
|
||||
```python
|
||||
import asyncio
|
||||
from agents import Runner
|
||||
|
||||
|
||||
async def main():
|
||||
result = await Runner.run(
|
||||
triage_agent,
|
||||
"Who was the first president of the United States?",
|
||||
)
|
||||
print(result.final_output)
|
||||
print(f"Answered by: {result.last_agent.name}")
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
asyncio.run(main())
|
||||
```
|
||||
|
||||
## 参考コード例
|
||||
|
||||
このリポジトリには、同じ主要パターンに対応する完全なスクリプトが含まれています:
|
||||
|
||||
- [`examples/basic/hello_world.py`](https://github.com/openai/openai-agents-python/tree/main/examples/basic/hello_world.py) は最初の実行の例です。
|
||||
- [`examples/basic/tools.py`](https://github.com/openai/openai-agents-python/tree/main/examples/basic/tools.py) は関数ツールの例です。
|
||||
- [`examples/agent_patterns/routing.py`](https://github.com/openai/openai-agents-python/tree/main/examples/agent_patterns/routing.py) はマルチエージェントルーティングの例です。
|
||||
|
||||
## トレースの表示
|
||||
|
||||
エージェントの実行中に何が起きたかを確認するには、[OpenAI ダッシュボードのトレースビューアー](https://platform.openai.com/traces)に移動して、エージェント実行のトレースを表示してください。
|
||||
|
||||
## 次のステップ
|
||||
|
||||
より複雑なエージェント型フローの構築方法を学びましょう:
|
||||
|
||||
- [エージェント](agents.md)の設定方法について学びます。
|
||||
- [エージェントの実行](running_agents.md)と[セッション](sessions/index.md)について学びます。
|
||||
- 作業を実際のワークスペース内で行う必要がある場合は、[Sandbox エージェント](sandbox_agents.md)について学びます。
|
||||
- [ツール](tools.md)、[ガードレール](guardrails.md)、[モデル](models/index.md)について学びます。
|
||||
@@ -0,0 +1,348 @@
|
||||
---
|
||||
search:
|
||||
exclude: true
|
||||
---
|
||||
# Realtime エージェントガイド
|
||||
|
||||
このガイドでは、 OpenAI Agents SDK の realtime レイヤーが OpenAI Realtime API にどのように対応するか、および Python SDK がその上に追加する挙動について説明します。
|
||||
|
||||
!!! note "はじめに"
|
||||
|
||||
デフォルトの Python パスを使いたい場合は、まず [クイックスタート](quickstart.md) を読んでください。アプリでサーバー側 WebSocket または SIP のどちらを使うべきかを判断している場合は、 [Realtime トランスポート](transport.md) を読んでください。ブラウザー WebRTC トランスポートは Python SDK には含まれていません。
|
||||
|
||||
## 概要
|
||||
|
||||
Realtime エージェントは Realtime API への長寿命の接続を開いたままにするため、モデルはテキストと音声を段階的に処理し、音声出力をストリーミングし、ツールを呼び出し、中断を処理できます。ターンごとに新しいリクエストを再開始する必要はありません。
|
||||
|
||||
主な SDK コンポーネントは次のとおりです。
|
||||
|
||||
- **RealtimeAgent**: 1 つの realtime 専門エージェント向けの instructions、tools、出力ガードレール、ハンドオフ
|
||||
- **RealtimeRunner**: 開始エージェントを realtime トランスポートに接続するセッションファクトリ
|
||||
- **RealtimeSession**: 入力を送信し、イベントを受信し、履歴を追跡し、ツールを実行するライブセッション
|
||||
- **RealtimeModel**: トランスポート抽象化。デフォルトは OpenAI のサーバー側 WebSocket 実装です。
|
||||
|
||||
## セッションライフサイクル
|
||||
|
||||
一般的な realtime セッションは次のようになります。
|
||||
|
||||
1. 1 つ以上の `RealtimeAgent` を作成します。
|
||||
2. 開始エージェントを指定して `RealtimeRunner` を作成します。
|
||||
3. `await runner.run()` を呼び出して `RealtimeSession` を取得します。
|
||||
4. `async with session:` または `await session.enter()` でセッションに入ります。
|
||||
5. `send_message()` または `send_audio()` でユーザー入力を送信します。
|
||||
6. 会話が終了するまでセッションイベントを反復処理します。
|
||||
|
||||
テキストのみの実行とは異なり、 `runner.run()` は最終的な実行結果をすぐには生成しません。ローカル履歴、バックグラウンドでのツール実行、ガードレール状態、アクティブなエージェント設定をトランスポート層と同期し続けるライブセッションオブジェクトを返します。
|
||||
|
||||
デフォルトでは、 `RealtimeRunner` は `OpenAIRealtimeWebSocketModel` を使用するため、デフォルトの Python パスは Realtime API へのサーバー側 WebSocket 接続です。別の `RealtimeModel` を渡した場合でも、接続の仕組みは変わる可能性がありますが、同じセッションライフサイクルとエージェント機能が引き続き適用されます。
|
||||
|
||||
## エージェントとセッション設定
|
||||
|
||||
`RealtimeAgent` は通常の `Agent` 型より意図的に機能範囲が絞られています。
|
||||
|
||||
- モデル選択はエージェントごとではなく、セッションレベルで設定されます。
|
||||
- Structured outputs はサポートされていません。
|
||||
- voice は設定できますが、セッションがすでに発話音声を生成した後は変更できません。
|
||||
- instructions、関数ツール、ハンドオフ、フック、出力ガードレールはすべて引き続き機能します。
|
||||
|
||||
`RealtimeSessionModelSettings` は、新しいネストされた `audio` 設定と、古いフラットなエイリアスの両方をサポートします。新しいコードではネストされた形式を推奨し、新しい realtime エージェントでは `gpt-realtime-2.1` から始めてください。
|
||||
|
||||
```python
|
||||
runner = RealtimeRunner(
|
||||
starting_agent=agent,
|
||||
config={
|
||||
"model_settings": {
|
||||
"model_name": "gpt-realtime-2.1",
|
||||
"audio": {
|
||||
"input": {
|
||||
"format": "pcm16",
|
||||
"transcription": {"model": "gpt-4o-mini-transcribe"},
|
||||
"turn_detection": {"type": "semantic_vad", "interrupt_response": True},
|
||||
},
|
||||
"output": {"format": "pcm16", "voice": "ash"},
|
||||
},
|
||||
"tool_choice": "auto",
|
||||
}
|
||||
},
|
||||
)
|
||||
```
|
||||
|
||||
有用なセッションレベル設定には次のものがあります。
|
||||
|
||||
- `audio.input.format`, `audio.output.format`
|
||||
- `audio.input.transcription`
|
||||
- `audio.input.noise_reduction`
|
||||
- `audio.input.turn_detection`
|
||||
- `audio.output.voice`, `audio.output.speed`
|
||||
- `output_modalities`
|
||||
- `tool_choice`
|
||||
- `prompt`
|
||||
- `tracing`
|
||||
|
||||
`RealtimeRunner(config=...)` の有用な run レベル設定には次のものがあります。
|
||||
|
||||
- `async_tool_calls`
|
||||
- `output_guardrails`
|
||||
- `guardrails_settings.debounce_text_length`
|
||||
- `tool_error_formatter`
|
||||
- `tracing_disabled`
|
||||
|
||||
完全な型付きインターフェースについては、 [`RealtimeRunConfig`][agents.realtime.config.RealtimeRunConfig] と [`RealtimeSessionModelSettings`][agents.realtime.config.RealtimeSessionModelSettings] を参照してください。
|
||||
|
||||
## 入力と出力
|
||||
|
||||
### テキストと構造化ユーザーメッセージ
|
||||
|
||||
プレーンテキストまたは構造化された realtime メッセージには、 [`session.send_message()`][agents.realtime.session.RealtimeSession.send_message] を使用します。
|
||||
|
||||
```python
|
||||
from agents.realtime import RealtimeUserInputMessage
|
||||
|
||||
await session.send_message("Summarize what we discussed so far.")
|
||||
|
||||
message: RealtimeUserInputMessage = {
|
||||
"type": "message",
|
||||
"role": "user",
|
||||
"content": [
|
||||
{"type": "input_text", "text": "Describe this image."},
|
||||
{"type": "input_image", "image_url": image_data_url, "detail": "high"},
|
||||
],
|
||||
}
|
||||
await session.send_message(message)
|
||||
```
|
||||
|
||||
構造化メッセージは、 realtime 会話に画像入力を含める主な方法です。 [`examples/realtime/app/server.py`](https://github.com/openai/openai-agents-python/tree/main/examples/realtime/app/server.py) のサンプル Web デモでは、この方法で `input_image` メッセージを転送しています。
|
||||
|
||||
### 音声入力
|
||||
|
||||
生の音声バイトをストリーミングするには、 [`session.send_audio()`][agents.realtime.session.RealtimeSession.send_audio] を使用します。
|
||||
|
||||
```python
|
||||
await session.send_audio(audio_bytes)
|
||||
```
|
||||
|
||||
サーバー側のターン検出が無効な場合、ターン境界をマークする責任は開発者側にあります。高レベルの便利な方法は次のとおりです。
|
||||
|
||||
```python
|
||||
await session.send_audio(audio_bytes, commit=True)
|
||||
```
|
||||
|
||||
より低レベルの制御が必要な場合は、基盤となるモデルトランスポートを通じて `input_audio_buffer.commit` などの raw クライアントイベントを送信することもできます。
|
||||
|
||||
### 手動応答制御
|
||||
|
||||
`session.send_message()` は高レベルパスを使ってユーザー入力を送信し、応答を開始します。生の音声バッファリングは、すべての設定で同じことを自動的に行うわけでは **ありません** 。
|
||||
|
||||
Realtime API レベルでは、手動のターン制御とは、 raw `session.update` で `turn_detection` をクリアし、その後に `input_audio_buffer.commit` と `response.create` を自分で送信することを意味します。
|
||||
|
||||
ターンを手動で管理している場合は、モデルのトランスポートを通じて raw クライアントイベントを送信できます。
|
||||
|
||||
```python
|
||||
from agents.realtime.model_inputs import RealtimeModelSendRawMessage
|
||||
|
||||
await session.model.send_event(
|
||||
RealtimeModelSendRawMessage(
|
||||
message={
|
||||
"type": "response.create",
|
||||
}
|
||||
)
|
||||
)
|
||||
```
|
||||
|
||||
このパターンは次の場合に有用です。
|
||||
|
||||
- `turn_detection` が無効で、モデルがいつ応答すべきかを自分で決めたい場合
|
||||
- 応答をトリガーする前にユーザー入力を検査またはゲートしたい場合
|
||||
- アウトオブバンド応答にカスタムプロンプトが必要な場合
|
||||
|
||||
[`examples/realtime/twilio_sip/server.py`](https://github.com/openai/openai-agents-python/tree/main/examples/realtime/twilio_sip/server.py) の SIP の例では、開始時の挨拶を強制するために raw `response.create` を使用しています。
|
||||
|
||||
## イベント、履歴、中断
|
||||
|
||||
`RealtimeSession` は、必要なときには raw モデルイベントも転送しつつ、より高レベルの SDK イベントを発行します。
|
||||
|
||||
有用性の高いセッションイベントには次のものがあります。
|
||||
|
||||
- `audio`, `audio_end`, `audio_interrupted`
|
||||
- `agent_start`, `agent_end`
|
||||
- `tool_start`, `tool_end`, `tool_approval_required`
|
||||
- `handoff`
|
||||
- `history_added`, `history_updated`
|
||||
- `guardrail_tripped`
|
||||
- `input_audio_timeout_triggered`
|
||||
- `error`
|
||||
- `raw_model_event`
|
||||
|
||||
UI 状態に最も有用なイベントは通常 `history_added` と `history_updated` です。これらは、ユーザーメッセージ、アシスタントメッセージ、ツール呼び出しを含む、セッションのローカル履歴を `RealtimeItem` オブジェクトとして公開します。
|
||||
|
||||
### 中断と再生トラッキング
|
||||
|
||||
ユーザーがアシスタントを中断すると、セッションは `audio_interrupted` を発行し、履歴を更新して、サーバー側の会話がユーザーが実際に聞いた内容と一致し続けるようにします。
|
||||
|
||||
低レイテンシーのローカル再生では、デフォルトの再生トラッカーで十分なことが多いです。リモート再生や遅延再生のシナリオ、特にテレフォニーでは、 [`RealtimePlaybackTracker`][agents.realtime.model.RealtimePlaybackTracker] を使用してください。これにより、生成された音声がすべてすでに聞かれたと仮定するのではなく、実際の再生進行に基づいて中断時の切り詰めが行われます。
|
||||
|
||||
[`examples/realtime/twilio/twilio_handler.py`](https://github.com/openai/openai-agents-python/tree/main/examples/realtime/twilio/twilio_handler.py) の Twilio の例はこのパターンを示しています。
|
||||
|
||||
## ツール、承認、ハンドオフ、ガードレール
|
||||
|
||||
### 関数ツール
|
||||
|
||||
Realtime エージェントはライブ会話中に関数ツールをサポートします。
|
||||
|
||||
```python
|
||||
from agents import function_tool
|
||||
|
||||
|
||||
@function_tool
|
||||
def get_weather(city: str) -> str:
|
||||
"""Get current weather for a city."""
|
||||
return f"The weather in {city} is sunny, 72F."
|
||||
|
||||
|
||||
agent = RealtimeAgent(
|
||||
name="Assistant",
|
||||
instructions="You can answer weather questions.",
|
||||
tools=[get_weather],
|
||||
)
|
||||
```
|
||||
|
||||
### ツール承認
|
||||
|
||||
関数ツールは実行前に人間の承認を要求できます。その場合、セッションは `tool_approval_required` を発行し、 `approve_tool_call()` または `reject_tool_call()` を呼び出すまでツール実行を一時停止します。
|
||||
|
||||
ツールに入力ガードレールもある場合、それらのガードレールは承認後、実行の直前に実行されます。承認イベントが発行される前にそれらを実行するには、 `RealtimeRunner(..., config={"tool_execution": {"pre_approval_tool_input_guardrails": True}})` で runner を作成します。この事前承認チェックに合格した呼び出しも、承認後、実行前にもう一度チェックされます。
|
||||
|
||||
```python
|
||||
async for event in session:
|
||||
if event.type == "tool_approval_required":
|
||||
await session.approve_tool_call(event.call_id)
|
||||
```
|
||||
|
||||
具体的なサーバー側承認ループについては、 [`examples/realtime/app/server.py`](https://github.com/openai/openai-agents-python/tree/main/examples/realtime/app/server.py) を参照してください。人間参加型のドキュメントも、 [人間を介した処理](../human_in_the_loop.md) でこのフローを参照しています。
|
||||
|
||||
### ハンドオフ
|
||||
|
||||
Realtime ハンドオフにより、 1 つのエージェントがライブ会話を別の専門エージェントへ転送できます。
|
||||
|
||||
```python
|
||||
from agents.realtime import RealtimeAgent, realtime_handoff
|
||||
|
||||
billing_agent = RealtimeAgent(
|
||||
name="Billing Support",
|
||||
instructions="You specialize in billing issues.",
|
||||
)
|
||||
|
||||
main_agent = RealtimeAgent(
|
||||
name="Customer Service",
|
||||
instructions="Triage the request and hand off when needed.",
|
||||
handoffs=[
|
||||
realtime_handoff(
|
||||
billing_agent,
|
||||
tool_description_override="Transfer to billing support",
|
||||
)
|
||||
],
|
||||
)
|
||||
```
|
||||
|
||||
そのままの `RealtimeAgent` ハンドオフは自動的にラップされ、 `realtime_handoff(...)` では名前、説明、検証、コールバック、利用可否をカスタマイズできます。Realtime ハンドオフは通常のハンドオフの `input_filter` を **サポートしていません** 。
|
||||
|
||||
### ガードレール
|
||||
|
||||
Realtime エージェントは、エージェント応答に対する出力ガードレールと、関数ツール呼び出しに対する入力ガードレールをサポートします。出力ガードレールは、部分的なトークンごとではなく、デバウンスされたトランスクリプトの蓄積に対して実行され、例外を発生させる代わりに `guardrail_tripped` を発行します。
|
||||
|
||||
```python
|
||||
from agents.guardrail import GuardrailFunctionOutput, OutputGuardrail
|
||||
|
||||
|
||||
def sensitive_data_check(context, agent, output):
|
||||
return GuardrailFunctionOutput(
|
||||
tripwire_triggered="password" in output,
|
||||
output_info=None,
|
||||
)
|
||||
|
||||
|
||||
agent = RealtimeAgent(
|
||||
name="Assistant",
|
||||
instructions="...",
|
||||
output_guardrails=[OutputGuardrail(guardrail_function=sensitive_data_check)],
|
||||
)
|
||||
```
|
||||
|
||||
realtime 出力ガードレールが作動すると、セッションはアクティブな応答を中断し、 `response.cancel` を強制し、 `guardrail_tripped` を発行し、作動したガードレールの名前を示す後続のユーザーメッセージを送信して、モデルが代替応答を生成できるようにします。音声プレーヤーはそれでも `audio_interrupted` をリッスンし、ローカル再生をただちに停止する必要があります。これは、ガードレールがデバウンスされたトランスクリプトテキストに対して実行され、トリップワイヤーが作動した時点で一部の音声がすでにバッファリングされている可能性があるためです。
|
||||
|
||||
## SIP とテレフォニー
|
||||
|
||||
Python SDK には、 [`OpenAIRealtimeSIPModel`][agents.realtime.openai_realtime.OpenAIRealtimeSIPModel] を介したファーストクラスの SIP アタッチフローが含まれています。
|
||||
|
||||
Realtime Calls API 経由で通話が到着し、得られた `call_id` にエージェントセッションをアタッチしたい場合に使用します。
|
||||
|
||||
```python
|
||||
from agents.realtime import RealtimeRunner
|
||||
from agents.realtime.openai_realtime import OpenAIRealtimeSIPModel
|
||||
|
||||
runner = RealtimeRunner(starting_agent=agent, model=OpenAIRealtimeSIPModel())
|
||||
|
||||
async with await runner.run(
|
||||
model_config={
|
||||
"call_id": call_id_from_webhook,
|
||||
}
|
||||
) as session:
|
||||
async for event in session:
|
||||
...
|
||||
```
|
||||
|
||||
先に通話を受け付ける必要があり、 accept ペイロードをエージェント由来のセッション設定と一致させたい場合は、 `OpenAIRealtimeSIPModel.build_initial_session_payload(...)` を使用します。完全なフローは [`examples/realtime/twilio_sip/server.py`](https://github.com/openai/openai-agents-python/tree/main/examples/realtime/twilio_sip/server.py) に示されています。
|
||||
|
||||
## 低レベルアクセスとカスタムエンドポイント
|
||||
|
||||
`session.model` を通じて基盤となるトランスポートオブジェクトにアクセスできます。
|
||||
|
||||
次が必要な場合に使用します。
|
||||
|
||||
- `session.model.add_listener(...)` によるカスタムリスナー
|
||||
- `response.create` や `session.update` などの raw クライアントイベント
|
||||
- `model_config` によるカスタムの `url`、 `headers`、 `api_key` 処理
|
||||
- 既存の realtime 通話への `call_id` アタッチ
|
||||
|
||||
`RealtimeModelConfig` は次をサポートします。
|
||||
|
||||
- `api_key`
|
||||
- `url`
|
||||
- `headers`
|
||||
- `initial_model_settings`
|
||||
- `playback_tracker`
|
||||
- `call_id`
|
||||
|
||||
このリポジトリに同梱されている `call_id` のコード例は SIP です。より広範な Realtime API でも、一部のサーバー側制御フローに `call_id` を使用しますが、それらはここでは Python のコード例としてパッケージ化されていません。
|
||||
|
||||
Azure OpenAI に接続する場合は、 GA Realtime エンドポイント URL と明示的なヘッダーを渡します。例:
|
||||
|
||||
```python
|
||||
session = await runner.run(
|
||||
model_config={
|
||||
"url": "wss://<your-resource>.openai.azure.com/openai/v1/realtime?model=<deployment-name>",
|
||||
"headers": {"api-key": "<your-azure-api-key>"},
|
||||
}
|
||||
)
|
||||
```
|
||||
|
||||
トークンベースの認証では、 `headers` に Bearer トークンを使用します。
|
||||
|
||||
```python
|
||||
session = await runner.run(
|
||||
model_config={
|
||||
"url": "wss://<your-resource>.openai.azure.com/openai/v1/realtime?model=<deployment-name>",
|
||||
"headers": {"authorization": f"Bearer {token}"},
|
||||
}
|
||||
)
|
||||
```
|
||||
|
||||
`headers` を渡すと、 SDK は `Authorization` を自動的には追加しません。realtime エージェントでは、従来の beta パス (`/openai/realtime?api-version=...`) は避けてください。
|
||||
|
||||
## 関連資料
|
||||
|
||||
- [Realtime トランスポート](transport.md)
|
||||
- [クイックスタート](quickstart.md)
|
||||
- [OpenAI Realtime 会話](https://developers.openai.com/api/docs/guides/realtime-conversations/)
|
||||
- [OpenAI Realtime サーバー側コントロール](https://developers.openai.com/api/docs/guides/realtime-server-controls/)
|
||||
- [`examples/realtime`](https://github.com/openai/openai-agents-python/tree/main/examples/realtime)
|
||||
@@ -0,0 +1,158 @@
|
||||
---
|
||||
search:
|
||||
exclude: true
|
||||
---
|
||||
# クイックスタート
|
||||
|
||||
Python SDK のリアルタイムエージェントは、WebSocket トランスポート経由の OpenAI Realtime API 上に構築された、サーバー側の低レイテンシーエージェントです。
|
||||
|
||||
!!! note "Python SDK の境界"
|
||||
|
||||
Python SDK は、ブラウザーの WebRTC トランスポートを **提供していません** 。このページでは、サーバー側 WebSocket を介して Python で管理されるリアルタイムセッションのみを扱います。この SDK は、サーバー側のオーケストレーション、ツール、承認、テレフォニー連携に使用してください。併せて [リアルタイムトランスポート](transport.md) も参照してください。
|
||||
|
||||
## 前提条件
|
||||
|
||||
- Python 3.10 以上
|
||||
- OpenAI API キー
|
||||
- OpenAI Agents SDK の基本的な知識
|
||||
|
||||
## インストール
|
||||
|
||||
まだインストールしていない場合は、OpenAI Agents SDK をインストールしてください:
|
||||
|
||||
```bash
|
||||
pip install openai-agents
|
||||
```
|
||||
|
||||
## サーバー側リアルタイムセッションの作成
|
||||
|
||||
### 1. リアルタイムコンポーネントのインポート
|
||||
|
||||
```python
|
||||
import asyncio
|
||||
|
||||
from agents.realtime import RealtimeAgent, RealtimeRunner
|
||||
```
|
||||
|
||||
### 2. 開始エージェントの定義
|
||||
|
||||
```python
|
||||
agent = RealtimeAgent(
|
||||
name="Assistant",
|
||||
instructions="You are a helpful voice assistant. Keep responses short and conversational.",
|
||||
)
|
||||
```
|
||||
|
||||
### 3. ランナーの設定
|
||||
|
||||
新しいコードでは、ネストされた `audio.input` / `audio.output` のセッション設定形式を推奨します。新しいリアルタイムエージェントでは、`gpt-realtime-2.1` から始めてください。
|
||||
|
||||
```python
|
||||
runner = RealtimeRunner(
|
||||
starting_agent=agent,
|
||||
config={
|
||||
"model_settings": {
|
||||
"model_name": "gpt-realtime-2.1",
|
||||
"audio": {
|
||||
"input": {
|
||||
"format": "pcm16",
|
||||
"transcription": {"model": "gpt-4o-mini-transcribe"},
|
||||
"turn_detection": {
|
||||
"type": "semantic_vad",
|
||||
"interrupt_response": True,
|
||||
},
|
||||
},
|
||||
"output": {
|
||||
"format": "pcm16",
|
||||
"voice": "ash",
|
||||
},
|
||||
},
|
||||
}
|
||||
},
|
||||
)
|
||||
```
|
||||
|
||||
### 4. セッションの開始と入力の送信
|
||||
|
||||
`runner.run()` は `RealtimeSession` を返します。セッションコンテキストに入ると接続が開かれます。
|
||||
|
||||
```python
|
||||
async def main() -> None:
|
||||
session = await runner.run()
|
||||
|
||||
async with session:
|
||||
await session.send_message("Say hello in one short sentence.")
|
||||
|
||||
async for event in session:
|
||||
if event.type == "audio":
|
||||
# Forward or play event.audio.data.
|
||||
pass
|
||||
elif event.type == "history_added":
|
||||
print(event.item)
|
||||
elif event.type == "agent_end":
|
||||
# One assistant turn finished.
|
||||
break
|
||||
elif event.type == "error":
|
||||
print(f"Error: {event.error}")
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
asyncio.run(main())
|
||||
```
|
||||
|
||||
`session.send_message()` は、プレーン文字列または構造化されたリアルタイムメッセージのいずれかを受け取ります。生の音声チャンクには、[`session.send_audio()`][agents.realtime.session.RealtimeSession.send_audio] を使用してください。
|
||||
|
||||
## このクイックスタートに含まれない内容
|
||||
|
||||
- マイクのキャプチャおよびスピーカー再生のコード。[`examples/realtime`](https://github.com/openai/openai-agents-python/tree/main/examples/realtime) のリアルタイムのコード例を参照してください。
|
||||
- SIP / テレフォニーのアタッチフロー。[リアルタイムトランスポート](transport.md) と [SIP セクション](guide.md#sip-and-telephony) を参照してください。
|
||||
|
||||
## 主要設定
|
||||
|
||||
基本的なセッションが動作するようになったら、多くの方が次に利用する設定は次のとおりです:
|
||||
|
||||
- `model_name`
|
||||
- `audio.input.format`, `audio.output.format`
|
||||
- `audio.input.transcription`
|
||||
- `audio.input.noise_reduction`
|
||||
- `audio.input.turn_detection`(自動ターン検出用)
|
||||
- `audio.output.voice`
|
||||
- `tool_choice`, `prompt`, `tracing`
|
||||
- `async_tool_calls`, `tool_execution.pre_approval_tool_input_guardrails`, `guardrails_settings.debounce_text_length`, `tool_error_formatter`
|
||||
|
||||
`input_audio_format`、`output_audio_format`、`input_audio_transcription`、`turn_detection` などの古いフラットなエイリアスも引き続き機能しますが、新しいコードではネストされた `audio` 設定が推奨されます。
|
||||
|
||||
手動のターン制御には、[リアルタイムエージェントガイド](guide.md#manual-response-control) で説明されている raw な `session.update` / `input_audio_buffer.commit` / `response.create` フローを使用してください。
|
||||
|
||||
完全なスキーマについては、[`RealtimeRunConfig`][agents.realtime.config.RealtimeRunConfig] および [`RealtimeSessionModelSettings`][agents.realtime.config.RealtimeSessionModelSettings] を参照してください。
|
||||
|
||||
## 接続オプション
|
||||
|
||||
API キーを環境変数に設定してください:
|
||||
|
||||
```bash
|
||||
export OPENAI_API_KEY="your-api-key-here"
|
||||
```
|
||||
|
||||
または、セッションの開始時に直接渡します:
|
||||
|
||||
```python
|
||||
session = await runner.run(model_config={"api_key": "your-api-key"})
|
||||
```
|
||||
|
||||
`model_config` は以下にも対応しています:
|
||||
|
||||
- `url`: カスタム WebSocket エンドポイント
|
||||
- `headers`: カスタムリクエストヘッダー
|
||||
- `call_id`: 既存のリアルタイムコールにアタッチします。このリポジトリでドキュメント化されているアタッチフローは SIP です。
|
||||
- `playback_tracker`: ユーザーが実際に聞いた音声量を報告します
|
||||
|
||||
`headers` を明示的に渡す場合、SDK は `Authorization` ヘッダーを **挿入しません** 。
|
||||
|
||||
Azure OpenAI に接続する場合は、`model_config["url"]` に GA Realtime エンドポイント URL を指定し、明示的なヘッダーも渡してください。リアルタイムエージェントでは、レガシーな beta パス(`/openai/realtime?api-version=...`)の使用は避けてください。詳細については、[リアルタイムエージェントガイド](guide.md#low-level-access-and-custom-endpoints) を参照してください。
|
||||
|
||||
## 次のステップ
|
||||
|
||||
- サーバー側 WebSocket と SIP のどちらを選ぶかを判断するには、[リアルタイムトランスポート](transport.md) をお読みください。
|
||||
- ライフサイクル、構造化入力、承認、ハンドオフ、ガードレール、低レベル制御については、[リアルタイムエージェントガイド](guide.md) をお読みください。
|
||||
- [`examples/realtime`](https://github.com/openai/openai-agents-python/tree/main/examples/realtime) のコード例をご覧ください。
|
||||
@@ -0,0 +1,76 @@
|
||||
---
|
||||
search:
|
||||
exclude: true
|
||||
---
|
||||
# Realtime トランスポート
|
||||
|
||||
このページは、realtime エージェントを Python アプリケーションにどのように組み込むかを判断するために使用してください。
|
||||
|
||||
!!! note "Python SDK の境界"
|
||||
|
||||
Python SDK には、ブラウザー WebRTC トランスポートは含まれて **いません**。このページは、Python SDK のトランスポート選択肢であるサーバー側 WebSocket と SIP アタッチフローのみを扱います。ブラウザー WebRTC は別のプラットフォームトピックであり、公式の [WebRTC による Realtime API](https://developers.openai.com/api/docs/guides/realtime-webrtc/) ガイドに記載されています。
|
||||
|
||||
## 判断ガイド
|
||||
|
||||
| 目的 | はじめに | 理由 |
|
||||
| --- | --- | --- |
|
||||
| サーバー管理の realtime アプリを構築する | [クイックスタート](quickstart.md) | デフォルトの Python パスは、`RealtimeRunner` によって管理されるサーバー側 WebSocket セッションです。 |
|
||||
| 選択すべきトランスポートとデプロイ形態を理解する | このページ | トランスポートやデプロイ形態を決定する前に使用してください。 |
|
||||
| エージェントを電話または SIP 通話にアタッチする | [Realtime ガイド](guide.md) と [`examples/realtime/twilio_sip`](https://github.com/openai/openai-agents-python/tree/main/examples/realtime/twilio_sip) | このリポジトリには、`call_id` によって駆動される SIP アタッチフローが含まれています。 |
|
||||
|
||||
## デフォルトの Python パスであるサーバー側 WebSocket
|
||||
|
||||
カスタム `RealtimeModel` を渡さない限り、`RealtimeRunner` は `OpenAIRealtimeWebSocketModel` を使用します。
|
||||
|
||||
つまり、標準的な Python トポロジーは次のようになります。
|
||||
|
||||
1. Python サービスが `RealtimeRunner` を作成します。
|
||||
2. `await runner.run()` が `RealtimeSession` を返します。
|
||||
3. セッションに入り、テキスト、構造化メッセージ、または音声を送信します。
|
||||
4. `RealtimeSessionEvent` 項目を消費し、音声またはトランスクリプトをアプリケーションに転送します。
|
||||
|
||||
これは、コアデモアプリ、CLI の例、Twilio Media Streams の例で使用されているトポロジーです。
|
||||
|
||||
- [`examples/realtime/app`](https://github.com/openai/openai-agents-python/tree/main/examples/realtime/app)
|
||||
- [`examples/realtime/cli`](https://github.com/openai/openai-agents-python/tree/main/examples/realtime/cli)
|
||||
- [`examples/realtime/twilio`](https://github.com/openai/openai-agents-python/tree/main/examples/realtime/twilio)
|
||||
|
||||
サーバーが音声パイプライン、ツール実行、承認フロー、履歴処理を管理する場合は、このパスを使用してください。
|
||||
|
||||
## テレフォニー向けパスとしての SIP アタッチ
|
||||
|
||||
このリポジトリで説明されているテレフォニーフローでは、Python SDK は `call_id` を介して既存の realtime 通話にアタッチします。
|
||||
|
||||
このトポロジーは次のようになります。
|
||||
|
||||
1. OpenAI が `realtime.call.incoming` などの webhook をサービスに送信します。
|
||||
2. サービスが Realtime Calls API を通じて通話を受け入れます。
|
||||
3. Python サービスが `RealtimeRunner(..., model=OpenAIRealtimeSIPModel())` を開始します。
|
||||
4. セッションは `model_config={"call_id": ...}` で接続し、その後は他の realtime セッションと同様にイベントを処理します。
|
||||
|
||||
これは [`examples/realtime/twilio_sip`](https://github.com/openai/openai-agents-python/tree/main/examples/realtime/twilio_sip) に示されているトポロジーです。
|
||||
|
||||
より広範な Realtime API でも、一部のサーバー側制御パターンで `call_id` を使用しますが、このリポジトリに含まれるアタッチ例は SIP です。
|
||||
|
||||
## この SDK の範囲外であるブラウザー WebRTC
|
||||
|
||||
アプリの主なクライアントが Realtime WebRTC を使用するブラウザーである場合:
|
||||
|
||||
- このリポジトリの Python SDK ドキュメントの範囲外として扱ってください。
|
||||
- クライアント側のフローとイベントモデルについては、公式の [WebRTC による Realtime API](https://developers.openai.com/api/docs/guides/realtime-webrtc/) および [Realtime conversations](https://developers.openai.com/api/docs/guides/realtime-conversations/) ドキュメントを使用してください。
|
||||
- ブラウザー WebRTC クライアントの上にサイドバンドのサーバー接続が必要な場合は、公式の [Realtime server-side controls](https://developers.openai.com/api/docs/guides/realtime-server-controls/) ガイドを使用してください。
|
||||
- このリポジトリが、ブラウザー側の `RTCPeerConnection` 抽象化や、すぐに使えるブラウザー WebRTC サンプルを提供することは期待しないでください。
|
||||
|
||||
このリポジトリには、現在、ブラウザー WebRTC と Python サイドバンドを組み合わせた例も含まれていません。
|
||||
|
||||
## カスタムエンドポイントとアタッチポイント
|
||||
|
||||
[`RealtimeModelConfig`][agents.realtime.model.RealtimeModelConfig] のトランスポート設定サーフェスを使用すると、デフォルトのパスを調整できます。
|
||||
|
||||
- `url`: WebSocket エンドポイントを上書きします
|
||||
- `headers`: Azure 認証ヘッダーなどの明示的なヘッダーを指定します
|
||||
- `api_key`: API キーを直接、またはコールバック経由で渡します
|
||||
- `call_id`: 既存の realtime 通話にアタッチします。このリポジトリで記載されている例は SIP です。
|
||||
- `playback_tracker`: 割り込み処理のために実際の再生進捗を報告します
|
||||
|
||||
トポロジーを選択した後の詳細なライフサイクルと機能サーフェスについては、[Realtime エージェントガイド](guide.md) を参照してください。
|
||||
@@ -0,0 +1,186 @@
|
||||
---
|
||||
search:
|
||||
exclude: true
|
||||
---
|
||||
# リリースプロセス/変更履歴
|
||||
|
||||
このプロジェクトでは、`0.Y.Z` 形式を使用した、セマンティックバージョニングをわずかに変更した方式に従います。先頭の `0` は、SDK が依然として急速に進化していることを示します。各構成要素は次のように更新します。
|
||||
|
||||
## マイナー(`Y`)バージョン
|
||||
|
||||
ベータと明記されていない公開インターフェースに **破壊的変更** がある場合、マイナーバージョン `Y` を増やします。たとえば、`0.0.x` から `0.1.x` への移行には、破壊的変更が含まれる可能性があります。
|
||||
|
||||
破壊的変更を避けたい場合は、プロジェクトでバージョンを `0.0.x` に固定することを推奨します。
|
||||
|
||||
## パッチ(`Z`)バージョン
|
||||
|
||||
破壊的でない変更の場合は、`Z` を増やします。
|
||||
|
||||
- バグ修正
|
||||
- 新機能
|
||||
- 非公開インターフェースの変更
|
||||
- ベータ機能の更新
|
||||
|
||||
## 破壊的変更履歴
|
||||
|
||||
### 0.18.0
|
||||
|
||||
このマイナーリリースには、破壊的変更は **ありません**。マイナーバージョンの更新は、Realtime エージェントのデフォルトモデル更新のみを目的としています。
|
||||
|
||||
主な変更点:
|
||||
|
||||
- Realtime エージェントのデフォルトモデルが `gpt-realtime-2.1` になり、新しい Realtime セットアップでは追加の設定なしで最新の推奨モデルが使用されるようになりました。
|
||||
|
||||
### 0.17.0
|
||||
|
||||
このバージョンでは、サンドボックスでローカルソースを実体化する際、ソースパスが `Manifest.extra_path_grants` の対象でない限り、`LocalFile.src` と `LocalDir.src` は実体化先の `base_dir` 内に保持されます。`base_dir` は、マニフェストの適用時点における SDK プロセスの現在の作業ディレクトリです。相対パスのローカルソースはそのディレクトリを基準に解決され、絶対パスのローカルソースは、すでにそのディレクトリ内にあるか、明示的な許可の対象である必要があります。これにより、ローカルアーティファクトの境界に関する問題が解消されますが、そのベースディレクトリ外にある信頼済みのホストファイルやディレクトリを意図的にサンドボックスワークスペースへコピーするアプリケーションには影響する可能性があります。
|
||||
|
||||
移行するには、`SandboxPathGrant` を使用してマニフェストレベルで信頼済みのホストルートを許可してください。サンドボックスがそれらのファイルを読み取るだけでよい場合は、読み取り専用にすることを推奨します。
|
||||
|
||||
```python
|
||||
from pathlib import Path
|
||||
|
||||
from agents.sandbox import Manifest, SandboxPathGrant
|
||||
from agents.sandbox.entries import Dir, LocalDir
|
||||
|
||||
# This is an absolute host path outside the SDK process base_dir.
|
||||
TRUSTED_DOCS_ROOT = Path("/opt/my-app/docs")
|
||||
|
||||
manifest = Manifest(
|
||||
extra_path_grants=(
|
||||
# This host root is outside the SDK process base_dir, so the manifest must grant it.
|
||||
SandboxPathGrant(path=str(TRUSTED_DOCS_ROOT), read_only=True),
|
||||
),
|
||||
entries={
|
||||
# No grant is needed for local sources that stay under the SDK process base_dir.
|
||||
"fixtures": LocalDir(src=Path("fixtures"), description="Local test fixtures."),
|
||||
# This entry reads from the granted host root and copies it into the sandbox workspace.
|
||||
"docs": LocalDir(src=TRUSTED_DOCS_ROOT, description="Trusted local documents."),
|
||||
# Dir creates a sandbox workspace directory; it does not read from the host filesystem.
|
||||
"output": Dir(description="Generated artifacts."),
|
||||
},
|
||||
)
|
||||
```
|
||||
|
||||
`extra_path_grants` は、信頼済みのアプリケーション設定として扱ってください。アプリケーションが対象のホストパスを事前に承認していない限り、モデル出力やその他の信頼できないマニフェスト入力から許可設定を追加しないでください。
|
||||
|
||||
### 0.16.0
|
||||
|
||||
このバージョンでは、SDK のデフォルトモデルが `gpt-4.1` から `gpt-5.4-mini` に変更されました。これは、モデルを明示的に設定していないエージェントと実行に影響します。新しいデフォルトは GPT-5 モデルであるため、暗黙的なデフォルトモデル設定には、`reasoning.effort="none"` や `verbosity="low"` などの GPT-5 のデフォルト設定が含まれるようになりました。
|
||||
|
||||
以前のデフォルトモデルの動作を維持する必要がある場合は、エージェントまたは実行設定でモデルを明示的に指定するか、`OPENAI_DEFAULT_MODEL` 環境変数を設定してください。
|
||||
|
||||
```python
|
||||
agent = Agent(name="Assistant", model="gpt-4.1")
|
||||
```
|
||||
|
||||
主な変更点:
|
||||
|
||||
- `Runner.run`、`Runner.run_sync`、`Runner.run_streamed` で `max_turns=None` を指定し、ターン数の上限を無効にできるようになりました。
|
||||
- サンドボックスワークスペースのハイドレーションでは、ローカル、Docker、プロバイダー支援型のすべてのサンドボックス実装において、絶対パスのシンボリックリンク先を含め、アーカイブルート外を指すシンボリックリンクを含む tar アーカイブが拒否されるようになりました。
|
||||
|
||||
### 0.15.0
|
||||
|
||||
このバージョンでは、モデルによる拒否が空のテキスト出力として扱われたり、structured outputs の場合に `MaxTurnsExceeded` になるまで実行ループが再試行されたりする代わりに、`ModelRefusalError` として明示的に公開されるようになりました。
|
||||
|
||||
これは、拒否のみを含むモデル応答が `final_output == ""` で完了することを想定していたコードに影響します。例外を送出せずに拒否を処理するには、`model_refusal` 実行エラーハンドラーを指定してください。
|
||||
|
||||
```python
|
||||
result = Runner.run_sync(
|
||||
agent,
|
||||
input,
|
||||
error_handlers={"model_refusal": lambda data: data.error.refusal},
|
||||
)
|
||||
```
|
||||
|
||||
structured outputs を使用するエージェントでは、ハンドラーからエージェントの出力スキーマに一致する値を返すことができ、SDK は他の実行エラーハンドラーの最終出力と同様にその値を検証します。
|
||||
|
||||
### 0.14.0
|
||||
|
||||
このマイナーリリースには、破壊的変更は **ありません**。ただし、主要な新しいベータ機能領域である Sandbox エージェントと、ローカル環境、コンテナ環境、ホスト環境で使用するために必要なランタイム、バックエンド、ドキュメントのサポートが追加されています。
|
||||
|
||||
主な変更点:
|
||||
|
||||
- `SandboxAgent`、`Manifest`、`SandboxRunConfig` を中心とする新しいベータ版サンドボックスランタイムインターフェースを追加しました。これにより、エージェントは、ファイル、ディレクトリ、Git リポジトリ、マウント、スナップショット、再開機能を備えた永続的で隔離されたワークスペース内で作業できます。
|
||||
- `UnixLocalSandboxClient` と `DockerSandboxClient` により、ローカル開発およびコンテナ開発向けのサンドボックス実行バックエンドを追加しました。また、オプションの追加パッケージを通じて、Blaxel、Cloudflare、Daytona、E2B、Modal、Runloop、Vercel のホスト型プロバイダー統合も追加しました。
|
||||
- サンドボックスのメモリサポートを追加し、以降の実行で以前の実行から得た知見を再利用できるようになりました。段階的な情報開示、複数ターンのグループ化、設定可能な分離境界、および S3 支援型ワークフローを含む永続化メモリのコード例が用意されています。
|
||||
- ローカルおよび合成ワークスペースエントリ、S3/R2/GCS/Azure Blob Storage/S3 Files のリモートストレージマウント、移植可能なスナップショット、`RunState`、`SandboxSessionState`、または保存済みスナップショットを使用した再開フローを含む、より包括的なワークスペースおよび再開モデルを追加しました。
|
||||
- `examples/sandbox/` 以下に、サンドボックスに関する多数のコード例とチュートリアルを追加しました。スキルを使用したコーディングタスク、ハンドオフ、メモリ、プロバイダー固有のセットアップに加え、コードレビュー、データルーム QA、Web サイトのクローン作成などのエンドツーエンドのワークフローを扱っています。
|
||||
- サンドボックス対応のセッション準備、機能のバインド、状態のシリアライズ、統合トレーシング、プロンプトキャッシュキーのデフォルト設定、機密性の高い MCP 出力をより安全に秘匿する機能により、コアランタイムとトレーシングスタックを拡張しました。
|
||||
|
||||
### 0.13.0
|
||||
|
||||
このマイナーリリースには、破壊的変更は **ありません**。ただし、注目すべき Realtime のデフォルト更新、新しい MCP 機能、ランタイムの安定性向上が含まれています。
|
||||
|
||||
主な変更点:
|
||||
|
||||
- デフォルトの WebSocket Realtime モデルが `gpt-realtime-1.5` になり、新しい Realtime エージェントのセットアップでは追加の設定なしで新しいモデルが使用されるようになりました。
|
||||
- `MCPServer` で `list_resources()`、`list_resource_templates()`、`read_resource()` が公開されるようになりました。また、`MCPServerStreamableHttp` で `session_id` が公開されるようになり、再接続後やステートレスワーカー間でストリーミング可能な HTTP セッションを再開できるようになりました。
|
||||
- Chat Completions 統合で、`should_replay_reasoning_content` を通じて推論コンテンツのリプレイをオプトインできるようになりました。これにより、LiteLLM/DeepSeek などのアダプターにおいて、プロバイダー固有の推論やツール呼び出しの継続性が向上します。
|
||||
- `SQLAlchemySession` での最初の書き込みの競合、推論の除去後に孤立したアシスタントメッセージ ID を含む圧縮リクエスト、`remove_all_tools()` の実行後も MCP/推論項目が残る問題、関数ツールのバッチ実行機構における競合状態など、ランタイムとセッションに関する複数のエッジケースを修正しました。
|
||||
|
||||
### 0.12.0
|
||||
|
||||
このマイナーリリースには、破壊的変更は **ありません**。主要な機能追加については、[リリースノート](https://github.com/openai/openai-agents-python/releases/tag/v0.12.0)を確認してください。
|
||||
|
||||
### 0.11.0
|
||||
|
||||
このマイナーリリースには、破壊的変更は **ありません**。主要な機能追加については、[リリースノート](https://github.com/openai/openai-agents-python/releases/tag/v0.11.0)を確認してください。
|
||||
|
||||
### 0.10.0
|
||||
|
||||
このマイナーリリースには、破壊的変更は **ありません**。ただし、OpenAI Responses のユーザー向けに重要な新機能領域である、Responses API の WebSocket トランスポートサポートが含まれています。
|
||||
|
||||
主な変更点:
|
||||
|
||||
- OpenAI Responses モデルに WebSocket トランスポートのサポートを追加しました(オプトイン方式であり、HTTP が引き続きデフォルトのトランスポートです)。
|
||||
- 複数ターンの実行間で、共有の WebSocket 対応プロバイダーと `RunConfig` を再利用するための `responses_websocket_session()` ヘルパー/`ResponsesWebSocketSession` を追加しました。
|
||||
- ストリーミング、ツール、承認、フォローアップターンを扱う、新しい WebSocket ストリーミングのコード例(`examples/basic/stream_ws.py`)を追加しました。
|
||||
|
||||
### 0.9.0
|
||||
|
||||
このバージョンでは、Python 3.9 のサポートを終了しました。このメジャーバージョンは 3 か月前に EOL を迎えています。より新しいランタイムバージョンにアップグレードしてください。
|
||||
|
||||
さらに、`Agent#as_tool()` メソッドから返される値の型ヒントが、`Tool` から `FunctionTool` に絞り込まれました。通常、この変更によって破壊的な問題が生じることはありませんが、コードがより広範なユニオン型に依存している場合は、調整が必要になる可能性があります。
|
||||
|
||||
### 0.8.0
|
||||
|
||||
このバージョンでは、ランタイム動作に関する次の 2 つの変更により、移行作業が必要になる場合があります。
|
||||
|
||||
- **同期** Python 呼び出し可能オブジェクトをラップする関数ツールは、イベントループのスレッド上で実行される代わりに、`asyncio.to_thread(...)` を介してワーカースレッド上で実行されるようになりました。ツールのロジックがスレッドローカル状態やスレッドアフィニティを持つリソースに依存している場合は、非同期ツール実装へ移行するか、ツールのコード内でスレッドアフィニティを明示してください。
|
||||
- ローカル MCP ツールの失敗処理が設定可能になり、デフォルトの動作では、実行全体を失敗させる代わりに、モデルから参照可能なエラー出力を返す場合があります。即時失敗の動作に依存している場合は、`mcp_config={"failure_error_function": None}` を設定してください。サーバーレベルの `failure_error_function` の値はエージェントレベルの設定を上書きするため、明示的なハンドラーを持つ各ローカル MCP サーバーで `failure_error_function=None` を設定してください。
|
||||
|
||||
### 0.7.0
|
||||
|
||||
このバージョンでは、既存のアプリケーションに影響する可能性がある動作変更がいくつかあります。
|
||||
|
||||
- ネストされたハンドオフ履歴は **オプトイン** になりました(デフォルトでは無効です)。v0.6.x のデフォルトのネスト動作に依存していた場合は、`RunConfig(nest_handoff_history=True)` を明示的に設定してください。
|
||||
- `gpt-5.1`/`gpt-5.2` のデフォルトの `reasoning.effort` が、SDK のデフォルト設定で指定されていた従来の `"low"` から `"none"` に変更されました。プロンプトまたは品質/コスト特性が `"low"` に依存している場合は、`model_settings` で明示的に設定してください。
|
||||
|
||||
### 0.6.0
|
||||
|
||||
このバージョンでは、デフォルトのハンドオフ履歴が、生のユーザー/アシスタントのターンを公開する代わりに、1 件のアシスタントメッセージにまとめられるようになりました。これにより、後続のエージェントに簡潔で予測可能な要約が提供されます
|
||||
- 既存の単一メッセージ形式のハンドオフ記録は、デフォルトで `<CONVERSATION HISTORY>` ブロックの前に "For context, here is the conversation so far between the user and the previous agent:" という文言から始まるようになり、後続のエージェントに明確なラベル付きの要約が提供されます
|
||||
|
||||
### 0.5.0
|
||||
|
||||
このバージョンでは、目に見える破壊的変更は導入されていませんが、新機能と内部の重要な更新がいくつか含まれています。
|
||||
|
||||
- `RealtimeRunner` に [SIP プロトコル接続](https://platform.openai.com/docs/guides/realtime-sip)を処理するためのサポートを追加しました
|
||||
- Python 3.14 との互換性のため、`Runner#run_sync` の内部ロジックを大幅に改訂しました
|
||||
|
||||
### 0.4.0
|
||||
|
||||
このバージョンでは、[openai](https://pypi.org/project/openai/) パッケージの v1.x バージョンはサポートされなくなりました。この SDK とともに openai v2.x を使用してください。
|
||||
|
||||
### 0.3.0
|
||||
|
||||
このバージョンでは、Realtime API のサポートが gpt-realtime モデルとその API インターフェース(GA 版)に移行しました。
|
||||
|
||||
### 0.2.0
|
||||
|
||||
このバージョンでは、以前は引数として `Agent` を受け取っていた箇所の一部が、代わりに `AgentBase` を受け取るようになりました。たとえば、MCP サーバーの `list_tools()` 呼び出しが該当します。これは純粋に型付け上の変更であり、引き続き `Agent` オブジェクトを受け取ります。更新するには、`Agent` を `AgentBase` に置き換えて型エラーを修正するだけです。
|
||||
|
||||
### 0.1.0
|
||||
|
||||
このバージョンでは、[`MCPServer.list_tools()`][agents.mcp.server.MCPServer] に `run_context` と `agent` という 2 つの新しいパラメーターが追加されました。`MCPServer` を継承するすべてのクラスに、これらのパラメーターを追加する必要があります。
|
||||
@@ -0,0 +1,24 @@
|
||||
---
|
||||
search:
|
||||
exclude: true
|
||||
---
|
||||
# REPL ユーティリティ
|
||||
|
||||
SDK は、ターミナルでエージェントの動作を直接すばやく対話的にテストするための `run_demo_loop` を提供します。
|
||||
|
||||
|
||||
```python
|
||||
import asyncio
|
||||
from agents import Agent, run_demo_loop
|
||||
|
||||
async def main() -> None:
|
||||
agent = Agent(name="Assistant", instructions="You are a helpful assistant.")
|
||||
await run_demo_loop(agent)
|
||||
|
||||
if __name__ == "__main__":
|
||||
asyncio.run(main())
|
||||
```
|
||||
|
||||
`run_demo_loop` はループ内でユーザー入力を求め、ターン間の会話履歴を保持します。デフォルトでは、生成されるモデル出力をストリーミングします。上記の例を実行すると、run_demo_loop は対話型チャットセッションを開始します。入力を継続的に求め、ターン間の会話履歴全体を記憶し(そのためエージェントはこれまでに話し合われた内容を把握できます)、エージェントの応答が生成されるとリアルタイムで自動的にストリーミングします。
|
||||
|
||||
このチャットセッションを終了するには、単に `quit` または `exit` と入力して Enter キーを押すか、`Ctrl-D` キーボードショートカットを使用します。
|
||||
@@ -0,0 +1,165 @@
|
||||
---
|
||||
search:
|
||||
exclude: true
|
||||
---
|
||||
# 実行結果
|
||||
|
||||
`Runner.run` メソッドを呼び出すと、次の 2 つの実行結果型のいずれかを受け取ります。
|
||||
|
||||
- `Runner.run(...)` または `Runner.run_sync(...)` からの [`RunResult`][agents.result.RunResult]
|
||||
- `Runner.run_streamed(...)` からの [`RunResultStreaming`][agents.result.RunResultStreaming]
|
||||
|
||||
どちらも [`RunResultBase`][agents.result.RunResultBase] を継承しており、`final_output`、`new_items`、`last_agent`、`raw_responses`、`to_state()` などの共通の実行結果サーフェスを公開します。
|
||||
|
||||
`RunResultStreaming` は、[`stream_events()`][agents.result.RunResultStreaming.stream_events]、[`current_agent`][agents.result.RunResultStreaming.current_agent]、[`is_complete`][agents.result.RunResultStreaming.is_complete]、[`cancel(...)`][agents.result.RunResultStreaming.cancel] など、ストリーミング固有の制御機能を追加します。
|
||||
|
||||
## 適切な実行結果サーフェスの選択
|
||||
|
||||
ほとんどのアプリケーションでは、いくつかの実行結果プロパティまたはヘルパーだけで十分です。
|
||||
|
||||
| 必要なもの... | 使用するもの |
|
||||
| --- | --- |
|
||||
| ユーザーに表示する最終回答 | `final_output` |
|
||||
| 完全なローカルトランスクリプトを含む、リプレイ可能な次ターン入力リスト | `to_input_list()` |
|
||||
| エージェント、ツール、ハンドオフ、承認メタデータを含む詳細な実行項目 | `new_items` |
|
||||
| 通常、次のユーザーターンを処理すべきエージェント | `last_agent` |
|
||||
| `previous_response_id` による OpenAI Responses API チェーン | `last_response_id` |
|
||||
| 保留中の承認と再開可能なスナップショット | `interruptions` and `to_state()` |
|
||||
| 現在のネストされた `Agent.as_tool()` 呼び出しに関するメタデータ | `agent_tool_invocation` |
|
||||
| raw モデル呼び出しまたはガードレール診断 | `raw_responses` and the guardrail result arrays |
|
||||
|
||||
## 最終出力
|
||||
|
||||
[`final_output`][agents.result.RunResultBase.final_output] プロパティには、最後に実行されたエージェントの最終出力が含まれます。これは次のいずれかです。
|
||||
|
||||
- 最後のエージェントに `output_type` が定義されていなかった場合は `str`
|
||||
- 最後のエージェントに出力型が定義されていた場合は `last_agent.output_type` 型のオブジェクト
|
||||
- 承認中断で一時停止した場合など、最終出力が生成される前に実行が停止した場合は `None`
|
||||
|
||||
!!! note
|
||||
|
||||
`final_output` は `Any` として型付けされています。ハンドオフによって、どのエージェントが実行を終了するかが変わる可能性があるため、SDK は考えられる出力型の全体集合を静的に把握できません。
|
||||
|
||||
ストリーミングモードでは、ストリームの処理が完了するまで `final_output` は `None` のままです。イベントごとのフローについては、[ストリーミング](streaming.md)を参照してください。
|
||||
|
||||
## 入力、次ターン履歴、新規項目
|
||||
|
||||
これらのサーフェスは、それぞれ異なる問いに対応します。
|
||||
|
||||
| プロパティまたはヘルパー | 含まれる内容 | 最適な用途 |
|
||||
| --- | --- | --- |
|
||||
| [`input`][agents.result.RunResultBase.input] | この実行セグメントの基本入力です。ハンドオフ入力フィルターが履歴を書き換えた場合、実行が継続されたフィルター済み入力がここに反映されます。 | この実行が実際に入力として使用した内容の監査 |
|
||||
| [`to_input_list()`][agents.result.RunResultBase.to_input_list] | 実行を入力項目として見たビューです。デフォルトの `mode="preserve_all"` は、`new_items` から変換された完全な履歴を保持します。`mode="normalized"` は、ハンドオフフィルタリングによってモデル履歴が書き換えられた場合に、正規の継続入力を優先します。 | 手動のチャットループ、クライアント管理の会話状態、プレーンな項目履歴の確認 |
|
||||
| [`new_items`][agents.result.RunResultBase.new_items] | エージェント、ツール、ハンドオフ、承認メタデータを含む詳細な [`RunItem`][agents.items.RunItem] ラッパーです。 | ログ、UI、監査、デバッグ |
|
||||
| [`raw_responses`][agents.result.RunResultBase.raw_responses] | 実行内の各モデル呼び出しからの raw [`ModelResponse`][agents.items.ModelResponse] オブジェクトです。 | プロバイダーレベルの診断または raw レスポンスの確認 |
|
||||
|
||||
実際には、次のように使い分けます。
|
||||
|
||||
- 実行のプレーンな入力項目ビューが必要な場合は、`to_input_list()` を使用します。
|
||||
- ハンドオフフィルタリングまたはネストされたハンドオフ履歴の書き換え後に、次の `Runner.run(..., input=...)` 呼び出しに渡す正規のローカル入力が必要な場合は、`to_input_list(mode="normalized")` を使用します。
|
||||
- SDK に履歴の読み込みと保存を任せたい場合は、[`session=...`](sessions/index.md) を使用します。
|
||||
- `conversation_id` または `previous_response_id` を使って OpenAI のサーバー管理状態を使用している場合、通常は `to_input_list()` を再送信する代わりに、新しいユーザー入力のみを渡して保存済み ID を再利用します。
|
||||
- ログ、UI、監査向けに完全な変換済み履歴が必要な場合は、デフォルトの `to_input_list()` モードまたは `new_items` を使用します。
|
||||
|
||||
JavaScript SDK とは異なり、Python ではモデル形式の差分のみを表す個別の `output` プロパティは公開されません。SDK メタデータが必要な場合は `new_items` を使用し、raw モデルペイロードが必要な場合は `raw_responses` を確認してください。
|
||||
|
||||
コンピュータツールのリプレイは、raw Responses ペイロードの形状に従います。プレビューモデルの `computer_call` 項目は単一の `action` を保持しますが、`gpt-5.5` のコンピュータ呼び出しではバッチ化された `actions[]` を保持できます。[`to_input_list()`][agents.result.RunResultBase.to_input_list] と [`RunState`][agents.run_state.RunState] は、モデルが生成した形状をそのまま保持するため、手動リプレイ、一時停止/再開フロー、保存済みトランスクリプトは、プレビュー版と GA 版の両方のコンピュータツール呼び出しで引き続き機能します。ローカル実行結果は引き続き `new_items` 内の `computer_call_output` 項目として表示されます。
|
||||
|
||||
### 新規項目
|
||||
|
||||
[`new_items`][agents.result.RunResultBase.new_items] は、実行中に何が起きたかを最も詳細に確認できるビューです。一般的な項目型は次のとおりです。
|
||||
|
||||
- アシスタントメッセージ用の [`MessageOutputItem`][agents.items.MessageOutputItem]
|
||||
- 推論項目用の [`ReasoningItem`][agents.items.ReasoningItem]
|
||||
- Responses のツール検索リクエストと、ロードされたツール検索の実行結果用の [`ToolSearchCallItem`][agents.items.ToolSearchCallItem] および [`ToolSearchOutputItem`][agents.items.ToolSearchOutputItem]
|
||||
- ツール呼び出しとその実行結果用の [`ToolCallItem`][agents.items.ToolCallItem] および [`ToolCallOutputItem`][agents.items.ToolCallOutputItem]
|
||||
- 承認待ちで一時停止したツール呼び出し用の [`ToolApprovalItem`][agents.items.ToolApprovalItem]
|
||||
- ハンドオフリクエストと完了済みの引き継ぎ用の [`HandoffCallItem`][agents.items.HandoffCallItem] および [`HandoffOutputItem`][agents.items.HandoffOutputItem]
|
||||
|
||||
エージェントの関連付け、ツール出力、ハンドオフの境界、承認の境界が必要な場合は、常に `to_input_list()` よりも `new_items` を選択してください。
|
||||
|
||||
ホスト型ツール検索を使用する場合、モデルが生成した検索リクエストを確認するには `ToolSearchCallItem.raw_item` を確認し、そのターンでどの名前空間、関数、またはホスト型 MCP サーバーがロードされたかを確認するには `ToolSearchOutputItem.raw_item` を確認してください。
|
||||
|
||||
## 会話の継続または再開
|
||||
|
||||
### 次ターンのエージェント
|
||||
|
||||
[`last_agent`][agents.result.RunResultBase.last_agent] には、最後に実行されたエージェントが含まれます。これは多くの場合、ハンドオフ後の次のユーザーターンで再利用するのに最適なエージェントです。
|
||||
|
||||
ストリーミングモードでは、[`RunResultStreaming.current_agent`][agents.result.RunResultStreaming.current_agent] が実行の進行に合わせて更新されるため、ストリームが終了する前にハンドオフを観察できます。
|
||||
|
||||
### 中断と実行状態
|
||||
|
||||
ツールに承認が必要な場合、保留中の承認は [`RunResult.interruptions`][agents.result.RunResult.interruptions] または [`RunResultStreaming.interruptions`][agents.result.RunResultStreaming.interruptions] で公開されます。これには、直接呼び出されたツール、ハンドオフ後に到達したツール、またはネストされた [`Agent.as_tool()`][agents.agent.Agent.as_tool] 実行によって発生した承認が含まれることがあります。
|
||||
|
||||
[`to_state()`][agents.result.RunResult.to_state] を呼び出して、再開可能な [`RunState`][agents.run_state.RunState] を取得し、保留中の項目を承認または拒否してから、`Runner.run(...)` または `Runner.run_streamed(...)` で再開します。
|
||||
|
||||
```python
|
||||
from agents import Agent, Runner
|
||||
|
||||
agent = Agent(name="Assistant", instructions="Use tools when needed.")
|
||||
result = await Runner.run(agent, "Delete temp files that are no longer needed.")
|
||||
|
||||
if result.interruptions:
|
||||
state = result.to_state()
|
||||
for interruption in result.interruptions:
|
||||
state.approve(interruption)
|
||||
result = await Runner.run(agent, state)
|
||||
```
|
||||
|
||||
ストリーミング実行では、まず [`stream_events()`][agents.result.RunResultStreaming.stream_events] の消費を完了してから `result.interruptions` を確認し、`result.to_state()` から再開してください。承認フロー全体については、[ヒューマンインザループ](human_in_the_loop.md)を参照してください。
|
||||
|
||||
### サーバー管理の継続
|
||||
|
||||
[`last_response_id`][agents.result.RunResultBase.last_response_id] は、実行から得られた最新のモデルレスポンス ID です。OpenAI Responses API チェーンを継続したい場合は、次のターンで `previous_response_id` として渡してください。
|
||||
|
||||
すでに `to_input_list()`、`session`、または `conversation_id` で会話を継続している場合、通常は `last_response_id` は不要です。複数ステップの実行におけるすべてのモデルレスポンスが必要な場合は、代わりに `raw_responses` を確認してください。
|
||||
|
||||
## ツールとしてのエージェントのメタデータ
|
||||
|
||||
実行結果がネストされた [`Agent.as_tool()`][agents.agent.Agent.as_tool] 実行に由来する場合、[`agent_tool_invocation`][agents.result.RunResultBase.agent_tool_invocation] は外側のツール呼び出しに関する変更不可のメタデータを公開します。
|
||||
|
||||
- `tool_name`
|
||||
- `tool_call_id`
|
||||
- `tool_arguments`
|
||||
|
||||
通常のトップレベル実行では、`agent_tool_invocation` は `None` です。
|
||||
|
||||
これは、ネストされた実行結果を後処理する際に、外側のツール名、呼び出し ID、または生の引数が必要になることがある `custom_output_extractor` 内で特に便利です。関連する `Agent.as_tool()` パターンについては、[ツール](tools.md)を参照してください。
|
||||
|
||||
そのネストされた実行のパース済み構造化入力も必要な場合は、`context_wrapper.tool_input` を読み取ってください。これは、ネストされたツール入力に対して [`RunState`][agents.run_state.RunState] が汎用的にシリアライズするフィールドです。一方、`agent_tool_invocation` は、現在のネストされた呼び出しに対するライブの実行結果アクセサーです。
|
||||
|
||||
## ストリーミングのライフサイクルと診断
|
||||
|
||||
[`RunResultStreaming`][agents.result.RunResultStreaming] は、上記と同じ実行結果サーフェスを継承しますが、ストリーミング固有の制御機能を追加します。
|
||||
|
||||
- セマンティックなストリームイベントを消費するための [`stream_events()`][agents.result.RunResultStreaming.stream_events]
|
||||
- 実行途中でアクティブなエージェントを追跡するための [`current_agent`][agents.result.RunResultStreaming.current_agent]
|
||||
- ストリーミング実行が完全に終了したかどうかを確認するための [`is_complete`][agents.result.RunResultStreaming.is_complete]
|
||||
- 実行を即時または現在のターン後に停止するための [`cancel(...)`][agents.result.RunResultStreaming.cancel]
|
||||
|
||||
非同期イテレーターが終了するまで `stream_events()` を消費し続けてください。そのイテレーターが終了するまで、ストリーミング実行は完了していません。また、`final_output`、`interruptions`、`raw_responses` などの要約プロパティや、セッション永続化の副作用は、目に見える最後のトークンが到着した後もまだ確定中の場合があります。
|
||||
|
||||
`cancel()` を呼び出した場合は、キャンセルとクリーンアップが正しく完了できるように、`stream_events()` を消費し続けてください。
|
||||
|
||||
Python では、ストリーミング用の個別の `completed` プロミスや `error` プロパティは公開されません。終端的なストリーミング失敗は `stream_events()` から例外が送出されることで表面化し、`is_complete` は実行が終端状態に到達したかどうかを反映します。
|
||||
|
||||
### raw レスポンス
|
||||
|
||||
[`raw_responses`][agents.result.RunResultBase.raw_responses] には、実行中に収集された raw モデルレスポンスが含まれます。複数ステップの実行では、ハンドオフをまたいだり、モデル/ツール/モデルのサイクルが繰り返されたりする場合など、複数のレスポンスが生成されることがあります。
|
||||
|
||||
[`last_response_id`][agents.result.RunResultBase.last_response_id] は、`raw_responses` の最後のエントリの ID にすぎません。
|
||||
|
||||
### ガードレールの実行結果
|
||||
|
||||
エージェントレベルのガードレールは、[`input_guardrail_results`][agents.result.RunResultBase.input_guardrail_results] および [`output_guardrail_results`][agents.result.RunResultBase.output_guardrail_results] として公開されます。
|
||||
|
||||
ツールガードレールは、[`tool_input_guardrail_results`][agents.result.RunResultBase.tool_input_guardrail_results] および [`tool_output_guardrail_results`][agents.result.RunResultBase.tool_output_guardrail_results] として個別に公開されます。
|
||||
|
||||
これらの配列は実行全体で蓄積されるため、判定のログ記録、追加のガードレールメタデータの保存、または実行がブロックされた理由のデバッグに役立ちます。
|
||||
|
||||
### コンテキストと使用量
|
||||
|
||||
[`context_wrapper`][agents.result.RunResultBase.context_wrapper] は、アプリのコンテキストと、承認、使用量、ネストされた `tool_input` など SDK が管理するランタイムメタデータを公開します。
|
||||
|
||||
使用量は `context_wrapper.usage` で追跡されます。ストリーミング実行では、ストリームの最終チャンクが処理されるまで、使用量の合計値が遅れて反映される場合があります。ラッパーの完全な形状と永続化に関する注意事項については、[コンテキスト管理](context.md)を参照してください。
|
||||
@@ -0,0 +1,596 @@
|
||||
---
|
||||
search:
|
||||
exclude: true
|
||||
---
|
||||
# エージェントの実行
|
||||
|
||||
[`Runner`][agents.run.Runner] クラスを使用してエージェントを実行できます。次の 3 つの方法があります。
|
||||
|
||||
1. [`Runner.run()`][agents.run.Runner.run]:非同期で実行し、[`RunResult`][agents.result.RunResult] を返します。
|
||||
2. [`Runner.run_sync()`][agents.run.Runner.run_sync]:同期メソッドで、内部的には `.run()` を実行します。
|
||||
3. [`Runner.run_streamed()`][agents.run.Runner.run_streamed]:非同期で実行し、[`RunResultStreaming`][agents.result.RunResultStreaming] を返します。ストリーミングモードで LLM を呼び出し、受信したイベントをそのままストリーミングします。
|
||||
|
||||
```python
|
||||
from agents import Agent, Runner
|
||||
|
||||
async def main():
|
||||
agent = Agent(name="Assistant", instructions="You are a helpful assistant")
|
||||
|
||||
result = await Runner.run(agent, "Write a haiku about recursion in programming.")
|
||||
print(result.final_output)
|
||||
# Code within the code,
|
||||
# Functions calling themselves,
|
||||
# Infinite loop's dance
|
||||
```
|
||||
|
||||
詳細については、[実行結果ガイド](results.md)を参照してください。
|
||||
|
||||
## Runner のライフサイクルと設定
|
||||
|
||||
### エージェントループ
|
||||
|
||||
`Runner` の run メソッドを使用する場合、開始エージェントと入力を渡します。入力には次のものを使用できます。
|
||||
|
||||
- 文字列(ユーザーメッセージとして扱われます)
|
||||
- OpenAI Responses API 形式の入力項目のリスト
|
||||
- 中断された実行を再開する場合は [`RunState`][agents.run_state.RunState]
|
||||
|
||||
その後、runner はループを実行します。
|
||||
|
||||
1. 現在のエージェントに対して、現在の入力で LLM を呼び出します。
|
||||
2. LLM が出力を生成します。
|
||||
1. LLM が `final_output` を返した場合、ループを終了して実行結果を返します。
|
||||
2. LLM がハンドオフを行った場合、現在のエージェントと入力を更新し、ループを再実行します。
|
||||
3. LLM がツール呼び出しを生成した場合、そのツール呼び出しを実行して結果を追加し、ループを再実行します。
|
||||
3. 渡された `max_turns` を超えた場合、[`MaxTurnsExceeded`][agents.exceptions.MaxTurnsExceeded] 例外を発生させます。このターン制限を無効にするには、`max_turns=None` を渡します。
|
||||
|
||||
!!! note
|
||||
|
||||
LLM の出力が「最終出力」と見なされる条件は、目的の型のテキスト出力が生成され、ツール呼び出しが存在しないことです。
|
||||
|
||||
### ストリーミング
|
||||
|
||||
ストリーミングを使用すると、LLM の実行中にストリーミングイベントも受信できます。ストリームが完了すると、[`RunResultStreaming`][agents.result.RunResultStreaming] には、生成されたすべての新しい出力を含む、実行に関する完全な情報が格納されます。ストリーミングイベントには `.stream_events()` を呼び出せます。詳細については、[ストリーミングガイド](streaming.md)を参照してください。
|
||||
|
||||
#### Responses WebSocket トランスポート(オプションのヘルパー)
|
||||
|
||||
OpenAI Responses の websocket トランスポートを有効にしても、通常の `Runner` API を引き続き使用できます。接続を再利用するには websocket セッションヘルパーの使用を推奨しますが、必須ではありません。
|
||||
|
||||
これは websocket トランスポート上の Responses API であり、[Realtime API](realtime/guide.md)ではありません。
|
||||
|
||||
トランスポートの選択ルール、および具体的なモデルオブジェクトやカスタムプロバイダーに関する注意事項については、[モデル](models/index.md#responses-websocket-transport)を参照してください。
|
||||
|
||||
##### パターン 1:セッションヘルパーなし(動作可能)
|
||||
|
||||
websocket トランスポートのみが必要で、共有プロバイダーやセッションを SDK に管理させる必要がない場合に使用します。
|
||||
|
||||
```python
|
||||
import asyncio
|
||||
|
||||
from agents import Agent, Runner, set_default_openai_responses_transport
|
||||
|
||||
|
||||
async def main():
|
||||
set_default_openai_responses_transport("websocket")
|
||||
|
||||
agent = Agent(name="Assistant", instructions="Be concise.")
|
||||
result = Runner.run_streamed(agent, "Summarize recursion in one sentence.")
|
||||
|
||||
async for event in result.stream_events():
|
||||
if event.type == "raw_response_event":
|
||||
continue
|
||||
print(event.type)
|
||||
|
||||
|
||||
asyncio.run(main())
|
||||
```
|
||||
|
||||
このパターンは、単一の実行に適しています。`Runner.run()` / `Runner.run_streamed()` を繰り返し呼び出す場合、同じ `RunConfig` / プロバイダーインスタンスを手動で再利用しない限り、実行ごとに再接続される可能性があります。
|
||||
|
||||
##### パターン 2:`responses_websocket_session()` の使用(複数ターンでの再利用に推奨)
|
||||
|
||||
複数の実行で websocket 対応の共有プロバイダーと `RunConfig` を使用する場合は、[`responses_websocket_session()`][agents.responses_websocket_session] を使用します。これには、同じ `run_config` を継承する、ネストされた Agents-as-tools 呼び出しも含まれます。
|
||||
|
||||
```python
|
||||
import asyncio
|
||||
|
||||
from agents import Agent, responses_websocket_session
|
||||
|
||||
|
||||
async def main():
|
||||
agent = Agent(name="Assistant", instructions="Be concise.")
|
||||
|
||||
async with responses_websocket_session(
|
||||
responses_websocket_options={"ping_interval": 20.0, "ping_timeout": 60.0},
|
||||
) as ws:
|
||||
first = ws.run_streamed(agent, "Say hello in one short sentence.")
|
||||
async for _event in first.stream_events():
|
||||
pass
|
||||
|
||||
second = ws.run_streamed(
|
||||
agent,
|
||||
"Now say goodbye.",
|
||||
previous_response_id=first.last_response_id,
|
||||
)
|
||||
async for _event in second.stream_events():
|
||||
pass
|
||||
|
||||
|
||||
asyncio.run(main())
|
||||
```
|
||||
|
||||
コンテキストを終了する前に、ストリーミングされた実行結果の処理を完了してください。websocket リクエストが進行中の状態でコンテキストを終了すると、共有接続が強制的に閉じられる可能性があります。
|
||||
|
||||
長時間の推論ターンで websocket の keepalive タイムアウトが発生する場合は、`ping_timeout` を大きくするか、`ping_timeout=None` を設定してハートビートタイムアウトを無効にしてください。websocket のレイテンシよりも信頼性が重要な実行では、HTTP/SSE トランスポートを使用してください。
|
||||
|
||||
### 実行設定
|
||||
|
||||
`run_config` パラメーターを使用すると、エージェントの実行に関するグローバル設定を構成できます。
|
||||
|
||||
#### 一般的な実行設定カテゴリー
|
||||
|
||||
各エージェントの定義を変更せず、単一の実行に対する動作を上書きするには、`RunConfig` を使用します。
|
||||
|
||||
##### モデル、プロバイダー、セッションのデフォルト設定
|
||||
|
||||
- [`model`][agents.run.RunConfig.model]:各 Agent に設定されている `model` に関係なく、使用するグローバルな LLM モデルを設定できます。
|
||||
- [`model_provider`][agents.run.RunConfig.model_provider]:モデル名を検索するためのモデルプロバイダーです。デフォルトは OpenAI です。
|
||||
- [`model_settings`][agents.run.RunConfig.model_settings]:エージェント固有の設定を上書きします。たとえば、グローバルな `temperature` または `top_p` を設定できます。
|
||||
- [`session_settings`][agents.run.RunConfig.session_settings]:実行中に履歴を取得する際のセッションレベルのデフォルト設定(たとえば、`SessionSettings(limit=...)`)を上書きします。
|
||||
- [`session_input_callback`][agents.run.RunConfig.session_input_callback]:Sessions の使用時に、各ターンの前に新しいユーザー入力をセッション履歴とマージする方法をカスタマイズします。コールバックは同期または非同期にできます。
|
||||
|
||||
##### ガードレール、ハンドオフ、モデル入力の整形
|
||||
|
||||
- [`input_guardrails`][agents.run.RunConfig.input_guardrails]、[`output_guardrails`][agents.run.RunConfig.output_guardrails]:すべての実行に含める入力ガードレールまたは出力ガードレールのリストです。
|
||||
- [`handoff_input_filter`][agents.run.RunConfig.handoff_input_filter]:ハンドオフにフィルターがまだ設定されていない場合、すべてのハンドオフに適用するグローバル入力フィルターです。入力フィルターを使用すると、新しいエージェントに送信される入力を編集できます。詳細については、[`Handoff.input_filter`][agents.handoffs.Handoff.input_filter] のドキュメントを参照してください。
|
||||
- [`nest_handoff_history`][agents.run.RunConfig.nest_handoff_history]:次のエージェントを呼び出す前に、それまでのトランスクリプトを単一の assistant メッセージにまとめる、オプトインのベータ機能です。ネストされたハンドオフの安定化を進めているため、デフォルトでは無効です。有効にするには `True` を設定し、raw トランスクリプトをそのまま渡すには `False` のままにします。[Runner の各メソッド][agents.run.Runner]は、`RunConfig` が渡されなかった場合に自動的に作成するため、クイックスタートとコード例ではデフォルトで無効のままです。また、明示的な [`Handoff.input_filter`][agents.handoffs.Handoff.input_filter] コールバックは引き続きこの設定を上書きします。個々のハンドオフでは、[`Handoff.nest_handoff_history`][agents.handoffs.Handoff.nest_handoff_history] を使用してこの設定を上書きできます。
|
||||
- [`handoff_history_mapper`][agents.run.RunConfig.handoff_history_mapper]:`nest_handoff_history` を有効にした際に、正規化されたトランスクリプト(履歴とハンドオフ項目)を受け取るオプションの callable です。次のエージェントに転送する入力項目の正確なリストを返す必要があり、完全なハンドオフフィルターを記述することなく、組み込みの要約を置き換えられます。
|
||||
- [`call_model_input_filter`][agents.run.RunConfig.call_model_input_filter]:モデル呼び出しの直前に、完全に準備されたモデル入力(instructions と入力項目)を編集するためのフックです。たとえば、履歴の短縮やシステムプロンプトの挿入に使用できます。
|
||||
- [`reasoning_item_id_policy`][agents.run.RunConfig.reasoning_item_id_policy]:runner が以前の出力を次のターンのモデル入力に変換するときに、推論項目 ID を保持するか省略するかを制御します。
|
||||
|
||||
##### トレーシングと可観測性
|
||||
|
||||
- [`tracing_disabled`][agents.run.RunConfig.tracing_disabled]:実行全体の[トレーシング](tracing.md)を無効にできます。
|
||||
- [`tracing`][agents.run.RunConfig.tracing]:実行ごとのトレーシング API キーなど、トレースのエクスポート設定を上書きするには、[`TracingConfig`][agents.tracing.TracingConfig] を渡します。
|
||||
- [`trace_include_sensitive_data`][agents.run.RunConfig.trace_include_sensitive_data]:LLM やツール呼び出しの入出力など、機密である可能性があるデータをトレースに含めるかどうかを設定します。
|
||||
- [`workflow_name`][agents.run.RunConfig.workflow_name]、[`trace_id`][agents.run.RunConfig.trace_id]、[`group_id`][agents.run.RunConfig.group_id]:実行のトレーシングワークフロー名、トレース ID、トレースグループ ID を設定します。少なくとも `workflow_name` を設定することを推奨します。グループ ID は、複数の実行にわたってトレースを関連付けるためのオプションフィールドです。
|
||||
- [`trace_metadata`][agents.run.RunConfig.trace_metadata]:すべてのトレースに含めるメタデータです。
|
||||
|
||||
##### ツールの実行、承認、エラー動作
|
||||
|
||||
- [`tool_execution`][agents.run.RunConfig.tool_execution]:同時に実行する関数ツールの数を制限するなど、ローカルツール呼び出しに対する SDK 側の実行動作を設定します。
|
||||
- [`tool_not_found_behavior`][agents.run.RunConfig.tool_not_found_behavior]:モデルが出力した、解決できない関数ツール呼び出しを runner が処理する方法を設定します。デフォルトでは `ModelBehaviorError` が発生します。代わりに、モデルから参照可能なエラー出力を返すようオプトインできます。
|
||||
- [`tool_error_formatter`][agents.run.RunConfig.tool_error_formatter]:承認の拒否や、オプトインしたツール未検出時の出力など、モデルから参照可能なツールエラーメッセージをカスタマイズします。
|
||||
|
||||
ネストされたハンドオフは、オプトインのベータ機能として利用できます。トランスクリプトをまとめる動作を有効にするには、`RunConfig(nest_handoff_history=True)` を渡すか、特定のハンドオフに対して `handoff(..., nest_handoff_history=True)` を設定します。raw トランスクリプトを保持する場合(デフォルト)は、フラグを設定しないか、必要に応じて会話をそのまま転送する `handoff_input_filter`(または `handoff_history_mapper`)を指定します。カスタム mapper を記述せずに、生成される要約で使用されるラッパーテキストを変更するには、[`set_conversation_history_wrappers`][agents.handoffs.set_conversation_history_wrappers] を呼び出します。デフォルトに戻すには [`reset_conversation_history_wrappers`][agents.handoffs.reset_conversation_history_wrappers] を呼び出します。
|
||||
|
||||
#### 実行設定の詳細
|
||||
|
||||
##### `tool_execution`
|
||||
|
||||
実行時のローカル関数ツールの同時実行数を制限するなど、ローカル関数ツールに対する SDK 側の動作を設定する場合は、`tool_execution` を使用します。
|
||||
|
||||
```python
|
||||
from agents import Agent, RunConfig, Runner, ToolExecutionConfig
|
||||
|
||||
agent = Agent(name="Assistant", tools=[...])
|
||||
|
||||
result = await Runner.run(
|
||||
agent,
|
||||
"Run the required tool calls.",
|
||||
run_config=RunConfig(
|
||||
tool_execution=ToolExecutionConfig(
|
||||
max_function_tool_concurrency=2,
|
||||
pre_approval_tool_input_guardrails=True,
|
||||
),
|
||||
),
|
||||
)
|
||||
```
|
||||
|
||||
`max_function_tool_concurrency=None` はデフォルトの動作を維持します。モデルが 1 ターンで複数の関数ツール呼び出しを出力すると、SDK は出力されたすべてのローカル関数ツール呼び出しを開始します。同時に実行するローカル関数ツールの数を制限するには、整数値を設定します。
|
||||
|
||||
これは、プロバイダー側の [`ModelSettings.parallel_tool_calls`][agents.model_settings.ModelSettings.parallel_tool_calls] とは別のものです。`parallel_tool_calls` は、モデルが 1 回のレスポンスで複数のツール呼び出しを出力できるかどうかを制御します。`tool_execution.max_function_tool_concurrency` は、モデルがツール呼び出しを出力した後に、SDK がローカル関数ツール呼び出しを実行する方法を制御します。
|
||||
|
||||
`pre_approval_tool_input_guardrails=False` はデフォルトの承認フローを維持します。関数ツールに承認が必要な場合、実行は最初に一時停止し、ツール入力ガードレールは承認後の実行直前にのみ実行されます。保留中の承認による中断が発生する前に関数ツールの入力ガードレールを実行する場合は、`True` に設定します。この承認前チェックに合格した呼び出しでも、承認後に同じ入力ガードレールが再度実行されるため、時間依存のチェックは実行前に再検証されます。
|
||||
|
||||
##### `tool_not_found_behavior`
|
||||
|
||||
デフォルトでは、モデルが現在のエージェントで使用可能な関数ツールのいずれにも一致しない関数ツール呼び出しを出力すると、runner は `ModelBehaviorError` を発生させます。
|
||||
|
||||
実行を復旧可能な状態に保つ場合は、`tool_not_found_behavior="return_error_to_model"` を設定します。このモードでは、SDK は解決できないツール呼び出しに対する `function_call_output` を追加し、モデルを再実行します。これにより、モデルは使用可能なツールを選択するか、そのツールを使用せずに回答できます。
|
||||
|
||||
```python
|
||||
from agents import Agent, RunConfig, Runner
|
||||
|
||||
agent = Agent(name="Assistant", tools=[...])
|
||||
|
||||
result = await Runner.run(
|
||||
agent,
|
||||
"Handle this request with the available tools.",
|
||||
run_config=RunConfig(tool_not_found_behavior="return_error_to_model"),
|
||||
)
|
||||
```
|
||||
|
||||
現在、このオプションは解決できない関数ツール呼び出しにのみ適用されます。その他の無効なツールペイロードには、既存のエラー動作が引き続き適用されます。
|
||||
|
||||
##### `tool_error_formatter`
|
||||
|
||||
SDK がモデルから参照可能なツールエラー出力を作成する際にモデルへ返すメッセージをカスタマイズするには、`tool_error_formatter` を使用します。
|
||||
|
||||
formatter は、次の内容を含む [`ToolErrorFormatterArgs`][agents.run_config.ToolErrorFormatterArgs] を受け取ります。
|
||||
|
||||
- `kind`:`"approval_rejected"` や `"tool_not_found"` などのエラーカテゴリーです。
|
||||
- `tool_type`:ツールのランタイム(`"function"`、`"computer"`、`"shell"`、`"apply_patch"`、または `"custom"`)です。
|
||||
- `tool_name`:ツール名です。
|
||||
- `call_id`:ツール呼び出し ID です。
|
||||
- `default_message`:モデルから参照可能な SDK のデフォルトメッセージです。
|
||||
- `run_context`:アクティブな実行コンテキストのラッパーです。
|
||||
|
||||
メッセージを置き換えるには文字列を返し、SDK のデフォルトを使用するには `None` を返します。
|
||||
|
||||
```python
|
||||
from agents import Agent, RunConfig, Runner, ToolErrorFormatterArgs
|
||||
|
||||
|
||||
def format_rejection(args: ToolErrorFormatterArgs[None]) -> str | None:
|
||||
if args.kind == "approval_rejected":
|
||||
return (
|
||||
f"Tool call '{args.tool_name}' was rejected by a human reviewer. "
|
||||
"Ask for confirmation or propose a safer alternative."
|
||||
)
|
||||
if args.kind == "tool_not_found":
|
||||
return f"Tool '{args.tool_name}' is not available. Choose one of the listed tools."
|
||||
return None
|
||||
|
||||
|
||||
agent = Agent(name="Assistant")
|
||||
result = Runner.run_sync(
|
||||
agent,
|
||||
"Please delete the production database.",
|
||||
run_config=RunConfig(tool_error_formatter=format_rejection),
|
||||
)
|
||||
```
|
||||
|
||||
##### `reasoning_item_id_policy`
|
||||
|
||||
`reasoning_item_id_policy` は、runner が履歴を次のターンへ引き継ぐ際に、推論項目を次のターンのモデル入力へ変換する方法を制御します(たとえば、`RunResult.to_input_list()` またはセッションに基づく実行を使用する場合)。
|
||||
|
||||
- `None` または `"preserve"`(デフォルト):推論項目 ID を保持します。
|
||||
- `"omit"`:生成される次のターンの入力から推論項目 ID を削除します。
|
||||
|
||||
`"omit"` は主に、推論項目が `id` を伴って送信される一方で、必須の後続項目がない場合に発生する Responses API の 400 エラー群に対する、オプトインの緩和策として使用します(例:`Item 'rs_...' of type 'reasoning' was provided without its required following item.`)。
|
||||
|
||||
これは、SDK が以前の出力から後続入力を構築し、推論項目 ID が保持される一方で、プロバイダーがその ID と対応する後続項目とのペアを維持するよう要求する場合に、複数ターンのエージェント実行で発生する可能性があります。これには、セッションの永続化、サーバー管理の会話差分、ストリーミング/非ストリーミングの後続ターン、再開パスが含まれます。
|
||||
|
||||
`reasoning_item_id_policy="omit"` を設定すると、推論内容を保持しながら推論項目の `id` を削除できます。これにより、SDK が生成する後続入力で、その API の不変条件に抵触することを回避できます。
|
||||
|
||||
適用範囲に関する注意事項:
|
||||
|
||||
- これは、SDK が後続入力を構築するときに生成または転送する推論項目のみを変更します。
|
||||
- ユーザーが指定した初期入力項目は書き換えません。
|
||||
- このポリシーの適用後でも、`call_model_input_filter` によって意図的に推論 ID を再導入できます。
|
||||
|
||||
## 状態と会話の管理
|
||||
|
||||
### メモリ戦略の選択
|
||||
|
||||
状態を次のターンへ引き継ぐ一般的な方法は 4 つあります。
|
||||
|
||||
| 戦略 | 状態の保存場所 | 最適な用途 | 次のターンで渡すもの |
|
||||
| --- | --- | --- | --- |
|
||||
| `result.to_input_list()` | アプリのメモリ | 小規模なチャットループ、完全な手動制御、任意のプロバイダー | `result.to_input_list()` のリストと次のユーザーメッセージ |
|
||||
| `session` | ストレージと SDK | 永続的なチャット状態、再開可能な実行、カスタムストア | 同じ `session` インスタンス、または同じストアを参照する別のインスタンス |
|
||||
| `conversation_id` | OpenAI Conversations API | ワーカーやサービス間で共有する、名前付きのサーバー側会話 | 同じ `conversation_id` と新しいユーザーターンのみ |
|
||||
| `previous_response_id` | OpenAI Responses API | 会話リソースを作成せずに行う軽量なサーバー管理の継続 | `result.last_response_id` と新しいユーザーターンのみ |
|
||||
|
||||
`result.to_input_list()` と `session` はクライアント管理です。`conversation_id` と `previous_response_id` は OpenAI 管理であり、OpenAI Responses API を使用している場合にのみ適用されます。ほとんどのアプリケーションでは、会話ごとに 1 つの永続化戦略を選択してください。クライアント管理の履歴と OpenAI 管理の状態を混在させると、両方のレイヤーを意図的に調整している場合を除き、コンテキストが重複する可能性があります。
|
||||
|
||||
!!! note
|
||||
|
||||
セッションの永続化と、サーバー管理の会話設定
|
||||
(`conversation_id`、`previous_response_id`、または `auto_previous_response_id`)を
|
||||
同じ実行で組み合わせることはできません。呼び出しごとにいずれか 1 つの方法を選択してください。
|
||||
|
||||
### 会話/チャットスレッド
|
||||
|
||||
いずれかの run メソッドを呼び出すと、1 つ以上のエージェントが実行される可能性があり、それに伴って LLM が 1 回以上呼び出されますが、これはチャット会話における論理的な 1 ターンを表します。次に例を示します。
|
||||
|
||||
1. ユーザーターン:ユーザーがテキストを入力します。
|
||||
2. Runner の実行:最初のエージェントが LLM を呼び出し、ツールを実行して 2 番目のエージェントへハンドオフします。2 番目のエージェントがさらにツールを実行し、出力を生成します。
|
||||
|
||||
エージェントの実行終了時に、ユーザーに何を表示するかを選択できます。たとえば、エージェントが生成したすべての新しい項目を表示することも、最終出力のみを表示することもできます。いずれの場合も、ユーザーが続けて質問した場合は、run メソッドを再度呼び出せます。
|
||||
|
||||
#### 手動による会話管理
|
||||
|
||||
[`RunResultBase.to_input_list()`][agents.result.RunResultBase.to_input_list] メソッドを使用して次のターンの入力を取得し、会話履歴を手動で管理できます。
|
||||
|
||||
```python
|
||||
async def main():
|
||||
agent = Agent(name="Assistant", instructions="Reply very concisely.")
|
||||
|
||||
thread_id = "thread_123" # Example thread ID
|
||||
with trace(workflow_name="Conversation", group_id=thread_id):
|
||||
# First turn
|
||||
result = await Runner.run(agent, "What city is the Golden Gate Bridge in?")
|
||||
print(result.final_output)
|
||||
# San Francisco
|
||||
|
||||
# Second turn
|
||||
new_input = result.to_input_list() + [{"role": "user", "content": "What state is it in?"}]
|
||||
result = await Runner.run(agent, new_input)
|
||||
print(result.final_output)
|
||||
# California
|
||||
```
|
||||
|
||||
#### セッションによる自動会話管理
|
||||
|
||||
より簡単な方法として、[Sessions](sessions/index.md) を使用すると、`.to_input_list()` を手動で呼び出すことなく、会話履歴を自動的に処理できます。
|
||||
|
||||
```python
|
||||
from agents import Agent, Runner, SQLiteSession
|
||||
|
||||
async def main():
|
||||
agent = Agent(name="Assistant", instructions="Reply very concisely.")
|
||||
|
||||
# Create session instance
|
||||
session = SQLiteSession("conversation_123")
|
||||
|
||||
thread_id = "thread_123" # Example thread ID
|
||||
with trace(workflow_name="Conversation", group_id=thread_id):
|
||||
# First turn
|
||||
result = await Runner.run(agent, "What city is the Golden Gate Bridge in?", session=session)
|
||||
print(result.final_output)
|
||||
# San Francisco
|
||||
|
||||
# Second turn - agent automatically remembers previous context
|
||||
result = await Runner.run(agent, "What state is it in?", session=session)
|
||||
print(result.final_output)
|
||||
# California
|
||||
```
|
||||
|
||||
Sessions は次の処理を自動的に行います。
|
||||
|
||||
- 各実行の前に会話履歴を取得します。
|
||||
- 各実行の後に新しいメッセージを保存します。
|
||||
- セッション ID ごとに個別の会話を維持します。
|
||||
|
||||
詳細については、[Sessions のドキュメント](sessions/index.md)を参照してください。
|
||||
|
||||
|
||||
#### サーバー管理の会話
|
||||
|
||||
`to_input_list()` または `Sessions` を使用してローカルで処理する代わりに、OpenAI の会話状態機能にサーバー側で会話状態を管理させることもできます。これにより、過去のすべてのメッセージを毎回手動で再送信することなく、会話履歴を維持できます。以下のいずれかのサーバー管理方式では、各リクエストで新しいターンの入力のみを渡し、保存した ID を再利用します。詳細については、[OpenAI の会話状態ガイド](https://platform.openai.com/docs/guides/conversation-state?api-mode=responses)を参照してください。
|
||||
|
||||
OpenAI は、ターンをまたいで状態を追跡する 2 つの方法を提供します。
|
||||
|
||||
##### 1. `conversation_id` の使用
|
||||
|
||||
まず OpenAI Conversations API を使用して会話を作成し、その後の各呼び出しで ID を再利用します。
|
||||
|
||||
```python
|
||||
from agents import Agent, Runner
|
||||
from openai import AsyncOpenAI
|
||||
|
||||
client = AsyncOpenAI()
|
||||
|
||||
async def main():
|
||||
agent = Agent(name="Assistant", instructions="Reply very concisely.")
|
||||
|
||||
# Create a server-managed conversation
|
||||
conversation = await client.conversations.create()
|
||||
conv_id = conversation.id
|
||||
|
||||
while True:
|
||||
user_input = input("You: ")
|
||||
result = await Runner.run(agent, user_input, conversation_id=conv_id)
|
||||
print(f"Assistant: {result.final_output}")
|
||||
```
|
||||
|
||||
##### 2. `previous_response_id` の使用
|
||||
|
||||
もう 1 つの方法は **レスポンスチェーン** です。各ターンを前のターンのレスポンス ID に明示的に関連付けます。
|
||||
|
||||
```python
|
||||
from agents import Agent, Runner
|
||||
|
||||
async def main():
|
||||
agent = Agent(name="Assistant", instructions="Reply very concisely.")
|
||||
|
||||
previous_response_id = None
|
||||
|
||||
while True:
|
||||
user_input = input("You: ")
|
||||
|
||||
# Setting auto_previous_response_id=True enables response chaining automatically
|
||||
# for the first turn, even when there's no actual previous response ID yet.
|
||||
result = await Runner.run(
|
||||
agent,
|
||||
user_input,
|
||||
previous_response_id=previous_response_id,
|
||||
auto_previous_response_id=True,
|
||||
)
|
||||
previous_response_id = result.last_response_id
|
||||
print(f"Assistant: {result.final_output}")
|
||||
```
|
||||
|
||||
実行が承認待ちで一時停止し、[`RunState`][agents.run_state.RunState] から再開した場合、SDK は保存された `conversation_id` / `previous_response_id` / `auto_previous_response_id` の設定を保持するため、再開したターンは同じサーバー管理の会話内で継続されます。
|
||||
|
||||
`conversation_id` と `previous_response_id` は同時に使用できません。システム間で共有できる名前付き会話リソースが必要な場合は、`conversation_id` を使用します。ターン間で最も軽量な Responses API の継続用基本コンポーネントが必要な場合は、`previous_response_id` を使用します。
|
||||
|
||||
!!! note
|
||||
|
||||
SDK は `conversation_locked` エラーをバックオフ付きで自動的に再試行します。サーバー管理の
|
||||
会話を使用する実行では、同じ準備済み項目を問題なく再送信できるよう、再試行前に内部の
|
||||
conversation tracker の入力を巻き戻します。
|
||||
|
||||
ローカルのセッションに基づく実行(`conversation_id`、`previous_response_id`、
|
||||
`auto_previous_response_id` のいずれとも組み合わせられません)でも、SDK は再試行後に
|
||||
履歴項目が重複することを抑えるため、直近に永続化された入力項目のロールバックを可能な範囲で行います。
|
||||
|
||||
この互換性維持のための再試行は、`ModelSettings.retry` を設定していない場合でも行われます。
|
||||
モデルリクエストに対する、より広範なオプトインの再試行動作については、[Runner 管理の再試行](models/index.md#runner-managed-retries)を参照してください。
|
||||
|
||||
## フックとカスタマイズ
|
||||
|
||||
### モデル呼び出しの入力フィルター
|
||||
|
||||
モデル呼び出しの直前にモデル入力を編集するには、`call_model_input_filter` を使用します。このフックは、現在のエージェント、コンテキスト、および統合された入力項目(存在する場合はセッション履歴を含む)を受け取り、新しい `ModelInputData` を返します。
|
||||
|
||||
戻り値は [`ModelInputData`][agents.run.ModelInputData] オブジェクトである必要があります。その `input` フィールドは必須で、入力項目のリストでなければなりません。それ以外の形式を返すと `UserError` が発生します。
|
||||
|
||||
```python
|
||||
from agents import Agent, Runner, RunConfig
|
||||
from agents.run import CallModelData, ModelInputData
|
||||
|
||||
def drop_old_messages(data: CallModelData[None]) -> ModelInputData:
|
||||
# Keep only the last 5 items and preserve existing instructions.
|
||||
trimmed = data.model_data.input[-5:]
|
||||
return ModelInputData(input=trimmed, instructions=data.model_data.instructions)
|
||||
|
||||
agent = Agent(name="Assistant", instructions="Answer concisely.")
|
||||
result = Runner.run_sync(
|
||||
agent,
|
||||
"Explain quines",
|
||||
run_config=RunConfig(call_model_input_filter=drop_old_messages),
|
||||
)
|
||||
```
|
||||
|
||||
runner は準備済み入力リストのコピーをフックに渡すため、呼び出し元の元のリストを直接変更することなく、短縮、置換、並べ替えを行えます。
|
||||
|
||||
セッションを使用している場合、`call_model_input_filter` はセッション履歴がすでに読み込まれ、現在のターンとマージされた後に実行されます。この前段階のマージ処理自体をカスタマイズする場合は、[`session_input_callback`][agents.run.RunConfig.session_input_callback] を使用します。
|
||||
|
||||
`conversation_id`、`previous_response_id`、または `auto_previous_response_id` を使用して OpenAI のサーバー管理の会話状態を利用している場合、フックは次の Responses API 呼び出し用に準備されたペイロードに対して実行されます。そのペイロードは、以前の履歴全体の再現ではなく、新しいターンの差分のみをすでに表している場合があります。返された項目だけが、そのサーバー管理の継続処理に送信済みとしてマークされます。
|
||||
|
||||
機密データの編集、長い履歴の短縮、追加のシステムガイダンスの挿入を行うには、`run_config` を介して実行ごとにフックを設定します。
|
||||
|
||||
## エラーと復旧
|
||||
|
||||
### エラーハンドラー
|
||||
|
||||
すべての `Runner` エントリーポイントは、エラー種別をキーとする dict の `error_handlers` を受け取ります。サポートされているキーは `"max_turns"`、`"model_refusal"`、`"invalid_final_output"` です。対応するエラーで実行を終了する代わりに、制御された最終出力を返す場合に使用します。
|
||||
|
||||
```python
|
||||
from agents import (
|
||||
Agent,
|
||||
RunErrorHandlerInput,
|
||||
RunErrorHandlerResult,
|
||||
Runner,
|
||||
)
|
||||
|
||||
agent = Agent(name="Assistant", instructions="Be concise.")
|
||||
|
||||
|
||||
def on_max_turns(_data: RunErrorHandlerInput[None]) -> RunErrorHandlerResult:
|
||||
return RunErrorHandlerResult(
|
||||
final_output="I couldn't finish within the turn limit. Please narrow the request.",
|
||||
include_in_history=False,
|
||||
)
|
||||
|
||||
|
||||
result = Runner.run_sync(
|
||||
agent,
|
||||
"Analyze this long transcript",
|
||||
max_turns=3,
|
||||
error_handlers={"max_turns": on_max_turns},
|
||||
)
|
||||
print(result.final_output)
|
||||
```
|
||||
|
||||
モデルメッセージがエージェントの structured な `output_type` に対する検証に失敗した場合、またはモデルが structured な最終メッセージを返さない場合は、`"invalid_final_output"` を使用します。ハンドラーはアプリケーション固有のフォールバックを返すことができ、SDK は同じ `output_type` に対してそれを検証します。モデル呼び出しの再試行や、ツールの副作用の再実行は行いません。`None` を返すと、復旧を行いません。フォールバックがない場合、空でないレスポンスの検証失敗では引き続き `ModelBehaviorError` が発生し、空の structured レスポンスでは既存の次ターンの動作が維持されます。
|
||||
|
||||
```python
|
||||
from pydantic import BaseModel
|
||||
|
||||
from agents import Agent, ModelBehaviorError, RunErrorHandlerInput, Runner
|
||||
|
||||
|
||||
class Recipe(BaseModel):
|
||||
ingredients: list[str]
|
||||
recovered_from_invalid_output: bool = False
|
||||
|
||||
|
||||
def on_invalid_final_output(data: RunErrorHandlerInput[None]) -> Recipe:
|
||||
assert isinstance(data.error, ModelBehaviorError)
|
||||
return Recipe(ingredients=[], recovered_from_invalid_output=True)
|
||||
|
||||
|
||||
agent = Agent(
|
||||
name="Recipe assistant",
|
||||
instructions="Return a structured recipe.",
|
||||
output_type=Recipe,
|
||||
)
|
||||
|
||||
result = Runner.run_sync(
|
||||
agent,
|
||||
"Plan tonight's dinner.",
|
||||
error_handlers={"invalid_final_output": on_invalid_final_output},
|
||||
)
|
||||
print(result.final_output)
|
||||
```
|
||||
|
||||
フォールバック出力を会話履歴に追加しない場合は、`include_in_history=False` を設定します。
|
||||
|
||||
モデルによる拒否が発生した際に、`ModelRefusalError` で実行を終了する代わりにアプリケーション固有のフォールバックを生成する場合は、`"model_refusal"` を使用します。
|
||||
|
||||
```python
|
||||
from pydantic import BaseModel
|
||||
|
||||
from agents import Agent, ModelRefusalError, RunErrorHandlerInput, Runner
|
||||
|
||||
|
||||
class Recipe(BaseModel):
|
||||
ingredients: list[str]
|
||||
refusal_reason: str | None = None
|
||||
|
||||
|
||||
def on_model_refusal(data: RunErrorHandlerInput[None]) -> Recipe:
|
||||
assert isinstance(data.error, ModelRefusalError)
|
||||
return Recipe(ingredients=[], refusal_reason=data.error.refusal)
|
||||
|
||||
|
||||
agent = Agent(
|
||||
name="Recipe assistant",
|
||||
instructions="Return a structured recipe.",
|
||||
output_type=Recipe,
|
||||
)
|
||||
|
||||
result = Runner.run_sync(
|
||||
agent,
|
||||
"Make me something unsafe.",
|
||||
error_handlers={"model_refusal": on_model_refusal},
|
||||
)
|
||||
print(result.final_output)
|
||||
```
|
||||
|
||||
## 永続的な実行の統合とヒューマンインザループ
|
||||
|
||||
ツール承認の一時停止/再開パターンについては、専用の[ヒューマンインザループガイド](human_in_the_loop.md)から参照してください。以下の統合は、実行が長時間の待機、再試行、プロセスの再起動にまたがる可能性がある場合の永続的なオーケストレーションを目的としています。
|
||||
|
||||
### Dapr
|
||||
|
||||
Agents SDK の [Dapr](https://dapr.io) Diagrid 統合を使用すると、ヒューマンインザループをサポートし、障害から自動的に復旧する、永続的かつ長時間実行されるエージェントを実行できます。Dapr はベンダー中立の [CNCF](https://cncf.io) ワークフローオーケストレーターです。Dapr と OpenAI エージェントの使用を開始するには、[こちら](https://docs.diagrid.io/getting-started/quickstarts/ai-agents/?agentframework=openai)を参照してください。
|
||||
|
||||
### Temporal
|
||||
|
||||
Agents SDK の [Temporal](https://temporal.io/) 統合を使用すると、ヒューマンインザループのタスクを含む、永続的で長時間実行されるワークフローを実行できます。Temporal と Agents SDK が連携して長時間実行タスクを完了するデモについては、[この動画](https://www.youtube.com/watch?v=fFBZqzT4DD8)を参照してください。また、[ドキュメントはこちら](https://github.com/temporalio/sdk-python/tree/main/temporalio/contrib/openai_agents)から確認できます。
|
||||
|
||||
### Restate
|
||||
|
||||
Agents SDK の [Restate](https://restate.dev/) 統合を使用すると、人による承認、ハンドオフ、セッション管理を含む、軽量で永続的なエージェントを利用できます。この統合では、Restate の単一バイナリランタイムが依存関係として必要です。また、エージェントをプロセス/コンテナまたはサーバーレス関数として実行できます。詳細については、[概要](https://www.restate.dev/blog/durable-orchestration-for-ai-agents-with-restate-and-openai-sdk)または[ドキュメント](https://docs.restate.dev/ai)を参照してください。
|
||||
|
||||
### DBOS
|
||||
|
||||
Agents SDK の [DBOS](https://dbos.dev/) 統合を使用すると、障害や再起動が発生しても進行状況を保持する、信頼性の高いエージェントを実行できます。長時間実行されるエージェント、ヒューマンインザループのワークフロー、ハンドオフをサポートします。同期メソッドと非同期メソッドの両方に対応しています。この統合に必要なのは、SQLite または Postgres データベースのみです。詳細については、統合の[リポジトリ](https://github.com/dbos-inc/dbos-openai-agents)と[ドキュメント](https://docs.dbos.dev/integrations/openai-agents)を参照してください。
|
||||
|
||||
## 例外
|
||||
|
||||
SDK は特定の状況で例外を発生させます。完全な一覧は [`agents.exceptions`][] にあります。概要は次のとおりです。
|
||||
|
||||
- [`AgentsException`][agents.exceptions.AgentsException]:SDK 内で発生するすべての例外の基底クラスです。他のすべての具体的な例外は、この汎用型から派生します。
|
||||
- [`MaxTurnsExceeded`][agents.exceptions.MaxTurnsExceeded]:エージェントの実行が、`Runner.run`、`Runner.run_sync`、または `Runner.run_streamed` メソッドに渡された `max_turns` 制限を超えた場合に発生する例外です。指定された対話ターン数以内にエージェントがタスクを完了できなかったことを示します。制限を無効にするには、`max_turns=None` を設定します。
|
||||
- [`ModelBehaviorError`][agents.exceptions.ModelBehaviorError]:基盤となるモデル(LLM)が予期しない出力または無効な出力を生成した場合に発生する例外です。これには次のものが含まれます。
|
||||
- 不正な JSON:特に特定の `output_type` が定義されている場合に、モデルがツール呼び出しまたは直接出力で不正な JSON 構造を返した場合です。
|
||||
- 予期しないツール関連の失敗:モデルが想定された方法でツールを使用できなかった場合です。
|
||||
- [`ToolTimeoutError`][agents.exceptions.ToolTimeoutError]:関数ツール呼び出しが設定されたタイムアウトを超え、そのツールが `timeout_behavior="raise_exception"` を使用している場合に発生する例外です。
|
||||
- [`UserError`][agents.exceptions.UserError]:SDK を使用するコードを作成しているユーザーが、SDK の使用時に誤りを犯した場合に発生する例外です。通常は、不適切なコード実装、無効な設定、SDK API の誤用によって発生します。
|
||||
- [`InputGuardrailTripwireTriggered`][agents.exceptions.InputGuardrailTripwireTriggered]、[`OutputGuardrailTripwireTriggered`][agents.exceptions.OutputGuardrailTripwireTriggered]:それぞれ、入力ガードレールまたは出力ガードレールの条件が満たされた場合に発生する例外です。入力ガードレールは処理前に受信メッセージをチェックし、出力ガードレールは配信前にエージェントの最終レスポンスをチェックします。
|
||||
@@ -0,0 +1,141 @@
|
||||
---
|
||||
search:
|
||||
exclude: true
|
||||
---
|
||||
# サンドボックスクライアント
|
||||
|
||||
このページでは、サンドボックスでの作業をどこで実行するかを選択します。ほとんどの場合、`SandboxAgent` の定義は同じままにし、サンドボックスクライアントとクライアント固有のオプションを [`SandboxRunConfig`][agents.run_config.SandboxRunConfig] で変更します。
|
||||
|
||||
!!! warning "ベータ機能"
|
||||
|
||||
サンドボックスエージェントはベータ版です。一般提供までに API の詳細、デフォルト値、サポートされる機能が変更される可能性があります。また、時間とともにより高度な機能が追加される見込みです。
|
||||
|
||||
## 判断ガイド
|
||||
|
||||
<div class="sandbox-nowrap-first-column-table" markdown="1">
|
||||
|
||||
| 目的 | まず使うもの | 理由 |
|
||||
| --- | --- | --- |
|
||||
| macOS または Linux での最速のローカル反復 | `UnixLocalSandboxClient` | 追加インストール不要で、シンプルなローカルファイルシステム開発ができます。 |
|
||||
| 基本的なコンテナ分離 | `DockerSandboxClient` | 特定のイメージを使って Docker 内で作業を実行します。 |
|
||||
| ホスト型実行または本番環境スタイルの分離 | ホスト型サンドボックスクライアント | ワークスペース境界をプロバイダー管理環境へ移します。 |
|
||||
|
||||
</div>
|
||||
|
||||
## ローカルクライアント
|
||||
|
||||
ほとんどのユーザーは、これら 2 つのサンドボックスクライアントのいずれかから始めることをおすすめします。
|
||||
|
||||
<div class="sandbox-nowrap-first-column-table" markdown="1">
|
||||
|
||||
| クライアント | インストール | 選ぶ場面 | 例 |
|
||||
| --- | --- | --- | --- |
|
||||
| `UnixLocalSandboxClient` | なし | macOS または Linux で最速のローカル反復が必要な場合。ローカル開発の既定として適しています。 | [Unix-local スターター](https://github.com/openai/openai-agents-python/blob/main/examples/sandbox/unix_local_runner.py) |
|
||||
| `DockerSandboxClient` | `openai-agents[docker]` | コンテナ分離、またはローカルで同等性を保つための特定のイメージが必要な場合。 | [Docker スターター](https://github.com/openai/openai-agents-python/blob/main/examples/sandbox/docker/docker_runner.py) |
|
||||
|
||||
</div>
|
||||
|
||||
Unix-local は、ローカルファイルシステムに対して開発を始める最も簡単な方法です。より強い環境分離や本番環境スタイルの同等性が必要になったら、Docker またはホスト型プロバイダーへ移行してください。
|
||||
|
||||
Unix-local から Docker に切り替えるには、エージェント定義は同じままにして、実行設定だけを変更します。
|
||||
|
||||
```python
|
||||
from docker import from_env as docker_from_env
|
||||
|
||||
from agents.run import RunConfig
|
||||
from agents.sandbox import SandboxRunConfig
|
||||
from agents.sandbox.sandboxes.docker import DockerSandboxClient, DockerSandboxClientOptions
|
||||
|
||||
run_config = RunConfig(
|
||||
sandbox=SandboxRunConfig(
|
||||
client=DockerSandboxClient(docker_from_env()),
|
||||
options=DockerSandboxClientOptions(image="python:3.14-slim"),
|
||||
),
|
||||
)
|
||||
```
|
||||
|
||||
コンテナ分離またはイメージの同等性が必要な場合に使用してください。[examples/sandbox/docker/docker_runner.py](https://github.com/openai/openai-agents-python/blob/main/examples/sandbox/docker/docker_runner.py) を参照してください。
|
||||
|
||||
## マウントとリモートストレージ
|
||||
|
||||
マウントエントリーはどのストレージを公開するかを表し、マウント戦略はサンドボックスバックエンドがそのストレージをどのようにアタッチするかを表します。組み込みのマウントエントリーと汎用戦略は `agents.sandbox.entries` からインポートします。ホスト型プロバイダーの戦略は `agents.extensions.sandbox` またはプロバイダー固有の拡張パッケージから利用できます。
|
||||
|
||||
一般的なマウントオプション:
|
||||
|
||||
- `mount_path`: ストレージがサンドボックス内で表示される場所です。相対パスはマニフェストルート配下で解決され、絶対パスはそのまま使用されます。
|
||||
- `read_only`: 既定は `True` です。サンドボックスがマウントされたストレージへ書き戻す必要がある場合にのみ `False` に設定してください。
|
||||
- `mount_strategy`: 必須です。マウントエントリーとサンドボックスバックエンドの両方に合う戦略を使用してください。
|
||||
|
||||
マウントは一時的なワークスペースエントリーとして扱われます。スナップショットと永続化のフローでは、マウントされたリモートストレージを保存済みワークスペースへコピーするのではなく、マウントされたパスをデタッチするかスキップします。
|
||||
|
||||
汎用ローカル / コンテナ戦略:
|
||||
|
||||
<div class="sandbox-nowrap-first-column-table" markdown="1">
|
||||
|
||||
| 戦略またはパターン | 使用する場面 | 備考 |
|
||||
| --- | --- | --- |
|
||||
| `InContainerMountStrategy(pattern=RcloneMountPattern(...))` | サンドボックスイメージで `rclone` を実行できる場合。 | S3、GCS、R2、Azure Blob、Box をサポートします。`RcloneMountPattern` は `fuse` モードまたは `nfs` モードで実行できます。 |
|
||||
| `InContainerMountStrategy(pattern=MountpointMountPattern(...))` | イメージに `mount-s3` があり、Mountpoint スタイルの S3 または S3 互換アクセスが必要な場合。 | `S3Mount` と `GCSMount` をサポートします。 |
|
||||
| `InContainerMountStrategy(pattern=FuseMountPattern(...))` | イメージに `blobfuse2` があり、FUSE サポートがある場合。 | `AzureBlobMount` をサポートします。 |
|
||||
| `InContainerMountStrategy(pattern=S3FilesMountPattern(...))` | イメージに `mount.s3files` があり、既存の S3 Files マウントターゲットに到達できる場合。 | `S3FilesMount` をサポートします。 |
|
||||
| `DockerVolumeMountStrategy(driver=...)` | Docker がコンテナ起動前にボリュームドライバー対応のマウントをアタッチする必要がある場合。 | Docker のみです。`rclone` は S3、GCS、R2、Azure Blob、Box をサポートし、`mountpoint` は S3 と GCS もサポートします。 |
|
||||
|
||||
</div>
|
||||
|
||||
## サポートされるホスト型プラットフォーム
|
||||
|
||||
ホスト型環境が必要な場合、通常は同じ `SandboxAgent` 定義をそのまま引き継ぎ、[`SandboxRunConfig`][agents.run_config.SandboxRunConfig] でサンドボックスクライアントだけを変更します。
|
||||
|
||||
このリポジトリのチェックアウトではなく公開されている SDK を使用している場合は、対応するパッケージ extra を通じてサンドボックスクライアントの依存関係をインストールしてください。
|
||||
|
||||
プロバイダー固有のセットアップメモと、チェックイン済みの拡張コード例へのリンクについては、[examples/sandbox/extensions/README.md](https://github.com/openai/openai-agents-python/blob/main/examples/sandbox/extensions/README.md) を参照してください。
|
||||
|
||||
<div class="sandbox-nowrap-first-column-table" markdown="1">
|
||||
|
||||
| クライアント | インストール | 例 |
|
||||
| --- | --- | --- |
|
||||
| `BlaxelSandboxClient` | `openai-agents[blaxel]` | [Blaxel ランナー](https://github.com/openai/openai-agents-python/blob/main/examples/sandbox/extensions/blaxel_runner.py) |
|
||||
| `CloudflareSandboxClient` | `openai-agents[cloudflare]` | [Cloudflare ランナー](https://github.com/openai/openai-agents-python/blob/main/examples/sandbox/extensions/cloudflare_runner.py) |
|
||||
| `DaytonaSandboxClient` | `openai-agents[daytona]` | [Daytona ランナー](https://github.com/openai/openai-agents-python/blob/main/examples/sandbox/extensions/daytona/daytona_runner.py) |
|
||||
| `E2BSandboxClient` | `openai-agents[e2b]` | [E2B ランナー](https://github.com/openai/openai-agents-python/blob/main/examples/sandbox/extensions/e2b_runner.py) |
|
||||
| `ModalSandboxClient` | `openai-agents[modal]` | [Modal ランナー](https://github.com/openai/openai-agents-python/blob/main/examples/sandbox/extensions/modal_runner.py) |
|
||||
| `RunloopSandboxClient` | `openai-agents[runloop]` | [Runloop ランナー](https://github.com/openai/openai-agents-python/blob/main/examples/sandbox/extensions/runloop/runner.py) |
|
||||
| `VercelSandboxClient` | `openai-agents[vercel]` | [Vercel ランナー](https://github.com/openai/openai-agents-python/blob/main/examples/sandbox/extensions/vercel_runner.py) |
|
||||
|
||||
</div>
|
||||
|
||||
ホスト型サンドボックスクライアントは、プロバイダー固有のマウント戦略を公開します。ストレージプロバイダーに最も合うバックエンドとマウント戦略を選択してください。
|
||||
|
||||
<div class="sandbox-nowrap-first-column-table" markdown="1">
|
||||
|
||||
| バックエンド | マウントに関する注記 |
|
||||
| --- | --- |
|
||||
| Docker | `InContainerMountStrategy` や `DockerVolumeMountStrategy` などのローカル戦略で、`S3Mount`、`GCSMount`、`R2Mount`、`AzureBlobMount`、`BoxMount`、`S3FilesMount` をサポートします。 |
|
||||
| `ModalSandboxClient` | `S3Mount`、`R2Mount`、HMAC 認証済みの `GCSMount` で、`ModalCloudBucketMountStrategy` による Modal のクラウドバケットマウントをサポートします。インライン認証情報、または名前付きの Modal Secret を使用できます。 |
|
||||
| `CloudflareSandboxClient` | `S3Mount`、`R2Mount`、HMAC 認証済みの `GCSMount` で、`CloudflareBucketMountStrategy` による Cloudflare バケットマウントをサポートします。 |
|
||||
| `BlaxelSandboxClient` | `S3Mount`、`R2Mount`、`GCSMount` で、`BlaxelCloudBucketMountStrategy` によるクラウドバケットマウントをサポートします。`agents.extensions.sandbox.blaxel` の `BlaxelDriveMount` と `BlaxelDriveMountStrategy` による永続的な Blaxel Drives もサポートします。 |
|
||||
| `DaytonaSandboxClient` | `DaytonaCloudBucketMountStrategy` による `rclone` ベースのクラウドストレージマウントをサポートします。`S3Mount`、`GCSMount`、`R2Mount`、`AzureBlobMount`、`BoxMount` と組み合わせて使用してください。 |
|
||||
| `E2BSandboxClient` | `E2BCloudBucketMountStrategy` による `rclone` ベースのクラウドストレージマウントをサポートします。`S3Mount`、`GCSMount`、`R2Mount`、`AzureBlobMount`、`BoxMount` と組み合わせて使用してください。 |
|
||||
| `RunloopSandboxClient` | `RunloopCloudBucketMountStrategy` による `rclone` ベースのクラウドストレージマウントをサポートします。`S3Mount`、`GCSMount`、`R2Mount`、`AzureBlobMount`、`BoxMount` と組み合わせて使用してください。 |
|
||||
| `VercelSandboxClient` | 現時点ではホスト型固有のマウント戦略は公開されていません。代わりにマニフェストファイル、リポジトリ、またはその他のワークスペース入力を使用してください。 |
|
||||
|
||||
</div>
|
||||
|
||||
以下の表は、各バックエンドが直接マウントできるリモートストレージエントリーをまとめたものです。
|
||||
|
||||
<div class="sandbox-nowrap-first-column-table" markdown="1">
|
||||
|
||||
| バックエンド | AWS S3 | Cloudflare R2 | GCS | Azure Blob Storage | Box | S3 Files |
|
||||
| --- | --- | --- | --- | --- | --- | --- |
|
||||
| Docker | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ |
|
||||
| `ModalSandboxClient` | ✓ | ✓ | ✓ | - | - | - |
|
||||
| `CloudflareSandboxClient` | ✓ | ✓ | ✓ | - | - | - |
|
||||
| `BlaxelSandboxClient` | ✓ | ✓ | ✓ | - | - | - |
|
||||
| `DaytonaSandboxClient` | ✓ | ✓ | ✓ | ✓ | ✓ | - |
|
||||
| `E2BSandboxClient` | ✓ | ✓ | ✓ | ✓ | ✓ | - |
|
||||
| `RunloopSandboxClient` | ✓ | ✓ | ✓ | ✓ | ✓ | - |
|
||||
| `VercelSandboxClient` | - | - | - | - | - | - |
|
||||
|
||||
</div>
|
||||
|
||||
実行可能なコード例をさらに見るには、ローカル、コーディング、メモリ、ハンドオフ、エージェント合成パターンについては [examples/sandbox/](https://github.com/openai/openai-agents-python/tree/main/examples/sandbox) を、ホスト型サンドボックスクライアントについては [examples/sandbox/extensions/](https://github.com/openai/openai-agents-python/tree/main/examples/sandbox/extensions) を参照してください。
|
||||
@@ -0,0 +1,861 @@
|
||||
---
|
||||
search:
|
||||
exclude: true
|
||||
---
|
||||
# 概念
|
||||
|
||||
!!! warning "ベータ機能"
|
||||
|
||||
サンドボックスエージェントはベータ版です。一般提供までに API の詳細、デフォルト、サポートされる機能が変更される可能性があります。また、今後さらに高度な機能が追加される予定です。
|
||||
|
||||
最新のエージェントは、ファイルシステム上の実際のファイルを操作できる場合に最も効果を発揮します。**サンドボックスエージェント**は、特化したツールやシェルコマンドを使用して、大規模なドキュメントセットの検索や操作、ファイルの編集、成果物の生成、コマンドの実行を行えます。サンドボックスは、エージェントがユーザーに代わって作業するために利用できる永続的なワークスペースをモデルに提供します。Agents SDK のサンドボックスエージェントを使用すると、サンドボックス環境と組み合わせたエージェントを簡単に実行できます。また、適切なファイルをファイルシステム上に配置し、サンドボックスをオーケストレーションすることで、大規模なタスクの開始、停止、再開を容易に行えます。
|
||||
|
||||
エージェントが必要とするデータを中心にワークスペースを定義します。GitHub リポジトリ、ローカルのファイルやディレクトリ、合成タスクファイル、S3 や Azure Blob Storage などのリモートファイルシステム、および提供するその他のサンドボックス入力から開始できます。
|
||||
|
||||
<div class="sandbox-harness-image" markdown="1">
|
||||
|
||||

|
||||
|
||||
</div>
|
||||
|
||||
`SandboxAgent` も引き続き `Agent` です。`instructions`、`prompt`、`tools`、`handoffs`、`mcp_servers`、`model_settings`、`output_type`、ガードレール、フックなど、通常のエージェントインターフェースを維持し、通常の `Runner` API を通じて実行されます。異なるのは実行境界です。
|
||||
|
||||
- `SandboxAgent` はエージェント自体を定義します。通常のエージェント設定に加えて、`default_manifest`、`base_instructions`、`run_as` などのサンドボックス固有のデフォルト、およびファイルシステムツール、シェルアクセス、スキル、メモリ、コンパクションなどの機能を含みます。
|
||||
- `Manifest` は、ファイル、リポジトリ、マウント、環境など、新しいサンドボックスワークスペースの初期内容とレイアウトを宣言します。
|
||||
- サンドボックスセッションは、コマンドが実行され、ファイルが変更される稼働中の分離環境です。
|
||||
- [`SandboxRunConfig`][agents.run_config.SandboxRunConfig] は、サンドボックスセッションを直接注入する、シリアライズされたサンドボックスセッション状態から再接続する、サンドボックスクライアントを通じて新しいサンドボックスセッションを作成するなど、実行がサンドボックスセッションを取得する方法を決定します。
|
||||
- 保存されたサンドボックス状態とスナップショットにより、後続の実行は以前の作業へ再接続したり、保存された内容を使用して新しいサンドボックスセッションを初期化したりできます。
|
||||
|
||||
`Manifest` は新規セッション用のワークスペース契約であり、稼働中のすべてのサンドボックスに関する完全な信頼できる情報源ではありません。実行時に有効となるワークスペースは、再利用されたサンドボックスセッション、シリアライズされたサンドボックスセッション状態、または実行時に選択されたスナップショットから取得される場合があります。
|
||||
|
||||
このページでは、「サンドボックスセッション」はサンドボックスクライアントによって管理される稼働中の実行環境を意味します。これは、[セッション](../sessions/index.md)で説明されている SDK の会話用 [`Session`][agents.memory.session.Session] インターフェースとは異なります。
|
||||
|
||||
外側のランタイムは、引き続き承認、トレーシング、ハンドオフ、再開時の記録管理を担います。サンドボックスセッションは、コマンド、ファイル変更、環境の分離を担います。この分担は、このモデルの中核をなす要素です。
|
||||
|
||||
### 各要素の連携
|
||||
|
||||
サンドボックス実行では、エージェント定義と実行ごとのサンドボックス設定を組み合わせます。ランナーはエージェントを準備して稼働中のサンドボックスセッションにバインドし、後続の実行のために状態を保存できます。
|
||||
|
||||
```mermaid
|
||||
flowchart LR
|
||||
agent["SandboxAgent<br/><small>full Agent + sandbox defaults</small>"]
|
||||
config["SandboxRunConfig<br/><small>client / session / resume inputs</small>"]
|
||||
runner["Runner<br/><small>prepare instructions<br/>bind capability tools</small>"]
|
||||
sandbox["sandbox session<br/><small>workspace where commands run<br/>and files change</small>"]
|
||||
saved["saved state / snapshot<br/><small>for resume or fresh-start later</small>"]
|
||||
|
||||
agent --> runner
|
||||
config --> runner
|
||||
runner --> sandbox
|
||||
sandbox --> saved
|
||||
```
|
||||
|
||||
サンドボックス固有のデフォルトは `SandboxAgent` に保持します。実行ごとのサンドボックスセッションの選択は `SandboxRunConfig` に保持します。
|
||||
|
||||
ライフサイクルは、次の 3 段階で考えます。
|
||||
|
||||
1. `SandboxAgent`、`Manifest`、機能を使用して、エージェントと新規ワークスペースの契約を定義します。
|
||||
2. サンドボックスセッションを注入、再開、または作成する `SandboxRunConfig` を `Runner` に渡して実行します。
|
||||
3. ランナーが管理する `RunState`、明示的なサンドボックスの `session_state`、または保存済みワークスペースのスナップショットから、後で処理を継続します。
|
||||
|
||||
シェルアクセスがたまにしか使用しないツールの 1 つにすぎない場合は、[ツールガイド](../tools.md)のホステッドシェルから始めてください。ワークスペースの分離、サンドボックスクライアントの選択、またはサンドボックスセッションの再開動作が設計の一部である場合は、サンドボックスエージェントを使用してください。
|
||||
|
||||
## 使用に適した状況
|
||||
|
||||
サンドボックスエージェントは、次のようなワークスペース中心のワークフローに適しています。
|
||||
|
||||
- コーディングとデバッグ。たとえば、GitHub リポジトリの Issue レポートに対する自動修正をオーケストレーションし、対象を絞ったテストを実行する場合
|
||||
- ドキュメントの処理と編集。たとえば、ユーザーの財務書類から情報を抽出し、記入済みの税務フォームの下書きを作成する場合
|
||||
- ファイルを根拠とするレビューや分析。たとえば、回答前にオンボーディング資料、生成されたレポート、成果物のバンドルを確認する場合
|
||||
- 分離されたマルチエージェントパターン。たとえば、各レビュアーやコーディング用サブエージェントに専用のワークスペースを提供する場合
|
||||
- 複数ステップのワークスペースタスク。たとえば、ある実行でバグを修正し、後で回帰テストを追加する場合や、スナップショットまたはサンドボックスセッション状態から再開する場合
|
||||
|
||||
ファイルや稼働中のファイルシステムへのアクセスが不要な場合は、引き続き `Agent` を使用してください。シェルアクセスがたまにしか使用しない機能の 1 つであればホステッドシェルを追加し、ワークスペース境界自体が機能の一部であればサンドボックスエージェントを使用します。
|
||||
|
||||
## サンドボックスクライアントの選択
|
||||
|
||||
ローカル開発では `UnixLocalSandboxClient` から始めてください。コンテナ分離やイメージの同等性が必要な場合は `DockerSandboxClient` に移行します。プロバイダー管理の実行が必要な場合は、ホステッドプロバイダーに移行します。
|
||||
|
||||
ほとんどの場合、`SandboxAgent` の定義はそのまま維持し、[`SandboxRunConfig`][agents.run_config.SandboxRunConfig] 内のサンドボックスクライアントとそのオプションのみを変更します。ローカル、Docker、ホステッド、リモートマウントのオプションについては、[サンドボックスクライアント](clients.md)を参照してください。
|
||||
|
||||
## 中核要素
|
||||
|
||||
<div class="sandbox-nowrap-first-column-table" markdown="1">
|
||||
|
||||
| レイヤー | 主な SDK 要素 | 回答する内容 |
|
||||
| --- | --- | --- |
|
||||
| エージェント定義 | `SandboxAgent`、`Manifest`、機能 | どのエージェントを実行し、どの新規セッション用ワークスペース契約から開始するか? |
|
||||
| サンドボックス実行 | `SandboxRunConfig`、サンドボックスクライアント、稼働中のサンドボックスセッション | この実行は稼働中のサンドボックスセッションをどのように取得し、作業はどこで実行されるか? |
|
||||
| 保存済みサンドボックス状態 | `RunState` のサンドボックスペイロード、`session_state`、スナップショット | このワークフローは以前のサンドボックス作業へどのように再接続し、保存された内容から新しいサンドボックスセッションをどのように初期化するか? |
|
||||
|
||||
</div>
|
||||
|
||||
主な SDK 要素は、次のようにこれらのレイヤーに対応します。
|
||||
|
||||
<div class="sandbox-nowrap-first-column-table" markdown="1">
|
||||
|
||||
| 要素 | 担当範囲 | 確認すべき内容 |
|
||||
| --- | --- | --- |
|
||||
| [`SandboxAgent`][agents.sandbox.sandbox_agent.SandboxAgent] | エージェント定義 | このエージェントは何を実行し、どのデフォルト設定を引き継ぐべきか? |
|
||||
| [`Manifest`][agents.sandbox.manifest.Manifest] | 新規セッション用ワークスペースのファイルとフォルダー | 実行開始時に、どのファイルとフォルダーがファイルシステム上に存在すべきか? |
|
||||
| [`Capability`][agents.sandbox.capabilities.capability.Capability] | サンドボックスネイティブの動作 | どのツール、指示フラグメント、ランタイム動作をこのエージェントに付与すべきか? |
|
||||
| [`SandboxRunConfig`][agents.run_config.SandboxRunConfig] | 実行ごとのサンドボックスクライアントとサンドボックスセッションの取得元 | この実行では、サンドボックスセッションを注入、再開、作成のいずれで取得すべきか? |
|
||||
| [`RunState`][agents.run_state.RunState] | ランナーが管理する保存済みサンドボックス状態 | 以前のランナー管理ワークフローを再開し、そのサンドボックス状態を自動的に引き継いでいるか? |
|
||||
| [`SandboxRunConfig.session_state`][agents.run_config.SandboxRunConfig.session_state] | 明示的にシリアライズされたサンドボックスセッション状態 | `RunState` の外部で既にシリアライズしたサンドボックス状態から再開するか? |
|
||||
| [`SandboxRunConfig.snapshot`][agents.run_config.SandboxRunConfig.snapshot] | 新しいサンドボックスセッション用に保存されたワークスペース内容 | 新しいサンドボックスセッションを保存済みのファイルや成果物から開始するか? |
|
||||
|
||||
</div>
|
||||
|
||||
実用的な設計順序は次のとおりです。
|
||||
|
||||
1. `Manifest` で新規セッション用ワークスペース契約を定義します。
|
||||
2. `SandboxAgent` でエージェントを定義します。
|
||||
3. 組み込みまたはカスタムの機能を追加します。
|
||||
4. `RunConfig(sandbox=SandboxRunConfig(...))` で、各実行がサンドボックスセッションを取得する方法を決定します。
|
||||
|
||||
## サンドボックス実行の準備
|
||||
|
||||
実行時に、ランナーはその定義を具体的なサンドボックス対応の実行へ変換します。
|
||||
|
||||
1. `SandboxRunConfig` からサンドボックスセッションを解決します。`session=...` を渡した場合、その稼働中のサンドボックスセッションを再利用します。それ以外の場合は、`client=...` を使用してセッションを作成または再開します。
|
||||
2. 実行で有効となるワークスペース入力を決定します。実行でサンドボックスセッションを注入または再開する場合、その既存のサンドボックス状態が優先されます。それ以外の場合、ランナーは一時的なマニフェストオーバーライドまたは `agent.default_manifest` から開始します。このため、`Manifest` だけでは、すべての実行における最終的な稼働中ワークスペースは定義されません。
|
||||
3. 機能が生成されたマニフェストを処理できるようにします。これにより、最終的なエージェントの準備前に、機能がファイル、マウント、その他のワークスペース単位の動作を追加できます。
|
||||
4. 最終的な指示を固定された順序で構築します。SDK のデフォルトのサンドボックスプロンプト、または明示的にオーバーライドした場合は `base_instructions`、次に `instructions`、機能の指示フラグメント、リモートマウントのポリシーテキスト、レンダリングされたファイルシステムツリーの順です。
|
||||
5. 機能ツールを稼働中のサンドボックスセッションにバインドし、準備済みのエージェントを通常の `Runner` API を通じて実行します。
|
||||
|
||||
サンドボックス化によって、ターンの意味は変わりません。ターンは引き続きモデルの 1 ステップであり、単一のシェルコマンドやサンドボックス操作ではありません。サンドボックス側の操作とターンの間に固定された 1 対 1 の対応関係はありません。一部の作業はサンドボックス実行レイヤー内に留まる場合がありますが、他の操作ではツールの結果、承認、または別のモデルステップを必要とするその他の状態が返されます。実用上は、サンドボックスで作業が行われた後、エージェントランタイムが別のモデル応答を必要とする場合にのみ、追加のターンが消費されます。
|
||||
|
||||
これらの準備手順があるため、`SandboxAgent` を設計する際には、`default_manifest`、`instructions`、`base_instructions`、`capabilities`、`run_as` が主なサンドボックス固有の検討事項になります。
|
||||
|
||||
## `SandboxAgent` のオプション
|
||||
|
||||
通常の `Agent` フィールドに加えて、次のサンドボックス固有オプションがあります。
|
||||
|
||||
<div class="sandbox-nowrap-first-column-table" markdown="1">
|
||||
|
||||
| オプション | 最適な用途 |
|
||||
| --- | --- |
|
||||
| `default_manifest` | ランナーが作成する新しいサンドボックスセッション用のデフォルトワークスペース。 |
|
||||
| `instructions` | SDK のサンドボックスプロンプトの後に追加される、ロール、ワークフロー、成功条件。 |
|
||||
| `base_instructions` | SDK のサンドボックスプロンプトを置き換える高度なエスケープハッチ。 |
|
||||
| `capabilities` | このエージェントとともに引き継ぐサンドボックスネイティブのツールと動作。 |
|
||||
| `run_as` | シェルコマンド、ファイル読み取り、パッチなど、モデル向けサンドボックスツールで使用するユーザー ID。 |
|
||||
|
||||
</div>
|
||||
|
||||
サンドボックスクライアントの選択、サンドボックスセッションの再利用、マニフェストのオーバーライド、スナップショットの選択は、エージェントではなく [`SandboxRunConfig`][agents.run_config.SandboxRunConfig] に設定します。
|
||||
|
||||
### `default_manifest`
|
||||
|
||||
`default_manifest` は、ランナーがこのエージェント用に新しいサンドボックスセッションを作成するときに使用するデフォルトの [`Manifest`][agents.sandbox.manifest.Manifest] です。エージェントが通常、開始時に必要とするファイル、リポジトリ、補助資料、出力ディレクトリ、マウントに使用します。
|
||||
|
||||
これはデフォルトにすぎません。実行時に `SandboxRunConfig(manifest=...)` でオーバーライドでき、再利用または再開されたサンドボックスセッションは既存のワークスペース状態を維持します。
|
||||
|
||||
### `instructions` と `base_instructions`
|
||||
|
||||
異なるプロンプト間でも維持すべき短いルールには、`instructions` を使用します。`SandboxAgent` では、これらの指示は SDK のサンドボックス基本プロンプトの後に追加されるため、組み込みのサンドボックスガイダンスを維持しながら、独自のロール、ワークフロー、成功条件を追加できます。
|
||||
|
||||
SDK のサンドボックス基本プロンプトを置き換える場合にのみ、`base_instructions` を使用してください。ほとんどのエージェントでは設定しないでください。
|
||||
|
||||
<div class="sandbox-nowrap-first-column-table" markdown="1">
|
||||
|
||||
| 設定先 | 用途 | 例 |
|
||||
| --- | --- | --- |
|
||||
| `instructions` | エージェントの安定したロール、ワークフロールール、成功条件。 | 「オンボーディング書類を確認してから、ハンドオフしてください」、「最終ファイルを `output/` に書き込んでください」。 |
|
||||
| `base_instructions` | SDK のサンドボックス基本プロンプト全体の置き換え。 | カスタムの低レベルサンドボックスラッパープロンプト。 |
|
||||
| ユーザープロンプト | この実行に固有のリクエスト。 | 「このワークスペースを要約してください」。 |
|
||||
| マニフェスト内のワークスペースファイル | 長いタスク仕様、リポジトリローカルの指示、範囲を限定した参考資料。 | `repo/task.md`、ドキュメントバンドル、サンプル資料。 |
|
||||
|
||||
</div>
|
||||
|
||||
`instructions` の適切な使用例は次のとおりです。
|
||||
|
||||
- [examples/sandbox/unix_local_pty.py](https://github.com/openai/openai-agents-python/blob/main/examples/sandbox/unix_local_pty.py) では、PTY の状態が重要な場合に、エージェントを単一の対話型プロセス内に維持します。
|
||||
- [examples/sandbox/handoffs.py](https://github.com/openai/openai-agents-python/blob/main/examples/sandbox/handoffs.py) では、サンドボックスレビュアーが確認後にユーザーへ直接回答することを禁止します。
|
||||
- [examples/sandbox/tax_prep.py](https://github.com/openai/openai-agents-python/blob/main/examples/sandbox/tax_prep.py) では、最終的な記入済みファイルが実際に `output/` に配置されることを必須とします。
|
||||
- [examples/sandbox/docs/coding_task.py](https://github.com/openai/openai-agents-python/blob/main/examples/sandbox/docs/coding_task.py) では、正確な検証コマンドを固定し、ワークスペースルート相対のパッチパスを明確にします。
|
||||
|
||||
ユーザーの一時的なタスクを `instructions` にコピーすること、マニフェストに置くべき長い参考資料を埋め込むこと、組み込み機能が既に注入するツールドキュメントを繰り返すこと、モデルが実行時に必要としないローカルインストールの注意事項を混在させることは避けてください。
|
||||
|
||||
`instructions` を省略しても、SDK はデフォルトのサンドボックスプロンプトを含めます。低レベルのラッパーにはこれで十分ですが、ほとんどのユーザー向けエージェントでは、明示的な `instructions` も指定する必要があります。
|
||||
|
||||
### `capabilities`
|
||||
|
||||
機能は、サンドボックスネイティブの動作を `SandboxAgent` に付与します。実行開始前にワークスペースを形成し、サンドボックス固有の指示を追加し、稼働中のサンドボックスセッションにバインドされるツールを公開し、そのエージェントのモデル動作や入力処理を調整できます。
|
||||
|
||||
組み込み機能には次のものがあります。
|
||||
|
||||
<div class="sandbox-nowrap-first-column-table" markdown="1">
|
||||
|
||||
| 機能 | 追加する状況 | 注記 |
|
||||
| --- | --- | --- |
|
||||
| `Shell` | エージェントにシェルアクセスが必要な場合。 | `exec_command` を追加し、サンドボックスクライアントが PTY 対話をサポートする場合は `write_stdin` も追加します。 |
|
||||
| `Filesystem` | エージェントがファイルを編集したり、ローカル画像を確認したりする必要がある場合。 | `apply_patch` と `view_image` を追加します。パッチパスはワークスペースルート相対です。 |
|
||||
| `Skills` | サンドボックス内でスキルの検出とマテリアライズを行う場合。 | `.agents` または `.agents/skills` を手動でマウントするよりも、こちらを推奨します。`Skills` がスキルのインデックス作成とサンドボックスへのマテリアライズを行います。 |
|
||||
| `Memory` | 後続の実行でメモリ成果物を読み取り、または生成する必要がある場合。 | `Shell` が必要です。ライブ更新には `Filesystem` も必要です。 |
|
||||
| `Compaction` | 長時間実行されるフローで、コンパクション項目の後にコンテキストを削減する必要がある場合。 | モデルのサンプリングと入力処理を調整します。 |
|
||||
|
||||
</div>
|
||||
|
||||
デフォルトでは、`SandboxAgent.capabilities` は `Capabilities.default()` を使用し、これには `Filesystem()`、`Shell()`、`Compaction()` が含まれます。`capabilities=[...]` を渡すと、そのリストがデフォルトを置き換えるため、引き続き必要なデフォルト機能を含めてください。
|
||||
|
||||
スキルについては、マテリアライズ方法に応じてソースを選択します。
|
||||
|
||||
- `Skills(lazy_from=LocalDirLazySkillSource(...))` は、モデルが最初にインデックスを検出し、必要なものだけを読み込めるため、大規模なローカルスキルディレクトリに適したデフォルトです。
|
||||
- `LocalDirLazySkillSource(source=LocalDir(src=...))` は、SDK プロセスが実行されているファイルシステムから読み取ります。サンドボックスイメージまたはワークスペース内にのみ存在するパスではなく、元のホスト側スキルディレクトリを渡してください。
|
||||
- `Skills(from_=LocalDir(src=...))` は、事前にステージングする小規模なローカルバンドルに適しています。
|
||||
- `Skills(from_=GitRepo(repo=..., ref=...))` は、スキル自体をリポジトリから取得する場合に適しています。
|
||||
|
||||
`LocalDir.src` は SDK ホスト上のソースパスです。`skills_path` はサンドボックスワークスペース内の相対的な配置先パスであり、`load_skill` の呼び出し時にスキルがステージングされます。
|
||||
|
||||
スキルが既に `.agents/skills/<name>/SKILL.md` のような場所に存在する場合は、そのソースルートを `LocalDir(...)` に指定し、引き続き `Skills(...)` を使用して公開してください。別のサンドボックス内レイアウトに依存する既存のワークスペース契約がない限り、デフォルトの `skills_path=".agents"` を維持してください。
|
||||
|
||||
要件に適合する場合は、組み込み機能を優先してください。組み込み機能では対応できないサンドボックス固有のツールや指示インターフェースが必要な場合にのみ、カスタム機能を作成します。
|
||||
|
||||
## 概念
|
||||
|
||||
### マニフェスト
|
||||
|
||||
[`Manifest`][agents.sandbox.manifest.Manifest] は、新しいサンドボックスセッション用のワークスペースを記述します。ワークスペースの `root` の設定、ファイルとディレクトリの宣言、ローカルファイルのコピー、Git リポジトリのクローン、リモートストレージマウントの接続、環境変数の設定、ユーザーやグループの定義、ワークスペース外にある特定の絶対パスへのアクセス許可を行えます。
|
||||
|
||||
マニフェストエントリのパスはワークスペース相対です。絶対パスにしたり、`..` を使用してワークスペース外へ移動したりすることはできません。これにより、ローカル、Docker、ホステッドクライアント間でワークスペース契約の移植性が保たれます。
|
||||
|
||||
作業開始前にエージェントが必要とする素材には、マニフェストエントリを使用します。
|
||||
|
||||
<div class="sandbox-nowrap-first-column-table" markdown="1">
|
||||
|
||||
| マニフェストエントリ | 用途 |
|
||||
| --- | --- |
|
||||
| `File`、`Dir` | 小規模な合成入力、補助ファイル、出力ディレクトリ。 |
|
||||
| `LocalFile`、`LocalDir` | サンドボックス内にマテリアライズするホストのファイルまたはディレクトリ。 |
|
||||
| `GitRepo` | ワークスペースに取得するリポジトリ。 |
|
||||
| `S3Mount`、`GCSMount`、`R2Mount`、`AzureBlobMount`、`BoxMount`、`S3FilesMount` などのマウント | サンドボックス内に表示する外部ストレージ。 |
|
||||
|
||||
</div>
|
||||
|
||||
`Dir` は、合成の子要素からサンドボックスワークスペース内にディレクトリを作成するか、出力先を作成します。ホストのファイルシステムから読み取るものではありません。既存のホストディレクトリをサンドボックスワークスペースへコピーする場合は、`LocalDir` を使用します。
|
||||
|
||||
`LocalFile.src` と `LocalDir.src` は、デフォルトでは SDK プロセスの作業ディレクトリを基準に解決されます。ソースは、`extra_path_grants` の対象でない限り、その基準ディレクトリ内に置く必要があります。これにより、ローカルソースのマテリアライズは、サンドボックスマニフェストの他の部分と同じホストパスの信頼境界内に保たれます。
|
||||
|
||||
マウントエントリは公開するストレージを記述し、マウント戦略はサンドボックスバックエンドがそのストレージを接続する方法を記述します。マウントオプションとプロバイダーのサポートについては、[サンドボックスクライアント](clients.md#mounts-and-remote-storage)を参照してください。
|
||||
|
||||
適切なマニフェスト設計では通常、ワークスペース契約を必要最小限に保ち、長いタスク手順を `repo/task.md` などのワークスペースファイルに配置し、指示内では `repo/task.md` や `output/report.md` などのワークスペース相対パスを使用します。エージェントが `Filesystem` 機能の `apply_patch` ツールでファイルを編集する場合、パッチパスはシェルの `workdir` ではなく、サンドボックスワークスペースのルートからの相対パスであることに注意してください。
|
||||
|
||||
エージェントがワークスペース外の具体的な絶対パスを必要とする場合、またはマニフェストが SDK プロセスの作業ディレクトリ外にある信頼済みローカルソースをコピーする必要がある場合にのみ、`extra_path_grants` を使用してください。例としては、一時的なツール出力用の `/tmp`、読み取り専用ランタイム用の `/opt/toolchain`、サンドボックス内にマテリアライズする生成済みスキルディレクトリなどがあります。許可は、ローカルソースのマテリアライズ、SDK のファイル API、およびバックエンドがファイルシステムポリシーを適用できる場合のシェル実行に適用されます。
|
||||
|
||||
```python
|
||||
from agents.sandbox import Manifest, SandboxPathGrant
|
||||
|
||||
manifest = Manifest(
|
||||
extra_path_grants=(
|
||||
SandboxPathGrant(path="/tmp"),
|
||||
SandboxPathGrant(path="/opt/toolchain", read_only=True),
|
||||
),
|
||||
)
|
||||
```
|
||||
|
||||
`extra_path_grants` を含むマニフェストは、信頼済み設定として扱ってください。アプリケーションが対象のホストパスを事前に承認していない限り、モデル出力やその他の信頼できないペイロードから許可設定を読み込まないでください。
|
||||
|
||||
スナップショットと `persist_workspace()` に含まれるのは、引き続きワークスペースルートのみです。追加で許可されたパスはランタイムアクセスであり、永続的なワークスペース状態ではありません。
|
||||
|
||||
### 権限
|
||||
|
||||
`Permissions` は、マニフェストエントリのファイルシステム権限を制御します。対象となるのはサンドボックスがマテリアライズするファイルであり、モデルの権限、承認ポリシー、API 認証情報ではありません。
|
||||
|
||||
デフォルトでは、マニフェストエントリは所有者が読み取り、書き込み、実行可能であり、グループおよびその他のユーザーは読み取り、実行可能です。ステージングされたファイルを非公開、読み取り専用、または実行可能にする必要がある場合は、これをオーバーライドします。
|
||||
|
||||
```python
|
||||
from agents.sandbox import FileMode, Permissions
|
||||
from agents.sandbox.entries import File
|
||||
|
||||
private_notes = File(
|
||||
content=b"internal notes",
|
||||
permissions=Permissions(
|
||||
owner=FileMode.READ | FileMode.WRITE,
|
||||
group=FileMode.NONE,
|
||||
other=FileMode.NONE,
|
||||
),
|
||||
)
|
||||
```
|
||||
|
||||
`Permissions` は、所有者、グループ、その他のユーザーごとに個別のビットを保存し、さらにエントリがディレクトリかどうかも保持します。直接構築するか、`Permissions.from_str(...)` でモード文字列から解析するか、`Permissions.from_mode(...)` で OS モードから生成できます。
|
||||
|
||||
ユーザーは、サンドボックス内で作業を実行できる ID です。その ID をサンドボックス内に存在させる場合は `User` をマニフェストに追加し、シェルコマンド、ファイル読み取り、パッチなどのモデル向けサンドボックスツールをそのユーザーとして実行する場合は、`SandboxAgent.run_as` を設定します。`run_as` がマニフェストにまだ存在しないユーザーを指している場合、ランナーがそのユーザーを有効なマニフェストに自動的に追加します。
|
||||
|
||||
```python
|
||||
from agents import Runner
|
||||
from agents.run import RunConfig
|
||||
from agents.sandbox import FileMode, Manifest, Permissions, SandboxAgent, SandboxRunConfig, User
|
||||
from agents.sandbox.entries import Dir, LocalDir
|
||||
from agents.sandbox.sandboxes.unix_local import UnixLocalSandboxClient
|
||||
|
||||
analyst = User(name="analyst")
|
||||
|
||||
agent = SandboxAgent(
|
||||
name="Dataroom analyst",
|
||||
instructions="Review the files in `dataroom/` and write findings to `output/`.",
|
||||
default_manifest=Manifest(
|
||||
# Declare the sandbox user so manifest entries can grant access to it.
|
||||
users=[analyst],
|
||||
entries={
|
||||
"dataroom": LocalDir(
|
||||
src="./dataroom",
|
||||
# Let the analyst traverse and read the mounted dataroom, but not edit it.
|
||||
group=analyst,
|
||||
permissions=Permissions(
|
||||
owner=FileMode.READ | FileMode.EXEC,
|
||||
group=FileMode.READ | FileMode.EXEC,
|
||||
other=FileMode.NONE,
|
||||
),
|
||||
),
|
||||
"output": Dir(
|
||||
# Give the analyst a writable scratch/output directory for artifacts.
|
||||
group=analyst,
|
||||
permissions=Permissions(
|
||||
owner=FileMode.ALL,
|
||||
group=FileMode.ALL,
|
||||
other=FileMode.NONE,
|
||||
),
|
||||
),
|
||||
},
|
||||
),
|
||||
# Run model-facing sandbox actions as this user, so those permissions apply.
|
||||
run_as=analyst,
|
||||
)
|
||||
|
||||
result = await Runner.run(
|
||||
agent,
|
||||
"Summarize the contracts and call out renewal dates.",
|
||||
run_config=RunConfig(
|
||||
sandbox=SandboxRunConfig(client=UnixLocalSandboxClient()),
|
||||
),
|
||||
)
|
||||
```
|
||||
|
||||
ファイル単位の共有ルールも必要な場合は、ユーザーをマニフェストのグループおよびエントリの `group` メタデータと組み合わせます。`run_as` のユーザーはサンドボックスネイティブの操作を誰が実行するかを制御し、`Permissions` はサンドボックスがワークスペースをマテリアライズした後、そのユーザーがどのファイルを読み取り、書き込み、実行できるかを制御します。
|
||||
|
||||
### SnapshotSpec
|
||||
|
||||
`SnapshotSpec` は、新しいサンドボックスセッションが保存済みワークスペース内容を復元する場所、および内容を再び永続化する場所を指定します。これはサンドボックスワークスペースのスナップショットポリシーであり、`session_state` は特定のサンドボックスバックエンドを再開するためにシリアライズされた接続状態です。
|
||||
|
||||
ローカルの永続スナップショットには `LocalSnapshotSpec` を使用し、アプリがリモートスナップショットクライアントを提供する場合は `RemoteSnapshotSpec` を使用します。ローカルスナップショットを設定できない場合は、フォールバックとして何もしないスナップショットが使用されます。高度な呼び出し元は、ワークスペーススナップショットの永続化が不要な場合に、これを明示的に使用できます。
|
||||
|
||||
```python
|
||||
from pathlib import Path
|
||||
|
||||
from agents.run import RunConfig
|
||||
from agents.sandbox import LocalSnapshotSpec, SandboxRunConfig
|
||||
from agents.sandbox.sandboxes.unix_local import UnixLocalSandboxClient
|
||||
|
||||
run_config = RunConfig(
|
||||
sandbox=SandboxRunConfig(
|
||||
client=UnixLocalSandboxClient(),
|
||||
snapshot=LocalSnapshotSpec(base_path=Path("/tmp/my-sandbox-snapshots")),
|
||||
)
|
||||
)
|
||||
```
|
||||
|
||||
ランナーが新しいサンドボックスセッションを作成すると、サンドボックスクライアントはそのセッション用のスナップショットインスタンスを構築します。開始時にスナップショットが復元可能であれば、実行を続行する前にサンドボックスが保存済みワークスペース内容を復元します。クリーンアップ時には、ランナー所有のサンドボックスセッションがワークスペースをアーカイブし、スナップショットを通じて再び永続化します。
|
||||
|
||||
`snapshot` を省略すると、ランタイムは可能な場合にデフォルトのローカルスナップショット保存先を使用しようとします。設定できない場合は、何もしないスナップショットへフォールバックします。マウントされたパスと一時パスは、永続的なワークスペース内容としてスナップショットにコピーされません。
|
||||
|
||||
### サンドボックスのライフサイクル
|
||||
|
||||
ライフサイクルには、**SDK 所有**と**開発者所有**の 2 つのモードがあります。
|
||||
|
||||
<div class="sandbox-lifecycle-diagram" markdown="1">
|
||||
|
||||
```mermaid
|
||||
sequenceDiagram
|
||||
participant App
|
||||
participant Runner
|
||||
participant Client
|
||||
participant Sandbox
|
||||
|
||||
App->>Runner: Runner.run(..., SandboxRunConfig(client=...))
|
||||
Runner->>Client: create or resume sandbox
|
||||
Client-->>Runner: sandbox session
|
||||
Runner->>Sandbox: start, run tools
|
||||
Runner->>Sandbox: stop and persist snapshot
|
||||
Runner->>Client: delete runner-owned resources
|
||||
|
||||
App->>Client: create(...)
|
||||
Client-->>App: sandbox session
|
||||
App->>Sandbox: async with sandbox
|
||||
App->>Runner: Runner.run(..., SandboxRunConfig(session=sandbox))
|
||||
Runner->>Sandbox: run tools
|
||||
App->>Sandbox: cleanup on context exit / aclose()
|
||||
```
|
||||
|
||||
</div>
|
||||
|
||||
サンドボックスが 1 回の実行中のみ存在すればよい場合は、SDK 所有のライフサイクルを使用します。`client`、任意の `manifest`、任意の `snapshot`、クライアントの `options` を渡します。ランナーがサンドボックスを作成または再開して起動し、エージェントを実行し、スナップショット対応のワークスペース状態を永続化し、サンドボックスを停止して、ランナー所有リソースをクライアントにクリーンアップさせます。
|
||||
|
||||
```python
|
||||
result = await Runner.run(
|
||||
agent,
|
||||
"Inspect the workspace and summarize what changed.",
|
||||
run_config=RunConfig(
|
||||
sandbox=SandboxRunConfig(client=UnixLocalSandboxClient()),
|
||||
),
|
||||
)
|
||||
```
|
||||
|
||||
サンドボックスを事前に作成する場合、稼働中の 1 つのサンドボックスを複数回の実行で再利用する場合、実行後にファイルを確認する場合、自分で作成したサンドボックスでストリーミングする場合、またはクリーンアップのタイミングを厳密に決定する場合は、開発者所有のライフサイクルを使用します。`session=...` を渡すと、ランナーはその稼働中のサンドボックスを使用しますが、自動的には閉じません。
|
||||
|
||||
```python
|
||||
sandbox = await client.create(manifest=agent.default_manifest)
|
||||
|
||||
async with sandbox:
|
||||
run_config = RunConfig(sandbox=SandboxRunConfig(session=sandbox))
|
||||
await Runner.run(agent, "Analyze the files.", run_config=run_config)
|
||||
await Runner.run(agent, "Write the final report.", run_config=run_config)
|
||||
```
|
||||
|
||||
通常はコンテキストマネージャーを使用します。開始時にサンドボックスを起動し、終了時にセッションのクリーンアップライフサイクルを実行します。アプリでコンテキストマネージャーを使用できない場合は、ライフサイクルメソッドを直接呼び出します。
|
||||
|
||||
```python
|
||||
sandbox = await client.create(
|
||||
manifest=agent.default_manifest,
|
||||
snapshot=LocalSnapshotSpec(base_path=Path("/tmp/my-sandbox-snapshots")),
|
||||
)
|
||||
try:
|
||||
await sandbox.start()
|
||||
await Runner.run(
|
||||
agent,
|
||||
"Analyze the files.",
|
||||
run_config=RunConfig(sandbox=SandboxRunConfig(session=sandbox)),
|
||||
)
|
||||
# Persist a checkpoint of the live workspace before doing more work.
|
||||
# `aclose()` also calls `stop()`, so this is only needed for an explicit mid-lifecycle save.
|
||||
await sandbox.stop()
|
||||
finally:
|
||||
await sandbox.aclose()
|
||||
```
|
||||
|
||||
`stop()` はスナップショット対応のワークスペース内容を永続化するだけで、サンドボックスを破棄しません。`aclose()` は完全なセッションクリーンアップ処理です。停止前フックを実行し、`stop()` を呼び出し、サンドボックスリソースを停止して、セッション単位の依存関係を閉じます。
|
||||
|
||||
## `SandboxRunConfig` のオプション
|
||||
|
||||
[`SandboxRunConfig`][agents.run_config.SandboxRunConfig] は、サンドボックスセッションの取得元と、新しいセッションの初期化方法を決定する実行ごとのオプションを保持します。
|
||||
|
||||
### サンドボックスの取得元
|
||||
|
||||
次のオプションは、ランナーがサンドボックスセッションを再利用、再開、作成のいずれで取得するかを決定します。
|
||||
|
||||
<div class="sandbox-nowrap-first-column-table" markdown="1">
|
||||
|
||||
| オプション | 使用する状況 | 注記 |
|
||||
| --- | --- | --- |
|
||||
| `client` | ランナーにサンドボックスセッションの作成、再開、クリーンアップを任せる場合。 | 稼働中のサンドボックス `session` を指定しない限り必須です。 |
|
||||
| `session` | 稼働中のサンドボックスセッションを既に自分で作成している場合。 | 呼び出し元がライフサイクルを所有し、ランナーはその稼働中のサンドボックスセッションを再利用します。 |
|
||||
| `session_state` | シリアライズされたサンドボックスセッション状態はあるものの、稼働中のサンドボックスセッションオブジェクトがない場合。 | `client` が必要です。ランナーは、その明示的な状態から所有セッションとして再開します。 |
|
||||
|
||||
</div>
|
||||
|
||||
実際には、ランナーは次の順序でサンドボックスセッションを解決します。
|
||||
|
||||
1. `run_config.sandbox.session` を注入した場合、その稼働中のサンドボックスセッションを直接再利用します。
|
||||
2. それ以外で、実行を `RunState` から再開する場合は、保存済みのサンドボックスセッション状態を再開します。
|
||||
3. それ以外で、`run_config.sandbox.session_state` を渡した場合は、その明示的にシリアライズされたサンドボックスセッション状態から再開します。
|
||||
4. それ以外の場合、ランナーは新しいサンドボックスセッションを作成します。その新しいセッションでは、`run_config.sandbox.manifest` が指定されていればそれを使用し、指定されていなければ `agent.default_manifest` を使用します。
|
||||
|
||||
### 新規セッションの入力
|
||||
|
||||
次のオプションは、ランナーが新しいサンドボックスセッションを作成する場合にのみ適用されます。
|
||||
|
||||
<div class="sandbox-nowrap-first-column-table" markdown="1">
|
||||
|
||||
| オプション | 使用する状況 | 注記 |
|
||||
| --- | --- | --- |
|
||||
| `manifest` | 新規セッションのワークスペースを一時的にオーバーライドする場合。 | 省略時は `agent.default_manifest` にフォールバックします。 |
|
||||
| `snapshot` | 新しいサンドボックスセッションをスナップショットから初期化する場合。 | 再開に似たフローやリモートスナップショットクライアントに役立ちます。 |
|
||||
| `options` | サンドボックスクライアントが作成時オプションを必要とする場合。 | Docker イメージ、Modal アプリ名、E2B テンプレート、タイムアウト、同様のクライアント固有設定でよく使用します。 |
|
||||
|
||||
</div>
|
||||
|
||||
### マテリアライズの制御
|
||||
|
||||
`concurrency_limits` は、サンドボックスのマテリアライズ処理を並列実行できる量を制御します。大規模なマニフェストやローカルディレクトリのコピーで、より厳密なリソース制御が必要な場合は、`SandboxConcurrencyLimits(manifest_entries=..., local_dir_files=...)` を使用します。いずれかの値を `None` に設定すると、その制限のみが無効になります。
|
||||
|
||||
`archive_limits` は、アーカイブ展開に対する SDK 側のリソースチェックを制御します。SDK のデフォルトしきい値を有効にするには `archive_limits=SandboxArchiveLimits()` を設定します。アーカイブに対してより厳密なリソース制御が必要な場合は、`SandboxArchiveLimits(max_input_bytes=..., max_extracted_bytes=..., max_members=...)` などの明示的な値を渡します。SDK のアーカイブリソース制限がないデフォルト動作を維持するには `archive_limits=None` のままにし、特定の制限だけを無効にするには個別のフィールドを `None` に設定します。
|
||||
|
||||
次の点に注意してください。
|
||||
|
||||
- 新規セッション: `manifest=` と `snapshot=` は、ランナーが新しいサンドボックスセッションを作成する場合にのみ適用されます。
|
||||
- 再開とスナップショット: `session_state=` は以前にシリアライズされたサンドボックス状態へ再接続しますが、`snapshot=` は保存済みワークスペース内容から新しいサンドボックスセッションを初期化します。
|
||||
- クライアント固有オプション: `options=` はサンドボックスクライアントによって異なります。Docker および多くのホステッドクライアントでは必須です。
|
||||
- 注入された稼働中セッション: 実行中のサンドボックス `session` を渡した場合、機能によるマニフェスト更新で、互換性のあるマウント以外のエントリを追加できます。ただし、`manifest.root`、`manifest.environment`、`manifest.users`、`manifest.groups` の変更、既存エントリの削除、エントリ型の置き換え、マウントエントリの追加または変更はできません。
|
||||
- ランナー API: `SandboxAgent` の実行でも、通常の `Runner.run()`、`Runner.run_sync()`、`Runner.run_streamed()` API を使用します。
|
||||
|
||||
## 完全なコード例: コーディングタスク
|
||||
|
||||
次のコーディング形式のコード例は、デフォルトの出発点として適しています。
|
||||
|
||||
```python
|
||||
import asyncio
|
||||
from pathlib import Path
|
||||
|
||||
from agents import ModelSettings, Runner
|
||||
from agents.run import RunConfig
|
||||
from agents.sandbox import Manifest, SandboxAgent, SandboxRunConfig
|
||||
from agents.sandbox.capabilities import (
|
||||
Capabilities,
|
||||
LocalDirLazySkillSource,
|
||||
Skills,
|
||||
)
|
||||
from agents.sandbox.entries import LocalDir
|
||||
from agents.sandbox.sandboxes.unix_local import UnixLocalSandboxClient
|
||||
|
||||
EXAMPLE_DIR = Path(__file__).resolve().parent
|
||||
HOST_REPO_DIR = EXAMPLE_DIR / "repo"
|
||||
HOST_SKILLS_DIR = EXAMPLE_DIR / "skills"
|
||||
TARGET_TEST_CMD = "sh tests/test_credit_note.sh"
|
||||
|
||||
|
||||
def build_agent(model: str) -> SandboxAgent[None]:
|
||||
return SandboxAgent(
|
||||
name="Sandbox engineer",
|
||||
model=model,
|
||||
instructions=(
|
||||
"Inspect the repo, make the smallest correct change, run the most relevant checks, "
|
||||
"and summarize the file changes and risks. "
|
||||
"Read `repo/task.md` before editing files. Stay grounded in the repository, preserve "
|
||||
"existing behavior, and mention the exact verification command you ran. "
|
||||
"Use the `$credit-note-fixer` skill before editing files. If the repo lives under "
|
||||
"`repo/`, remember that `apply_patch` paths stay relative to the sandbox workspace "
|
||||
"root, so edits still target `repo/...`."
|
||||
),
|
||||
# Put repos and task files in the manifest.
|
||||
default_manifest=Manifest(
|
||||
entries={
|
||||
"repo": LocalDir(src=HOST_REPO_DIR),
|
||||
}
|
||||
),
|
||||
capabilities=Capabilities.default() + [
|
||||
Skills(
|
||||
lazy_from=LocalDirLazySkillSource(
|
||||
# This is a host path read by the SDK process.
|
||||
# Requested skills are copied into `skills_path` in the sandbox.
|
||||
source=LocalDir(src=HOST_SKILLS_DIR),
|
||||
)
|
||||
),
|
||||
],
|
||||
model_settings=ModelSettings(tool_choice="required"),
|
||||
)
|
||||
|
||||
|
||||
async def main(model: str, prompt: str) -> None:
|
||||
result = await Runner.run(
|
||||
build_agent(model),
|
||||
prompt,
|
||||
run_config=RunConfig(
|
||||
sandbox=SandboxRunConfig(client=UnixLocalSandboxClient()),
|
||||
workflow_name="Sandbox coding example",
|
||||
),
|
||||
)
|
||||
print(result.final_output)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
asyncio.run(
|
||||
main(
|
||||
model="gpt-5.6-sol",
|
||||
prompt=(
|
||||
"Open `repo/task.md`, use the `$credit-note-fixer` skill, fix the bug, "
|
||||
f"run `{TARGET_TEST_CMD}`, and summarize the change."
|
||||
),
|
||||
)
|
||||
)
|
||||
```
|
||||
|
||||
[examples/sandbox/docs/coding_task.py](https://github.com/openai/openai-agents-python/blob/main/examples/sandbox/docs/coding_task.py)を参照してください。このコード例では、Unix ローカル実行で決定論的に検証できるように、小規模なシェルベースのリポジトリを使用しています。実際のタスクリポジトリでは、もちろん Python、JavaScript、その他の任意の言語を使用できます。
|
||||
|
||||
## 一般的なパターン
|
||||
|
||||
上記の完全なコード例から始めてください。多くの場合、同じ `SandboxAgent` をそのまま維持し、サンドボックスクライアント、サンドボックスセッションの取得元、またはワークスペースの取得元のみを変更できます。
|
||||
|
||||
### サンドボックスクライアントの切り替え
|
||||
|
||||
エージェント定義は同じまま維持し、実行設定のみを変更します。コンテナ分離やイメージの同等性が必要な場合は Docker を使用し、プロバイダー管理の実行が必要な場合はホステッドプロバイダーを使用します。コード例とプロバイダーオプションについては、[サンドボックスクライアント](clients.md)を参照してください。
|
||||
|
||||
### ワークスペースのオーバーライド
|
||||
|
||||
エージェント定義は同じまま維持し、新規セッション用マニフェストのみを差し替えます。
|
||||
|
||||
```python
|
||||
from agents.run import RunConfig
|
||||
from agents.sandbox import Manifest, SandboxRunConfig
|
||||
from agents.sandbox.entries import GitRepo
|
||||
from agents.sandbox.sandboxes.unix_local import UnixLocalSandboxClient
|
||||
|
||||
run_config = RunConfig(
|
||||
sandbox=SandboxRunConfig(
|
||||
client=UnixLocalSandboxClient(),
|
||||
manifest=Manifest(
|
||||
entries={
|
||||
"repo": GitRepo(repo="openai/openai-agents-python", ref="main"),
|
||||
}
|
||||
),
|
||||
),
|
||||
)
|
||||
```
|
||||
|
||||
エージェントを再構築せずに、同じエージェントロールを異なるリポジトリ、資料、タスクバンドルに対して実行する場合に使用します。上記の検証済みコーディングコード例では、一時的なオーバーライドではなく `default_manifest` を使用して同じパターンを示しています。
|
||||
|
||||
### サンドボックスセッションの注入
|
||||
|
||||
ライフサイクルの明示的な制御、実行後の確認、出力のコピーが必要な場合は、稼働中のサンドボックスセッションを注入します。
|
||||
|
||||
```python
|
||||
from agents import Runner
|
||||
from agents.run import RunConfig
|
||||
from agents.sandbox import SandboxRunConfig
|
||||
from agents.sandbox.sandboxes.unix_local import UnixLocalSandboxClient
|
||||
|
||||
client = UnixLocalSandboxClient()
|
||||
sandbox = await client.create(manifest=agent.default_manifest)
|
||||
|
||||
async with sandbox:
|
||||
result = await Runner.run(
|
||||
agent,
|
||||
prompt,
|
||||
run_config=RunConfig(
|
||||
sandbox=SandboxRunConfig(session=sandbox),
|
||||
),
|
||||
)
|
||||
```
|
||||
|
||||
実行後にワークスペースを確認する場合、または起動済みのサンドボックスセッションでストリーミングする場合に使用します。[examples/sandbox/docs/coding_task.py](https://github.com/openai/openai-agents-python/blob/main/examples/sandbox/docs/coding_task.py)および[examples/sandbox/docker/docker_runner.py](https://github.com/openai/openai-agents-python/blob/main/examples/sandbox/docker/docker_runner.py)を参照してください。
|
||||
|
||||
### セッション状態からの再開
|
||||
|
||||
`RunState` の外部でサンドボックス状態を既にシリアライズしている場合は、ランナーにその状態から再接続させます。
|
||||
|
||||
```python
|
||||
from agents.run import RunConfig
|
||||
from agents.sandbox import SandboxRunConfig
|
||||
|
||||
serialized = load_saved_payload()
|
||||
restored_state = client.deserialize_session_state(serialized)
|
||||
|
||||
run_config = RunConfig(
|
||||
sandbox=SandboxRunConfig(
|
||||
client=client,
|
||||
session_state=restored_state,
|
||||
),
|
||||
)
|
||||
```
|
||||
|
||||
サンドボックス状態を独自のストレージやジョブシステムに保存し、`Runner` でその状態から直接再開する場合に使用します。シリアライズとデシリアライズのフローについては、[examples/sandbox/extensions/blaxel_runner.py](https://github.com/openai/openai-agents-python/blob/main/examples/sandbox/extensions/blaxel_runner.py)を参照してください。
|
||||
|
||||
### スナップショットからの開始
|
||||
|
||||
保存済みのファイルや成果物から新しいサンドボックスを初期化します。
|
||||
|
||||
```python
|
||||
from pathlib import Path
|
||||
|
||||
from agents.run import RunConfig
|
||||
from agents.sandbox import LocalSnapshotSpec, SandboxRunConfig
|
||||
from agents.sandbox.sandboxes.unix_local import UnixLocalSandboxClient
|
||||
|
||||
run_config = RunConfig(
|
||||
sandbox=SandboxRunConfig(
|
||||
client=UnixLocalSandboxClient(),
|
||||
snapshot=LocalSnapshotSpec(base_path=Path("/tmp/my-sandbox-snapshot")),
|
||||
),
|
||||
)
|
||||
```
|
||||
|
||||
新しい実行を `agent.default_manifest` だけでなく、保存済みワークスペース内容から開始する場合に使用します。ローカルスナップショットのフローについては [examples/sandbox/memory.py](https://github.com/openai/openai-agents-python/blob/main/examples/sandbox/memory.py)、リモートスナップショットクライアントについては [examples/sandbox/sandbox_agent_with_remote_snapshot.py](https://github.com/openai/openai-agents-python/blob/main/examples/sandbox/sandbox_agent_with_remote_snapshot.py)を参照してください。
|
||||
|
||||
### Git からのスキル読み込み
|
||||
|
||||
ローカルスキルソースを、リポジトリを使用するソースに置き換えます。
|
||||
|
||||
```python
|
||||
from agents.sandbox.capabilities import Capabilities, Skills
|
||||
from agents.sandbox.entries import GitRepo
|
||||
|
||||
capabilities = Capabilities.default() + [
|
||||
Skills(from_=GitRepo(repo="sdcoffey/tax-prep-skills", ref="main")),
|
||||
]
|
||||
```
|
||||
|
||||
スキルバンドルに独自のリリースサイクルがある場合や、複数のサンドボックス間で共有する場合に使用します。[examples/sandbox/tax_prep.py](https://github.com/openai/openai-agents-python/blob/main/examples/sandbox/tax_prep.py)を参照してください。
|
||||
|
||||
### ツールとしての公開
|
||||
|
||||
ツールエージェントは、独自のサンドボックス境界を使用するか、親実行の稼働中サンドボックスを再利用できます。再利用は、高速な読み取り専用の探索エージェントに役立ちます。別のサンドボックスを作成、ハイドレート、スナップショット化するコストをかけずに、親が使用しているワークスペースをそのまま確認できます。
|
||||
|
||||
```python
|
||||
from agents import Runner
|
||||
from agents.run import RunConfig
|
||||
from agents.sandbox import FileMode, Manifest, Permissions, SandboxAgent, SandboxRunConfig, User
|
||||
from agents.sandbox.entries import Dir, File
|
||||
from agents.sandbox.sandboxes.unix_local import UnixLocalSandboxClient
|
||||
|
||||
coordinator = User(name="coordinator")
|
||||
explorer = User(name="explorer")
|
||||
|
||||
manifest = Manifest(
|
||||
users=[coordinator, explorer],
|
||||
entries={
|
||||
"pricing_packet": Dir(
|
||||
group=coordinator,
|
||||
permissions=Permissions(
|
||||
owner=FileMode.ALL,
|
||||
group=FileMode.ALL,
|
||||
other=FileMode.READ | FileMode.EXEC,
|
||||
directory=True,
|
||||
),
|
||||
children={
|
||||
"pricing.md": File(
|
||||
content=b"Pricing packet contents...",
|
||||
group=coordinator,
|
||||
permissions=Permissions(
|
||||
owner=FileMode.ALL,
|
||||
group=FileMode.ALL,
|
||||
other=FileMode.READ,
|
||||
),
|
||||
),
|
||||
},
|
||||
),
|
||||
"work": Dir(
|
||||
group=coordinator,
|
||||
permissions=Permissions(
|
||||
owner=FileMode.ALL,
|
||||
group=FileMode.ALL,
|
||||
other=FileMode.NONE,
|
||||
directory=True,
|
||||
),
|
||||
),
|
||||
},
|
||||
)
|
||||
|
||||
pricing_explorer = SandboxAgent(
|
||||
name="Pricing Explorer",
|
||||
instructions="Read `pricing_packet/` and summarize commercial risk. Do not edit files.",
|
||||
run_as=explorer,
|
||||
)
|
||||
|
||||
client = UnixLocalSandboxClient()
|
||||
sandbox = await client.create(manifest=manifest)
|
||||
|
||||
async with sandbox:
|
||||
shared_run_config = RunConfig(
|
||||
sandbox=SandboxRunConfig(session=sandbox),
|
||||
)
|
||||
|
||||
orchestrator = SandboxAgent(
|
||||
name="Revenue Operations Coordinator",
|
||||
instructions="Coordinate the review and write final notes to `work/`.",
|
||||
run_as=coordinator,
|
||||
tools=[
|
||||
pricing_explorer.as_tool(
|
||||
tool_name="review_pricing_packet",
|
||||
tool_description="Inspect the pricing packet and summarize commercial risk.",
|
||||
run_config=shared_run_config,
|
||||
max_turns=2,
|
||||
),
|
||||
],
|
||||
)
|
||||
|
||||
result = await Runner.run(
|
||||
orchestrator,
|
||||
"Review the pricing packet, then write final notes to `work/summary.md`.",
|
||||
run_config=shared_run_config,
|
||||
)
|
||||
```
|
||||
|
||||
ここでは、親エージェントが `coordinator` として実行され、探索用ツールエージェントが同じ稼働中サンドボックスセッション内で `explorer` として実行されます。`pricing_packet/` のエントリは `other` ユーザーが読み取れるため、探索エージェントはすばやく確認できますが、書き込み権限はありません。`work/` ディレクトリはコーディネーターのユーザーまたはグループのみが利用できるため、探索エージェントを読み取り専用に維持しながら、親は最終成果物を書き込めます。
|
||||
|
||||
ツールエージェントに実際の分離が必要な場合は、独自のサンドボックス `RunConfig` を指定します。
|
||||
|
||||
```python
|
||||
from docker import from_env as docker_from_env
|
||||
|
||||
from agents.run import RunConfig
|
||||
from agents.sandbox import SandboxAgent, SandboxRunConfig
|
||||
from agents.sandbox.sandboxes.docker import DockerSandboxClient, DockerSandboxClientOptions
|
||||
|
||||
rollout_agent = SandboxAgent(
|
||||
name="Rollout Reviewer",
|
||||
instructions="Inspect the rollout packet and summarize implementation risk.",
|
||||
)
|
||||
|
||||
rollout_agent.as_tool(
|
||||
tool_name="review_rollout_risk",
|
||||
tool_description="Inspect the rollout packet and summarize implementation risk.",
|
||||
run_config=RunConfig(
|
||||
sandbox=SandboxRunConfig(
|
||||
client=DockerSandboxClient(docker_from_env()),
|
||||
options=DockerSandboxClientOptions(image="python:3.14-slim"),
|
||||
),
|
||||
),
|
||||
)
|
||||
```
|
||||
|
||||
ツールエージェントが自由に変更を行う場合、信頼できないコマンドを実行する場合、または異なるバックエンドやイメージを使用する場合は、別のサンドボックスを使用します。[examples/sandbox/sandbox_agents_as_tools.py](https://github.com/openai/openai-agents-python/blob/main/examples/sandbox/sandbox_agents_as_tools.py)を参照してください。
|
||||
|
||||
### ローカルツールおよび MCP との組み合わせ
|
||||
|
||||
サンドボックスワークスペースを維持しながら、同じエージェントで通常のツールも使用できます。
|
||||
|
||||
```python
|
||||
from agents.sandbox import SandboxAgent
|
||||
from agents.sandbox.capabilities import Shell
|
||||
|
||||
agent = SandboxAgent(
|
||||
name="Workspace reviewer",
|
||||
instructions="Inspect the workspace and call host tools when needed.",
|
||||
tools=[get_discount_approval_path],
|
||||
mcp_servers=[server],
|
||||
capabilities=[Shell()],
|
||||
)
|
||||
```
|
||||
|
||||
ワークスペースの確認がエージェントの作業の一部にすぎない場合に使用します。[examples/sandbox/sandbox_agent_with_tools.py](https://github.com/openai/openai-agents-python/blob/main/examples/sandbox/sandbox_agent_with_tools.py)を参照してください。
|
||||
|
||||
## メモリ
|
||||
|
||||
後続のサンドボックスエージェント実行で以前の実行から学習する必要がある場合は、`Memory` 機能を使用します。メモリは SDK の会話用 `Session` メモリとは別のものです。学習内容をサンドボックスワークスペース内のファイルに抽出し、後続の実行でそのファイルを読み取れるようにします。
|
||||
|
||||
設定、読み取りと生成の動作、複数ターンの会話、レイアウトの分離については、[エージェントメモリ](memory.md)を参照してください。
|
||||
|
||||
## 構成パターン
|
||||
|
||||
単一エージェントのパターンを理解したら、次の設計上の検討事項は、より大きなシステムのどこにサンドボックス境界を配置するかです。
|
||||
|
||||
サンドボックスエージェントは、引き続き SDK の他の要素と組み合わせられます。
|
||||
|
||||
- [ハンドオフ](../handoffs.md): ドキュメント量の多い作業を、サンドボックスを使用しない受付エージェントからサンドボックスレビュアーへ引き継ぎます。
|
||||
- [Agents as tools](../tools.md#agents-as-tools): 複数のサンドボックスエージェントをツールとして公開します。通常は、各 `Agent.as_tool(...)` 呼び出しに `run_config=RunConfig(sandbox=SandboxRunConfig(...))` を渡し、各ツールに独自のサンドボックス境界を割り当てます。
|
||||
- [MCP](../mcp.md) と通常の関数ツール: サンドボックス機能は、`mcp_servers` および通常の Python ツールと共存できます。
|
||||
- [エージェントの実行](../running_agents.md): サンドボックス実行でも通常の `Runner` API を使用します。
|
||||
|
||||
特に一般的なのは、次の 2 つのパターンです。
|
||||
|
||||
- サンドボックスを使用しないエージェントが、ワークスペースの分離を必要とするワークフロー部分だけをサンドボックスエージェントへハンドオフする
|
||||
- オーケストレーターが複数のサンドボックスエージェントをツールとして公開し、通常は `Agent.as_tool(...)` 呼び出しごとに個別のサンドボックス `RunConfig` を指定して、各ツールに独自の分離ワークスペースを割り当てる
|
||||
|
||||
### ターンとサンドボックス実行
|
||||
|
||||
ハンドオフと、エージェントをツールとして使用する呼び出しは、分けて説明すると理解しやすくなります。
|
||||
|
||||
ハンドオフでは、トップレベルの実行とトップレベルのターンループは引き続き 1 つです。アクティブなエージェントは変わりますが、実行がネストされるわけではありません。サンドボックスを使用しない受付エージェントがサンドボックスレビュアーへハンドオフすると、同じ実行内の次のモデル呼び出しはサンドボックスエージェント用に準備され、そのサンドボックスエージェントが次のターンを担当します。つまり、ハンドオフによって、同じ実行の次のターンを担当するエージェントが変わります。[examples/sandbox/handoffs.py](https://github.com/openai/openai-agents-python/blob/main/examples/sandbox/handoffs.py)を参照してください。
|
||||
|
||||
`Agent.as_tool(...)` では関係が異なります。外側のオーケストレーターは、ツールを呼び出すかどうかの決定に外側の 1 ターンを使用し、そのツール呼び出しによってサンドボックスエージェントのネストされた実行が開始されます。ネストされた実行には、独自のターンループ、`max_turns`、承認、通常は独自のサンドボックス `RunConfig` があります。ネストされた 1 ターンで完了する場合も、複数ターンかかる場合もあります。外側のオーケストレーターから見ると、これらの作業はすべて 1 回のツール呼び出しの背後で行われるため、ネストされたターンによって外側の実行のターンカウンターが増えることはありません。[examples/sandbox/sandbox_agents_as_tools.py](https://github.com/openai/openai-agents-python/blob/main/examples/sandbox/sandbox_agents_as_tools.py)を参照してください。
|
||||
|
||||
承認の動作も同様に分かれます。
|
||||
|
||||
- ハンドオフでは、サンドボックスエージェントが同じ実行内のアクティブなエージェントになるため、承認は同じトップレベルの実行に維持されます。
|
||||
- `Agent.as_tool(...)` では、サンドボックスのツールエージェント内で発生した承認も外側の実行に表示されますが、保存されたネスト済み実行状態から取得され、外側の実行の再開時にネストされたサンドボックス実行を再開します。
|
||||
|
||||
## 関連資料
|
||||
|
||||
- [クイックスタート](../sandbox_agents.md): サンドボックスエージェントを 1 つ実行します。
|
||||
- [サンドボックスクライアント](clients.md): ローカル、Docker、ホステッド、マウントのオプションを選択します。
|
||||
- [エージェントメモリ](memory.md): 以前のサンドボックス実行から得た学習内容を保存し、再利用します。
|
||||
- [examples/sandbox/](https://github.com/openai/openai-agents-python/tree/main/examples/sandbox): 実行可能なローカル、コーディング、メモリ、ハンドオフ、エージェント構成のパターン。
|
||||
@@ -0,0 +1,189 @@
|
||||
---
|
||||
search:
|
||||
exclude: true
|
||||
---
|
||||
# エージェントメモリ
|
||||
|
||||
メモリにより、今後の sandbox エージェントの実行は過去の実行から学習できます。これは、メッセージ履歴を保存する SDK の会話用 [`Session`](../sessions/index.md) メモリとは別のものです。メモリは、過去の実行から得た学びを sandbox ワークスペース内のファイルに要約します。
|
||||
|
||||
!!! warning "ベータ機能"
|
||||
|
||||
Sandbox エージェントはベータ版です。一般提供までに API の詳細、デフォルト値、サポートされる機能が変更される可能性があり、時間とともにさらに高度な機能が追加されることも想定してください。
|
||||
|
||||
メモリは、今後の実行における 3 種類のコストを削減できます。
|
||||
|
||||
1. エージェントのコスト: エージェントがワークフローの完了に長い時間を要した場合、次回の実行では探索が少なくて済むはずです。これにより、トークン使用量と完了までの時間を削減できます。
|
||||
2. ユーザーのコスト: ユーザーがエージェントを修正したり好みを表明したりした場合、今後の実行でそのフィードバックを記憶できます。これにより、人による介入を削減できます。
|
||||
3. コンテキストのコスト: エージェントが以前にタスクを完了していて、ユーザーがそのタスクを発展させたい場合、ユーザーは以前のスレッドを探したり、すべてのコンテキストを再入力したりする必要がないはずです。これにより、タスク説明を短くできます。
|
||||
|
||||
バグを修正し、メモリを生成し、スナップショットを再開し、そのメモリを後続の検証実行で使用する、2 回の実行からなる完全なコード例については、[examples/sandbox/memory.py](https://github.com/openai/openai-agents-python/blob/main/examples/sandbox/memory.py) を参照してください。独立したメモリレイアウトを持つマルチターン、マルチエージェントのコード例については、[examples/sandbox/memory_multi_agent_multiturn.py](https://github.com/openai/openai-agents-python/blob/main/examples/sandbox/memory_multi_agent_multiturn.py) を参照してください。
|
||||
|
||||
## メモリの有効化
|
||||
|
||||
sandbox エージェントに機能として `Memory()` を追加します。
|
||||
|
||||
```python
|
||||
from pathlib import Path
|
||||
import tempfile
|
||||
|
||||
from agents.sandbox import LocalSnapshotSpec, SandboxAgent
|
||||
from agents.sandbox.capabilities import Filesystem, Memory, Shell
|
||||
|
||||
agent = SandboxAgent(
|
||||
name="Memory-enabled reviewer",
|
||||
instructions="Inspect the workspace and preserve useful lessons for follow-up runs.",
|
||||
capabilities=[Memory(), Filesystem(), Shell()],
|
||||
)
|
||||
|
||||
with tempfile.TemporaryDirectory(prefix="sandbox-memory-example-") as snapshot_dir:
|
||||
sandbox = await client.create(
|
||||
manifest=manifest,
|
||||
snapshot=LocalSnapshotSpec(base_path=Path(snapshot_dir)),
|
||||
)
|
||||
```
|
||||
|
||||
読み取りが有効な場合、`Memory()` には `Shell()` が必要です。これにより、挿入されたサマリーだけでは不十分なときに、エージェントがメモリファイルを読み取り、検索できます。ライブメモリ更新が有効な場合(デフォルト)、`Filesystem()` も必要です。これにより、エージェントが古くなったメモリを発見した場合や、ユーザーがメモリの更新を依頼した場合に、`memories/MEMORY.md` を更新できます。
|
||||
|
||||
デフォルトでは、メモリアーティファクトは sandbox ワークスペースの `memories/` 配下に保存されます。後の実行で再利用するには、同じライブ sandbox セッションを維持するか、永続化されたセッション状態またはスナップショットから再開することで、設定済みのメモリディレクトリ全体を保持して再利用してください。新しい空の sandbox は空のメモリで開始されます。
|
||||
|
||||
`Memory()` は、メモリの読み取りと生成の両方を有効にします。メモリを読み取るが新しいメモリは生成すべきでないエージェントには、`Memory(generate=None)` を使用します。たとえば、内部エージェント、サブエージェント、チェッカー、または実行から得られるシグナルが多くない 1 回限りのツールエージェントです。後で使うメモリを生成する必要はあるものの、ユーザーが既存メモリによる影響を望まない場合は、`Memory(read=None)` を使用します。
|
||||
|
||||
## メモリの読み取り
|
||||
|
||||
メモリ読み取りでは段階的開示を使用します。実行の開始時に、SDK は一般的に役立つヒント、ユーザーの好み、利用可能なメモリの小さなサマリー(`memory_summary.md`)を、エージェントの developer プロンプトに挿入します。これにより、エージェントは過去の作業が関連しそうかどうかを判断するのに十分なコンテキストを得られます。
|
||||
|
||||
過去の作業が関連しそうな場合、エージェントは現在のタスクからキーワードを抽出して、設定されたメモリインデックス(`memories_dir` 配下の `MEMORY.md`)を検索します。より詳細が必要な場合にのみ、設定された `rollout_summaries/` ディレクトリ配下にある対応する過去のロールアウトサマリーを開きます。
|
||||
|
||||
メモリは古くなることがあります。エージェントには、メモリをガイダンスとしてのみ扱い、現在の環境を信頼するよう指示されています。デフォルトでは、メモリ読み取りでは `live_update` が有効です。そのため、エージェントが古くなったメモリを発見した場合、同じ実行内で設定済みの `MEMORY.md` を更新できます。実行中にメモリを読み取るが変更してほしくない場合、たとえばレイテンシに敏感な実行では、ライブ更新を無効にしてください。
|
||||
|
||||
## メモリの生成
|
||||
|
||||
実行が完了すると、sandbox ランタイムはその実行セグメントを会話ファイルに追記します。蓄積された会話ファイルは、sandbox セッションが閉じられるときに処理されます。
|
||||
|
||||
メモリ生成には 2 つのフェーズがあります。
|
||||
|
||||
1. フェーズ 1: 会話の抽出。メモリ生成モデルが、蓄積された 1 つの会話ファイルを処理し、会話サマリーを生成します。system、developer、reasoning のコンテンツは省略されます。会話が長すぎる場合は、先頭と末尾を保持したうえで、コンテキストウィンドウに収まるよう切り詰められます。また、未加工のメモリ抽出も生成します。これは、フェーズ 2 が統合できる会話からの簡潔なメモです。
|
||||
2. フェーズ 2: レイアウトの統合。統合エージェントは、1 つのメモリレイアウトに対応する未加工のメモリを読み取り、より多くの根拠が必要な場合は会話サマリーを開き、パターンを `MEMORY.md` と `memory_summary.md` に抽出します。
|
||||
|
||||
デフォルトのワークスペースレイアウトは次のとおりです。
|
||||
|
||||
```text
|
||||
workspace/
|
||||
├── sessions/
|
||||
│ └── <rollout-id>.jsonl
|
||||
└── memories/
|
||||
├── memory_summary.md
|
||||
├── MEMORY.md
|
||||
├── raw_memories.md (intermediate)
|
||||
├── phase_two_selection.json (intermediate)
|
||||
├── raw_memories/ (intermediate)
|
||||
│ └── <rollout-id>.md
|
||||
├── rollout_summaries/
|
||||
│ └── <rollout-id>_<slug>.md
|
||||
└── skills/
|
||||
```
|
||||
|
||||
`MemoryGenerateConfig` でメモリ生成を設定できます。
|
||||
|
||||
```python
|
||||
from agents.sandbox import MemoryGenerateConfig
|
||||
from agents.sandbox.capabilities import Memory
|
||||
|
||||
memory = Memory(
|
||||
generate=MemoryGenerateConfig(
|
||||
max_raw_memories_for_consolidation=128,
|
||||
extra_prompt="Pay extra attention to what made the customer more satisfied or annoyed",
|
||||
),
|
||||
)
|
||||
```
|
||||
|
||||
`extra_prompt` を使用して、GTM エージェント向けの顧客や会社の詳細など、ユースケースで最も重要なシグナルをメモリ生成器に伝えます。
|
||||
|
||||
最近の未加工メモリが `max_raw_memories_for_consolidation`(デフォルトは 256)を超える場合、フェーズ 2 は最新の会話のメモリだけを保持し、古いものを削除します。新しさは、会話が最後に更新された時刻に基づきます。この忘却メカニズムにより、メモリが最新の環境を反映しやすくなります。
|
||||
|
||||
## マルチターン会話
|
||||
|
||||
マルチターンの sandbox チャットでは、同じライブ sandbox セッションとともに通常の SDK `Session` を使用します。
|
||||
|
||||
```python
|
||||
from agents import Runner, SQLiteSession
|
||||
from agents.run import RunConfig
|
||||
from agents.sandbox import SandboxRunConfig
|
||||
|
||||
conversation_session = SQLiteSession("gtm-q2-pipeline-review")
|
||||
sandbox = await client.create(manifest=agent.default_manifest)
|
||||
|
||||
async with sandbox:
|
||||
run_config = RunConfig(
|
||||
sandbox=SandboxRunConfig(session=sandbox),
|
||||
workflow_name="GTM memory example",
|
||||
)
|
||||
await Runner.run(
|
||||
agent,
|
||||
"Analyze data/leads.csv and identify one promising GTM segment.",
|
||||
session=conversation_session,
|
||||
run_config=run_config,
|
||||
)
|
||||
await Runner.run(
|
||||
agent,
|
||||
"Using that analysis, write a short outreach hypothesis.",
|
||||
session=conversation_session,
|
||||
run_config=run_config,
|
||||
)
|
||||
```
|
||||
|
||||
どちらの実行も、同じ SDK 会話セッション(`session=conversation_session`)を渡すため、1 つのメモリ会話ファイルに追記され、したがって同じ `session.session_id` を共有します。これはライブワークスペースを識別する sandbox(`sandbox`)とは異なります。`sandbox` はメモリ会話 ID としては使用されません。sandbox セッションが閉じられると、フェーズ 1 は蓄積された会話を参照するため、2 つの孤立したターンではなく、やり取り全体からメモリを抽出できます。
|
||||
|
||||
複数の `Runner.run(...)` 呼び出しを 1 つのメモリ会話にしたい場合は、それらの呼び出し全体で安定した識別子を渡してください。メモリが実行を会話に関連付けるときは、次の順序で解決します。
|
||||
|
||||
1. `conversation_id`(`Runner.run(...)` に渡した場合)
|
||||
2. `session.session_id`(`SQLiteSession` などの SDK `Session` を渡した場合)
|
||||
3. `RunConfig.group_id`(上記のどちらも存在しない場合)
|
||||
4. 生成された実行ごとの ID(安定した識別子が存在しない場合)
|
||||
|
||||
## エージェントごとのメモリ分離における異なるレイアウトの利用
|
||||
|
||||
メモリの分離はエージェント名ではなく `MemoryLayoutConfig` に基づきます。同じレイアウトと同じメモリ会話 ID を持つエージェントは、1 つのメモリ会話と 1 つの統合済みメモリを共有します。異なるレイアウトを持つエージェントは、同じ sandbox ワークスペースを共有している場合でも、別々のロールアウトファイル、未加工メモリ、`MEMORY.md`、`memory_summary.md` を保持します。
|
||||
|
||||
複数のエージェントが 1 つの sandbox を共有するものの、メモリは共有すべきでない場合は、別々のレイアウトを使用します。
|
||||
|
||||
```python
|
||||
from agents import SQLiteSession
|
||||
from agents.sandbox import MemoryLayoutConfig, SandboxAgent
|
||||
from agents.sandbox.capabilities import Filesystem, Memory, Shell
|
||||
|
||||
gtm_agent = SandboxAgent(
|
||||
name="GTM reviewer",
|
||||
instructions="Analyze GTM workspace data and write concise recommendations.",
|
||||
capabilities=[
|
||||
Memory(
|
||||
layout=MemoryLayoutConfig(
|
||||
memories_dir="memories/gtm",
|
||||
sessions_dir="sessions/gtm",
|
||||
)
|
||||
),
|
||||
Filesystem(),
|
||||
Shell(),
|
||||
],
|
||||
)
|
||||
|
||||
engineering_agent = SandboxAgent(
|
||||
name="Engineering reviewer",
|
||||
instructions="Inspect engineering workspaces and summarize fixes and risks.",
|
||||
capabilities=[
|
||||
Memory(
|
||||
layout=MemoryLayoutConfig(
|
||||
memories_dir="memories/engineering",
|
||||
sessions_dir="sessions/engineering",
|
||||
)
|
||||
),
|
||||
Filesystem(),
|
||||
Shell(),
|
||||
],
|
||||
)
|
||||
|
||||
gtm_session = SQLiteSession("gtm-q2-pipeline-review")
|
||||
engineering_session = SQLiteSession("eng-invoice-test-fix")
|
||||
```
|
||||
|
||||
これにより、GTM 分析がエンジニアリングのバグ修正メモリに統合されたり、その逆が起きたりすることを防げます。
|
||||
@@ -0,0 +1,117 @@
|
||||
---
|
||||
search:
|
||||
exclude: true
|
||||
---
|
||||
# クイックスタート
|
||||
|
||||
!!! warning "ベータ機能"
|
||||
|
||||
サンドボックスエージェントはベータ版です。一般提供までに API の詳細、デフォルト、サポートされる機能が変更される可能性があります。また、今後さらに高度な機能が追加される予定です。
|
||||
|
||||
最新のエージェントは、ファイルシステム上の実ファイルを操作できるときに最大限の力を発揮します。Agents SDK の **サンドボックスエージェント** は、大規模なドキュメント群の検索、ファイルの編集、コマンドの実行、成果物の生成、保存済みのサンドボックス状態からの作業再開が可能な永続ワークスペースをモデルに提供します。
|
||||
|
||||
SDK は、ファイルのステージング、ファイルシステムツール、シェルアクセス、サンドボックスのライフサイクル、スナップショット、プロバイダー固有の連携コードを自分で組み合わせることなく、この実行基盤を提供します。通常の `Agent` と `Runner` のフローを維持しながら、ワークスペース用の `Manifest`、サンドボックスネイティブツール用の機能、作業の実行場所を指定する `SandboxRunConfig` を追加できます。
|
||||
|
||||
## 前提条件
|
||||
|
||||
- Python 3.10 以降
|
||||
- OpenAI Agents SDK に関する基本的な知識
|
||||
- サンドボックスクライアント。ローカル開発では、まず `UnixLocalSandboxClient` を使用してください。
|
||||
|
||||
## インストール
|
||||
|
||||
SDK をまだインストールしていない場合は、次を実行します。
|
||||
|
||||
```bash
|
||||
pip install openai-agents
|
||||
```
|
||||
|
||||
Docker ベースのサンドボックスの場合は、次を実行します。
|
||||
|
||||
```bash
|
||||
pip install "openai-agents[docker]"
|
||||
```
|
||||
|
||||
## ローカルサンドボックスエージェントの作成
|
||||
|
||||
この例では、ローカルリポジトリを `repo/` 配下にステージングし、ローカルスキルを遅延読み込みして、実行時にランナーが Unix ローカルのサンドボックスセッションを作成できるようにします。
|
||||
|
||||
```python
|
||||
import asyncio
|
||||
from pathlib import Path
|
||||
|
||||
from agents import Runner
|
||||
from agents.run import RunConfig
|
||||
from agents.sandbox import Manifest, SandboxAgent, SandboxRunConfig
|
||||
from agents.sandbox.capabilities import Capabilities, LocalDirLazySkillSource, Skills
|
||||
from agents.sandbox.entries import LocalDir
|
||||
from agents.sandbox.sandboxes.unix_local import UnixLocalSandboxClient
|
||||
|
||||
EXAMPLE_DIR = Path(__file__).resolve().parent
|
||||
HOST_REPO_DIR = EXAMPLE_DIR / "repo"
|
||||
HOST_SKILLS_DIR = EXAMPLE_DIR / "skills"
|
||||
|
||||
|
||||
def build_agent(model: str) -> SandboxAgent[None]:
|
||||
return SandboxAgent(
|
||||
name="Sandbox engineer",
|
||||
model=model,
|
||||
instructions=(
|
||||
"Read `repo/task.md` before editing files. Stay grounded in the repository, preserve "
|
||||
"existing behavior, and mention the exact verification command you ran. "
|
||||
"If you edit files with apply_patch, paths are relative to the sandbox workspace root."
|
||||
),
|
||||
default_manifest=Manifest(
|
||||
entries={
|
||||
"repo": LocalDir(src=HOST_REPO_DIR),
|
||||
}
|
||||
),
|
||||
capabilities=Capabilities.default() + [
|
||||
Skills(
|
||||
lazy_from=LocalDirLazySkillSource(
|
||||
# This is a host path read by the SDK process.
|
||||
# Requested skills are copied into `skills_path` in the sandbox.
|
||||
source=LocalDir(src=HOST_SKILLS_DIR),
|
||||
)
|
||||
),
|
||||
],
|
||||
)
|
||||
|
||||
|
||||
async def main() -> None:
|
||||
result = await Runner.run(
|
||||
build_agent("gpt-5.6-sol"),
|
||||
"Open `repo/task.md`, fix the issue, run the targeted test, and summarize the change.",
|
||||
run_config=RunConfig(
|
||||
sandbox=SandboxRunConfig(client=UnixLocalSandboxClient()),
|
||||
workflow_name="Sandbox coding example",
|
||||
),
|
||||
)
|
||||
print(result.final_output)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
asyncio.run(main())
|
||||
```
|
||||
|
||||
[examples/sandbox/docs/coding_task.py](https://github.com/openai/openai-agents-python/blob/main/examples/sandbox/docs/coding_task.py) を参照してください。この例では、Unix ローカルでの実行間で決定論的に検証できるように、シェルベースの小規模なリポジトリを使用しています。
|
||||
|
||||
## 主な選択肢
|
||||
|
||||
基本的な実行が動作した後、多くの場合、次の選択肢を検討します。
|
||||
|
||||
- `default_manifest`: 新規サンドボックスセッション向けのファイル、リポジトリ、ディレクトリ、マウント
|
||||
- `instructions`: 複数のプロンプトにわたって適用する短いワークフロールール
|
||||
- `base_instructions`: SDK のサンドボックスプロンプトを置き換えるための高度な回避手段
|
||||
- `capabilities`: ファイルシステムの編集/画像検査、シェル、スキル、メモリ、コンパクションなどのサンドボックスネイティブツール
|
||||
- `run_as`: モデル向けツールで使用するサンドボックスのユーザー ID
|
||||
- `SandboxRunConfig.client`: サンドボックスのバックエンド
|
||||
- `SandboxRunConfig.session`、`session_state`、または `snapshot`: 後続の実行を以前の作業へ再接続する方法
|
||||
|
||||
## 次のステップ
|
||||
|
||||
- [概念](sandbox/guide.md): マニフェスト、機能、権限、スナップショット、実行設定、構成パターンについて理解します。
|
||||
- [サンドボックスクライアント](sandbox/clients.md): Unix ローカル、Docker、ホステッドプロバイダー、マウント戦略を選択します。
|
||||
- [エージェントメモリ](sandbox/memory.md): 過去のサンドボックス実行から得た知見を保持し、再利用します。
|
||||
|
||||
シェルアクセスを一時的なツールとしてのみ使用する場合は、[ツールガイド](tools.md)のホステッドシェルから始めてください。ワークスペースの分離、サンドボックスクライアントの選択、またはサンドボックスセッションの再開動作が設計に含まれる場合は、サンドボックスエージェントを使用してください。
|
||||
@@ -0,0 +1,459 @@
|
||||
---
|
||||
search:
|
||||
exclude: true
|
||||
---
|
||||
# セッション
|
||||
|
||||
Agents SDK は、複数のエージェント実行にわたって会話履歴を自動で維持する組み込みのセッションメモリを提供し、ターン間で手動で `.to_input_list()` を扱う必要をなくします。
|
||||
|
||||
セッションは特定のセッションに対する会話履歴を保存し、明示的な手動メモリ管理なしでエージェントがコンテキストを維持できるようにします。これは、エージェントに過去のやり取りを記憶させたいチャットアプリケーションやマルチターンの会話を構築する際に特に有用です。
|
||||
|
||||
## クイックスタート
|
||||
|
||||
```python
|
||||
from agents import Agent, Runner, SQLiteSession
|
||||
|
||||
# Create agent
|
||||
agent = Agent(
|
||||
name="Assistant",
|
||||
instructions="Reply very concisely.",
|
||||
)
|
||||
|
||||
# Create a session instance with a session ID
|
||||
session = SQLiteSession("conversation_123")
|
||||
|
||||
# First turn
|
||||
result = await Runner.run(
|
||||
agent,
|
||||
"What city is the Golden Gate Bridge in?",
|
||||
session=session
|
||||
)
|
||||
print(result.final_output) # "San Francisco"
|
||||
|
||||
# Second turn - agent automatically remembers previous context
|
||||
result = await Runner.run(
|
||||
agent,
|
||||
"What state is it in?",
|
||||
session=session
|
||||
)
|
||||
print(result.final_output) # "California"
|
||||
|
||||
# Also works with synchronous runner
|
||||
result = Runner.run_sync(
|
||||
agent,
|
||||
"What's the population?",
|
||||
session=session
|
||||
)
|
||||
print(result.final_output) # "Approximately 39 million"
|
||||
```
|
||||
|
||||
## 仕組み
|
||||
|
||||
セッションメモリが有効な場合:
|
||||
|
||||
1. **各実行の前**: ランナーはセッションの会話履歴を自動的に取得し、入力アイテムの前に付加します。
|
||||
2. **各実行の後**: 実行中に生成されたすべての新しいアイテム (ユーザー入力、アシスタントの応答、ツール呼び出しなど) は自動的にセッションに保存されます。
|
||||
3. **コンテキスト保持**: 同一セッションでの後続の実行には完全な会話履歴が含まれ、エージェントはコンテキストを維持できます。
|
||||
|
||||
これにより、ターン間で `.to_input_list()` を手動で呼び出して会話状態を管理する必要がなくなります。
|
||||
|
||||
## メモリ操作
|
||||
|
||||
### 基本操作
|
||||
|
||||
セッションは会話履歴を管理するためにいくつかの操作をサポートします:
|
||||
|
||||
```python
|
||||
from agents import SQLiteSession
|
||||
|
||||
session = SQLiteSession("user_123", "conversations.db")
|
||||
|
||||
# Get all items in a session
|
||||
items = await session.get_items()
|
||||
|
||||
# Add new items to a session
|
||||
new_items = [
|
||||
{"role": "user", "content": "Hello"},
|
||||
{"role": "assistant", "content": "Hi there!"}
|
||||
]
|
||||
await session.add_items(new_items)
|
||||
|
||||
# Remove and return the most recent item
|
||||
last_item = await session.pop_item()
|
||||
print(last_item) # {"role": "assistant", "content": "Hi there!"}
|
||||
|
||||
# Clear all items from a session
|
||||
await session.clear_session()
|
||||
```
|
||||
|
||||
### 修正のための pop_item の使用
|
||||
|
||||
会話内の最後のアイテムを取り消したり修正したい場合、`pop_item` メソッドが特に便利です:
|
||||
|
||||
```python
|
||||
from agents import Agent, Runner, SQLiteSession
|
||||
|
||||
agent = Agent(name="Assistant")
|
||||
session = SQLiteSession("correction_example")
|
||||
|
||||
# Initial conversation
|
||||
result = await Runner.run(
|
||||
agent,
|
||||
"What's 2 + 2?",
|
||||
session=session
|
||||
)
|
||||
print(f"Agent: {result.final_output}")
|
||||
|
||||
# User wants to correct their question
|
||||
assistant_item = await session.pop_item() # Remove agent's response
|
||||
user_item = await session.pop_item() # Remove user's question
|
||||
|
||||
# Ask a corrected question
|
||||
result = await Runner.run(
|
||||
agent,
|
||||
"What's 2 + 3?",
|
||||
session=session
|
||||
)
|
||||
print(f"Agent: {result.final_output}")
|
||||
```
|
||||
|
||||
## メモリオプション
|
||||
|
||||
### メモリなし (デフォルト)
|
||||
|
||||
```python
|
||||
# Default behavior - no session memory
|
||||
result = await Runner.run(agent, "Hello")
|
||||
```
|
||||
|
||||
### OpenAI Conversations API メモリ
|
||||
|
||||
自前のデータベースを管理せずに [会話状態](https://platform.openai.com/docs/guides/conversation-state?api-mode=responses#using-the-conversations-api) を永続化するには、[OpenAI Conversations API](https://platform.openai.com/docs/api-reference/conversations/create) を使用します。これは、会話履歴の保存に OpenAI がホストするインフラストラクチャに既に依存している場合に役立ちます。
|
||||
|
||||
```python
|
||||
from agents import OpenAIConversationsSession
|
||||
|
||||
session = OpenAIConversationsSession()
|
||||
|
||||
# Optionally resume a previous conversation by passing a conversation ID
|
||||
# session = OpenAIConversationsSession(conversation_id="conv_123")
|
||||
|
||||
result = await Runner.run(
|
||||
agent,
|
||||
"Hello",
|
||||
session=session,
|
||||
)
|
||||
```
|
||||
|
||||
### SQLite メモリ
|
||||
|
||||
```python
|
||||
from agents import SQLiteSession
|
||||
|
||||
# In-memory database (lost when process ends)
|
||||
session = SQLiteSession("user_123")
|
||||
|
||||
# Persistent file-based database
|
||||
session = SQLiteSession("user_123", "conversations.db")
|
||||
|
||||
# Use the session
|
||||
result = await Runner.run(
|
||||
agent,
|
||||
"Hello",
|
||||
session=session
|
||||
)
|
||||
```
|
||||
|
||||
### 複数セッション
|
||||
|
||||
```python
|
||||
from agents import Agent, Runner, SQLiteSession
|
||||
|
||||
agent = Agent(name="Assistant")
|
||||
|
||||
# Different sessions maintain separate conversation histories
|
||||
session_1 = SQLiteSession("user_123", "conversations.db")
|
||||
session_2 = SQLiteSession("user_456", "conversations.db")
|
||||
|
||||
result1 = await Runner.run(
|
||||
agent,
|
||||
"Hello",
|
||||
session=session_1
|
||||
)
|
||||
result2 = await Runner.run(
|
||||
agent,
|
||||
"Hello",
|
||||
session=session_2
|
||||
)
|
||||
```
|
||||
|
||||
### SQLAlchemy ベースのセッション
|
||||
|
||||
より高度なユースケースでは、SQLAlchemy ベースのセッションバックエンドを使用できます。これにより、セッションストレージに SQLAlchemy がサポートする任意のデータベース (PostgreSQL、MySQL、SQLite など) を使用できます。
|
||||
|
||||
**例 1: `from_url` を使ったインメモリ SQLite**
|
||||
|
||||
これは最も簡単な開始方法で、開発やテストに最適です。
|
||||
|
||||
```python
|
||||
import asyncio
|
||||
from agents import Agent, Runner
|
||||
from agents.extensions.memory.sqlalchemy_session import SQLAlchemySession
|
||||
|
||||
async def main():
|
||||
agent = Agent("Assistant")
|
||||
session = SQLAlchemySession.from_url(
|
||||
"user-123",
|
||||
url="sqlite+aiosqlite:///:memory:",
|
||||
create_tables=True, # Auto-create tables for the demo
|
||||
)
|
||||
|
||||
result = await Runner.run(agent, "Hello", session=session)
|
||||
|
||||
if __name__ == "__main__":
|
||||
asyncio.run(main())
|
||||
```
|
||||
|
||||
**例 2: 既存の SQLAlchemy エンジンを使用**
|
||||
|
||||
本番アプリケーションでは、すでに SQLAlchemy の `AsyncEngine` インスタンスを持っている可能性が高いです。これをそのままセッションに渡せます。
|
||||
|
||||
```python
|
||||
import asyncio
|
||||
from agents import Agent, Runner
|
||||
from agents.extensions.memory.sqlalchemy_session import SQLAlchemySession
|
||||
from sqlalchemy.ext.asyncio import create_async_engine
|
||||
|
||||
async def main():
|
||||
# In your application, you would use your existing engine
|
||||
engine = create_async_engine("sqlite+aiosqlite:///conversations.db")
|
||||
|
||||
agent = Agent("Assistant")
|
||||
session = SQLAlchemySession(
|
||||
"user-456",
|
||||
engine=engine,
|
||||
create_tables=True, # Auto-create tables for the demo
|
||||
)
|
||||
|
||||
result = await Runner.run(agent, "Hello", session=session)
|
||||
print(result.final_output)
|
||||
|
||||
await engine.dispose()
|
||||
|
||||
if __name__ == "__main__":
|
||||
asyncio.run(main())
|
||||
```
|
||||
|
||||
### 暗号化セッション
|
||||
|
||||
保存時に会話データの暗号化が必要なアプリケーションでは、`EncryptedSession` を使用して任意のセッションバックエンドを透過的な暗号化と自動 TTL ベースの有効期限でラップできます。これには `encrypt` エクストラが必要です: `pip install openai-agents[encrypt]`。
|
||||
|
||||
`EncryptedSession` は、セッションごとのキー導出 (HKDF) を用いた Fernet 暗号化を使用し、古いメッセージの自動期限切れをサポートします。アイテムが TTL を超えると、取得時に静かにスキップされます。
|
||||
|
||||
**例: SQLAlchemy セッションデータの暗号化**
|
||||
|
||||
```python
|
||||
import asyncio
|
||||
from agents import Agent, Runner
|
||||
from agents.extensions.memory import EncryptedSession, SQLAlchemySession
|
||||
|
||||
async def main():
|
||||
# Create underlying session (works with any SessionABC implementation)
|
||||
underlying_session = SQLAlchemySession.from_url(
|
||||
session_id="user-123",
|
||||
url="postgresql+asyncpg://app:secret@db.example.com/agents",
|
||||
create_tables=True,
|
||||
)
|
||||
|
||||
# Wrap with encryption and TTL-based expiration
|
||||
session = EncryptedSession(
|
||||
session_id="user-123",
|
||||
underlying_session=underlying_session,
|
||||
encryption_key="your-encryption-key", # Use a secure key from your secrets management
|
||||
ttl=600, # 10 minutes - items older than this are silently skipped
|
||||
)
|
||||
|
||||
agent = Agent("Assistant")
|
||||
result = await Runner.run(agent, "Hello", session=session)
|
||||
print(result.final_output)
|
||||
|
||||
if __name__ == "__main__":
|
||||
asyncio.run(main())
|
||||
```
|
||||
|
||||
**主な特長:**
|
||||
|
||||
- **透過的な暗号化**: 保存前にすべてのセッションアイテムを自動的に暗号化し、取得時に復号化します
|
||||
- **セッションごとのキー導出**: セッション ID をソルトとした HKDF で一意の暗号鍵を導出します
|
||||
- **TTL ベースの有効期限**: 設定可能な有効期間に基づいて古いメッセージを自動的に期限切れにします (デフォルト: 10 分)
|
||||
- **柔軟な鍵入力**: Fernet キーまたは生の文字列のいずれも暗号鍵として受け付けます
|
||||
- **任意のセッションをラップ**: SQLite、SQLAlchemy、またはカスタムセッション実装で動作します
|
||||
|
||||
!!! warning "重要なセキュリティに関する注意"
|
||||
|
||||
- 暗号鍵は安全に保管してください (例: 環境変数、シークレットマネージャー)
|
||||
- 期限切れトークンの拒否はアプリケーション サーバーのシステムクロックに基づきます。正当なトークンがクロックずれにより拒否されないよう、すべてのサーバーが NTP で時刻同期されていることを確認してください
|
||||
- 基盤となるセッションは暗号化済みデータを保存し続けるため、データベース インフラストラクチャの管理権限は保持されます
|
||||
|
||||
|
||||
## カスタムメモリ実装
|
||||
|
||||
[`Session`][agents.memory.session.Session] プロトコルに従うクラスを作成することで、独自のセッションメモリを実装できます:
|
||||
|
||||
```python
|
||||
from agents.memory.session import SessionABC
|
||||
from agents.items import TResponseInputItem
|
||||
from typing import List
|
||||
|
||||
class MyCustomSession(SessionABC):
|
||||
"""Custom session implementation following the Session protocol."""
|
||||
|
||||
def __init__(self, session_id: str):
|
||||
self.session_id = session_id
|
||||
# Your initialization here
|
||||
|
||||
async def get_items(self, limit: int | None = None) -> List[TResponseInputItem]:
|
||||
"""Retrieve conversation history for this session."""
|
||||
# Your implementation here
|
||||
pass
|
||||
|
||||
async def add_items(self, items: List[TResponseInputItem]) -> None:
|
||||
"""Store new items for this session."""
|
||||
# Your implementation here
|
||||
pass
|
||||
|
||||
async def pop_item(self) -> TResponseInputItem | None:
|
||||
"""Remove and return the most recent item from this session."""
|
||||
# Your implementation here
|
||||
pass
|
||||
|
||||
async def clear_session(self) -> None:
|
||||
"""Clear all items for this session."""
|
||||
# Your implementation here
|
||||
pass
|
||||
|
||||
# Use your custom session
|
||||
agent = Agent(name="Assistant")
|
||||
result = await Runner.run(
|
||||
agent,
|
||||
"Hello",
|
||||
session=MyCustomSession("my_session")
|
||||
)
|
||||
```
|
||||
|
||||
## セッション管理
|
||||
|
||||
### セッション ID の命名
|
||||
|
||||
会話の整理に役立つわかりやすいセッション ID を使用します:
|
||||
|
||||
- ユーザー基準: `"user_12345"`
|
||||
- スレッド基準: `"thread_abc123"`
|
||||
- コンテキスト基準: `"support_ticket_456"`
|
||||
|
||||
### メモリ永続化
|
||||
|
||||
- 一時的な会話にはインメモリ SQLite (`SQLiteSession("session_id")`) を使用
|
||||
- 永続的な会話にはファイルベース SQLite (`SQLiteSession("session_id", "path/to/db.sqlite")`) を使用
|
||||
- 既存のデータベースを持つ本番システムには SQLAlchemy ベースのセッション (`SQLAlchemySession("session_id", engine=engine, create_tables=True)`) を使用
|
||||
- 履歴を OpenAI Conversations API に保存したい場合は OpenAI がホストするストレージ (`OpenAIConversationsSession()`) を使用
|
||||
- 透過的な暗号化と TTL ベースの有効期限で任意のセッションをラップするには暗号化セッション (`EncryptedSession(session_id, underlying_session, encryption_key)`) を使用
|
||||
- さらに高度なユースケース向けに、他の本番システム (Redis、Django など) 用のカスタムセッションバックエンドの実装を検討
|
||||
|
||||
### セッション管理
|
||||
|
||||
```python
|
||||
# Clear a session when conversation should start fresh
|
||||
await session.clear_session()
|
||||
|
||||
# Different agents can share the same session
|
||||
support_agent = Agent(name="Support")
|
||||
billing_agent = Agent(name="Billing")
|
||||
session = SQLiteSession("user_123")
|
||||
|
||||
# Both agents will see the same conversation history
|
||||
result1 = await Runner.run(
|
||||
support_agent,
|
||||
"Help me with my account",
|
||||
session=session
|
||||
)
|
||||
result2 = await Runner.run(
|
||||
billing_agent,
|
||||
"What are my charges?",
|
||||
session=session
|
||||
)
|
||||
```
|
||||
|
||||
## 完全な例
|
||||
|
||||
セッションメモリの動作を示す完全な例です:
|
||||
|
||||
```python
|
||||
import asyncio
|
||||
from agents import Agent, Runner, SQLiteSession
|
||||
|
||||
|
||||
async def main():
|
||||
# Create an agent
|
||||
agent = Agent(
|
||||
name="Assistant",
|
||||
instructions="Reply very concisely.",
|
||||
)
|
||||
|
||||
# Create a session instance that will persist across runs
|
||||
session = SQLiteSession("conversation_123", "conversation_history.db")
|
||||
|
||||
print("=== Sessions Example ===")
|
||||
print("The agent will remember previous messages automatically.\n")
|
||||
|
||||
# First turn
|
||||
print("First turn:")
|
||||
print("User: What city is the Golden Gate Bridge in?")
|
||||
result = await Runner.run(
|
||||
agent,
|
||||
"What city is the Golden Gate Bridge in?",
|
||||
session=session
|
||||
)
|
||||
print(f"Assistant: {result.final_output}")
|
||||
print()
|
||||
|
||||
# Second turn - the agent will remember the previous conversation
|
||||
print("Second turn:")
|
||||
print("User: What state is it in?")
|
||||
result = await Runner.run(
|
||||
agent,
|
||||
"What state is it in?",
|
||||
session=session
|
||||
)
|
||||
print(f"Assistant: {result.final_output}")
|
||||
print()
|
||||
|
||||
# Third turn - continuing the conversation
|
||||
print("Third turn:")
|
||||
print("User: What's the population of that state?")
|
||||
result = await Runner.run(
|
||||
agent,
|
||||
"What's the population of that state?",
|
||||
session=session
|
||||
)
|
||||
print(f"Assistant: {result.final_output}")
|
||||
print()
|
||||
|
||||
print("=== Conversation Complete ===")
|
||||
print("Notice how the agent remembered the context from previous turns!")
|
||||
print("Sessions automatically handles conversation history.")
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
asyncio.run(main())
|
||||
```
|
||||
|
||||
## API リファレンス
|
||||
|
||||
詳細な API ドキュメントは以下をご覧ください:
|
||||
|
||||
- [`Session`][agents.memory.Session] - プロトコルインターフェース
|
||||
- [`SQLiteSession`][agents.memory.SQLiteSession] - SQLite 実装
|
||||
- [`OpenAIConversationsSession`](ref/memory/openai_conversations_session.md) - OpenAI Conversations API 実装
|
||||
- [`SQLAlchemySession`][agents.extensions.memory.sqlalchemy_session.SQLAlchemySession] - SQLAlchemy ベースの実装
|
||||
- [`EncryptedSession`][agents.extensions.memory.encrypt_session.EncryptedSession] - TTL 付き暗号化セッションラッパー
|
||||
@@ -0,0 +1,307 @@
|
||||
---
|
||||
search:
|
||||
exclude: true
|
||||
---
|
||||
# 高度な SQLite セッション
|
||||
|
||||
`AdvancedSQLiteSession` は基本的な `SQLiteSession` の拡張版であり、会話の分岐、詳細な使用状況分析、構造化された会話クエリなど、高度な会話管理機能を提供します。
|
||||
|
||||
## 機能
|
||||
|
||||
- **会話の分岐**: 任意のユーザーメッセージから別の会話パスを作成します
|
||||
- **使用状況の追跡**: ターンごとの詳細なトークン使用状況分析を、完全な JSON 内訳付きで提供します
|
||||
- **構造化クエリ**: ターン別の会話、ツール使用状況の統計などを取得します
|
||||
- **ブランチ管理**: 独立したブランチ切り替えと管理を行います
|
||||
- **メッセージ構造メタデータ**: メッセージタイプ、ツール使用、会話フローを追跡します
|
||||
|
||||
## クイックスタート
|
||||
|
||||
```python
|
||||
from agents import Agent, Runner
|
||||
from agents.extensions.memory import AdvancedSQLiteSession
|
||||
|
||||
# Create agent
|
||||
agent = Agent(
|
||||
name="Assistant",
|
||||
instructions="Reply very concisely.",
|
||||
)
|
||||
|
||||
# Create an advanced session
|
||||
session = AdvancedSQLiteSession(
|
||||
session_id="conversation_123",
|
||||
db_path="conversations.db",
|
||||
create_tables=True
|
||||
)
|
||||
|
||||
# First conversation turn
|
||||
result = await Runner.run(
|
||||
agent,
|
||||
"What city is the Golden Gate Bridge in?",
|
||||
session=session
|
||||
)
|
||||
print(result.final_output) # "San Francisco"
|
||||
|
||||
# IMPORTANT: Store usage data
|
||||
await session.store_run_usage(result)
|
||||
|
||||
# Continue conversation
|
||||
result = await Runner.run(
|
||||
agent,
|
||||
"What state is it in?",
|
||||
session=session
|
||||
)
|
||||
print(result.final_output) # "California"
|
||||
await session.store_run_usage(result)
|
||||
```
|
||||
|
||||
## 初期化
|
||||
|
||||
```python
|
||||
from agents.extensions.memory import AdvancedSQLiteSession
|
||||
|
||||
# Basic initialization
|
||||
session = AdvancedSQLiteSession(
|
||||
session_id="my_conversation",
|
||||
create_tables=True # Auto-create advanced tables
|
||||
)
|
||||
|
||||
# With persistent storage
|
||||
session = AdvancedSQLiteSession(
|
||||
session_id="user_123",
|
||||
db_path="path/to/conversations.db",
|
||||
create_tables=True
|
||||
)
|
||||
|
||||
# With custom logger
|
||||
import logging
|
||||
logger = logging.getLogger("my_app")
|
||||
session = AdvancedSQLiteSession(
|
||||
session_id="session_456",
|
||||
create_tables=True,
|
||||
logger=logger
|
||||
)
|
||||
```
|
||||
|
||||
### パラメーター
|
||||
|
||||
- `session_id` (str): 会話セッションの一意の識別子
|
||||
- `db_path` (str | Path): SQLite データベースファイルへのパス。デフォルトはインメモリストレージ用の `:memory:` です
|
||||
- `create_tables` (bool): 高度なテーブルを自動的に作成するかどうか。デフォルトは `False` です
|
||||
- `logger` (logging.Logger | None): セッション用のカスタムロガー。デフォルトはモジュールロガーです
|
||||
|
||||
## 使用状況の追跡
|
||||
|
||||
AdvancedSQLiteSession は、会話ターンごとにトークン使用状況データを保存することで、詳細な使用状況分析を提供します。 **これは、各エージェント実行後に `store_run_usage` メソッドが呼び出されることに完全に依存します。**
|
||||
|
||||
### 使用状況データの保存
|
||||
|
||||
```python
|
||||
# After each agent run, store the usage data
|
||||
result = await Runner.run(agent, "Hello", session=session)
|
||||
await session.store_run_usage(result)
|
||||
|
||||
# This stores:
|
||||
# - Total tokens used
|
||||
# - Input/output token breakdown
|
||||
# - Request count
|
||||
# - Detailed JSON token information (if available)
|
||||
```
|
||||
|
||||
### 使用状況統計の取得
|
||||
|
||||
```python
|
||||
# Get session-level usage (all branches)
|
||||
session_usage = await session.get_session_usage()
|
||||
if session_usage:
|
||||
print(f"Total requests: {session_usage['requests']}")
|
||||
print(f"Total tokens: {session_usage['total_tokens']}")
|
||||
print(f"Input tokens: {session_usage['input_tokens']}")
|
||||
print(f"Output tokens: {session_usage['output_tokens']}")
|
||||
print(f"Total turns: {session_usage['total_turns']}")
|
||||
|
||||
# Get usage for specific branch
|
||||
branch_usage = await session.get_session_usage(branch_id="main")
|
||||
|
||||
# Get usage by turn
|
||||
turn_usage = await session.get_turn_usage()
|
||||
for turn_data in turn_usage:
|
||||
print(f"Turn {turn_data['user_turn_number']}: {turn_data['total_tokens']} tokens")
|
||||
if turn_data['input_tokens_details']:
|
||||
print(f" Input details: {turn_data['input_tokens_details']}")
|
||||
if turn_data['output_tokens_details']:
|
||||
print(f" Output details: {turn_data['output_tokens_details']}")
|
||||
|
||||
# Get usage for specific turn
|
||||
turn_2_usage = await session.get_turn_usage(user_turn_number=2)
|
||||
```
|
||||
|
||||
## 会話の分岐
|
||||
|
||||
AdvancedSQLiteSession の主要機能の 1 つは、任意のユーザーメッセージから会話ブランチを作成し、別の会話パスを探索できることです。
|
||||
|
||||
### ブランチの作成
|
||||
|
||||
```python
|
||||
# Get available turns for branching
|
||||
turns = await session.get_conversation_turns()
|
||||
for turn in turns:
|
||||
print(f"Turn {turn['turn']}: {turn['content']}")
|
||||
print(f"Can branch: {turn['can_branch']}")
|
||||
|
||||
# Create a branch from turn 2
|
||||
branch_id = await session.create_branch_from_turn(2)
|
||||
print(f"Created branch: {branch_id}")
|
||||
|
||||
# Create a branch with custom name
|
||||
branch_id = await session.create_branch_from_turn(
|
||||
2,
|
||||
branch_name="alternative_path"
|
||||
)
|
||||
|
||||
# Create branch by searching for content
|
||||
branch_id = await session.create_branch_from_content(
|
||||
"weather",
|
||||
branch_name="weather_focus"
|
||||
)
|
||||
```
|
||||
|
||||
### ブランチ管理
|
||||
|
||||
```python
|
||||
# List all branches
|
||||
branches = await session.list_branches()
|
||||
for branch in branches:
|
||||
current = " (current)" if branch["is_current"] else ""
|
||||
print(f"{branch['branch_id']}: {branch['user_turns']} turns, {branch['message_count']} messages{current}")
|
||||
|
||||
# Switch between branches
|
||||
await session.switch_to_branch("main")
|
||||
await session.switch_to_branch(branch_id)
|
||||
|
||||
# Delete a branch
|
||||
await session.delete_branch(branch_id, force=True) # force=True allows deleting current branch
|
||||
```
|
||||
|
||||
### ブランチワークフロー例
|
||||
|
||||
```python
|
||||
# Original conversation
|
||||
result = await Runner.run(agent, "What's the capital of France?", session=session)
|
||||
await session.store_run_usage(result)
|
||||
|
||||
result = await Runner.run(agent, "What's the weather like there?", session=session)
|
||||
await session.store_run_usage(result)
|
||||
|
||||
# Create branch from turn 2 (weather question)
|
||||
branch_id = await session.create_branch_from_turn(2, "weather_focus")
|
||||
|
||||
# Continue in new branch with different question
|
||||
result = await Runner.run(
|
||||
agent,
|
||||
"What are the main tourist attractions in Paris?",
|
||||
session=session
|
||||
)
|
||||
await session.store_run_usage(result)
|
||||
|
||||
# Switch back to main branch
|
||||
await session.switch_to_branch("main")
|
||||
|
||||
# Continue original conversation
|
||||
result = await Runner.run(
|
||||
agent,
|
||||
"How expensive is it to visit?",
|
||||
session=session
|
||||
)
|
||||
await session.store_run_usage(result)
|
||||
```
|
||||
|
||||
## 構造化クエリ
|
||||
|
||||
AdvancedSQLiteSession は、会話の構造と内容を分析するための複数のメソッドを提供します。
|
||||
|
||||
### 会話分析
|
||||
|
||||
```python
|
||||
# Get conversation organized by turns
|
||||
conversation_by_turns = await session.get_conversation_by_turns()
|
||||
for turn_num, items in conversation_by_turns.items():
|
||||
print(f"Turn {turn_num}: {len(items)} items")
|
||||
for item in items:
|
||||
if item["tool_name"]:
|
||||
print(f" - {item['type']} (tool: {item['tool_name']})")
|
||||
else:
|
||||
print(f" - {item['type']}")
|
||||
|
||||
# Get tool usage statistics
|
||||
tool_usage = await session.get_tool_usage()
|
||||
for tool_name, count, turn in tool_usage:
|
||||
print(f"{tool_name}: used {count} times in turn {turn}")
|
||||
|
||||
# Find turns by content
|
||||
matching_turns = await session.find_turns_by_content("weather")
|
||||
for turn in matching_turns:
|
||||
print(f"Turn {turn['turn']}: {turn['content']}")
|
||||
```
|
||||
|
||||
### メッセージ構造
|
||||
|
||||
セッションは、次を含むメッセージ構造を自動的に追跡します。
|
||||
|
||||
- メッセージタイプ(ユーザー、assistant、tool_call など)
|
||||
- ツール呼び出しのツール名
|
||||
- ターン番号とシーケンス番号
|
||||
- ブランチとの関連付け
|
||||
- タイムスタンプ
|
||||
|
||||
## データベーススキーマ
|
||||
|
||||
AdvancedSQLiteSession は、基本的な SQLite スキーマを 2 つの追加テーブルで拡張します。
|
||||
|
||||
### message_structure テーブル
|
||||
|
||||
```sql
|
||||
CREATE TABLE message_structure (
|
||||
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
||||
session_id TEXT NOT NULL,
|
||||
message_id INTEGER NOT NULL,
|
||||
branch_id TEXT NOT NULL DEFAULT 'main',
|
||||
message_type TEXT NOT NULL,
|
||||
sequence_number INTEGER NOT NULL,
|
||||
user_turn_number INTEGER,
|
||||
branch_turn_number INTEGER,
|
||||
tool_name TEXT,
|
||||
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
||||
FOREIGN KEY (session_id) REFERENCES agent_sessions(session_id) ON DELETE CASCADE,
|
||||
FOREIGN KEY (message_id) REFERENCES agent_messages(id) ON DELETE CASCADE
|
||||
);
|
||||
```
|
||||
|
||||
### turn_usage テーブル
|
||||
|
||||
```sql
|
||||
CREATE TABLE turn_usage (
|
||||
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
||||
session_id TEXT NOT NULL,
|
||||
branch_id TEXT NOT NULL DEFAULT 'main',
|
||||
user_turn_number INTEGER NOT NULL,
|
||||
requests INTEGER DEFAULT 0,
|
||||
input_tokens INTEGER DEFAULT 0,
|
||||
output_tokens INTEGER DEFAULT 0,
|
||||
total_tokens INTEGER DEFAULT 0,
|
||||
input_tokens_details JSON,
|
||||
output_tokens_details JSON,
|
||||
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
||||
FOREIGN KEY (session_id) REFERENCES agent_sessions(session_id) ON DELETE CASCADE,
|
||||
UNIQUE(session_id, branch_id, user_turn_number)
|
||||
);
|
||||
```
|
||||
|
||||
## 完全な例
|
||||
|
||||
すべての機能を包括的に示す [完全な例](https://github.com/openai/openai-agents-python/tree/main/examples/memory/advanced_sqlite_session_example.py) を確認してください。
|
||||
|
||||
|
||||
## API リファレンス
|
||||
|
||||
- [`AdvancedSQLiteSession`][agents.extensions.memory.advanced_sqlite_session.AdvancedSQLiteSession] - メインクラス
|
||||
- [`Session`][agents.memory.session.Session] - ベースセッションプロトコル
|
||||
@@ -0,0 +1,179 @@
|
||||
---
|
||||
search:
|
||||
exclude: true
|
||||
---
|
||||
# 暗号化セッション
|
||||
|
||||
`EncryptedSession` は、任意のセッション実装に透過的な暗号化を提供し、古いアイテムの自動期限切れによって会話データを保護します。
|
||||
|
||||
## 機能
|
||||
|
||||
- **透過的な暗号化**: 任意のセッションを Fernet 暗号化でラップします
|
||||
- **セッションごとのキー**: HKDF キー導出を使用して、セッションごとに一意の暗号化を行います
|
||||
- **自動期限切れ**: TTL が期限切れになると、古いアイテムは取得時に黙ってスキップされます
|
||||
- **ドロップイン置換**: 既存の任意のセッション実装で動作します
|
||||
|
||||
## インストール
|
||||
|
||||
暗号化セッションには `encrypt` extra が必要です。
|
||||
|
||||
```bash
|
||||
pip install openai-agents[encrypt]
|
||||
```
|
||||
|
||||
## クイックスタート
|
||||
|
||||
```python
|
||||
import asyncio
|
||||
from agents import Agent, Runner
|
||||
from agents.extensions.memory import EncryptedSession, SQLAlchemySession
|
||||
|
||||
async def main():
|
||||
agent = Agent("Assistant")
|
||||
|
||||
# Create underlying session
|
||||
underlying_session = SQLAlchemySession.from_url(
|
||||
"user-123",
|
||||
url="sqlite+aiosqlite:///:memory:",
|
||||
create_tables=True
|
||||
)
|
||||
|
||||
# Wrap with encryption
|
||||
session = EncryptedSession(
|
||||
session_id="user-123",
|
||||
underlying_session=underlying_session,
|
||||
encryption_key="your-secret-key-here",
|
||||
ttl=600 # 10 minutes
|
||||
)
|
||||
|
||||
result = await Runner.run(agent, "Hello", session=session)
|
||||
print(result.final_output)
|
||||
|
||||
if __name__ == "__main__":
|
||||
asyncio.run(main())
|
||||
```
|
||||
|
||||
## 設定
|
||||
|
||||
### 暗号化キー
|
||||
|
||||
暗号化キーには、Fernet キーまたは任意の文字列を指定できます。
|
||||
|
||||
```python
|
||||
from agents.extensions.memory import EncryptedSession
|
||||
|
||||
# Using a Fernet key (base64-encoded)
|
||||
session = EncryptedSession(
|
||||
session_id="user-123",
|
||||
underlying_session=underlying_session,
|
||||
encryption_key="your-fernet-key-here",
|
||||
ttl=600
|
||||
)
|
||||
|
||||
# Using a raw string (will be derived to a key)
|
||||
session = EncryptedSession(
|
||||
session_id="user-123",
|
||||
underlying_session=underlying_session,
|
||||
encryption_key="my-secret-password",
|
||||
ttl=600
|
||||
)
|
||||
```
|
||||
|
||||
### TTL (有効期間)
|
||||
|
||||
暗号化されたアイテムが有効であり続ける期間を設定します。
|
||||
|
||||
```python
|
||||
# Items expire after 1 hour
|
||||
session = EncryptedSession(
|
||||
session_id="user-123",
|
||||
underlying_session=underlying_session,
|
||||
encryption_key="secret",
|
||||
ttl=3600 # 1 hour in seconds
|
||||
)
|
||||
|
||||
# Items expire after 1 day
|
||||
session = EncryptedSession(
|
||||
session_id="user-123",
|
||||
underlying_session=underlying_session,
|
||||
encryption_key="secret",
|
||||
ttl=86400 # 24 hours in seconds
|
||||
)
|
||||
```
|
||||
|
||||
## さまざまなセッションタイプでの使用
|
||||
|
||||
### SQLite セッションでの使用
|
||||
|
||||
```python
|
||||
from agents import SQLiteSession
|
||||
from agents.extensions.memory import EncryptedSession
|
||||
|
||||
# Create encrypted SQLite session
|
||||
underlying = SQLiteSession("user-123", "conversations.db")
|
||||
|
||||
session = EncryptedSession(
|
||||
session_id="user-123",
|
||||
underlying_session=underlying,
|
||||
encryption_key="secret-key"
|
||||
)
|
||||
```
|
||||
|
||||
### SQLAlchemy セッションでの使用
|
||||
|
||||
```python
|
||||
from agents.extensions.memory import EncryptedSession, SQLAlchemySession
|
||||
|
||||
# Create encrypted SQLAlchemy session
|
||||
underlying = SQLAlchemySession.from_url(
|
||||
"user-123",
|
||||
url="postgresql+asyncpg://user:pass@localhost/db",
|
||||
create_tables=True
|
||||
)
|
||||
|
||||
session = EncryptedSession(
|
||||
session_id="user-123",
|
||||
underlying_session=underlying,
|
||||
encryption_key="secret-key"
|
||||
)
|
||||
```
|
||||
|
||||
!!! warning "高度なセッション機能"
|
||||
|
||||
`EncryptedSession` を `AdvancedSQLiteSession` のような高度なセッション実装と使用する場合は、次の点に注意してください。
|
||||
|
||||
- メッセージ内容が暗号化されるため、`find_turns_by_content()` のようなメソッドは効果的に動作しません
|
||||
- コンテンツベースの検索は暗号化されたデータに対して実行されるため、有効性が制限されます
|
||||
|
||||
|
||||
|
||||
## キー導出
|
||||
|
||||
EncryptedSession は HKDF (HMAC-based Key Derivation Function) を使用して、セッションごとに一意の暗号化キーを導出します。
|
||||
|
||||
- **マスターキー**: 提供された暗号化キー
|
||||
- **セッションソルト**: セッション ID
|
||||
- **情報文字列**: `"agents.session-store.hkdf.v1"`
|
||||
- **出力**: 32 バイトの Fernet キー
|
||||
|
||||
これにより、次のことが保証されます。
|
||||
- 各セッションに一意の暗号化キーがあります
|
||||
- マスターキーがなければキーを導出できません
|
||||
- セッションデータを異なるセッション間で復号できません
|
||||
|
||||
## 自動期限切れ
|
||||
|
||||
アイテムが TTL を超えると、取得時に自動的にスキップされます。
|
||||
|
||||
```python
|
||||
# Items older than TTL are silently ignored
|
||||
items = await session.get_items() # Only returns non-expired items
|
||||
|
||||
# Expired items don't affect session behavior
|
||||
result = await Runner.run(agent, "Continue conversation", session=session)
|
||||
```
|
||||
|
||||
## API リファレンス
|
||||
|
||||
- [`EncryptedSession`][agents.extensions.memory.encrypt_session.EncryptedSession] - メインクラス
|
||||
- [`Session`][agents.memory.session.Session] - ベースセッションプロトコル
|
||||
@@ -0,0 +1,711 @@
|
||||
---
|
||||
search:
|
||||
exclude: true
|
||||
---
|
||||
# セッション
|
||||
|
||||
Agents SDK は、複数のエージェント実行にまたがって会話履歴を自動的に維持する組み込みのセッションメモリを提供し、ターン間で `.to_input_list()` を手動で扱う必要をなくします。
|
||||
|
||||
セッションは特定のセッションの会話履歴を保存し、明示的な手動メモリ管理を必要とせずに、エージェントがコンテキストを維持できるようにします。これは、エージェントに以前のやり取りを覚えておいてほしいチャットアプリケーションや複数ターンの会話を構築する場合に特に便利です。
|
||||
|
||||
SDK にクライアント側メモリを管理させたい場合は、セッションを使用します。セッションは、同じ実行内で `conversation_id`、`previous_response_id`、または `auto_previous_response_id` と組み合わせることはできません。代わりに OpenAI のサーバー管理による継続を使用したい場合は、セッションを重ねて使うのではなく、それらの仕組みのいずれかを選択してください。
|
||||
|
||||
## クイックスタート
|
||||
|
||||
```python
|
||||
from agents import Agent, Runner, SQLiteSession
|
||||
|
||||
# Create agent
|
||||
agent = Agent(
|
||||
name="Assistant",
|
||||
instructions="Reply very concisely.",
|
||||
)
|
||||
|
||||
# Create a session instance with a session ID
|
||||
session = SQLiteSession("conversation_123")
|
||||
|
||||
# First turn
|
||||
result = await Runner.run(
|
||||
agent,
|
||||
"What city is the Golden Gate Bridge in?",
|
||||
session=session
|
||||
)
|
||||
print(result.final_output) # "San Francisco"
|
||||
|
||||
# Second turn - agent automatically remembers previous context
|
||||
result = await Runner.run(
|
||||
agent,
|
||||
"What state is it in?",
|
||||
session=session
|
||||
)
|
||||
print(result.final_output) # "California"
|
||||
|
||||
# Also works with synchronous runner
|
||||
result = Runner.run_sync(
|
||||
agent,
|
||||
"What's the population?",
|
||||
session=session
|
||||
)
|
||||
print(result.final_output) # "Approximately 39 million"
|
||||
```
|
||||
|
||||
## 同じセッションによる中断された実行の再開
|
||||
|
||||
実行が承認待ちで一時停止した場合は、同じセッションインスタンス(または同じバッキングストアを指す別のセッションインスタンス)で再開し、再開されたターンが同じ保存済み会話履歴を継続するようにします。
|
||||
|
||||
```python
|
||||
result = await Runner.run(agent, "Delete temporary files that are no longer needed.", session=session)
|
||||
|
||||
if result.interruptions:
|
||||
state = result.to_state()
|
||||
for interruption in result.interruptions:
|
||||
state.approve(interruption)
|
||||
result = await Runner.run(agent, state, session=session)
|
||||
```
|
||||
|
||||
## コアセッション動作
|
||||
|
||||
セッションメモリが有効な場合:
|
||||
|
||||
1. **各実行の前**: ランナーはセッションの会話履歴を自動的に取得し、入力アイテムの前に追加します。
|
||||
2. **各実行の後**: 実行中に生成されたすべての新しいアイテム(ユーザー入力、アシスタントの応答、ツール呼び出しなど)がセッションに自動的に保存されます。
|
||||
3. **コンテキストの保持**: 同じセッションでの後続の各実行には完全な会話履歴が含まれるため、エージェントはコンテキストを維持できます。
|
||||
|
||||
これにより、`.to_input_list()` を手動で呼び出したり、実行間の会話状態を管理したりする必要がなくなります。
|
||||
|
||||
## 履歴と新しい入力のマージ方法の制御
|
||||
|
||||
セッションを渡すと、ランナーは通常、モデル入力を次のように準備します。
|
||||
|
||||
1. セッション履歴(`session.get_items(...)` から取得)
|
||||
2. 新しいターン入力
|
||||
|
||||
モデル呼び出しの前にこのマージ手順をカスタマイズするには、[`RunConfig.session_input_callback`][agents.run.RunConfig.session_input_callback] を使用します。コールバックは次の 2 つのリストを受け取ります。
|
||||
|
||||
- `history`: 取得されたセッション履歴(すでに入力アイテム形式に正規化済み)
|
||||
- `new_input`: 現在のターンの新しい入力アイテム
|
||||
|
||||
モデルに送信する最終的な入力アイテムのリストを返します。
|
||||
|
||||
コールバックは両方のリストのコピーを受け取るため、安全に変更できます。返されたリストはそのターンのモデル入力を制御しますが、SDK は新しいターンに属するアイテムのみを永続化します。そのため、古い履歴を並べ替えたりフィルタリングしたりしても、古いセッションアイテムが新しい入力として再度保存されることはありません。
|
||||
|
||||
```python
|
||||
from agents import Agent, RunConfig, Runner, SQLiteSession
|
||||
|
||||
|
||||
def keep_recent_history(history, new_input):
|
||||
# Keep only the last 10 history items, then append the new turn.
|
||||
return history[-10:] + new_input
|
||||
|
||||
|
||||
agent = Agent(name="Assistant")
|
||||
session = SQLiteSession("conversation_123")
|
||||
|
||||
result = await Runner.run(
|
||||
agent,
|
||||
"Continue from the latest updates only.",
|
||||
session=session,
|
||||
run_config=RunConfig(session_input_callback=keep_recent_history),
|
||||
)
|
||||
```
|
||||
|
||||
セッションがアイテムを保存する方法を変更せずに、カスタムの枝刈り、並べ替え、または履歴の選択的な取り込みが必要な場合に使用します。モデル呼び出しの直前にさらに最終的な処理が必要な場合は、[エージェント実行ガイド](../running_agents.md)の [`call_model_input_filter`][agents.run.RunConfig.call_model_input_filter] を使用してください。
|
||||
|
||||
## 取得する履歴の制限
|
||||
|
||||
各実行の前に取得する履歴の量を制御するには、[`SessionSettings`][agents.memory.SessionSettings] を使用します。
|
||||
|
||||
- `SessionSettings(limit=None)`(デフォルト): 利用可能なすべてのセッションアイテムを取得します
|
||||
- `SessionSettings(limit=N)`: 直近の `N` アイテムのみを取得します
|
||||
|
||||
これは、[`RunConfig.session_settings`][agents.run.RunConfig.session_settings] を介して実行ごとに適用できます。
|
||||
|
||||
```python
|
||||
from agents import Agent, RunConfig, Runner, SessionSettings, SQLiteSession
|
||||
|
||||
agent = Agent(name="Assistant")
|
||||
session = SQLiteSession("conversation_123")
|
||||
|
||||
result = await Runner.run(
|
||||
agent,
|
||||
"Summarize our recent discussion.",
|
||||
session=session,
|
||||
run_config=RunConfig(session_settings=SessionSettings(limit=50)),
|
||||
)
|
||||
```
|
||||
|
||||
セッション実装がデフォルトのセッション設定を公開している場合、`RunConfig.session_settings` はその実行について `None` ではない値を上書きします。これは、セッションのデフォルト動作を変更せずに取得サイズを上限設定したい長い会話で便利です。
|
||||
|
||||
## メモリ操作
|
||||
|
||||
### 基本操作
|
||||
|
||||
セッションは、会話履歴を管理するためのいくつかの操作をサポートしています。
|
||||
|
||||
```python
|
||||
from agents import SQLiteSession
|
||||
|
||||
session = SQLiteSession("user_123", "conversations.db")
|
||||
|
||||
# Get all items in a session
|
||||
items = await session.get_items()
|
||||
|
||||
# Add new items to a session
|
||||
new_items = [
|
||||
{"role": "user", "content": "Hello"},
|
||||
{"role": "assistant", "content": "Hi there!"}
|
||||
]
|
||||
await session.add_items(new_items)
|
||||
|
||||
# Remove and return the most recent item
|
||||
last_item = await session.pop_item()
|
||||
print(last_item) # {"role": "assistant", "content": "Hi there!"}
|
||||
|
||||
# Clear all items from a session
|
||||
await session.clear_session()
|
||||
```
|
||||
|
||||
### 修正のための pop_item の使用
|
||||
|
||||
`pop_item` メソッドは、会話内の最後のアイテムを取り消したり変更したりしたい場合に特に便利です。
|
||||
|
||||
```python
|
||||
from agents import Agent, Runner, SQLiteSession
|
||||
|
||||
agent = Agent(name="Assistant")
|
||||
session = SQLiteSession("correction_example")
|
||||
|
||||
# Initial conversation
|
||||
result = await Runner.run(
|
||||
agent,
|
||||
"What's 2 + 2?",
|
||||
session=session
|
||||
)
|
||||
print(f"Agent: {result.final_output}")
|
||||
|
||||
# User wants to correct their question
|
||||
assistant_item = await session.pop_item() # Remove agent's response
|
||||
user_item = await session.pop_item() # Remove user's question
|
||||
|
||||
# Ask a corrected question
|
||||
result = await Runner.run(
|
||||
agent,
|
||||
"What's 2 + 3?",
|
||||
session=session
|
||||
)
|
||||
print(f"Agent: {result.final_output}")
|
||||
```
|
||||
|
||||
## 組み込みセッション実装
|
||||
|
||||
SDK は、さまざまなユースケース向けに複数のセッション実装を提供しています。
|
||||
|
||||
### 組み込みセッション実装の選択
|
||||
|
||||
以下の詳細な例を読む前に、開始点を選ぶためにこの表を使用してください。
|
||||
|
||||
| セッションタイプ | 最適な用途 | 注記 |
|
||||
| --- | --- | --- |
|
||||
| `SQLiteSession` | ローカル開発とシンプルなアプリ | 組み込み、軽量、ファイルバックまたはインメモリ |
|
||||
| `AsyncSQLiteSession` | `aiosqlite` を使用した非同期 SQLite | 非同期ドライバー対応の拡張バックエンド |
|
||||
| `RedisSession` | ワーカーやサービス間で共有するメモリ | 低レイテンシの分散デプロイに適しています |
|
||||
| `SQLAlchemySession` | 既存データベースを使用する本番アプリ | SQLAlchemy がサポートするデータベースで動作します |
|
||||
| `MongoDBSession` | すでに MongoDB を使用しているアプリ、またはマルチプロセスストレージが必要なアプリ | 非同期 pymongo;順序付け用のアトミックシーケンスカウンター |
|
||||
| `DaprSession` | Dapr サイドカーを使用するクラウドネイティブデプロイ | 複数のステートストアに加え、TTL と整合性制御をサポートします |
|
||||
| `OpenAIConversationsSession` | OpenAI でのサーバー管理ストレージ | OpenAI Conversations API をバックエンドとする履歴 |
|
||||
| `OpenAIResponsesCompactionSession` | 自動圧縮を伴う長い会話 | 別のセッションバックエンドをラップします |
|
||||
| `AdvancedSQLiteSession` | SQLite に加えて分岐や分析 | より多機能です。専用ページを参照してください |
|
||||
| `EncryptedSession` | 別のセッション上での暗号化と TTL | ラッパーです。まず基盤となるバックエンドを選択してください |
|
||||
|
||||
一部の実装には、追加の詳細を含む専用ページがあります。それらは各サブセクション内でリンクされています。
|
||||
|
||||
ChatKit 用の Python サーバーを実装している場合は、ChatKit のスレッドとアイテムの永続化に `chatkit.store.Store` 実装を使用してください。`SQLAlchemySession` などの Agents SDK セッションは SDK 側の会話履歴を管理しますが、ChatKit のストアのドロップイン置き換えではありません。[ChatKit データストアの実装に関する `chatkit-python` ガイド](https://github.com/openai/chatkit-python/blob/main/docs/guides/respond-to-user-message.md#implement-your-chatkit-data-store)を参照してください。
|
||||
|
||||
### OpenAI Conversations API セッション
|
||||
|
||||
`OpenAIConversationsSession` を通じて [OpenAI の Conversations API](https://platform.openai.com/docs/api-reference/conversations)を使用します。
|
||||
|
||||
```python
|
||||
from agents import Agent, Runner, OpenAIConversationsSession
|
||||
|
||||
# Create agent
|
||||
agent = Agent(
|
||||
name="Assistant",
|
||||
instructions="Reply very concisely.",
|
||||
)
|
||||
|
||||
# Create a new conversation
|
||||
session = OpenAIConversationsSession()
|
||||
|
||||
# Optionally resume a previous conversation by passing a conversation ID
|
||||
# session = OpenAIConversationsSession(conversation_id="conv_123")
|
||||
|
||||
# Start conversation
|
||||
result = await Runner.run(
|
||||
agent,
|
||||
"What city is the Golden Gate Bridge in?",
|
||||
session=session
|
||||
)
|
||||
print(result.final_output) # "San Francisco"
|
||||
|
||||
# Continue the conversation
|
||||
result = await Runner.run(
|
||||
agent,
|
||||
"What state is it in?",
|
||||
session=session
|
||||
)
|
||||
print(result.final_output) # "California"
|
||||
```
|
||||
|
||||
### OpenAI Responses 圧縮セッション
|
||||
|
||||
Responses API(`responses.compact`)で保存済みの会話履歴を圧縮するには、`OpenAIResponsesCompactionSession` を使用します。これは基盤となるセッションをラップし、`should_trigger_compaction` に基づいて各ターンの後に自動的に圧縮できます。`OpenAIConversationsSession` をこれでラップしないでください。この 2 つの機能は異なる方法で履歴を管理します。
|
||||
|
||||
#### 一般的な使用方法(自動圧縮)
|
||||
|
||||
```python
|
||||
from agents import Agent, Runner, SQLiteSession
|
||||
from agents.memory import OpenAIResponsesCompactionSession
|
||||
|
||||
underlying = SQLiteSession("conversation_123")
|
||||
session = OpenAIResponsesCompactionSession(
|
||||
session_id="conversation_123",
|
||||
underlying_session=underlying,
|
||||
)
|
||||
|
||||
agent = Agent(name="Assistant")
|
||||
result = await Runner.run(agent, "Hello", session=session)
|
||||
print(result.final_output)
|
||||
```
|
||||
|
||||
デフォルトでは、候補しきい値に達すると各ターンの後に圧縮が実行されます。
|
||||
|
||||
`compaction_mode="previous_response_id"` は、Responses API の応答 ID でターンをすでに連鎖させている場合に最も適しています。`compaction_mode="input"` は、代わりに現在のセッションアイテムから圧縮リクエストを再構築します。これは、応答チェーンが利用できない場合や、セッション内容を信頼できる情報源にしたい場合に便利です。デフォルトの `"auto"` は、利用可能な中で最も安全な選択肢を選びます。
|
||||
|
||||
エージェントが `ModelSettings(store=False)` で実行される場合、Responses API は後で検索するための最後の応答を保持しません。このステートレスな構成では、デフォルトの `"auto"` モードは `previous_response_id` に依存するのではなく、入力ベースの圧縮にフォールバックします。完全な例については、[`examples/memory/compaction_session_stateless_example.py`](https://github.com/openai/openai-agents-python/tree/main/examples/memory/compaction_session_stateless_example.py) を参照してください。
|
||||
|
||||
#### auto-compaction によるストリーミングのブロック
|
||||
|
||||
圧縮はセッション履歴をクリアして書き換えるため、SDK は実行完了とみなす前に圧縮の完了を待ちます。ストリーミングモードでは、圧縮が重い場合、最後の出力トークンの後も `run.stream_events()` が数秒間開いたままになることがあります。
|
||||
|
||||
低レイテンシのストリーミングや高速なターン処理が必要な場合は、自動圧縮を無効にし、ターン間(またはアイドル時間中)に自分で `run_compaction()` を呼び出してください。独自の基準に基づいて、いつ圧縮を強制するかを決めることができます。
|
||||
|
||||
```python
|
||||
from agents import Agent, Runner, SQLiteSession
|
||||
from agents.memory import OpenAIResponsesCompactionSession
|
||||
|
||||
underlying = SQLiteSession("conversation_123")
|
||||
session = OpenAIResponsesCompactionSession(
|
||||
session_id="conversation_123",
|
||||
underlying_session=underlying,
|
||||
# Disable triggering the auto compaction
|
||||
should_trigger_compaction=lambda _: False,
|
||||
)
|
||||
|
||||
agent = Agent(name="Assistant")
|
||||
result = await Runner.run(agent, "Hello", session=session)
|
||||
|
||||
# Decide when to compact (e.g., on idle, every N turns, or size thresholds).
|
||||
await session.run_compaction({"force": True})
|
||||
```
|
||||
|
||||
### SQLite セッション
|
||||
|
||||
SQLite を使用するデフォルトの軽量セッション実装です。
|
||||
|
||||
```python
|
||||
from agents import SQLiteSession
|
||||
|
||||
# In-memory database (lost when process ends)
|
||||
session = SQLiteSession("user_123")
|
||||
|
||||
# Persistent file-based database
|
||||
session = SQLiteSession("user_123", "conversations.db")
|
||||
|
||||
# Use the session
|
||||
result = await Runner.run(
|
||||
agent,
|
||||
"Hello",
|
||||
session=session
|
||||
)
|
||||
```
|
||||
|
||||
### 非同期 SQLite セッション
|
||||
|
||||
`aiosqlite` をバックエンドとする SQLite の永続化が必要な場合は、`AsyncSQLiteSession` を使用します。
|
||||
|
||||
```bash
|
||||
pip install aiosqlite
|
||||
```
|
||||
|
||||
```python
|
||||
from agents import Agent, Runner
|
||||
from agents.extensions.memory import AsyncSQLiteSession
|
||||
|
||||
agent = Agent(name="Assistant")
|
||||
session = AsyncSQLiteSession("user_123", db_path="conversations.db")
|
||||
result = await Runner.run(agent, "Hello", session=session)
|
||||
```
|
||||
|
||||
### Redis セッション
|
||||
|
||||
複数のワーカーまたはサービス間で共有セッションメモリを使用するには、`RedisSession` を使用します。
|
||||
|
||||
```bash
|
||||
pip install openai-agents[redis]
|
||||
```
|
||||
|
||||
```python
|
||||
from agents import Agent, Runner
|
||||
from agents.extensions.memory import RedisSession
|
||||
|
||||
agent = Agent(name="Assistant")
|
||||
session = RedisSession.from_url(
|
||||
"user_123",
|
||||
url="redis://localhost:6379/0",
|
||||
)
|
||||
result = await Runner.run(agent, "Hello", session=session)
|
||||
```
|
||||
|
||||
### SQLAlchemy セッション
|
||||
|
||||
SQLAlchemy がサポートする任意のデータベースを使用した、本番対応の Agents SDK セッション永続化です。
|
||||
|
||||
```python
|
||||
from agents.extensions.memory import SQLAlchemySession
|
||||
|
||||
# Using database URL
|
||||
session = SQLAlchemySession.from_url(
|
||||
"user_123",
|
||||
url="postgresql+asyncpg://user:pass@localhost/db",
|
||||
create_tables=True
|
||||
)
|
||||
|
||||
# Using existing engine
|
||||
from sqlalchemy.ext.asyncio import create_async_engine
|
||||
engine = create_async_engine("postgresql+asyncpg://user:pass@localhost/db")
|
||||
session = SQLAlchemySession("user_123", engine=engine, create_tables=True)
|
||||
```
|
||||
|
||||
詳細なドキュメントについては、[SQLAlchemy セッション](sqlalchemy_session.md)を参照してください。
|
||||
|
||||
### Dapr セッション
|
||||
|
||||
すでに Dapr サイドカーを実行している場合、またはエージェントコードを変更せずに異なるステートストアバックエンドへ移行できるセッションストレージが必要な場合は、`DaprSession` を使用します。
|
||||
|
||||
```bash
|
||||
pip install openai-agents[dapr]
|
||||
```
|
||||
|
||||
```python
|
||||
from agents import Agent, Runner
|
||||
from agents.extensions.memory import DaprSession
|
||||
|
||||
agent = Agent(name="Assistant")
|
||||
|
||||
async with DaprSession.from_address(
|
||||
"user_123",
|
||||
state_store_name="statestore",
|
||||
dapr_address="localhost:50001",
|
||||
) as session:
|
||||
result = await Runner.run(agent, "Hello", session=session)
|
||||
print(result.final_output)
|
||||
```
|
||||
|
||||
注記:
|
||||
|
||||
- `from_address(...)` は Dapr クライアントを作成し、所有します。アプリがすでにクライアントを管理している場合は、`dapr_client=...` を指定して `DaprSession(...)` を直接構築してください。
|
||||
- 基盤となるステートストアが TTL をサポートしている場合に古いセッションデータを自動的に期限切れにするには、`ttl=...` を渡します。
|
||||
- より強い read-after-write 保証が必要な場合は、`consistency=DAPR_CONSISTENCY_STRONG` を渡します。
|
||||
- Dapr Python SDK は HTTP サイドカーエンドポイントもチェックします。ローカル開発では、`dapr_address` で使用する gRPC ポートに加えて、`--dapr-http-port 3500` でも Dapr を起動してください。
|
||||
- ローカルコンポーネントやトラブルシューティングを含む完全なセットアップ手順については、[`examples/memory/dapr_session_example.py`](https://github.com/openai/openai-agents-python/tree/main/examples/memory/dapr_session_example.py) を参照してください。
|
||||
|
||||
|
||||
### MongoDB セッション
|
||||
|
||||
すでに MongoDB を使用しているアプリケーション、または水平スケーラブルでマルチプロセス対応のセッションストレージが必要なアプリケーションには、`MongoDBSession` を使用します。
|
||||
|
||||
```bash
|
||||
pip install openai-agents[mongodb]
|
||||
```
|
||||
|
||||
```python
|
||||
from agents import Agent, Runner
|
||||
from agents.extensions.memory import MongoDBSession
|
||||
|
||||
agent = Agent(name="Assistant")
|
||||
|
||||
# Create from URI — owns the client and closes it when session.close() is called
|
||||
session = MongoDBSession.from_uri(
|
||||
"user-123",
|
||||
uri="mongodb://localhost:27017",
|
||||
database="agents",
|
||||
)
|
||||
result = await Runner.run(agent, "Hello", session=session)
|
||||
print(result.final_output)
|
||||
await session.close()
|
||||
```
|
||||
|
||||
注記:
|
||||
|
||||
- `from_uri(...)` は `AsyncMongoClient` を作成し、所有し、`session.close()` で閉じます。アプリケーションがすでにクライアントを管理している場合は、`client=...` を指定して `MongoDBSession(...)` を直接構築してください。その場合、`session.close()` は no-op となり、ライフサイクルは呼び出し元が保持します。
|
||||
- ほかの変更なしに、`from_uri(...)` に `mongodb+srv://user:password@cluster.example.mongodb.net` URI を渡すことで [MongoDB Atlas](https://www.mongodb.com/products/platform) に接続できます。
|
||||
- 2 つのコレクションが使用され、どちらの名前も `sessions_collection=`(デフォルトは `agent_sessions`)と `messages_collection=`(デフォルトは `agent_messages`)で設定できます。インデックスは初回使用時に自動的に作成されます。各メッセージドキュメントは、同時実行の書き込み元やプロセスをまたいで順序を保持する単調増加の `seq` カウンターを持ちます。
|
||||
- 最初の実行前に接続性を確認するには、`await session.ping()` を使用します。
|
||||
|
||||
### 高度な SQLite セッション
|
||||
|
||||
会話の分岐、使用状況分析、構造化クエリを備えた拡張 SQLite セッションです。
|
||||
|
||||
```python
|
||||
from agents.extensions.memory import AdvancedSQLiteSession
|
||||
|
||||
# Create with advanced features
|
||||
session = AdvancedSQLiteSession(
|
||||
session_id="user_123",
|
||||
db_path="conversations.db",
|
||||
create_tables=True
|
||||
)
|
||||
|
||||
# Automatic usage tracking
|
||||
result = await Runner.run(agent, "Hello", session=session)
|
||||
await session.store_run_usage(result) # Track token usage
|
||||
|
||||
# Conversation branching
|
||||
await session.create_branch_from_turn(2) # Branch from turn 2
|
||||
```
|
||||
|
||||
詳細なドキュメントについては、[高度な SQLite セッション](advanced_sqlite_session.md)を参照してください。
|
||||
|
||||
### 暗号化セッション
|
||||
|
||||
任意のセッション実装向けの透過的な暗号化ラッパーです。
|
||||
|
||||
```python
|
||||
from agents.extensions.memory import EncryptedSession, SQLAlchemySession
|
||||
|
||||
# Create underlying session
|
||||
underlying_session = SQLAlchemySession.from_url(
|
||||
"user_123",
|
||||
url="sqlite+aiosqlite:///conversations.db",
|
||||
create_tables=True
|
||||
)
|
||||
|
||||
# Wrap with encryption and TTL
|
||||
session = EncryptedSession(
|
||||
session_id="user_123",
|
||||
underlying_session=underlying_session,
|
||||
encryption_key="your-secret-key",
|
||||
ttl=600 # 10 minutes
|
||||
)
|
||||
|
||||
result = await Runner.run(agent, "Hello", session=session)
|
||||
```
|
||||
|
||||
詳細なドキュメントについては、[暗号化セッション](encrypted_session.md)を参照してください。
|
||||
|
||||
### その他のセッションタイプ
|
||||
|
||||
組み込みの選択肢はほかにもいくつかあります。`examples/memory/` と `extensions/memory/` 以下のソースコードを参照してください。
|
||||
|
||||
## 運用パターン
|
||||
|
||||
### セッション ID の命名
|
||||
|
||||
会話を整理しやすい、意味のあるセッション ID を使用してください。
|
||||
|
||||
- ユーザーベース: `"user_12345"`
|
||||
- スレッドベース: `"thread_abc123"`
|
||||
- コンテキストベース: `"support_ticket_456"`
|
||||
|
||||
### メモリの永続化
|
||||
|
||||
- 一時的な会話にはインメモリ SQLite(`SQLiteSession("session_id")`)を使用します
|
||||
- 永続的な会話にはファイルベース SQLite(`SQLiteSession("session_id", "path/to/db.sqlite")`)を使用します
|
||||
- `aiosqlite` ベースの実装が必要な場合は、非同期 SQLite(`AsyncSQLiteSession("session_id", db_path="...")`)を使用します
|
||||
- 共有された低レイテンシのセッションメモリには、Redis バックのセッション(`RedisSession.from_url("session_id", url="redis://...")`)を使用します
|
||||
- SQLAlchemy がサポートする既存データベースを持つ本番システムには、SQLAlchemy を利用したセッション(`SQLAlchemySession("session_id", engine=engine, create_tables=True)`) を使用します
|
||||
- すでに MongoDB を使用しているアプリケーション、またはマルチプロセスで水平スケーラブルなセッションストレージが必要なアプリケーションには、MongoDB セッション(`MongoDBSession.from_uri("session_id", uri="mongodb://localhost:27017")`)を使用します
|
||||
- 組み込みのテレメトリ、トレーシング、データ分離を備えた 30 以上のデータベースバックエンドをサポートする本番クラウドネイティブデプロイには、Dapr ステートストアセッション(`DaprSession.from_address("session_id", state_store_name="statestore", dapr_address="localhost:50001")`)を使用します
|
||||
- OpenAI Conversations API に履歴を保存したい場合は、OpenAI がホストするストレージ(`OpenAIConversationsSession()`)を使用します
|
||||
- 透過的な暗号化と TTL ベースの有効期限で任意のセッションをラップするには、暗号化セッション(`EncryptedSession(session_id, underlying_session, encryption_key)`)を使用します
|
||||
- より高度なユースケースでは、ほかの本番システム(たとえば Django)向けのカスタムセッションバックエンドの実装を検討してください
|
||||
|
||||
### 複数セッション
|
||||
|
||||
```python
|
||||
from agents import Agent, Runner, SQLiteSession
|
||||
|
||||
agent = Agent(name="Assistant")
|
||||
|
||||
# Different sessions maintain separate conversation histories
|
||||
session_1 = SQLiteSession("user_123", "conversations.db")
|
||||
session_2 = SQLiteSession("user_456", "conversations.db")
|
||||
|
||||
result1 = await Runner.run(
|
||||
agent,
|
||||
"Help me with my account",
|
||||
session=session_1
|
||||
)
|
||||
result2 = await Runner.run(
|
||||
agent,
|
||||
"What are my charges?",
|
||||
session=session_2
|
||||
)
|
||||
```
|
||||
|
||||
### セッション共有
|
||||
|
||||
```python
|
||||
# Different agents can share the same session
|
||||
support_agent = Agent(name="Support")
|
||||
billing_agent = Agent(name="Billing")
|
||||
session = SQLiteSession("user_123")
|
||||
|
||||
# Both agents will see the same conversation history
|
||||
result1 = await Runner.run(
|
||||
support_agent,
|
||||
"Help me with my account",
|
||||
session=session
|
||||
)
|
||||
result2 = await Runner.run(
|
||||
billing_agent,
|
||||
"What are my charges?",
|
||||
session=session
|
||||
)
|
||||
```
|
||||
|
||||
## 完全な例
|
||||
|
||||
セッションメモリの動作を示す完全な例を以下に示します。
|
||||
|
||||
```python
|
||||
import asyncio
|
||||
from agents import Agent, Runner, SQLiteSession
|
||||
|
||||
|
||||
async def main():
|
||||
# Create an agent
|
||||
agent = Agent(
|
||||
name="Assistant",
|
||||
instructions="Reply very concisely.",
|
||||
)
|
||||
|
||||
# Create a session instance that will persist across runs
|
||||
session = SQLiteSession("conversation_123", "conversation_history.db")
|
||||
|
||||
print("=== Sessions Example ===")
|
||||
print("The agent will remember previous messages automatically.\n")
|
||||
|
||||
# First turn
|
||||
print("First turn:")
|
||||
print("User: What city is the Golden Gate Bridge in?")
|
||||
result = await Runner.run(
|
||||
agent,
|
||||
"What city is the Golden Gate Bridge in?",
|
||||
session=session
|
||||
)
|
||||
print(f"Assistant: {result.final_output}")
|
||||
print()
|
||||
|
||||
# Second turn - the agent will remember the previous conversation
|
||||
print("Second turn:")
|
||||
print("User: What state is it in?")
|
||||
result = await Runner.run(
|
||||
agent,
|
||||
"What state is it in?",
|
||||
session=session
|
||||
)
|
||||
print(f"Assistant: {result.final_output}")
|
||||
print()
|
||||
|
||||
# Third turn - continuing the conversation
|
||||
print("Third turn:")
|
||||
print("User: What's the population of that state?")
|
||||
result = await Runner.run(
|
||||
agent,
|
||||
"What's the population of that state?",
|
||||
session=session
|
||||
)
|
||||
print(f"Assistant: {result.final_output}")
|
||||
print()
|
||||
|
||||
print("=== Conversation Complete ===")
|
||||
print("Notice how the agent remembered the context from previous turns!")
|
||||
print("Sessions automatically handles conversation history.")
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
asyncio.run(main())
|
||||
```
|
||||
|
||||
## カスタムセッション実装
|
||||
|
||||
[`Session`][agents.memory.session.Session] プロトコルに従うクラスを作成することで、独自のセッションメモリを実装できます。
|
||||
|
||||
```python
|
||||
from agents.memory.session import SessionABC
|
||||
from agents.items import TResponseInputItem
|
||||
from typing import List
|
||||
|
||||
class MyCustomSession(SessionABC):
|
||||
"""Custom session implementation following the Session protocol."""
|
||||
|
||||
def __init__(self, session_id: str):
|
||||
self.session_id = session_id
|
||||
# Your initialization here
|
||||
|
||||
async def get_items(self, limit: int | None = None) -> List[TResponseInputItem]:
|
||||
"""Retrieve conversation history for this session."""
|
||||
# Your implementation here
|
||||
pass
|
||||
|
||||
async def add_items(self, items: List[TResponseInputItem]) -> None:
|
||||
"""Store new items for this session."""
|
||||
# Your implementation here
|
||||
pass
|
||||
|
||||
async def pop_item(self) -> TResponseInputItem | None:
|
||||
"""Remove and return the most recent item from this session."""
|
||||
# Your implementation here
|
||||
pass
|
||||
|
||||
async def clear_session(self) -> None:
|
||||
"""Clear all items for this session."""
|
||||
# Your implementation here
|
||||
pass
|
||||
|
||||
# Use your custom session
|
||||
agent = Agent(name="Assistant")
|
||||
result = await Runner.run(
|
||||
agent,
|
||||
"Hello",
|
||||
session=MyCustomSession("my_session")
|
||||
)
|
||||
```
|
||||
|
||||
## コミュニティによるセッション実装
|
||||
|
||||
コミュニティは追加のセッション実装を開発しています。
|
||||
|
||||
| パッケージ | 説明 |
|
||||
|---------|-------------|
|
||||
| [openai-django-sessions](https://pypi.org/project/openai-django-sessions/) | 任意の Django 対応データベース(PostgreSQL、MySQL、SQLite など)向けの Django ORM ベースのセッション |
|
||||
|
||||
セッション実装を構築した場合は、ぜひドキュメント PR を送ってここに追加してください。
|
||||
|
||||
## API リファレンス
|
||||
|
||||
詳細な API ドキュメントについては、以下を参照してください。
|
||||
|
||||
- [`Session`][agents.memory.session.Session] - プロトコルインターフェイス
|
||||
- [`OpenAIConversationsSession`][agents.memory.OpenAIConversationsSession] - OpenAI Conversations API 実装
|
||||
- [`OpenAIResponsesCompactionSession`][agents.memory.openai_responses_compaction_session.OpenAIResponsesCompactionSession] - Responses API 圧縮ラッパー
|
||||
- [`SQLiteSession`][agents.memory.sqlite_session.SQLiteSession] - 基本的な SQLite 実装
|
||||
- [`AsyncSQLiteSession`][agents.extensions.memory.async_sqlite_session.AsyncSQLiteSession] - `aiosqlite` に基づく非同期 SQLite 実装
|
||||
- [`RedisSession`][agents.extensions.memory.redis_session.RedisSession] - Redis バックのセッション実装
|
||||
- [`SQLAlchemySession`][agents.extensions.memory.sqlalchemy_session.SQLAlchemySession] - SQLAlchemy を利用した実装
|
||||
- [`MongoDBSession`][agents.extensions.memory.mongodb_session.MongoDBSession] - MongoDB バックのセッション実装
|
||||
- [`DaprSession`][agents.extensions.memory.dapr_session.DaprSession] - Dapr ステートストア実装
|
||||
- [`AdvancedSQLiteSession`][agents.extensions.memory.advanced_sqlite_session.AdvancedSQLiteSession] - 分岐と分析を備えた拡張 SQLite
|
||||
- [`EncryptedSession`][agents.extensions.memory.encrypt_session.EncryptedSession] - 任意のセッション向けの暗号化ラッパー
|
||||
@@ -0,0 +1,80 @@
|
||||
---
|
||||
search:
|
||||
exclude: true
|
||||
---
|
||||
# SQLAlchemy セッション
|
||||
|
||||
`SQLAlchemySession` は SQLAlchemy を使用して、本番環境に対応したセッション実装を提供します。これにより、セッションストレージとして SQLAlchemy がサポートする任意のデータベース (PostgreSQL、MySQL、SQLite など) を使用できます。
|
||||
|
||||
## インストール
|
||||
|
||||
SQLAlchemy セッションには `sqlalchemy` extra が必要です:
|
||||
|
||||
```bash
|
||||
pip install openai-agents[sqlalchemy]
|
||||
```
|
||||
|
||||
## クイックスタート
|
||||
|
||||
### データベース URL の使用
|
||||
|
||||
始めるための最も簡単な方法です:
|
||||
|
||||
```python
|
||||
import asyncio
|
||||
from agents import Agent, Runner
|
||||
from agents.extensions.memory import SQLAlchemySession
|
||||
|
||||
async def main():
|
||||
agent = Agent("Assistant")
|
||||
|
||||
# Create session using database URL
|
||||
session = SQLAlchemySession.from_url(
|
||||
"user-123",
|
||||
url="sqlite+aiosqlite:///:memory:",
|
||||
create_tables=True
|
||||
)
|
||||
|
||||
result = await Runner.run(agent, "Hello", session=session)
|
||||
print(result.final_output)
|
||||
|
||||
if __name__ == "__main__":
|
||||
asyncio.run(main())
|
||||
```
|
||||
|
||||
### 既存エンジンの使用
|
||||
|
||||
既存の SQLAlchemy エンジンを持つアプリケーション向けです:
|
||||
|
||||
```python
|
||||
import asyncio
|
||||
from agents import Agent, Runner
|
||||
from agents.extensions.memory import SQLAlchemySession
|
||||
from sqlalchemy.ext.asyncio import create_async_engine
|
||||
|
||||
async def main():
|
||||
# Create your database engine
|
||||
engine = create_async_engine("postgresql+asyncpg://user:pass@localhost/db")
|
||||
|
||||
agent = Agent("Assistant")
|
||||
session = SQLAlchemySession(
|
||||
"user-456",
|
||||
engine=engine,
|
||||
create_tables=True
|
||||
)
|
||||
|
||||
result = await Runner.run(agent, "Hello", session=session)
|
||||
print(result.final_output)
|
||||
|
||||
# Clean up
|
||||
await engine.dispose()
|
||||
|
||||
if __name__ == "__main__":
|
||||
asyncio.run(main())
|
||||
```
|
||||
|
||||
|
||||
## API リファレンス
|
||||
|
||||
- [`SQLAlchemySession`][agents.extensions.memory.sqlalchemy_session.SQLAlchemySession] - メインクラス
|
||||
- [`Session`][agents.memory.session.Session] - 基本セッションプロトコル
|
||||
@@ -0,0 +1,145 @@
|
||||
---
|
||||
search:
|
||||
exclude: true
|
||||
---
|
||||
# ストリーミング
|
||||
|
||||
ストリーミングにより、エージェントの実行が進むにつれて更新を購読できます。これは、エンドユーザーに進捗状況の更新や部分的なレスポンスを表示する場合に役立ちます。
|
||||
|
||||
ストリーミングするには、[`Runner.run_streamed()`][agents.run.Runner.run_streamed] を呼び出します。これにより [`RunResultStreaming`][agents.result.RunResultStreaming] が返されます。`result.stream_events()` を呼び出すと、以下で説明する [`StreamEvent`][agents.stream_events.StreamEvent] オブジェクトの非同期ストリームが得られます。
|
||||
|
||||
非同期イテレーターが終了するまで、`result.stream_events()` を消費し続けてください。ストリーミング実行は、イテレーターが終了するまで完了しません。また、セッションの永続化、承認の記録管理、履歴の圧縮などの後処理は、最後の可視トークンが到着した後に完了する場合があります。ループが終了すると、`result.is_complete` は最終的な実行状態を反映します。
|
||||
|
||||
## raw レスポンスイベント
|
||||
|
||||
[`RawResponsesStreamEvent`][agents.stream_events.RawResponsesStreamEvent] は、LLM から直接渡される raw イベントです。これらは OpenAI Responses API 形式であり、各イベントには型(`response.created`、`response.output_text.delta` など)とデータがあります。これらのイベントは、レスポンスメッセージが生成され次第、ユーザーにストリーミングしたい場合に役立ちます。
|
||||
|
||||
コンピュータツールの raw イベントは、保存された実行結果と同じ preview と GA の区別を維持します。Preview フローでは、1 つの `action` を持つ `computer_call` アイテムをストリーミングします。一方、`gpt-5.5` では、バッチ化された `actions[]` を持つ `computer_call` アイテムをストリーミングできます。高レベルの [`RunItemStreamEvent`][agents.stream_events.RunItemStreamEvent] サーフェスは、このために特別なコンピュータ専用イベント名を追加しません。どちらの形式も引き続き `tool_called` として表面化し、スクリーンショットの実行結果は `computer_call_output` アイテムをラップする `tool_output` として返されます。
|
||||
|
||||
たとえば、これは LLM によって生成されたテキストをトークンごとに出力します。
|
||||
|
||||
```python
|
||||
import asyncio
|
||||
from openai.types.responses import ResponseTextDeltaEvent
|
||||
from agents import Agent, Runner
|
||||
|
||||
async def main():
|
||||
agent = Agent(
|
||||
name="Joker",
|
||||
instructions="You are a helpful assistant.",
|
||||
)
|
||||
|
||||
result = Runner.run_streamed(agent, input="Please tell me 5 jokes.")
|
||||
async for event in result.stream_events():
|
||||
if event.type == "raw_response_event" and isinstance(event.data, ResponseTextDeltaEvent):
|
||||
print(event.data.delta, end="", flush=True)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
asyncio.run(main())
|
||||
```
|
||||
|
||||
## ストリーミングと承認
|
||||
|
||||
ストリーミングは、ツール承認のために一時停止する実行と互換性があります。ツールに承認が必要な場合、`result.stream_events()` は終了し、保留中の承認は [`RunResultStreaming.interruptions`][agents.result.RunResultStreaming.interruptions] で公開されます。`result.to_state()` を使って実行結果を [`RunState`][agents.run_state.RunState] に変換し、中断を承認または拒否してから、`Runner.run_streamed(...)` で再開します。
|
||||
|
||||
```python
|
||||
result = Runner.run_streamed(agent, "Delete temporary files if they are no longer needed.")
|
||||
async for _event in result.stream_events():
|
||||
pass
|
||||
|
||||
if result.interruptions:
|
||||
state = result.to_state()
|
||||
for interruption in result.interruptions:
|
||||
state.approve(interruption)
|
||||
result = Runner.run_streamed(agent, state)
|
||||
async for _event in result.stream_events():
|
||||
pass
|
||||
```
|
||||
|
||||
一時停止/再開の完全なウォークスルーについては、[human-in-the-loop ガイド](human_in_the_loop.md)を参照してください。
|
||||
|
||||
## 現在のターン後のストリーミングのキャンセル
|
||||
|
||||
途中でストリーミング実行を停止する必要がある場合は、[`result.cancel()`][agents.result.RunResultStreaming.cancel] を呼び出します。デフォルトでは、これにより実行はすぐに停止します。停止する前に現在のターンを正常に完了させるには、代わりに `result.cancel(mode="after_turn")` を呼び出します。
|
||||
|
||||
ストリーミング実行は、`result.stream_events()` が終了するまで完了しません。最後の可視トークンの後も、SDK がセッションアイテムを永続化したり、承認状態を確定したり、履歴を圧縮したりしている場合があります。
|
||||
|
||||
[`result.to_input_list(mode="normalized")`][agents.result.RunResultBase.to_input_list] から手動で継続しており、`cancel(mode="after_turn")` がツールターンの後で停止した場合は、すぐに新しいユーザーターンを追加するのではなく、その正規化された入力で `result.last_agent` を再実行して、未完了のターンを継続してください。
|
||||
- ストリーミング実行がツール承認のために停止した場合、それを新しいターンとして扱わないでください。ストリームの読み出しを最後まで完了し、`result.interruptions` を確認して、代わりに `result.to_state()` から再開してください。
|
||||
- 次のモデル呼び出しの前に、取得したセッション履歴と新しいユーザー入力をどのようにマージするかをカスタマイズするには、[`RunConfig.session_input_callback`][agents.run.RunConfig.session_input_callback] を使用します。そこで新しいターンのアイテムを書き換えた場合、その書き換え後のバージョンがそのターンとして永続化されます。
|
||||
|
||||
## 実行アイテムイベントとエージェントイベント
|
||||
|
||||
[`RunItemStreamEvent`][agents.stream_events.RunItemStreamEvent] は、より高レベルのイベントです。アイテムが完全に生成されたタイミングを通知します。これにより、各トークン単位ではなく、「メッセージが生成された」「ツールが実行された」などのレベルで進捗更新を送信できます。同様に、[`AgentUpdatedStreamEvent`][agents.stream_events.AgentUpdatedStreamEvent] は、現在のエージェントが変更されたとき(例: ハンドオフの結果として)に更新を提供します。
|
||||
|
||||
### 実行アイテムイベント名
|
||||
|
||||
`RunItemStreamEvent.name` は、固定された一連のセマンティックなイベント名を使用します。
|
||||
|
||||
- `message_output_created`
|
||||
- `handoff_requested`
|
||||
- `handoff_occured`
|
||||
- `tool_called`
|
||||
- `tool_search_called`
|
||||
- `tool_search_output_created`
|
||||
- `tool_output`
|
||||
- `reasoning_item_created`
|
||||
- `mcp_approval_requested`
|
||||
- `mcp_approval_response`
|
||||
- `mcp_list_tools`
|
||||
|
||||
`handoff_occured` は、後方互換性のため意図的にスペルミスのままになっています。
|
||||
|
||||
ホストされたツール検索を使用する場合、モデルがツール検索リクエストを発行すると `tool_search_called` が送出され、Responses API が読み込まれたサブセットを返すと `tool_search_output_created` が送出されます。
|
||||
|
||||
たとえば、これは raw イベントを無視し、更新をユーザーにストリーミングします。
|
||||
|
||||
```python
|
||||
import asyncio
|
||||
import random
|
||||
from agents import Agent, ItemHelpers, Runner, function_tool
|
||||
|
||||
@function_tool
|
||||
def how_many_jokes() -> int:
|
||||
return random.randint(1, 10)
|
||||
|
||||
|
||||
async def main():
|
||||
agent = Agent(
|
||||
name="Joker",
|
||||
instructions="First call the `how_many_jokes` tool, then tell that many jokes.",
|
||||
tools=[how_many_jokes],
|
||||
)
|
||||
|
||||
result = Runner.run_streamed(
|
||||
agent,
|
||||
input="Hello",
|
||||
)
|
||||
print("=== Run starting ===")
|
||||
|
||||
async for event in result.stream_events():
|
||||
# We'll ignore the raw responses event deltas
|
||||
if event.type == "raw_response_event":
|
||||
continue
|
||||
# When the agent updates, print that
|
||||
elif event.type == "agent_updated_stream_event":
|
||||
print(f"Agent updated: {event.new_agent.name}")
|
||||
continue
|
||||
# When items are generated, print them
|
||||
elif event.type == "run_item_stream_event":
|
||||
if event.item.type == "tool_call_item":
|
||||
print("-- Tool was called")
|
||||
elif event.item.type == "tool_call_output_item":
|
||||
print(f"-- Tool output: {event.item.output}")
|
||||
elif event.item.type == "message_output_item":
|
||||
print(f"-- Message output:\n {ItemHelpers.text_message_output(event.item)}")
|
||||
else:
|
||||
pass # Ignore other event types
|
||||
|
||||
print("=== Run complete ===")
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
asyncio.run(main())
|
||||
```
|
||||
@@ -0,0 +1,834 @@
|
||||
---
|
||||
search:
|
||||
exclude: true
|
||||
---
|
||||
# ツール
|
||||
|
||||
ツールを使用すると、データの取得、コードの実行、外部 API の呼び出し、さらにはコンピュータ操作など、エージェントがさまざまなアクションを実行できます。SDK は、次の 5 つのカテゴリーをサポートしています。
|
||||
|
||||
- OpenAI がホストするツール:OpenAI のサーバー上でモデルとともに実行されます。
|
||||
- ローカル/ランタイム実行ツール:`ComputerTool` と `ApplyPatchTool` は常にユーザーの環境で実行され、`ShellTool` はローカルまたはホスト型コンテナで実行できます。
|
||||
- Function Calling:任意の Python 関数をツールとしてラップします。
|
||||
- Agents as tools:完全なハンドオフを行わずに、エージェントを呼び出し可能なツールとして公開します。
|
||||
- 実験的機能:Codex ツール:ツール呼び出しから、ワークスペースにスコープされた Codex タスクを実行します。
|
||||
|
||||
## ツールタイプの選択
|
||||
|
||||
このページをカタログとして使用し、制御するランタイムに該当するセクションへ移動してください。
|
||||
|
||||
| 目的 | 参照先 |
|
||||
| --- | --- |
|
||||
| OpenAI が管理するツール(Web 検索、ファイル検索、Code Interpreter、ホスト型 MCP、画像生成)を使用する | [ホスト型ツール](#hosted-tools) |
|
||||
| ツール検索を使用して、大規模なツール群の読み込みをランタイムまで延期する | [ホスト型ツール検索](#hosted-tool-search) |
|
||||
| 独自のプロセスまたは環境でツールを実行する | [ローカルランタイムツール](#local-runtime-tools) |
|
||||
| Python 関数をツールとしてラップする | [関数ツール](#function-tools) |
|
||||
| ハンドオフを行わず、あるエージェントから別のエージェントを呼び出す | [Agents as tools](#agents-as-tools) |
|
||||
| エージェントから、ワークスペースにスコープされた Codex タスクを実行する | [実験的機能:Codex ツール](#experimental-codex-tool) |
|
||||
|
||||
## ホスト型ツール
|
||||
|
||||
[`OpenAIResponsesModel`][agents.models.openai_responses.OpenAIResponsesModel] を使用する場合、OpenAI はいくつかの組み込みツールを提供します。
|
||||
|
||||
- [`WebSearchTool`][agents.tool.WebSearchTool] を使用すると、エージェントは Web を検索できます。
|
||||
- [`FileSearchTool`][agents.tool.FileSearchTool] を使用すると、OpenAI のベクトルストアから情報を取得できます。
|
||||
- [`CodeInterpreterTool`][agents.tool.CodeInterpreterTool] を使用すると、LLM はサンドボックス環境でコードを実行できます。
|
||||
- [`HostedMCPTool`][agents.tool.HostedMCPTool] は、リモート MCP サーバーのツールをモデルに公開します。
|
||||
- [`ImageGenerationTool`][agents.tool.ImageGenerationTool] は、プロンプトから画像を生成します。
|
||||
- [`ToolSearchTool`][agents.tool.ToolSearchTool] を使用すると、モデルは遅延読み込みされるツール、名前空間、またはホスト型 MCP サーバーをオンデマンドで読み込めます。
|
||||
|
||||
ホスト型検索の高度なオプション:
|
||||
|
||||
- `FileSearchTool` は、`vector_store_ids` と `max_num_results` に加えて、`filters`、`ranking_options`、`include_search_results` をサポートします。
|
||||
- `WebSearchTool` は、`filters`、`user_location`、`search_context_size` をサポートします。
|
||||
|
||||
```python
|
||||
from agents import Agent, FileSearchTool, Runner, WebSearchTool
|
||||
|
||||
agent = Agent(
|
||||
name="Assistant",
|
||||
tools=[
|
||||
WebSearchTool(),
|
||||
FileSearchTool(
|
||||
max_num_results=3,
|
||||
vector_store_ids=["VECTOR_STORE_ID"],
|
||||
),
|
||||
],
|
||||
)
|
||||
|
||||
async def main():
|
||||
result = await Runner.run(agent, "Which coffee shop should I go to, taking into account my preferences and the weather today in SF?")
|
||||
print(result.final_output)
|
||||
```
|
||||
|
||||
### ホスト型ツール検索
|
||||
|
||||
ツール検索を使用すると、OpenAI Responses モデルは大規模なツール群の読み込みをランタイムまで延期できるため、現在のターンに必要なサブセットのみをモデルが読み込みます。多数の関数ツール、名前空間グループ、またはホスト型 MCP サーバーがあり、すべてのツールを事前に公開せずにツールスキーマのトークンを削減したい場合に便利です。
|
||||
|
||||
エージェントを構築する時点で候補ツールがすでに判明している場合は、ホスト型ツール検索から始めてください。アプリケーション側で読み込む内容を動的に決定する必要がある場合、Responses API はクライアント実行型のツール検索もサポートしていますが、標準の `Runner` はそのモードを自動実行しません。
|
||||
|
||||
```python
|
||||
from typing import Annotated
|
||||
|
||||
from agents import Agent, Runner, ToolSearchTool, function_tool, tool_namespace
|
||||
|
||||
|
||||
@function_tool(defer_loading=True)
|
||||
def get_customer_profile(
|
||||
customer_id: Annotated[str, "The customer ID to look up."],
|
||||
) -> str:
|
||||
"""Fetch a CRM customer profile."""
|
||||
return f"profile for {customer_id}"
|
||||
|
||||
|
||||
@function_tool(defer_loading=True)
|
||||
def list_open_orders(
|
||||
customer_id: Annotated[str, "The customer ID to look up."],
|
||||
) -> str:
|
||||
"""List open orders for a customer."""
|
||||
return f"open orders for {customer_id}"
|
||||
|
||||
|
||||
crm_tools = tool_namespace(
|
||||
name="crm",
|
||||
description="CRM tools for customer lookups.",
|
||||
tools=[get_customer_profile, list_open_orders],
|
||||
)
|
||||
|
||||
|
||||
agent = Agent(
|
||||
name="Operations assistant",
|
||||
model="gpt-5.6-sol",
|
||||
instructions="Load the crm namespace before using CRM tools.",
|
||||
tools=[*crm_tools, ToolSearchTool()],
|
||||
)
|
||||
|
||||
result = await Runner.run(agent, "Look up customer_42 and list their open orders.")
|
||||
print(result.final_output)
|
||||
```
|
||||
|
||||
注意事項:
|
||||
|
||||
- ホスト型ツール検索は、OpenAI Responses モデルでのみ利用できます。現在の Python SDK のサポートは `openai>=2.25.0` に依存します。
|
||||
- エージェントに遅延読み込み対象を設定する場合は、`ToolSearchTool()` を 1 つだけ追加してください。
|
||||
- 検索可能な対象には、`@function_tool(defer_loading=True)`、`tool_namespace(name=..., description=..., tools=[...])`、`HostedMCPTool(tool_config={..., "defer_loading": True})` が含まれます。
|
||||
- 遅延読み込みされる関数ツールは、`ToolSearchTool()` と組み合わせる必要があります。名前空間のみの構成でも `ToolSearchTool()` を使用すると、モデルが適切なグループをオンデマンドで読み込めます。
|
||||
- `tool_namespace()` は、共有の名前空間名と説明の下に `FunctionTool` インスタンスをまとめます。通常、`crm`、`billing`、`shipping` など、関連するツールが多数ある場合に最適です。
|
||||
- OpenAI の公式ベストプラクティスガイダンスは、[可能な限り名前空間を使用する](https://developers.openai.com/api/docs/guides/tools-tool-search#use-namespaces-where-possible)ことです。
|
||||
- 可能であれば、個別に遅延読み込みされる関数を多数使用するのではなく、名前空間またはホスト型 MCP サーバーを優先してください。通常、その方がモデルにとって優れた高レベルの検索対象となり、トークンをより効果的に節約できます。
|
||||
- 名前空間では、即時利用可能なツールと遅延読み込みされるツールを混在させられます。`defer_loading=True` が指定されていないツールは即座に呼び出し可能なままであり、同じ名前空間内の遅延ツールはツール検索を通じて読み込まれます。
|
||||
- 目安として、各名前空間は比較的小さく保ち、関数を 10 個未満にすることが理想的です。
|
||||
- 名前付きの `tool_choice` では、単独の名前空間名や遅延読み込み専用ツールを対象にできません。`auto`、`required`、または実際にトップレベルで呼び出し可能なツール名を使用してください。
|
||||
- `ToolSearchTool(execution="client")` は、Responses を手動でオーケストレーションするためのものです。モデルがクライアント実行型の `tool_search_call` を出力した場合、標準の `Runner` はそれを実行せずに例外を発生させます。
|
||||
- ツール検索のアクティビティは、専用の項目型およびイベント型として [`RunResult.new_items`](results.md#new-items) と [`RunItemStreamEvent`](streaming.md#run-item-event-names) に表示されます。
|
||||
- 名前空間による読み込みとトップレベルの遅延ツールの両方を扱う、実行可能な完全なコード例については、`examples/tools/tool_search.py` を参照してください。
|
||||
- 公式プラットフォームガイド:[ツール検索](https://developers.openai.com/api/docs/guides/tools-tool-search)。
|
||||
|
||||
### ホスト型コンテナシェルとスキル
|
||||
|
||||
`ShellTool` は、OpenAI がホストするコンテナでの実行もサポートしています。ローカルランタイムではなく、管理されたコンテナ内でモデルにシェルコマンドを実行させたい場合は、このモードを使用してください。
|
||||
|
||||
```python
|
||||
from agents import Agent, Runner, ShellTool, ShellToolSkillReference
|
||||
|
||||
csv_skill: ShellToolSkillReference = {
|
||||
"type": "skill_reference",
|
||||
"skill_id": "skill_698bbe879adc81918725cbc69dcae7960bc5613dadaed377",
|
||||
"version": "1",
|
||||
}
|
||||
|
||||
agent = Agent(
|
||||
name="Container shell agent",
|
||||
model="gpt-5.6-sol",
|
||||
instructions="Use the mounted skill when helpful.",
|
||||
tools=[
|
||||
ShellTool(
|
||||
environment={
|
||||
"type": "container_auto",
|
||||
"network_policy": {"type": "disabled"},
|
||||
"skills": [csv_skill],
|
||||
}
|
||||
)
|
||||
],
|
||||
)
|
||||
|
||||
result = await Runner.run(
|
||||
agent,
|
||||
"Use the configured skill to analyze CSV files in /mnt/data and summarize totals by region.",
|
||||
)
|
||||
print(result.final_output)
|
||||
```
|
||||
|
||||
後続の実行で既存のコンテナを再利用するには、`environment={"type": "container_reference", "container_id": "cntr_..."}` を設定します。
|
||||
|
||||
注意事項:
|
||||
|
||||
- ホスト型シェルは、Responses API のシェルツールを通じて利用できます。
|
||||
- `container_auto` はリクエスト用のコンテナをプロビジョニングし、`container_reference` は既存のコンテナを再利用します。
|
||||
- `container_auto` には、`file_ids` と `memory_limit` も指定できます。
|
||||
- `environment.skills` は、スキル参照およびインラインスキルバンドルを受け付けます。
|
||||
- ホスト型環境では、`ShellTool` に `executor`、`needs_approval`、`on_approval` を設定しないでください。
|
||||
- `network_policy` は、`disabled` モードと `allowlist` モードをサポートします。
|
||||
- 許可リストモードでは、`network_policy.domain_secrets` を使用して、ドメインにスコープされたシークレットを名前で注入できます。
|
||||
- 完全なコード例については、`examples/tools/container_shell_skill_reference.py` と `examples/tools/container_shell_inline_skill.py` を参照してください。
|
||||
- OpenAI プラットフォームガイド:[シェル](https://platform.openai.com/docs/guides/tools-shell)および[スキル](https://platform.openai.com/docs/guides/tools-skills)。
|
||||
|
||||
## ローカルランタイムツール
|
||||
|
||||
ローカルランタイムツールは、モデルのレスポンス自体の外部で実行されます。モデルは引き続き呼び出すタイミングを決定しますが、実際の処理はアプリケーションまたは設定された実行環境が行います。
|
||||
|
||||
`ComputerTool` と `ApplyPatchTool` には、ユーザーが提供するローカル実装が常に必要です。`ShellTool` は両方のモードに対応しています。管理された実行が必要な場合は上記のホスト型コンテナ設定を使用し、独自のプロセスでコマンドを実行する場合は以下のローカルランタイム設定を使用してください。
|
||||
|
||||
ローカルランタイムツールを使用するには、実装を提供する必要があります。
|
||||
|
||||
- [`ComputerTool`][agents.tool.ComputerTool]:GUI/ブラウザーの自動化を有効にするには、[`Computer`][agents.computer.Computer] または [`AsyncComputer`][agents.computer.AsyncComputer] インターフェースを実装します。
|
||||
- [`ShellTool`][agents.tool.ShellTool]:ローカル実行とホスト型コンテナ実行の両方に対応する最新のシェルツールです。
|
||||
- [`LocalShellTool`][agents.tool.LocalShellTool]:従来のローカルシェル統合です。
|
||||
- [`ApplyPatchTool`][agents.tool.ApplyPatchTool]:差分をローカルに適用するには、[`ApplyPatchEditor`][agents.editor.ApplyPatchEditor] を実装します。
|
||||
- `ShellTool(environment={"type": "local", "skills": [...]})` を使用すると、ローカルシェルスキルを利用できます。
|
||||
|
||||
### ComputerTool と Responses のコンピュータツール
|
||||
|
||||
`ComputerTool` は引き続きローカルハーネスです。[`Computer`][agents.computer.Computer] または [`AsyncComputer`][agents.computer.AsyncComputer] の実装を提供すると、SDK がそのハーネスを OpenAI Responses API のコンピュータ機能にマッピングします。
|
||||
|
||||
明示的な [`gpt-5.5`](https://developers.openai.com/api/docs/models/gpt-5.5) リクエストでは、SDK は GA の組み込みツールペイロード `{"type": "computer"}` を送信します。以前の `computer-use-preview` モデルでは、プレビューペイロード `{"type": "computer_use_preview", "environment": ..., "display_width": ..., "display_height": ...}` が引き続き使用されます。これは、OpenAI の[コンピュータ操作ガイド](https://developers.openai.com/api/docs/guides/tools-computer-use/)で説明されているプラットフォーム移行に対応しています。
|
||||
|
||||
- モデル:`computer-use-preview` -> `gpt-5.5`
|
||||
- ツールセレクター:`computer_use_preview` -> `computer`
|
||||
- コンピュータ呼び出しの形式:`computer_call` ごとに 1 つの `action` -> `computer_call` 上の一括 `actions[]`
|
||||
- 切り詰め:プレビューパスでは `ModelSettings(truncation="auto")` が必須 -> GA パスでは不要
|
||||
|
||||
SDK は、実際の Responses リクエストで有効なモデルに基づいて、そのワイヤ形式を選択します。プロンプトテンプレートを使用しており、モデルがプロンプト側で指定されているためリクエストで `model` が省略される場合、`model="gpt-5.5"` を明示したままにするか、`ModelSettings(tool_choice="computer")` または `ModelSettings(tool_choice="computer_use")` で GA セレクターを強制しない限り、SDK はプレビュー互換のコンピュータペイロードを維持します。
|
||||
|
||||
[`ComputerTool`][agents.tool.ComputerTool] が存在する場合、`tool_choice="computer"`、`"computer_use"`、`"computer_use_preview"` はすべて受け付けられ、有効なリクエストモデルに一致する組み込みセレクターへ正規化されます。`ComputerTool` がない場合、これらの文字列は通常の関数名として動作します。
|
||||
|
||||
`ComputerTool` が [`ComputerProvider`][agents.tool.ComputerProvider] ファクトリーによって提供される場合、この違いは重要です。GA の `computer` ペイロードでは、シリアライズ時に `environment` や表示サイズが不要なため、未解決のファクトリーでも問題ありません。一方、プレビュー互換のシリアライズでは、SDK が `environment`、`display_width`、`display_height` を送信できるよう、解決済みの `Computer` または `AsyncComputer` インスタンスが必要です。
|
||||
|
||||
ランタイムでは、どちらのパスも同じローカルハーネスを使用します。プレビューのレスポンスは、単一の `action` を持つ `computer_call` 項目を出力します。`gpt-5.5` は一括の `actions[]` を出力でき、SDK は `computer_call_output` スクリーンショット項目を生成する前に、それらを順番に実行します。Playwright ベースの実行可能なハーネスについては、`examples/tools/computer_use.py` を参照してください。
|
||||
|
||||
```python
|
||||
from agents import Agent, ApplyPatchTool, ShellTool
|
||||
from agents.computer import AsyncComputer
|
||||
from agents.editor import ApplyPatchResult, ApplyPatchOperation, ApplyPatchEditor
|
||||
|
||||
|
||||
class NoopComputer(AsyncComputer):
|
||||
environment = "browser"
|
||||
dimensions = (1024, 768)
|
||||
async def screenshot(self): return ""
|
||||
async def click(self, x, y, button): ...
|
||||
async def double_click(self, x, y): ...
|
||||
async def scroll(self, x, y, scroll_x, scroll_y): ...
|
||||
async def type(self, text): ...
|
||||
async def wait(self): ...
|
||||
async def move(self, x, y): ...
|
||||
async def keypress(self, keys): ...
|
||||
async def drag(self, path): ...
|
||||
|
||||
|
||||
class NoopEditor(ApplyPatchEditor):
|
||||
async def create_file(self, op: ApplyPatchOperation): return ApplyPatchResult(status="completed")
|
||||
async def update_file(self, op: ApplyPatchOperation): return ApplyPatchResult(status="completed")
|
||||
async def delete_file(self, op: ApplyPatchOperation): return ApplyPatchResult(status="completed")
|
||||
|
||||
|
||||
async def run_shell(request):
|
||||
return "shell output"
|
||||
|
||||
|
||||
agent = Agent(
|
||||
name="Local tools agent",
|
||||
tools=[
|
||||
ShellTool(executor=run_shell),
|
||||
ApplyPatchTool(editor=NoopEditor()),
|
||||
# ComputerTool expects a Computer/AsyncComputer implementation; omitted here for brevity.
|
||||
],
|
||||
)
|
||||
```
|
||||
|
||||
## 関数ツール
|
||||
|
||||
任意の Python 関数をツールとして使用できます。Agents SDK がツールを自動的にセットアップします。
|
||||
|
||||
- ツール名には Python 関数の名前が使用されます(または名前を指定できます)
|
||||
- ツールの説明には関数の docstring が使用されます(または説明を指定できます)
|
||||
- 関数入力のスキーマは、関数の引数から自動的に作成されます
|
||||
- 無効にしない限り、各入力の説明は関数の docstring から取得されます
|
||||
|
||||
Python の `inspect` モジュールを使用して関数シグネチャを抽出し、[`griffe`](https://mkdocstrings.github.io/griffe/) で docstring を解析し、`pydantic` でスキーマを作成します。
|
||||
|
||||
OpenAI Responses モデルを使用している場合、`@function_tool(defer_loading=True)` は、`ToolSearchTool()` が読み込むまで関数ツールを非表示にします。[`tool_namespace()`][agents.tool.tool_namespace] を使用して、関連する関数ツールをグループ化することもできます。完全な設定と制約については、[ホスト型ツール検索](#hosted-tool-search)を参照してください。
|
||||
|
||||
```python
|
||||
import json
|
||||
|
||||
from typing_extensions import TypedDict, Any
|
||||
|
||||
from agents import Agent, FunctionTool, RunContextWrapper, function_tool
|
||||
|
||||
|
||||
class Location(TypedDict):
|
||||
lat: float
|
||||
long: float
|
||||
|
||||
@function_tool # (1)!
|
||||
async def fetch_weather(location: Location) -> str:
|
||||
# (2)!
|
||||
"""Fetch the weather for a given location.
|
||||
|
||||
Args:
|
||||
location: The location to fetch the weather for.
|
||||
"""
|
||||
# In real life, we'd fetch the weather from a weather API
|
||||
return "sunny"
|
||||
|
||||
|
||||
@function_tool(name_override="fetch_data") # (3)!
|
||||
def read_file(ctx: RunContextWrapper[Any], path: str, directory: str | None = None) -> str:
|
||||
"""Read the contents of a file.
|
||||
|
||||
Args:
|
||||
path: The path to the file to read.
|
||||
directory: The directory to read the file from.
|
||||
"""
|
||||
# In real life, we'd read the file from the file system
|
||||
return "<file contents>"
|
||||
|
||||
|
||||
agent = Agent(
|
||||
name="Assistant",
|
||||
tools=[fetch_weather, read_file], # (4)!
|
||||
)
|
||||
|
||||
for tool in agent.tools:
|
||||
if isinstance(tool, FunctionTool):
|
||||
print(tool.name)
|
||||
print(tool.description)
|
||||
print(json.dumps(tool.params_json_schema, indent=2))
|
||||
print()
|
||||
|
||||
```
|
||||
|
||||
1. 関数の引数には任意の Python 型を使用でき、関数は同期または非同期にできます。
|
||||
2. docstring が存在する場合、説明および引数の説明を取得するために使用されます
|
||||
3. 関数は必要に応じて `context` を受け取れます(最初の引数である必要があります)。ツール名、説明、使用する docstring スタイルなどをオーバーライドすることもできます。
|
||||
4. デコレートした関数をツールのリストに渡せます。
|
||||
|
||||
??? note "出力の展開表示"
|
||||
|
||||
```
|
||||
fetch_weather
|
||||
Fetch the weather for a given location.
|
||||
{
|
||||
"$defs": {
|
||||
"Location": {
|
||||
"properties": {
|
||||
"lat": {
|
||||
"title": "Lat",
|
||||
"type": "number"
|
||||
},
|
||||
"long": {
|
||||
"title": "Long",
|
||||
"type": "number"
|
||||
}
|
||||
},
|
||||
"required": [
|
||||
"lat",
|
||||
"long"
|
||||
],
|
||||
"title": "Location",
|
||||
"type": "object"
|
||||
}
|
||||
},
|
||||
"properties": {
|
||||
"location": {
|
||||
"$ref": "#/$defs/Location",
|
||||
"description": "The location to fetch the weather for."
|
||||
}
|
||||
},
|
||||
"required": [
|
||||
"location"
|
||||
],
|
||||
"title": "fetch_weather_args",
|
||||
"type": "object"
|
||||
}
|
||||
|
||||
fetch_data
|
||||
Read the contents of a file.
|
||||
{
|
||||
"properties": {
|
||||
"path": {
|
||||
"description": "The path to the file to read.",
|
||||
"title": "Path",
|
||||
"type": "string"
|
||||
},
|
||||
"directory": {
|
||||
"anyOf": [
|
||||
{
|
||||
"type": "string"
|
||||
},
|
||||
{
|
||||
"type": "null"
|
||||
}
|
||||
],
|
||||
"default": null,
|
||||
"description": "The directory to read the file from.",
|
||||
"title": "Directory"
|
||||
}
|
||||
},
|
||||
"required": [
|
||||
"path"
|
||||
],
|
||||
"title": "fetch_data_args",
|
||||
"type": "object"
|
||||
}
|
||||
```
|
||||
|
||||
### 関数ツールからの画像またはファイルの返却
|
||||
|
||||
テキスト出力に加えて、1 つまたは複数の画像やファイルを関数ツールの出力として返せます。そのためには、次のいずれかを返します。
|
||||
|
||||
- 画像:[`ToolOutputImage`][agents.tool.ToolOutputImage](または TypedDict 版の [`ToolOutputImageDict`][agents.tool.ToolOutputImageDict])
|
||||
- ファイル:[`ToolOutputFileContent`][agents.tool.ToolOutputFileContent](または TypedDict 版の [`ToolOutputFileContentDict`][agents.tool.ToolOutputFileContentDict])
|
||||
- テキスト:文字列、文字列化可能なオブジェクト、または [`ToolOutputText`][agents.tool.ToolOutputText](または TypedDict 版の [`ToolOutputTextDict`][agents.tool.ToolOutputTextDict])
|
||||
|
||||
### カスタム関数ツール
|
||||
|
||||
Python 関数をツールとして使用したくない場合もあります。必要に応じて、[`FunctionTool`][agents.tool.FunctionTool] を直接作成できます。次の項目を指定する必要があります。
|
||||
|
||||
- `name`
|
||||
- `description`
|
||||
- `params_json_schema`:引数の JSON スキーマ
|
||||
- `on_invoke_tool`:[ツールコンテキスト][agents.tool_context.ToolContext]と JSON 文字列形式の引数を受け取り、ツール出力(テキスト、構造化されたツール出力オブジェクト、出力のリストなど)を返す非同期関数
|
||||
|
||||
```python
|
||||
from typing import Any
|
||||
|
||||
from pydantic import BaseModel
|
||||
|
||||
from agents import RunContextWrapper, FunctionTool
|
||||
|
||||
|
||||
|
||||
def do_some_work(data: str) -> str:
|
||||
return "done"
|
||||
|
||||
|
||||
class FunctionArgs(BaseModel):
|
||||
username: str
|
||||
age: int
|
||||
|
||||
|
||||
async def run_function(ctx: RunContextWrapper[Any], args: str) -> str:
|
||||
parsed = FunctionArgs.model_validate_json(args)
|
||||
return do_some_work(data=f"{parsed.username} is {parsed.age} years old")
|
||||
|
||||
|
||||
tool = FunctionTool(
|
||||
name="process_user",
|
||||
description="Processes extracted user data",
|
||||
params_json_schema=FunctionArgs.model_json_schema(),
|
||||
on_invoke_tool=run_function,
|
||||
)
|
||||
```
|
||||
|
||||
### 引数と docstring の自動解析
|
||||
|
||||
前述のように、関数シグネチャを自動的に解析してツールのスキーマを抽出し、docstring を解析してツールおよび個々の引数の説明を抽出します。これに関する注意事項は次のとおりです。
|
||||
|
||||
1. シグネチャの解析は `inspect` モジュールを使用して行われます。型アノテーションを使用して引数の型を把握し、スキーマ全体を表す Pydantic モデルを動的に構築します。Python の基本型、Pydantic モデル、TypedDict など、ほとんどの型をサポートしています。
|
||||
2. docstring の解析には `griffe` を使用します。サポートされる docstring 形式は `google`、`sphinx`、`numpy` です。docstring 形式の自動検出を試みますが、これはベストエフォートであり、`function_tool` の呼び出し時に明示的に設定できます。`use_docstring_info` を `False` に設定して、docstring の解析を無効にすることもできます。
|
||||
|
||||
スキーマ抽出のコードは [`agents.function_schema`][] にあります。
|
||||
|
||||
### Pydantic Field による引数の制約と説明
|
||||
|
||||
Pydantic の [`Field`](https://docs.pydantic.dev/latest/concepts/fields/) を使用して、ツール引数に制約(数値の最小値/最大値、文字列の長さやパターンなど)と説明を追加できます。Pydantic と同様に、デフォルト値ベースの形式(`arg: int = Field(..., ge=1)`)と `Annotated` 形式(`arg: Annotated[int, Field(..., ge=1)]`)の両方がサポートされます。生成される JSON スキーマとバリデーションには、これらの制約が含まれます。
|
||||
|
||||
```python
|
||||
from typing import Annotated
|
||||
from pydantic import Field
|
||||
from agents import function_tool
|
||||
|
||||
# Default-based form
|
||||
@function_tool
|
||||
def score_a(score: int = Field(..., ge=0, le=100, description="Score from 0 to 100")) -> str:
|
||||
return f"Score recorded: {score}"
|
||||
|
||||
# Annotated form
|
||||
@function_tool
|
||||
def score_b(score: Annotated[int, Field(..., ge=0, le=100, description="Score from 0 to 100")]) -> str:
|
||||
return f"Score recorded: {score}"
|
||||
```
|
||||
|
||||
### 関数ツールのタイムアウト
|
||||
|
||||
`@function_tool(timeout=...)` を使用して、非同期関数ツールの呼び出しごとにタイムアウトを設定できます。
|
||||
|
||||
```python
|
||||
import asyncio
|
||||
from agents import Agent, Runner, function_tool
|
||||
|
||||
|
||||
@function_tool(timeout=2.0)
|
||||
async def slow_lookup(query: str) -> str:
|
||||
await asyncio.sleep(10)
|
||||
return f"Result for {query}"
|
||||
|
||||
|
||||
agent = Agent(
|
||||
name="Timeout demo",
|
||||
instructions="Use tools when helpful.",
|
||||
tools=[slow_lookup],
|
||||
)
|
||||
```
|
||||
|
||||
タイムアウトに達した場合、デフォルトの動作は `timeout_behavior="error_as_result"` で、モデルから確認できるタイムアウトメッセージ(例:`Tool 'slow_lookup' timed out after 2 seconds.`)を送信します。
|
||||
|
||||
タイムアウト処理は次のように制御できます。
|
||||
|
||||
- `timeout_behavior="error_as_result"`(デフォルト):モデルが復旧できるよう、タイムアウトメッセージをモデルに返します。
|
||||
- `timeout_behavior="raise_exception"`:[`ToolTimeoutError`][agents.exceptions.ToolTimeoutError] を発生させ、実行を失敗させます。
|
||||
- `timeout_error_function=...`:`error_as_result` を使用する場合のタイムアウトメッセージをカスタマイズします。
|
||||
|
||||
```python
|
||||
import asyncio
|
||||
from agents import Agent, Runner, ToolTimeoutError, function_tool
|
||||
|
||||
|
||||
@function_tool(timeout=1.5, timeout_behavior="raise_exception")
|
||||
async def slow_tool() -> str:
|
||||
await asyncio.sleep(5)
|
||||
return "done"
|
||||
|
||||
|
||||
agent = Agent(name="Timeout hard-fail", tools=[slow_tool])
|
||||
|
||||
try:
|
||||
await Runner.run(agent, "Run the tool")
|
||||
except ToolTimeoutError as e:
|
||||
print(f"{e.tool_name} timed out in {e.timeout_seconds} seconds")
|
||||
```
|
||||
|
||||
!!! note
|
||||
|
||||
タイムアウト設定は、非同期の `@function_tool` ハンドラーでのみサポートされます。
|
||||
|
||||
### 関数ツールでのエラー処理
|
||||
|
||||
`@function_tool` を使用して関数ツールを作成する場合、`failure_error_function` を渡せます。これは、ツール呼び出しがクラッシュした場合に LLM へエラーレスポンスを提供する関数です。
|
||||
|
||||
- デフォルトでは(何も渡さない場合)、エラーが発生したことを LLM に通知する `default_tool_error_function` が実行されます。
|
||||
- 独自のエラー関数を渡した場合は、代わりにその関数が実行され、レスポンスが LLM に送信されます。
|
||||
- 明示的に `None` を渡した場合、ツール呼び出しのエラーは再度発生し、ユーザー側で処理できます。モデルが無効な JSON を生成した場合は `ModelBehaviorError`、コードがクラッシュした場合は `UserError` になる可能性があります。
|
||||
|
||||
```python
|
||||
from agents import function_tool, RunContextWrapper
|
||||
from typing import Any
|
||||
|
||||
def my_custom_error_function(context: RunContextWrapper[Any], error: Exception) -> str:
|
||||
"""A custom function to provide a user-friendly error message."""
|
||||
print(f"A tool call failed with the following error: {error}")
|
||||
return "An internal server error occurred. Please try again later."
|
||||
|
||||
@function_tool(failure_error_function=my_custom_error_function)
|
||||
def get_user_profile(user_id: str) -> str:
|
||||
"""Fetches a user profile from a mock API.
|
||||
This function demonstrates a 'flaky' or failing API call.
|
||||
"""
|
||||
if user_id == "user_123":
|
||||
return "User profile for user_123 successfully retrieved."
|
||||
else:
|
||||
raise ValueError(f"Could not retrieve profile for user_id: {user_id}. API returned an error.")
|
||||
|
||||
```
|
||||
|
||||
`FunctionTool` オブジェクトを手動で作成する場合、`on_invoke_tool` 関数内でエラーを処理する必要があります。
|
||||
|
||||
## Agents as tools
|
||||
|
||||
ワークフローによっては、制御をハンドオフする代わりに、中央のエージェントで特化型エージェントのネットワークをオーケストレーションしたい場合があります。これは、エージェントをツールとしてモデル化することで実現できます。
|
||||
|
||||
```python
|
||||
from agents import Agent, Runner
|
||||
import asyncio
|
||||
|
||||
spanish_agent = Agent(
|
||||
name="Spanish agent",
|
||||
instructions="You translate the user's message to Spanish",
|
||||
)
|
||||
|
||||
french_agent = Agent(
|
||||
name="French agent",
|
||||
instructions="You translate the user's message to French",
|
||||
)
|
||||
|
||||
orchestrator_agent = Agent(
|
||||
name="orchestrator_agent",
|
||||
instructions=(
|
||||
"You are a translation agent. You use the tools given to you to translate. "
|
||||
"If asked for multiple translations, you call the relevant tools."
|
||||
),
|
||||
tools=[
|
||||
spanish_agent.as_tool(
|
||||
tool_name="translate_to_spanish",
|
||||
tool_description="Translate the user's message to Spanish",
|
||||
),
|
||||
french_agent.as_tool(
|
||||
tool_name="translate_to_french",
|
||||
tool_description="Translate the user's message to French",
|
||||
),
|
||||
],
|
||||
)
|
||||
|
||||
async def main():
|
||||
result = await Runner.run(orchestrator_agent, input="Say 'Hello, how are you?' in Spanish.")
|
||||
print(result.final_output)
|
||||
```
|
||||
|
||||
### ツールエージェントのカスタマイズ
|
||||
|
||||
`agent.as_tool` 関数は、エージェントを簡単にツールへ変換するための便利なメソッドです。`max_turns`、`run_config`、`hooks`、`previous_response_id`、`conversation_id`、`session`、`needs_approval` など、一般的なランタイムオプションをサポートします。また、`parameters`、`input_builder`、`include_input_schema` による構造化入力もサポートします。
|
||||
|
||||
状態オプションは、ツール呼び出しによって開始されるネストされたエージェント実行を設定します。親実行の会話状態は自動的には継承されません。クライアント管理の履歴を親実行とネストされた実行の間で共有するには、同じ `session` を両方に明示的に渡してください。`Runner.run` と同様に、ネストされた実行には 1 つの状態戦略を選択してください。クライアント管理の `session`、または `previous_response_id` や `conversation_id` を使用したサーバー管理の継続のいずれかです。
|
||||
|
||||
```python
|
||||
@function_tool
|
||||
async def run_my_agent() -> str:
|
||||
"""A tool that runs the agent with custom configs"""
|
||||
|
||||
agent = Agent(name="My agent", instructions="...")
|
||||
|
||||
result = await Runner.run(
|
||||
agent,
|
||||
input="...",
|
||||
max_turns=5,
|
||||
run_config=...
|
||||
)
|
||||
|
||||
return str(result.final_output)
|
||||
```
|
||||
|
||||
### ツールエージェントの構造化入力
|
||||
|
||||
デフォルトでは、`Agent.as_tool()` は単一の文字列入力(`{"input": "..."}`)を想定しますが、`parameters`(Pydantic モデルまたは dataclass 型)を渡すことで構造化スキーマを公開できます。
|
||||
|
||||
追加オプション:
|
||||
|
||||
- `include_input_schema=True` を指定すると、生成されるネストされた入力に完全な JSON Schema が含まれます。
|
||||
- `input_builder=...` を使用すると、構造化されたツール引数をネストされたエージェント入力へ変換する方法を完全にカスタマイズできます。
|
||||
- `RunContextWrapper.tool_input` には、ネストされた実行コンテキスト内で解析済みの構造化ペイロードが格納されます。
|
||||
|
||||
```python
|
||||
from pydantic import BaseModel, Field
|
||||
|
||||
|
||||
class TranslationInput(BaseModel):
|
||||
text: str = Field(description="Text to translate.")
|
||||
source: str = Field(description="Source language.")
|
||||
target: str = Field(description="Target language.")
|
||||
|
||||
|
||||
translator_tool = translator_agent.as_tool(
|
||||
tool_name="translate_text",
|
||||
tool_description="Translate text between languages.",
|
||||
parameters=TranslationInput,
|
||||
include_input_schema=True,
|
||||
)
|
||||
```
|
||||
|
||||
実行可能な完全なコード例については、`examples/agent_patterns/agents_as_tools_structured.py` を参照してください。
|
||||
|
||||
### ツールエージェントの承認ゲート
|
||||
|
||||
`Agent.as_tool(..., needs_approval=...)` は、`function_tool` と同じ承認フローを使用します。承認が必要な場合、実行は一時停止し、保留中の項目が `result.interruptions` に表示されます。次に `result.to_state()` を使用し、`state.approve(...)` または `state.reject(...)` を呼び出した後に再開します。完全な一時停止/再開パターンについては、[Human-in-the-loop ガイド](human_in_the_loop.md)を参照してください。
|
||||
|
||||
### カスタム出力の抽出
|
||||
|
||||
場合によっては、中央のエージェントに返す前に、ツールエージェントの出力を変更したいことがあります。これは、次のような場合に役立ちます。
|
||||
|
||||
- サブエージェントのチャット履歴から特定の情報(JSON ペイロードなど)を抽出する。
|
||||
- エージェントの最終回答を変換または再フォーマットする(Markdown をプレーンテキストや CSV に変換するなど)。
|
||||
- 出力を検証する。または、エージェントのレスポンスが欠落しているか不正な形式の場合にフォールバック値を提供する。
|
||||
|
||||
これは、`as_tool` メソッドに `custom_output_extractor` 引数を指定することで実現できます。
|
||||
|
||||
```python
|
||||
async def extract_json_payload(run_result: RunResult) -> str:
|
||||
# Scan the agent’s outputs in reverse order until we find a JSON-like message from a tool call.
|
||||
for item in reversed(run_result.new_items):
|
||||
if isinstance(item, ToolCallOutputItem) and item.output.strip().startswith("{"):
|
||||
return item.output.strip()
|
||||
# Fallback to an empty JSON object if nothing was found
|
||||
return "{}"
|
||||
|
||||
|
||||
json_tool = data_agent.as_tool(
|
||||
tool_name="get_data_json",
|
||||
tool_description="Run the data agent and return only its JSON payload",
|
||||
custom_output_extractor=extract_json_payload,
|
||||
)
|
||||
```
|
||||
|
||||
カスタム抽出関数内では、ネストされた [`RunResult`][agents.result.RunResult] から [`agent_tool_invocation`][agents.result.RunResultBase.agent_tool_invocation] にもアクセスできます。これは、ネストされた実行結果を後処理する際に、外側のツール名、呼び出し ID、または raw 引数が必要な場合に便利です。[実行結果ガイド](results.md#agent-as-tool-metadata)を参照してください。
|
||||
|
||||
### ネストされたエージェント実行のストリーミング
|
||||
|
||||
`as_tool` に `on_stream` コールバックを渡すと、ネストされたエージェントが出力するストリーミングイベントを受け取りながら、ストリームの完了後に最終出力を返せます。
|
||||
|
||||
```python
|
||||
from agents import AgentToolStreamEvent
|
||||
|
||||
|
||||
async def handle_stream(event: AgentToolStreamEvent) -> None:
|
||||
# Inspect the underlying StreamEvent along with agent metadata.
|
||||
print(f"[stream] {event['agent'].name} :: {event['event'].type}")
|
||||
|
||||
|
||||
billing_agent_tool = billing_agent.as_tool(
|
||||
tool_name="billing_helper",
|
||||
tool_description="Answer billing questions.",
|
||||
on_stream=handle_stream, # Can be sync or async.
|
||||
)
|
||||
```
|
||||
|
||||
想定される動作:
|
||||
|
||||
- イベント型は `StreamEvent["type"]` と同様です:`raw_response_event`、`run_item_stream_event`、`agent_updated_stream_event`。
|
||||
- `on_stream` を指定すると、ネストされたエージェントは自動的にストリーミングモードで実行され、最終出力を返す前にストリームが最後まで処理されます。
|
||||
- ハンドラーは同期または非同期にできます。各イベントは到着した順に渡されます。
|
||||
- モデルのツール呼び出し経由でツールが呼び出された場合、`tool_call` が存在します。直接呼び出した場合は `None` になることがあります。
|
||||
- 実行可能な完全なサンプルについては、`examples/agent_patterns/agents_as_tools_streaming.py` を参照してください。
|
||||
|
||||
### 条件付きツール有効化
|
||||
|
||||
`is_enabled` パラメーターを使用して、ランタイムでエージェントツールを条件付きで有効または無効にできます。これにより、コンテキスト、ユーザー設定、ランタイム条件に基づいて、LLM が利用できるツールを動的にフィルタリングできます。
|
||||
|
||||
```python
|
||||
import asyncio
|
||||
from agents import Agent, AgentBase, Runner, RunContextWrapper
|
||||
from pydantic import BaseModel
|
||||
|
||||
class LanguageContext(BaseModel):
|
||||
language_preference: str = "french_spanish"
|
||||
|
||||
def french_enabled(ctx: RunContextWrapper[LanguageContext], agent: AgentBase) -> bool:
|
||||
"""Enable French for French+Spanish preference."""
|
||||
return ctx.context.language_preference == "french_spanish"
|
||||
|
||||
# Create specialized agents
|
||||
spanish_agent = Agent(
|
||||
name="spanish_agent",
|
||||
instructions="You respond in Spanish. Always reply to the user's question in Spanish.",
|
||||
)
|
||||
|
||||
french_agent = Agent(
|
||||
name="french_agent",
|
||||
instructions="You respond in French. Always reply to the user's question in French.",
|
||||
)
|
||||
|
||||
# Create orchestrator with conditional tools
|
||||
orchestrator = Agent(
|
||||
name="orchestrator",
|
||||
instructions=(
|
||||
"You are a multilingual assistant. You use the tools given to you to respond to users. "
|
||||
"You must call ALL available tools to provide responses in different languages. "
|
||||
"You never respond in languages yourself, you always use the provided tools."
|
||||
),
|
||||
tools=[
|
||||
spanish_agent.as_tool(
|
||||
tool_name="respond_spanish",
|
||||
tool_description="Respond to the user's question in Spanish",
|
||||
is_enabled=True, # Always enabled
|
||||
),
|
||||
french_agent.as_tool(
|
||||
tool_name="respond_french",
|
||||
tool_description="Respond to the user's question in French",
|
||||
is_enabled=french_enabled,
|
||||
),
|
||||
],
|
||||
)
|
||||
|
||||
async def main():
|
||||
context = RunContextWrapper(LanguageContext(language_preference="french_spanish"))
|
||||
result = await Runner.run(orchestrator, "How are you?", context=context.context)
|
||||
print(result.final_output)
|
||||
|
||||
asyncio.run(main())
|
||||
```
|
||||
|
||||
`is_enabled` パラメーターは、次の値を受け付けます。
|
||||
|
||||
- **ブール値**:`True`(常に有効)または `False`(常に無効)
|
||||
- **呼び出し可能な関数**:`(context, agent)` を受け取り、ブール値を返す関数
|
||||
- **非同期関数**:複雑な条件ロジックのための非同期関数
|
||||
|
||||
無効なツールはランタイムで LLM から完全に非表示になるため、次の用途に役立ちます。
|
||||
|
||||
- ユーザー権限に基づく機能制御
|
||||
- 環境固有のツール可用性(開発環境と本番環境)
|
||||
- 異なるツール設定の A/B テスト
|
||||
- ランタイム状態に基づく動的なツールフィルタリング
|
||||
|
||||
## 実験的機能:Codex ツール
|
||||
|
||||
`codex_tool` は Codex CLI をラップし、エージェントがツール呼び出し中にワークスペースにスコープされたタスク(シェル、ファイル編集、MCP ツール)を実行できるようにします。この機能は実験的であり、変更される可能性があります。
|
||||
|
||||
メインエージェントが現在の実行を離れることなく、範囲が限定されたワークスペースタスクを Codex に委任する場合に使用します。デフォルトのツール名は `codex` です。カスタム名を設定する場合、その名前は `codex` であるか、`codex_` で始まる必要があります。エージェントに複数の Codex ツールを含める場合、それぞれに一意の名前を使用する必要があります。
|
||||
|
||||
```python
|
||||
from agents import Agent
|
||||
from agents.extensions.experimental.codex import ThreadOptions, TurnOptions, codex_tool
|
||||
|
||||
agent = Agent(
|
||||
name="Codex Agent",
|
||||
instructions="Use the codex tool to inspect the workspace and answer the question.",
|
||||
tools=[
|
||||
codex_tool(
|
||||
sandbox_mode="workspace-write",
|
||||
working_directory="/path/to/repo",
|
||||
default_thread_options=ThreadOptions(
|
||||
model="gpt-5.5",
|
||||
model_reasoning_effort="low",
|
||||
network_access_enabled=True,
|
||||
web_search_mode="disabled",
|
||||
approval_policy="never",
|
||||
),
|
||||
default_turn_options=TurnOptions(
|
||||
idle_timeout_seconds=60,
|
||||
),
|
||||
persist_session=True,
|
||||
)
|
||||
],
|
||||
)
|
||||
```
|
||||
|
||||
まず、次のオプショングループから設定してください。
|
||||
|
||||
- 実行対象:`sandbox_mode` と `working_directory` は、Codex が操作できる場所を定義します。これらは組み合わせて使用し、作業ディレクトリが Git リポジトリ内にない場合は `skip_git_repo_check=True` を設定してください。
|
||||
- スレッドのデフォルト:`default_thread_options=ThreadOptions(...)` は、モデル、推論強度、承認ポリシー、追加ディレクトリ、ネットワークアクセス、Web 検索モードを設定します。従来の `web_search_enabled` よりも `web_search_mode` を優先してください。
|
||||
- ターンのデフォルト:`default_turn_options=TurnOptions(...)` は、`idle_timeout_seconds` やオプションのキャンセル用 `signal` など、ターンごとの動作を設定します。
|
||||
- ツール I/O:ツール呼び出しには、`{ "type": "text", "text": ... }` または `{ "type": "local_image", "path": ... }` を持つ `inputs` 項目を少なくとも 1 つ含める必要があります。`output_schema` を使用すると、構造化された Codex レスポンスを必須にできます。
|
||||
|
||||
スレッドの再利用と永続化は、別々に制御されます。
|
||||
|
||||
- `persist_session=True` は、同じツールインスタンスへの繰り返し呼び出しで 1 つの Codex スレッドを再利用します。
|
||||
- `use_run_context_thread_id=True` は、同じ変更可能なコンテキストオブジェクトを共有する複数の実行にわたり、実行コンテキスト内にスレッド ID を保存して再利用します。
|
||||
- スレッド ID の優先順位は、呼び出しごとの `thread_id`、実行コンテキストのスレッド ID(有効な場合)、設定済みの `thread_id` オプションの順です。
|
||||
- デフォルトの実行コンテキストキーは、`name="codex"` の場合は `codex_thread_id`、`name="codex_<suffix>"` の場合は `codex_thread_id_<suffix>` です。`run_context_thread_id_key` でオーバーライドできます。
|
||||
|
||||
ランタイム設定:
|
||||
|
||||
- 認証:`CODEX_API_KEY`(推奨)または `OPENAI_API_KEY` を設定するか、`codex_options={"api_key": "..."}` を渡します。
|
||||
- ランタイム:`codex_options.base_url` は CLI のベース URL をオーバーライドします。
|
||||
- バイナリ解決:CLI のパスを固定するには、`codex_options.codex_path_override`(または `CODEX_PATH`)を設定します。それ以外の場合、SDK は `PATH` から `codex` を解決し、見つからなければ同梱のベンダーバイナリを使用します。
|
||||
- 環境:`codex_options.env` は、サブプロセス環境を完全に制御します。指定した場合、サブプロセスは `os.environ` を継承しません。
|
||||
- ストリーム制限:`codex_options.codex_subprocess_stream_limit_bytes`(または `OPENAI_AGENTS_CODEX_SUBPROCESS_STREAM_LIMIT_BYTES`)は、stdout/stderr リーダーの制限を制御します。有効範囲は `65536` から `67108864` で、デフォルトは `8388608` です。
|
||||
- ストリーミング:`on_stream` は、スレッド/ターンのライフサイクルイベントと項目イベント(`reasoning`、`command_execution`、`mcp_tool_call`、`file_change`、`web_search`、`todo_list`、`error` の項目更新)を受け取ります。
|
||||
- 出力:実行結果には `response`、`usage`、`thread_id` が含まれます。使用量は `RunContextWrapper.usage` に追加されます。
|
||||
|
||||
リファレンス:
|
||||
|
||||
- [Codex ツール API リファレンス](ref/extensions/experimental/codex/codex_tool.md)
|
||||
- [ThreadOptions リファレンス](ref/extensions/experimental/codex/thread_options.md)
|
||||
- [TurnOptions リファレンス](ref/extensions/experimental/codex/turn_options.md)
|
||||
- 実行可能な完全なサンプルについては、`examples/tools/codex.py` と `examples/tools/codex_same_thread.py` を参照してください。
|
||||
@@ -0,0 +1,223 @@
|
||||
---
|
||||
search:
|
||||
exclude: true
|
||||
---
|
||||
# トレーシング
|
||||
|
||||
Agents SDK には組み込みのトレーシングが含まれており、エージェント実行中のイベント(LLM 生成、ツール呼び出し、ハンドオフ、ガードレール、さらには発生したカスタムイベントまで)を包括的に収集します。[Traces ダッシュボード](https://platform.openai.com/traces)を使用すると、開発中および本番環境でワークフローをデバッグ、可視化、監視できます。
|
||||
|
||||
!!!note
|
||||
|
||||
トレーシングはデフォルトで有効です。一般的には次の 3 つの方法で無効化できます:
|
||||
|
||||
1. 環境変数 `OPENAI_AGENTS_DISABLE_TRACING=1` を設定することで、トレーシングをグローバルに無効化できます
|
||||
2. コード内で [`set_tracing_disabled(True)`][agents.set_tracing_disabled] を使用して、トレーシングをグローバルに無効化できます
|
||||
3. [`agents.run.RunConfig.tracing_disabled`][] を `True` に設定することで、単一の実行に対してトレーシングを無効化できます
|
||||
|
||||
***OpenAI の API を使用し、Zero Data Retention (ZDR) ポリシーの下で運用している組織では、トレーシングは利用できません。***
|
||||
|
||||
## トレースとスパン
|
||||
|
||||
- **トレース** は、「ワークフロー」の単一のエンドツーエンド操作を表します。トレースはスパンで構成されます。トレースには次のプロパティがあります:
|
||||
- `workflow_name`: 論理的なワークフローまたはアプリです。たとえば「コード生成」や「カスタマーサービス」です。
|
||||
- `trace_id`: トレースの一意な ID です。指定しない場合は自動生成されます。形式は `trace_<32_alphanumeric>` である必要があります。
|
||||
- `group_id`: 任意のグループ ID で、同じ会話からの複数のトレースを関連付けるために使用します。たとえば、チャットスレッド ID を使用できます。
|
||||
- `disabled`: True の場合、トレースは記録されません。
|
||||
- `metadata`: トレースの任意のメタデータです。
|
||||
- **スパン** は、開始時刻と終了時刻を持つ操作を表します。スパンには次のものがあります:
|
||||
- `started_at` と `ended_at` のタイムスタンプ。
|
||||
- `trace_id`: 所属するトレースを表します
|
||||
- `parent_id`: このスパンの親スパン(存在する場合)を指します
|
||||
- `span_data`: スパンに関する情報です。たとえば、`AgentSpanData` にはエージェントに関する情報が含まれ、`GenerationSpanData` には LLM 生成に関する情報が含まれます。
|
||||
|
||||
## デフォルトのトレーシング
|
||||
|
||||
デフォルトでは、SDK は次をトレースします:
|
||||
|
||||
- `Runner.{run, run_sync, run_streamed}()` 全体は `trace()` でラップされます。
|
||||
- エージェントが実行されるたびに、`agent_span()` でラップされます
|
||||
- LLM 生成は `generation_span()` でラップされます
|
||||
- 各関数ツール呼び出しは `function_span()` でラップされます
|
||||
- ガードレールは `guardrail_span()` でラップされます
|
||||
- ハンドオフは `handoff_span()` でラップされます
|
||||
- 音声入力(音声からテキストへの変換)は `transcription_span()` でラップされます
|
||||
- 音声出力(テキストから音声への変換)は `speech_span()` でラップされます
|
||||
- 関連する音声スパンは、`speech_group_span()` の下に親子関係として配置される場合があります
|
||||
|
||||
デフォルトでは、トレース名は「Agent workflow」です。`trace` を使用する場合はこの名前を設定できます。また、[`RunConfig`][agents.run.RunConfig] で名前やその他のプロパティを構成できます。
|
||||
|
||||
さらに、[カスタムトレーシングプロセッサー](#custom-tracing-processors)を設定して、トレースを他の送信先へ送ることもできます(置き換え先または副次的な送信先として)。
|
||||
|
||||
## 長時間稼働するワーカーと即時エクスポート
|
||||
|
||||
デフォルトの [`BatchTraceProcessor`][agents.tracing.processors.BatchTraceProcessor] は、数秒ごとにバックグラウンドでトレースをエクスポートします。メモリ内キューがサイズトリガーに達した場合はそれより早くエクスポートし、プロセス終了時には最終フラッシュも行います。Celery、RQ、Dramatiq、FastAPI のバックグラウンドタスクなどの長時間稼働するワーカーでは、通常、追加のコードなしでトレースが自動的にエクスポートされますが、各ジョブ完了直後に Traces ダッシュボードに表示されない場合があります。
|
||||
|
||||
作業単位の終了時に即時配信を保証する必要がある場合は、トレースコンテキストが終了した後に [`flush_traces()`][agents.tracing.flush_traces] を呼び出してください。
|
||||
|
||||
```python
|
||||
from agents import Runner, flush_traces, trace
|
||||
|
||||
|
||||
@celery_app.task
|
||||
def run_agent_task(prompt: str):
|
||||
try:
|
||||
with trace("celery_task"):
|
||||
result = Runner.run_sync(agent, prompt)
|
||||
return result.final_output
|
||||
finally:
|
||||
flush_traces()
|
||||
```
|
||||
|
||||
```python
|
||||
from fastapi import BackgroundTasks, FastAPI
|
||||
from agents import Runner, flush_traces, trace
|
||||
|
||||
app = FastAPI()
|
||||
|
||||
|
||||
def process_in_background(prompt: str) -> None:
|
||||
try:
|
||||
with trace("background_job"):
|
||||
Runner.run_sync(agent, prompt)
|
||||
finally:
|
||||
flush_traces()
|
||||
|
||||
|
||||
@app.post("/run")
|
||||
async def run(prompt: str, background_tasks: BackgroundTasks):
|
||||
background_tasks.add_task(process_in_background, prompt)
|
||||
return {"status": "queued"}
|
||||
```
|
||||
|
||||
[`flush_traces()`][agents.tracing.flush_traces] は、現在バッファーされているトレースとスパンがエクスポートされるまでブロックします。そのため、部分的に構築されたトレースをフラッシュしないよう、`trace()` が閉じた後に呼び出してください。デフォルトのエクスポート遅延で問題ない場合は、この呼び出しを省略できます。
|
||||
|
||||
## 上位レベルのトレース
|
||||
|
||||
場合によっては、`run()` への複数回の呼び出しを単一のトレースの一部にしたいことがあります。コード全体を `trace()` でラップすることで実現できます。
|
||||
|
||||
```python
|
||||
from agents import Agent, Runner, trace
|
||||
|
||||
async def main():
|
||||
agent = Agent(name="Joke generator", instructions="Tell funny jokes.")
|
||||
|
||||
with trace("Joke workflow"): # (1)!
|
||||
first_result = await Runner.run(agent, "Tell me a joke")
|
||||
second_result = await Runner.run(agent, f"Rate this joke: {first_result.final_output}")
|
||||
print(f"Joke: {first_result.final_output}")
|
||||
print(f"Rating: {second_result.final_output}")
|
||||
```
|
||||
|
||||
1. 2 回の `Runner.run` 呼び出しが `with trace()` でラップされているため、個々の実行は 2 つのトレースを作成するのではなく、全体のトレースの一部になります。
|
||||
|
||||
## トレースの作成
|
||||
|
||||
[`trace()`][agents.tracing.trace] 関数を使用してトレースを作成できます。トレースは開始し、終了する必要があります。その方法には 2 つの選択肢があります:
|
||||
|
||||
1. **推奨**: トレースをコンテキストマネージャーとして使用します。つまり、`with trace(...) as my_trace` のように使用します。これにより、適切なタイミングでトレースが自動的に開始および終了されます。
|
||||
2. [`trace.start()`][agents.tracing.Trace.start] と [`trace.finish()`][agents.tracing.Trace.finish] を手動で呼び出すこともできます。
|
||||
|
||||
現在のトレースは、Python の [`contextvar`](https://docs.python.org/3/library/contextvars.html) を介して追跡されます。これは、並行処理でも自動的に機能することを意味します。手動でトレースを開始/終了する場合は、現在のトレースを更新するために、`start()`/`finish()` に `mark_as_current` と `reset_current` を渡す必要があります。
|
||||
|
||||
## スパンの作成
|
||||
|
||||
各種 [`*_span()`][agents.tracing.create] メソッドを使用してスパンを作成できます。通常、手動でスパンを作成する必要はありません。カスタムスパン情報を追跡するために、[`custom_span()`][agents.tracing.custom_span] 関数を利用できます。
|
||||
|
||||
スパンは自動的に現在のトレースの一部となり、最も近い現在のスパンの下にネストされます。この現在のスパンは、Python の [`contextvar`](https://docs.python.org/3/library/contextvars.html) を介して追跡されます。
|
||||
|
||||
## 機密データ
|
||||
|
||||
一部のスパンは、潜在的に機密性の高いデータを取得する場合があります。
|
||||
|
||||
`generation_span()` は LLM 生成の入出力を保存し、`function_span()` は関数呼び出しの入出力を保存します。これらには機密データが含まれる可能性があるため、[`RunConfig.trace_include_sensitive_data`][agents.run.RunConfig.trace_include_sensitive_data] を使用してそのデータの取得を無効化できます。
|
||||
|
||||
同様に、音声スパンにはデフォルトで、入力音声と出力音声の base64 エンコードされた PCM データが含まれます。この音声データの取得は、[`VoicePipelineConfig.trace_include_sensitive_audio_data`][agents.voice.pipeline_config.VoicePipelineConfig.trace_include_sensitive_audio_data] を構成することで無効化できます。
|
||||
|
||||
デフォルトでは、`trace_include_sensitive_data` は `True` です。アプリを実行する前に `OPENAI_AGENTS_TRACE_INCLUDE_SENSITIVE_DATA` 環境変数を `true/1` または `false/0` にエクスポートすることで、コードを書かずにデフォルトを設定できます。
|
||||
|
||||
## カスタムトレーシングプロセッサー
|
||||
|
||||
トレーシングの高レベルのアーキテクチャは次のとおりです:
|
||||
|
||||
- 初期化時に、グローバルな [`TraceProvider`][agents.tracing.setup.TraceProvider] を作成します。これはトレースの作成を担います。
|
||||
- `TraceProvider` は、トレース/スパンをバッチ単位で [`BackendSpanExporter`][agents.tracing.processors.BackendSpanExporter] に送信する [`BatchTraceProcessor`][agents.tracing.processors.BatchTraceProcessor] で構成します。`BackendSpanExporter` は、スパンとトレースをバッチ単位で OpenAI バックエンドへエクスポートします。
|
||||
|
||||
このデフォルト設定をカスタマイズし、代替または追加のバックエンドへトレースを送信したり、エクスポーターの動作を変更したりするには、2 つの選択肢があります:
|
||||
|
||||
1. [`add_trace_processor()`][agents.tracing.add_trace_processor] を使用すると、トレースやスパンが準備でき次第それらを受け取る **追加の** トレースプロセッサーを追加できます。これにより、OpenAI のバックエンドへトレースを送信することに加えて、独自の処理を行えます。
|
||||
2. [`set_trace_processors()`][agents.tracing.set_trace_processors] を使用すると、デフォルトのプロセッサーを独自のトレースプロセッサーで **置き換える** ことができます。つまり、その処理を行う `TracingProcessor` を含めない限り、トレースは OpenAI のバックエンドに送信されません。
|
||||
|
||||
|
||||
## OpenAI 以外のモデルでのトレーシング
|
||||
|
||||
OpenAI 以外のモデルで OpenAI API キーを使用すると、トレーシングを無効化する必要なく、OpenAI Traces ダッシュボードで無料のトレーシングを有効にできます。アダプターの選択とセットアップ上の注意事項については、Models ガイドの[サードパーティアダプター](models/index.md#third-party-adapters)セクションを参照してください。
|
||||
|
||||
```python
|
||||
import os
|
||||
from agents import set_tracing_export_api_key, Agent, Runner
|
||||
from agents.extensions.models.any_llm_model import AnyLLMModel
|
||||
|
||||
tracing_api_key = os.environ["OPENAI_API_KEY"]
|
||||
set_tracing_export_api_key(tracing_api_key)
|
||||
|
||||
model = AnyLLMModel(
|
||||
model="your-provider/your-model-name",
|
||||
api_key="your-api-key",
|
||||
)
|
||||
|
||||
agent = Agent(
|
||||
name="Assistant",
|
||||
model=model,
|
||||
)
|
||||
```
|
||||
|
||||
単一の実行に対してのみ別のトレーシングキーが必要な場合は、グローバルエクスポーターを変更する代わりに `RunConfig` 経由で渡してください。
|
||||
|
||||
```python
|
||||
from agents import Runner, RunConfig
|
||||
|
||||
await Runner.run(
|
||||
agent,
|
||||
input="Hello",
|
||||
run_config=RunConfig(tracing={"api_key": "sk-tracing-123"}),
|
||||
)
|
||||
```
|
||||
|
||||
## 追加の注意事項
|
||||
- OpenAI Traces ダッシュボードで無料のトレースを表示できます。
|
||||
|
||||
|
||||
## エコシステム統合
|
||||
|
||||
次のコミュニティおよびベンダー統合は、OpenAI Agents SDK のトレーシングインターフェイスをサポートしています。
|
||||
|
||||
### 外部トレーシングプロセッサー一覧
|
||||
|
||||
- [Weights & Biases](https://weave-docs.wandb.ai/guides/integrations/openai_agents)
|
||||
- [Arize-Phoenix](https://docs.arize.com/phoenix/tracing/integrations-tracing/openai-agents-sdk)
|
||||
- [Future AGI](https://docs.futureagi.com/future-agi/products/observability/auto-instrumentation/openai_agents)
|
||||
- [MLflow (セルフホスト/OSS)](https://mlflow.org/docs/latest/tracing/integrations/openai-agent)
|
||||
- [MLflow (Databricks ホスト)](https://docs.databricks.com/aws/en/mlflow/mlflow-tracing#-automatic-tracing)
|
||||
- [Braintrust](https://braintrust.dev/docs/guides/traces/integrations#openai-agents-sdk)
|
||||
- [Pydantic Logfire](https://logfire.pydantic.dev/docs/integrations/llms/openai/#openai-agents)
|
||||
- [AgentOps](https://docs.agentops.ai/v1/integrations/agentssdk)
|
||||
- [Scorecard](https://docs.scorecard.io/docs/documentation/features/tracing#openai-agents-sdk-integration)
|
||||
- [Respan](https://respan.ai/docs/integrations/tracing/openai-agents-sdk)
|
||||
- [LangSmith](https://docs.smith.langchain.com/observability/how_to_guides/trace_with_openai_agents_sdk)
|
||||
- [Maxim AI](https://www.getmaxim.ai/docs/observe/integrations/openai-agents-sdk)
|
||||
- [Comet Opik](https://www.comet.com/docs/opik/tracing/integrations/openai_agents)
|
||||
- [Langfuse](https://langfuse.com/docs/integrations/openaiagentssdk/openai-agents)
|
||||
- [Langtrace](https://docs.langtrace.ai/supported-integrations/llm-frameworks/openai-agents-sdk)
|
||||
- [Okahu-Monocle](https://github.com/monocle2ai/monocle)
|
||||
- [Galileo](https://v2docs.galileo.ai/integrations/openai-agent-integration#openai-agent-integration)
|
||||
- [Portkey AI](https://portkey.ai/docs/integrations/agents/openai-agents)
|
||||
- [LangDB AI](https://docs.langdb.ai/getting-started/working-with-agent-frameworks/working-with-openai-agents-sdk)
|
||||
- [Agenta](https://docs.agenta.ai/observability/integrations/openai-agents)
|
||||
- [PostHog](https://posthog.com/docs/llm-analytics/installation/openai-agents)
|
||||
- [Traccia](https://traccia.ai/docs/integrations/openai-agents)
|
||||
- [PromptLayer](https://docs.promptlayer.com/languages/integrations#openai-agents-sdk)
|
||||
- [HoneyHive](https://docs.honeyhive.ai/v2/integrations/openai-agents)
|
||||
- [Asqav](https://www.asqav.com/docs/integrations#openai-agents)
|
||||
- [Datadog](https://docs.datadoghq.com/llm_observability/instrumentation/auto_instrumentation/?tab=python#openai-agents)
|
||||
- [Latitude](https://docs.latitude.so/telemetry/frameworks/openai-agents)
|
||||
- [DProvenanceKit](https://dprovenance.dev/openai-agents/)
|
||||
@@ -0,0 +1,90 @@
|
||||
---
|
||||
search:
|
||||
exclude: true
|
||||
---
|
||||
# 使用量
|
||||
|
||||
Agents SDK は、すべての実行についてトークン使用量を自動的に追跡します。使用量には実行コンテキストからアクセスでき、コストの監視、制限の適用、分析の記録に利用できます。
|
||||
|
||||
## 追跡対象
|
||||
|
||||
- **requests**: 実行された LLM API 呼び出しの数
|
||||
- **input_tokens**: 送信された入力トークンの合計
|
||||
- **output_tokens**: 受信された出力トークンの合計
|
||||
- **total_tokens**: 入力 + 出力
|
||||
- **request_usage_entries**: リクエストごとの使用量内訳のリスト
|
||||
- **details**:
|
||||
- `input_tokens_details.cached_tokens`
|
||||
- `output_tokens_details.reasoning_tokens`
|
||||
|
||||
## 実行からの使用量へのアクセス
|
||||
|
||||
`Runner.run(...)` の後、使用量には `result.context_wrapper.usage` 経由でアクセスします。
|
||||
|
||||
```python
|
||||
result = await Runner.run(agent, "What's the weather in Tokyo?")
|
||||
usage = result.context_wrapper.usage
|
||||
|
||||
print("Requests:", usage.requests)
|
||||
print("Input tokens:", usage.input_tokens)
|
||||
print("Output tokens:", usage.output_tokens)
|
||||
print("Total tokens:", usage.total_tokens)
|
||||
```
|
||||
|
||||
使用量は、この実行中のすべてのモデル呼び出し(ツール呼び出しやハンドオフを含む)にわたって集計されます。
|
||||
|
||||
### サードパーティ製アダプターでの使用量の有効化
|
||||
|
||||
使用量のレポートは、サードパーティ製アダプターやプロバイダーバックエンドによって異なります。アダプター経由のモデルに依存しており、正確な `result.context_wrapper.usage` の値が必要な場合は:
|
||||
|
||||
- `AnyLLMModel` では、上流プロバイダーが使用量を返す場合、使用量は自動的に伝播されます。ストリーミングされた Chat Completions バックエンドでは、使用量チャンクが出力される前に `ModelSettings(include_usage=True)` が必要になる場合があります。
|
||||
- `LitellmModel` では、一部のプロバイダーバックエンドはデフォルトで使用量を報告しないため、`ModelSettings(include_usage=True)` が必要になることがよくあります。
|
||||
|
||||
Models ガイドの [サードパーティ製アダプター](models/index.md#third-party-adapters) セクションにあるアダプター固有の注記を確認し、デプロイ予定の正確なプロバイダーバックエンドを検証してください。
|
||||
|
||||
## リクエストごとの使用量追跡
|
||||
|
||||
SDK は、各 API リクエストの使用量を `request_usage_entries` で自動的に追跡します。これは、詳細なコスト計算やコンテキストウィンドウ消費量の監視に役立ちます。
|
||||
|
||||
```python
|
||||
result = await Runner.run(agent, "What's the weather in Tokyo?")
|
||||
|
||||
for i, request in enumerate(result.context_wrapper.usage.request_usage_entries):
|
||||
print(f"Request {i + 1}: {request.input_tokens} in, {request.output_tokens} out")
|
||||
```
|
||||
|
||||
## セッションでの使用量へのアクセス
|
||||
|
||||
`Session`(例: `SQLiteSession`)を使用する場合、`Runner.run(...)` の各呼び出しは、その特定の実行の使用量を返します。セッションはコンテキスト用に会話履歴を保持しますが、各実行の使用量は独立しています。
|
||||
|
||||
```python
|
||||
session = SQLiteSession("my_conversation")
|
||||
|
||||
first = await Runner.run(agent, "Hi!", session=session)
|
||||
print(first.context_wrapper.usage.total_tokens) # Usage for first run
|
||||
|
||||
second = await Runner.run(agent, "Can you elaborate?", session=session)
|
||||
print(second.context_wrapper.usage.total_tokens) # Usage for second run
|
||||
```
|
||||
|
||||
セッションは実行間の会話コンテキストを保持しますが、各 `Runner.run()` 呼び出しから返される使用量メトリクスは、その特定の実行のみを表します。セッションでは、以前のメッセージが各実行に入力として再投入される場合があり、これにより以降のターンにおける入力トークン数に影響します。
|
||||
|
||||
## フックでの使用量の利用
|
||||
|
||||
`RunHooks` を使用している場合、各フックに渡される `context` オブジェクトには `usage` が含まれます。これにより、主要なライフサイクルのタイミングで使用量をログ記録できます。
|
||||
|
||||
```python
|
||||
class MyHooks(RunHooks):
|
||||
async def on_agent_end(self, context: RunContextWrapper, agent: Agent, output: Any) -> None:
|
||||
u = context.usage
|
||||
print(f"{agent.name} → {u.requests} requests, {u.total_tokens} total tokens")
|
||||
```
|
||||
|
||||
## API リファレンス
|
||||
|
||||
詳細な API ドキュメントについては、以下を参照してください:
|
||||
|
||||
- [`Usage`][agents.usage.Usage] - 使用量追跡データ構造
|
||||
- [`RequestUsage`][agents.usage.RequestUsage] - リクエストごとの使用量詳細
|
||||
- [`RunContextWrapper`][agents.run.RunContextWrapper] - 実行コンテキストからの使用量へのアクセス
|
||||
- [`RunHooks`][agents.run.RunHooks] - 使用量追跡ライフサイクルへのフック
|
||||
@@ -0,0 +1,107 @@
|
||||
---
|
||||
search:
|
||||
exclude: true
|
||||
---
|
||||
# エージェントの可視化
|
||||
|
||||
エージェントの可視化では、 **Graphviz** を使用してエージェントとその関係を構造化されたグラフィカルな表現として生成できます。これは、アプリケーション内でエージェント、ツール、ハンドオフがどのように相互作用するかを理解するのに役立ちます。
|
||||
|
||||
## インストール
|
||||
|
||||
オプションの `viz` 依存関係グループをインストールします:
|
||||
|
||||
```bash
|
||||
pip install "openai-agents[viz]"
|
||||
```
|
||||
|
||||
## グラフの生成
|
||||
|
||||
`draw_graph` 関数を使用して、エージェントの可視化を生成できます。この関数は、次のように表現される有向グラフを作成します。
|
||||
|
||||
- **エージェント** は黄色のボックスとして表されます。
|
||||
- **MCP サーバー** は灰色のボックスとして表されます。
|
||||
- **ツール** は緑色の楕円として表されます。
|
||||
- **ハンドオフ** は、あるエージェントから別のエージェントへの有向エッジです。
|
||||
|
||||
### 使用例
|
||||
|
||||
```python
|
||||
import os
|
||||
|
||||
from agents import Agent, function_tool
|
||||
from agents.mcp.server import MCPServerStdio
|
||||
from agents.extensions.visualization import draw_graph
|
||||
|
||||
@function_tool
|
||||
def get_weather(city: str) -> str:
|
||||
return f"The weather in {city} is sunny."
|
||||
|
||||
spanish_agent = Agent(
|
||||
name="Spanish agent",
|
||||
instructions="You only speak Spanish.",
|
||||
)
|
||||
|
||||
english_agent = Agent(
|
||||
name="English agent",
|
||||
instructions="You only speak English",
|
||||
)
|
||||
|
||||
current_dir = os.path.dirname(os.path.abspath(__file__))
|
||||
samples_dir = os.path.join(current_dir, "sample_files")
|
||||
mcp_server = MCPServerStdio(
|
||||
name="Filesystem Server, via npx",
|
||||
params={
|
||||
"command": "npx",
|
||||
"args": ["-y", "@modelcontextprotocol/server-filesystem", samples_dir],
|
||||
},
|
||||
)
|
||||
|
||||
triage_agent = Agent(
|
||||
name="Triage agent",
|
||||
instructions="Handoff to the appropriate agent based on the language of the request.",
|
||||
handoffs=[spanish_agent, english_agent],
|
||||
tools=[get_weather],
|
||||
mcp_servers=[mcp_server],
|
||||
)
|
||||
|
||||
draw_graph(triage_agent)
|
||||
```
|
||||
|
||||

|
||||
|
||||
これにより、 **トリアージエージェント** の構造と、サブエージェントおよびツールへの接続を視覚的に表すグラフが生成されます。
|
||||
|
||||
|
||||
## 可視化の理解
|
||||
|
||||
生成されたグラフには次のものが含まれます。
|
||||
|
||||
- エントリーポイントを示す **開始ノード** ( `__start__` )。
|
||||
- 黄色で塗りつぶされた **長方形** として表されるエージェント。
|
||||
- 緑色で塗りつぶされた **楕円** として表されるツール。
|
||||
- 灰色で塗りつぶされた **長方形** として表される MCP サーバー。
|
||||
- 相互作用を示す有向エッジ:
|
||||
- エージェント間ハンドオフを示す **実線の矢印** 。
|
||||
- ツール呼び出しを示す **点線の矢印** 。
|
||||
- MCP サーバー呼び出しを示す **破線の矢印** 。
|
||||
- 実行が終了する場所を示す **終了ノード** ( `__end__` )。
|
||||
|
||||
**注:** MCP サーバーは、最近のバージョンの `agents` パッケージで描画されます( **v0.2.8** で確認済み)。可視化で MCP ボックスが表示されない場合は、最新リリースにアップグレードしてください。
|
||||
|
||||
## グラフのカスタマイズ
|
||||
|
||||
### グラフの表示
|
||||
デフォルトでは、 `draw_graph` はグラフをインラインで表示します。グラフを別ウィンドウで表示するには、次のように記述します:
|
||||
|
||||
```python
|
||||
draw_graph(triage_agent).view()
|
||||
```
|
||||
|
||||
### グラフの保存
|
||||
デフォルトでは、 `draw_graph` はグラフをインラインで表示します。ファイルとして保存するには、ファイル名を指定します:
|
||||
|
||||
```python
|
||||
draw_graph(triage_agent, filename="agent_graph")
|
||||
```
|
||||
|
||||
これにより、作業ディレクトリに `agent_graph.png` が生成されます。
|
||||
@@ -0,0 +1,81 @@
|
||||
---
|
||||
search:
|
||||
exclude: true
|
||||
---
|
||||
# パイプラインとワークフロー
|
||||
|
||||
[`VoicePipeline`][agents.voice.pipeline.VoicePipeline] は、エージェント型ワークフローを音声アプリに変換しやすくするクラスです。実行するワークフローを渡すと、パイプラインが入力音声の文字起こし、音声の終了検出、適切なタイミングでのワークフロー呼び出し、ワークフロー出力の音声への変換を処理します。
|
||||
|
||||
```mermaid
|
||||
graph LR
|
||||
%% Input
|
||||
A["🎤 Audio Input"]
|
||||
|
||||
%% Voice Pipeline
|
||||
subgraph Voice_Pipeline [Voice Pipeline]
|
||||
direction TB
|
||||
B["Transcribe (speech-to-text)"]
|
||||
C["Your Code"]:::highlight
|
||||
D["Text-to-speech"]
|
||||
B --> C --> D
|
||||
end
|
||||
|
||||
%% Output
|
||||
E["🎧 Audio Output"]
|
||||
|
||||
%% Flow
|
||||
A --> Voice_Pipeline
|
||||
Voice_Pipeline --> E
|
||||
|
||||
%% Custom styling
|
||||
classDef highlight fill:#ffcc66,stroke:#333,stroke-width:1px,font-weight:700;
|
||||
|
||||
```
|
||||
|
||||
## パイプラインの設定
|
||||
|
||||
パイプラインを作成するときに、いくつかの項目を設定できます。
|
||||
|
||||
1. [`workflow`][agents.voice.workflow.VoiceWorkflowBase]。新しい音声が文字起こしされるたびに実行されるコードです。
|
||||
2. 使用される [`speech-to-text`][agents.voice.model.STTModel] モデルと [`text-to-speech`][agents.voice.model.TTSModel] モデル
|
||||
3. [`config`][agents.voice.pipeline_config.VoicePipelineConfig]。次のような項目を設定できます。
|
||||
- モデル名をモデルにマッピングできるモデルプロバイダー
|
||||
- トレーシング。トレーシングを無効にするか、音声ファイルをアップロードするか、ワークフロー名、トレース ID などを含みます。
|
||||
- TTS モデルと STT モデルの設定。プロンプト、言語、使用するデータ型などです。
|
||||
|
||||
## パイプラインの実行
|
||||
|
||||
[`run()`][agents.voice.pipeline.VoicePipeline.run] メソッドを通じてパイプラインを実行できます。このメソッドでは、音声入力を 2 つの形式で渡せます。
|
||||
|
||||
1. [`AudioInput`][agents.voice.input.AudioInput] は、完全な音声入力があり、それに対する実行結果だけを生成したい場合に使用します。これは、話者が話し終えたタイミングを検出する必要がない場合に便利です。たとえば、事前に録音された音声がある場合や、ユーザーが話し終えたことが明確なプッシュ・トゥ・トークアプリの場合です。
|
||||
2. [`StreamedAudioInput`][agents.voice.input.StreamedAudioInput] は、ユーザーが話し終えたタイミングを検出する必要がある場合に使用します。検出された音声チャンクをプッシュでき、音声パイプラインは「アクティビティ検出」と呼ばれるプロセスを通じて、適切なタイミングでエージェントワークフローを自動的に実行します。
|
||||
|
||||
## 実行結果
|
||||
|
||||
音声パイプライン実行の実行結果は [`StreamedAudioResult`][agents.voice.result.StreamedAudioResult] です。これは、イベントが発生したときにストリーミングできるオブジェクトです。[`VoiceStreamEvent`][agents.voice.events.VoiceStreamEvent] には、次のような種類があります。
|
||||
|
||||
1. [`VoiceStreamEventAudio`][agents.voice.events.VoiceStreamEventAudio]。音声チャンクを含みます。
|
||||
2. [`VoiceStreamEventLifecycle`][agents.voice.events.VoiceStreamEventLifecycle]。ターンの開始や終了などのライフサイクルイベントを通知します。
|
||||
3. [`VoiceStreamEventError`][agents.voice.events.VoiceStreamEventError]。エラーイベントです。
|
||||
|
||||
```python
|
||||
|
||||
result = await pipeline.run(input)
|
||||
|
||||
async for event in result.stream():
|
||||
if event.type == "voice_stream_event_audio":
|
||||
# play audio
|
||||
pass
|
||||
elif event.type == "voice_stream_event_lifecycle":
|
||||
# lifecycle
|
||||
pass
|
||||
elif event.type == "voice_stream_event_error":
|
||||
# error
|
||||
pass
|
||||
```
|
||||
|
||||
## ベストプラクティス
|
||||
|
||||
### 割り込み
|
||||
|
||||
Agents SDK は現在、[`StreamedAudioInput`][agents.voice.input.StreamedAudioInput] 向けの組み込みの割り込み処理を提供していません。代わりに、検出された各ターンがワークフローの個別の実行をトリガーします。アプリケーション内で割り込みを処理したい場合は、[`VoiceStreamEventLifecycle`][agents.voice.events.VoiceStreamEventLifecycle] イベントをリッスンできます。`turn_started` は、新しいターンが文字起こしされ、処理が開始されることを示します。`turn_ended` は、対応するターンのすべての音声が送出された後にトリガーされます。これらのイベントを使用して、モデルがターンを開始したときに話者のマイクをミュートし、そのターンに関連するすべての音声をフラッシュした後にミュートを解除できます。
|
||||
@@ -0,0 +1,198 @@
|
||||
---
|
||||
search:
|
||||
exclude: true
|
||||
---
|
||||
# クイックスタート
|
||||
|
||||
## 前提条件
|
||||
|
||||
Agents SDK の基本的な[クイックスタート手順](../quickstart.md)に従い、仮想環境をセットアップしていることを確認してください。次に、SDK のオプションの音声依存パッケージをインストールします。
|
||||
|
||||
```bash
|
||||
pip install 'openai-agents[voice]'
|
||||
```
|
||||
|
||||
## 基本概念
|
||||
|
||||
知っておくべき主要な概念は、3 ステップのプロセスである [`VoicePipeline`][agents.voice.pipeline.VoicePipeline] です。
|
||||
|
||||
1. 音声テキスト変換モデルを実行し、音声をテキストに変換します。
|
||||
2. 通常はエージェント型ワークフローであるコードを実行し、結果を生成します。
|
||||
3. テキスト音声変換モデルを実行し、結果のテキストを音声に戻します。
|
||||
|
||||
```mermaid
|
||||
graph LR
|
||||
%% Input
|
||||
A["🎤 Audio Input"]
|
||||
|
||||
%% Voice Pipeline
|
||||
subgraph Voice_Pipeline [Voice Pipeline]
|
||||
direction TB
|
||||
B["Transcribe (speech-to-text)"]
|
||||
C["Your Code"]:::highlight
|
||||
D["Text-to-speech"]
|
||||
B --> C --> D
|
||||
end
|
||||
|
||||
%% Output
|
||||
E["🎧 Audio Output"]
|
||||
|
||||
%% Flow
|
||||
A --> Voice_Pipeline
|
||||
Voice_Pipeline --> E
|
||||
|
||||
%% Custom styling
|
||||
classDef highlight fill:#ffcc66,stroke:#333,stroke-width:1px,font-weight:700;
|
||||
|
||||
```
|
||||
|
||||
## エージェント
|
||||
|
||||
まず、いくつかのエージェントをセットアップします。この SDK でエージェントを構築した経験があれば、馴染みのある作業でしょう。ここでは、2 つのエージェント、1 つのハンドオフ、1 つのツールを用意します。
|
||||
|
||||
```python
|
||||
import asyncio
|
||||
import random
|
||||
|
||||
from agents import (
|
||||
Agent,
|
||||
function_tool,
|
||||
)
|
||||
from agents.extensions.handoff_prompt import prompt_with_handoff_instructions
|
||||
|
||||
|
||||
|
||||
@function_tool
|
||||
def get_weather(city: str) -> str:
|
||||
"""Get the weather for a given city."""
|
||||
print(f"[debug] get_weather called with city: {city}")
|
||||
choices = ["sunny", "cloudy", "rainy", "snowy"]
|
||||
return f"The weather in {city} is {random.choice(choices)}."
|
||||
|
||||
|
||||
spanish_agent = Agent(
|
||||
name="Spanish",
|
||||
handoff_description="A Spanish-speaking agent.",
|
||||
instructions=prompt_with_handoff_instructions(
|
||||
"You're speaking to a human, so be polite and concise. Speak in Spanish.",
|
||||
),
|
||||
model="gpt-5.6-sol",
|
||||
)
|
||||
|
||||
agent = Agent(
|
||||
name="Assistant",
|
||||
instructions=prompt_with_handoff_instructions(
|
||||
"You're speaking to a human, so be polite and concise. If the user speaks in Spanish, hand off to the Spanish agent.",
|
||||
),
|
||||
model="gpt-5.6-sol",
|
||||
handoffs=[spanish_agent],
|
||||
tools=[get_weather],
|
||||
)
|
||||
```
|
||||
|
||||
## 音声パイプライン
|
||||
|
||||
ワークフローとして [`SingleAgentVoiceWorkflow`][agents.voice.workflow.SingleAgentVoiceWorkflow] を使用し、シンプルな音声パイプラインをセットアップします。
|
||||
|
||||
```python
|
||||
from agents.voice import SingleAgentVoiceWorkflow, VoicePipeline
|
||||
pipeline = VoicePipeline(workflow=SingleAgentVoiceWorkflow(agent))
|
||||
```
|
||||
|
||||
## パイプラインの実行
|
||||
|
||||
```python
|
||||
import numpy as np
|
||||
import sounddevice as sd
|
||||
from agents.voice import AudioInput
|
||||
|
||||
# For simplicity, we'll just create 3 seconds of silence
|
||||
# In reality, you'd get microphone data
|
||||
buffer = np.zeros(24000 * 3, dtype=np.int16)
|
||||
audio_input = AudioInput(buffer=buffer)
|
||||
|
||||
result = await pipeline.run(audio_input)
|
||||
|
||||
# Create an audio player using `sounddevice`
|
||||
player = sd.OutputStream(samplerate=24000, channels=1, dtype=np.int16)
|
||||
player.start()
|
||||
|
||||
# Play the audio stream as it comes in
|
||||
async for event in result.stream():
|
||||
if event.type == "voice_stream_event_audio":
|
||||
player.write(event.data)
|
||||
|
||||
```
|
||||
|
||||
## 全体の統合
|
||||
|
||||
```python
|
||||
import asyncio
|
||||
import random
|
||||
|
||||
import numpy as np
|
||||
import sounddevice as sd
|
||||
|
||||
from agents import (
|
||||
Agent,
|
||||
function_tool,
|
||||
set_tracing_disabled,
|
||||
)
|
||||
from agents.voice import (
|
||||
AudioInput,
|
||||
SingleAgentVoiceWorkflow,
|
||||
VoicePipeline,
|
||||
)
|
||||
from agents.extensions.handoff_prompt import prompt_with_handoff_instructions
|
||||
|
||||
|
||||
@function_tool
|
||||
def get_weather(city: str) -> str:
|
||||
"""Get the weather for a given city."""
|
||||
print(f"[debug] get_weather called with city: {city}")
|
||||
choices = ["sunny", "cloudy", "rainy", "snowy"]
|
||||
return f"The weather in {city} is {random.choice(choices)}."
|
||||
|
||||
|
||||
spanish_agent = Agent(
|
||||
name="Spanish",
|
||||
handoff_description="A Spanish-speaking agent.",
|
||||
instructions=prompt_with_handoff_instructions(
|
||||
"You're speaking to a human, so be polite and concise. Speak in Spanish.",
|
||||
),
|
||||
model="gpt-5.6-sol",
|
||||
)
|
||||
|
||||
agent = Agent(
|
||||
name="Assistant",
|
||||
instructions=prompt_with_handoff_instructions(
|
||||
"You're speaking to a human, so be polite and concise. If the user speaks in Spanish, hand off to the Spanish agent.",
|
||||
),
|
||||
model="gpt-5.6-sol",
|
||||
handoffs=[spanish_agent],
|
||||
tools=[get_weather],
|
||||
)
|
||||
|
||||
|
||||
async def main():
|
||||
pipeline = VoicePipeline(workflow=SingleAgentVoiceWorkflow(agent))
|
||||
buffer = np.zeros(24000 * 3, dtype=np.int16)
|
||||
audio_input = AudioInput(buffer=buffer)
|
||||
|
||||
result = await pipeline.run(audio_input)
|
||||
|
||||
# Create an audio player using `sounddevice`
|
||||
player = sd.OutputStream(samplerate=24000, channels=1, dtype=np.int16)
|
||||
player.start()
|
||||
|
||||
# Play the audio stream as it comes in
|
||||
async for event in result.stream():
|
||||
if event.type == "voice_stream_event_audio":
|
||||
player.write(event.data)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
asyncio.run(main())
|
||||
```
|
||||
|
||||
この例を実行すると、エージェントが話しかけてきます!自分でエージェントに話しかけられるデモについては、[examples/voice/static](https://github.com/openai/openai-agents-python/tree/main/examples/voice/static) の例をご覧ください。
|
||||
@@ -0,0 +1,18 @@
|
||||
---
|
||||
search:
|
||||
exclude: true
|
||||
---
|
||||
# トレーシング
|
||||
|
||||
[エージェントのトレーシング](../tracing.md)と同様に、音声パイプラインも自動的にトレーシングされます。
|
||||
|
||||
基本的なトレーシング情報については上記のトレーシングドキュメントを参照できますが、さらに [`VoicePipelineConfig`][agents.voice.pipeline_config.VoicePipelineConfig] を通じてパイプラインのトレーシングを設定できます。
|
||||
|
||||
トレーシングに関連する主なフィールドは次のとおりです。
|
||||
|
||||
- [`tracing_disabled`][agents.voice.pipeline_config.VoicePipelineConfig.tracing_disabled]: トレーシングを無効にするかどうかを制御します。デフォルトでは、トレーシングは有効です。
|
||||
- [`trace_include_sensitive_data`][agents.voice.pipeline_config.VoicePipelineConfig.trace_include_sensitive_data]: トレースに音声文字起こしなど、潜在的に機微なデータを含めるかどうかを制御します。これは音声パイプライン専用であり、Workflow 内で行われる処理には適用されません。
|
||||
- [`trace_include_sensitive_audio_data`][agents.voice.pipeline_config.VoicePipelineConfig.trace_include_sensitive_audio_data]: トレースに音声データを含めるかどうかを制御します。
|
||||
- [`workflow_name`][agents.voice.pipeline_config.VoicePipelineConfig.workflow_name]: トレースワークフローの名前です。
|
||||
- [`group_id`][agents.voice.pipeline_config.VoicePipelineConfig.group_id]: トレースの `group_id` で、複数のトレースを関連付けることができます。
|
||||
- [`trace_metadata`][agents.voice.pipeline_config.VoicePipelineConfig.trace_metadata]: トレースに含める追加のメタデータです。
|
||||
Reference in New Issue
Block a user