エージェントの実行
エージェントはそれ自体では何もしません。Runner クラスまたは run() ユーティリティで 実行 します。
ターンの実行、イベントのストリーミング、会話状態の管理を行いたくなったら、エージェント の後にこのページを読んでください。エージェントをどのように定義するかをまだ検討している場合は、まず エージェント から始めてください。
import { Agent, run } from '@openai/agents';
const agent = new Agent({ name: 'Assistant', instructions: 'You are a helpful assistant',});
const result = await run( agent, 'Write a haiku about recursion in programming.',);console.log(result.finalOutput);
// Code within the code,// Functions calling themselves,// Infinite loop's dance.カスタム runner が不要な場合は、シングルトンのデフォルト Runner インスタンスを実行する run() ユーティリティも使用できます。
または、独自の Runner インスタンスを作成できます。
import { Agent, Runner } from '@openai/agents';
const agent = new Agent({ name: 'Assistant', instructions: 'You are a helpful assistant',});
// You can pass custom configuration to the runnerconst runner = new Runner();
const result = await runner.run( agent, 'Write a haiku about recursion in programming.',);console.log(result.finalOutput);
// Code within the code,// Functions calling themselves,// Infinite loop's dance.エージェントを実行すると、最終出力と実行の完全な履歴を含む エージェントの実行結果 オブジェクトを受け取ります。
Runner のライフサイクルと設定
Section titled “Runner のライフサイクルと設定”エージェントループ
Section titled “エージェントループ”Runner の run メソッドを使用するときは、開始エージェントと入力を渡します。入力は文字列(ユーザーメッセージとして扱われます)または入力項目のリストにできます。これらの項目は OpenAI Responses API の項目です。
runner は次のループを実行します。
- 現在の入力で現在のエージェントのモデルを呼び出します。
- LLM のレスポンスを調べます。
- 最終出力 → 返します。
- ハンドオフ → 新しいエージェントに切り替え、蓄積された会話履歴を維持し、1 に戻ります。
- ツール呼び出し → ツールを実行し、その実行結果を会話に追加し、1 に戻ります。
maxTurnsがnullでない限り、maxTurnsに達するとMaxTurnsExceededErrorをスローします。
Runner のライフサイクル
Section titled “Runner のライフサイクル”アプリの起動時に Runner を作成し、リクエスト間で再利用してください。このインスタンスは、モデルプロバイダーやトレーシングオプションなどのグローバル設定を保存します。完全に異なる設定が必要な場合にのみ、別の Runner を作成してください。シンプルなスクリプトでは、内部的にデフォルト runner を使用する run() を呼び出すこともできます。
run() メソッドには、実行を開始する初期エージェント、実行用の入力、一連のオプションを渡します。
入力は、文字列(ユーザーメッセージとして扱われます)、入力項目 のリスト、または 人間の介入(HITL) エージェントを構築している場合は RunState オブジェクトにできます。
追加オプションは次のとおりです。
| オプション | デフォルト | 説明 |
|---|---|---|
stream | false | true の場合、呼び出しは StreamedRunResult を返し、モデルから到着したイベントを順次発行します。 |
context | – | すべてのツール / ガードレール / ハンドオフに転送されるコンテキストオブジェクトです。詳細は コンテキスト管理 を参照してください。 |
maxTurns | 10 | 安全上の制限です。到達すると MaxTurnsExceededError をスローします。制限を無効にするには null を渡します。 |
signal | – | キャンセル用の AbortSignal です。 |
session | – | セッション永続化の実装です。セッション を参照してください。 |
sessionInputCallback | – | セッション履歴と新しい入力をマージするカスタムロジックです。モデル呼び出しの前に実行されます。セッション を参照してください。 |
callModelInputFilter | – | モデルを呼び出す直前にモデル入力(項目 + 任意の instructions)を編集するフックです。モデル入力フィルターの呼び出し を参照してください。 |
toolErrorFormatter | – | モデルへ返されるツール承認拒否メッセージをカスタマイズするフックです。ツールエラーフォーマッター を参照してください。 |
reasoningItemIdPolicy | – | 以前の実行項目がモデル入力に戻されるときに、reasoning item の id を保持するか省略するかを制御します。Reasoning item ID ポリシー を参照してください。 |
tracing | – | 実行単位のトレーシング設定の上書き(例: エクスポート用 API キー)です。 |
sandbox | – | SandboxAgent 実行用のサンドボックスクライアント、ライブセッション、セッション状態、スナップショット、マニフェスト上書き、または同時実行制限です。コンセプト を参照してください。 |
toolExecution | – | ローカルツール呼び出しの SDK 側実行設定です。一度に実行する関数ツールの数を制限するには toolExecution.maxFunctionToolConcurrency を使用します。 |
errorHandlers | – | サポートされているランタイムエラー(現在は maxTurns)のハンドラーです。エラーハンドラー を参照してください。 |
conversationId | – | サーバー側の会話を再利用します(OpenAI Responses API + Conversations API のみ)。 |
previousResponseId | – | 会話を作成せず、前回の Responses API 呼び出しから継続します(OpenAI Responses API のみ)。 |
ストリーミング
Section titled “ストリーミング”ストリーミングを使うと、LLM の実行中にストリーミングイベントも受け取れます。ストリームが開始されると、StreamedRunResult には、生成されたすべての新しい出力を含む実行に関する完全な情報が含まれます。for await ループを使用してストリーミングイベントを反復処理できます。詳細は ストリーミング を参照してください。
独自の Runner インスタンスを作成する場合、runner を設定するために RunConfig オブジェクトを渡せます。
| フィールド | 型 | 目的 |
|---|---|---|
model | string | Model | 実行内の すべて のエージェントに特定のモデルを強制します。 |
modelProvider | ModelProvider | モデル名を解決します。デフォルトは OpenAI プロバイダーです。 |
modelSettings | ModelSettings | エージェントごとの設定を上書きするグローバルな調整パラメーターです。オプトインの再試行設定を含む詳細は、モデル を参照してください。 |
handoffInputFilter | HandoffInputFilter | ハンドオフの実行時に入力項目を変更します(ハンドオフ自体でまだ定義されていない場合)。 |
inputGuardrails | InputGuardrail[] | 初期 ユーザー入力に適用されるガードレールです。 |
outputGuardrails | OutputGuardrail[] | 最終 出力に適用されるガードレールです。 |
tracingDisabled | boolean | OpenAI トレーシングを完全に無効化します。 |
traceIncludeSensitiveData | boolean | スパンは出力しつつ、LLM/ツールの入力と出力をトレースから除外します。 |
workflowName | string | トレースダッシュボードに表示され、関連する実行のグループ化に役立ちます。 |
traceId / groupId | string | SDK に生成させる代わりに、トレース ID またはグループ ID を手動で指定します。 |
traceMetadata | Record<string, string> | すべてのスパンに付与する任意のメタデータです。 |
tracing | TracingConfig | 実行単位のトレーシング上書き(例: エクスポート用 API キー)です。 |
sessionInputCallback | SessionInputCallback | この runner 上のすべての実行に対するデフォルトの履歴マージ戦略です。 |
callModelInputFilter | CallModelInputFilter | 各モデル呼び出しの前にモデル入力を編集するグローバルフックです。 |
toolErrorFormatter | ToolErrorFormatter | モデルへ返されるツール承認拒否メッセージをカスタマイズするグローバルフックです。 |
reasoningItemIdPolicy | ReasoningItemIdPolicy | 生成済み項目を後続のモデル呼び出しへ再生するときに、reasoning item の id を保持するか省略するかのデフォルトポリシーです。 |
sandbox | SandboxRunConfig | SandboxAgent 実行用のデフォルトサンドボックスランタイム設定です。 |
toolExecution | ToolExecutionConfig | ローカルツール呼び出しのデフォルトの SDK 側実行設定です。maxFunctionToolConcurrency は、各ターンでのローカル関数ツールの同時実行数に上限を設定します。未設定または null の場合、そのターンで出力されたすべての関数ツール呼び出しを開始します。 |
toolExecution.maxFunctionToolConcurrency は 1 以上の整数である必要があります。この設定は、ローカル関数ツールの SDK 側実行のみを制限します。プロバイダー側の modelSettings.parallelToolCalls は変更しません。
状態と会話管理
Section titled “状態と会話管理”メモリ戦略の選択
Section titled “メモリ戦略の選択”状態を次のターンに引き継ぐ一般的な方法は 4 つあります。
| 戦略 | 状態の保存場所 | 最適な用途 | 次のターンで渡すもの |
|---|---|---|---|
result.history | アプリのメモリ | 小規模なチャットループ、完全な手動制御、任意のプロバイダー | result.history |
session | ストレージ + SDK | 永続的なチャット状態、再開可能な実行、カスタムストア | 同じ session インスタンス(またはストアに裏付けられたもの) |
conversationId | OpenAI Conversations API | ワーカー/サービス間で共有するサーバー側状態 | 同じ conversationId と新しいユーザーターンのみ |
previousResponseId | OpenAI Responses API のみ | 会話を作成せずに、サーバー管理で最もシンプルに継続する場合 | result.lastResponseId と新しいユーザーターンのみ |
result.history と session はクライアント管理です。conversationId と previousResponseId は OpenAI 管理で、OpenAI Responses API を使用している場合にのみ適用されます。ほとんどのアプリケーションでは、会話ごとに永続化戦略を 1 つ選びます。クライアント管理の履歴とサーバー管理の状態を混在させると、両方の層を意図的に照合している場合を除き、コンテキストが重複する可能性があります。
サンドボックスエージェントには、ライブサンドボックスワークスペースという別の状態レイヤーが追加されます。会話履歴には通常の SDK session、conversationId、または previousResponseId を使用し、サンドボックスファイルシステムの状態には sandbox.session、sandbox.sessionState、RunState、またはスナップショットを使用します。ワークスペースのライフサイクルについては、コンセプト を参照してください。
会話 / チャットスレッド
Section titled “会話 / チャットスレッド”runner.run()(または run() ユーティリティ)を呼び出すたびに、アプリケーションレベルの会話における 1 つの ターン を表します。RunResult のどの範囲をエンドユーザーに表示するかは選択できます。finalOutput だけを表示する場合もあれば、生成されたすべての項目を表示する場合もあります。
import { Agent, run } from '@openai/agents';import type { AgentInputItem } from '@openai/agents';
let thread: AgentInputItem[] = [];
const agent = new Agent({ name: 'Assistant',});
async function userSays(text: string) { const result = await run( agent, thread.concat({ role: 'user', content: text }), );
thread = result.history; // Carry over history + newly generated items return result.finalOutput;}
await userSays('What city is the Golden Gate Bridge in?');// -> "San Francisco"
await userSays('What state is it in?');// -> "California"インタラクティブなバージョンについては、チャットのコード例 を参照してください。
サーバー管理の会話
Section titled “サーバー管理の会話”毎ターン、ローカルの会話履歴全体を送信する代わりに、OpenAI Responses API に会話履歴を永続化させることができます。これは、長い会話や複数のサービスを調整している場合に便利です。以下のどちらのサーバー管理方式でも、各リクエストでは新しいターンの入力のみを渡します。API が以前の状態を再利用します。詳細は Conversation state ガイド を参照してください。
OpenAI では、サーバー側状態を再利用する方法を 2 つ提供しています。
1. 会話全体のための conversationId
Section titled “1. 会話全体のための conversationId”Conversations API を使用して会話を一度作成し、その ID をすべてのターンで再利用できます。SDK は新しく生成された項目だけを自動的に含めます。
import { Agent, run } from '@openai/agents';import { OpenAI } from 'openai';
const agent = new Agent({ name: 'Assistant', instructions: 'Reply very concisely.',});
async function main() { // Create a server-managed conversation: const client = new OpenAI(); const { id: conversationId } = await client.conversations.create({});
const first = await run(agent, 'What city is the Golden Gate Bridge in?', { conversationId, }); console.log(first.finalOutput); // -> "San Francisco"
const second = await run(agent, 'What state is it in?', { conversationId }); console.log(second.finalOutput); // -> "California"}
main().catch(console.error);2. 前回のターンから継続するための previousResponseId
Section titled “2. 前回のターンから継続するための previousResponseId”そもそも Responses API のみで始めたい場合は、前回のレスポンスから返された ID を使用して各リクエストをチェーンできます。これにより、完全な会話リソースを作成せずに、ターン間でコンテキストを維持できます。
import { Agent, run } from '@openai/agents';
const agent = new Agent({ name: 'Assistant', instructions: 'Reply very concisely.',});
async function main() { const first = await run(agent, 'What city is the Golden Gate Bridge in?'); console.log(first.finalOutput); // -> "San Francisco"
const previousResponseId = first.lastResponseId; const second = await run(agent, 'What state is it in?', { previousResponseId, }); console.log(second.finalOutput); // -> "California"}
main().catch(console.error);conversationId と previousResponseId は同時に使用できません。システム間で共有できる名前付きの会話リソースが必要な場合は conversationId を使用し、1 つのレスポンスから次のレスポンスへ継続するための最も軽量な SDK レベルの基本コンポーネントだけが必要な場合は previousResponseId を使用します。
フックとカスタマイズ
Section titled “フックとカスタマイズ”モデル入力フィルターの呼び出し
Section titled “モデル入力フィルターの呼び出し”callModelInputFilter を使用すると、モデルが呼び出される 直前 にモデル入力を編集できます。このフックは、現在のエージェント、コンテキスト、結合された入力項目(存在する場合はセッション履歴を含む)を受け取ります。更新された input 配列と任意の instructions を返して、機密データの編集、古いメッセージの削除、追加のシステムガイダンスの注入を行います。
実行ごとに runner.run(..., { callModelInputFilter }) で設定するか、Runner 設定(RunConfig の callModelInputFilter)のデフォルトとして設定します。
戻り値は ModelInputData オブジェクト、つまり { input: AgentInputItem[], instructions? } である必要があります。input フィールドは必須で、配列でなければなりません。これ以外の形を返すと UserError がスローされます。
SDK は、フィルターを呼び出す前に準備済みのターン入力をクローンします。session も使用している場合、フィルター適用後のクローンが永続化されるため、ここで適用された編集や切り詰めは、保存されるセッション履歴にも反映されます。
conversationId または previousResponseId を使用する場合、このフックは次の Responses API 呼び出し用に準備されたペイロードに対して実行されます。以前のサーバー管理コンテキストは API によって復元されるため、その呼び出しのフィルター済み配列は、以前の履歴全体の再生ではなく、新しいターンの差分だけをすでに表している場合があります。この最終フィルターステップの前に、保存済み履歴と現在のターンのマージ方法を変更する必要がある場合は、sessionInputCallback を使用します。
ツールエラーフォーマッター
Section titled “ツールエラーフォーマッター”toolErrorFormatter を使用すると、ツール呼び出しが拒否されたときにモデルへ送り返される承認拒否メッセージをカスタマイズできます。これにより、SDK のデフォルトメッセージではなく、ドメイン固有の文言(例: コンプライアンスガイダンス)を返せます。
formatter は、実行ごと(runner.run(..., { toolErrorFormatter }))または RunConfig(new Runner(...) の toolErrorFormatter)でグローバルに設定できます。
この formatter は承認拒否に対するグローバルなフォールバックです。特定の中断を result.state.reject(interruption, { message: '...' }) で拒否した場合、その呼び出しごとの message が toolErrorFormatter より優先されます。どちらも指定されていない場合、SDK はデフォルトの拒否テキスト Tool execution was not approved. にフォールバックします。
formatter は現在、approval_rejected イベントで実行され、次を受け取ります。
kind(現在は常に'approval_rejected')toolType('function'、'computer'、'shell'、または'apply_patch')toolNamecallIddefaultMessage(SDK のフォールバックメッセージ。現在はTool execution was not approved.)runContext
メッセージを上書きするには文字列を返し、SDK のデフォルトを維持するには undefined を返します。formatter がスローした場合(または文字列以外の値を返した場合)、SDK は警告をログに記録し、デフォルトの承認拒否メッセージにフォールバックします。
Reasoning item ID ポリシー
Section titled “Reasoning item ID ポリシー”reasoningItemIdPolicy を使用すると、SDK が以前に生成された実行項目を後続のモデル入力用に AgentInputItem[] へ戻すときに、reasoning item の id フィールドを保持するかどうかを制御できます。
これは、SDK が生成済みモデル項目を入力として再生する場所に影響します。たとえば次のような場合です。
- 同じ実行内のフォローアップモデル呼び出し(例: ツール実行後)
- 生成済み項目を入力/履歴として再利用する後続ターン
- 保存済み
RunStateから再開された実行 result.history/result.outputのような派生の実行結果ビュー(モデル入力の形をした配列)'preserve'(デフォルト)は reasoning item ID を保持します。'omit'は reasoning item が入力として送り返される前にidフィールドを削除します。- reasoning 以外の項目は影響を受けません。
これによって 変更されない もの:
- 元のモデルレスポンス(
result.rawResponses) - 実行項目(
result.newItems) - プロバイダーから返されるモデルの現在ターンの出力
言い換えると、このポリシーは SDK が以前に生成された項目から 次の入力 を構築するときに適用されます。
ポリシーは、実行ごと(runner.run(..., { reasoningItemIdPolicy: 'omit' }))または runner のデフォルト(new Runner({ reasoningItemIdPolicy: 'omit', ... }))として設定できます。保存済み RunState から再開する場合、上書きしない限り、以前に解決されたポリシーが再利用されます。
callModelInputFilter との相互作用
Section titled “callModelInputFilter との相互作用”reasoningItemIdPolicy は callModelInputFilter の前に適用されます。カスタム動作が必要な場合でも、callModelInputFilter は準備済み入力を検査し、モデル呼び出しの前に reasoning ID を手動で再導入または削除できます。
'omit' の使用タイミング
Section titled “'omit' の使用タイミング”再生される reasoning item を ID なしで正規化したい場合(例: 転送/再生されるモデル入力をよりシンプルに保つため、またはアプリのパイプラインにおける連携要件に合わせるため)は、'omit' を使用します。
また、バックエンド/プロバイダーが再生された reasoning item をリクエスト検証エラーで拒否する場合(例: フォローアップ入力内の reasoning item ID に関連する HTTP 400 エラー)にも、便利なトラブルシューティングオプションです。そのような場合、'omit' で再生された reasoning ID を削除すると、バックエンドが新しいリクエストでは無効と扱う ID の送信を避けられます。
SDK に再生入力を通して reasoning item ID を引き継がせたい場合、かつ連携先がそれを受け入れる場合は、'preserve' のままにしてください。
エラーと復旧
Section titled “エラーと復旧”エラーハンドラー
Section titled “エラーハンドラー”errorHandlers を使用すると、サポートされているランタイムエラーをスローする代わりに、最終出力へ変換できます。サポートされているキーは maxTurns と modelRefusal です。
errorHandlers.maxTurnsは最大ターン数エラーのみを処理します。errorHandlers.modelRefusalはModelRefusalErrorとして表面化したモデル拒否を処理します。errorHandlers.defaultは、サポートされている種類のフォールバックとして使用されます。- ハンドラーは
{ error, context, runData }を受け取り、{ finalOutput, includeInHistory? }を返せます。
SDK は、catch できる少数のエラーをスローします。
MaxTurnsExceededError–maxTurnsに達しました。ModelBehaviorError– モデルが無効な出力を生成しました(例: 不正な形式の JSON、不明なツール)。ModelRefusalError– モデルが要求された出力の生成を拒否しました。InputGuardrailTripwireTriggered/OutputGuardrailTripwireTriggered– ガードレール違反です。ToolInputGuardrailTripwireTriggered/ToolOutputGuardrailTripwireTriggered– ツールガードレール違反です。GuardrailExecutionError– ガードレールを完了できませんでした。ToolTimeoutError– 関数ツールがtimeoutMsを超過し、timeoutBehavior: 'raise_exception'を使用しました。ToolCallError– タイムアウト以外のエラーで関数ツールの実行に失敗しました。UserError– 設定またはユーザー入力に基づいてスローされる任意のエラーです。
すべて基本 AgentsError クラスを拡張しており、現在の実行状態にアクセスするための state プロパティを提供する場合があります。
以下は GuardrailExecutionError を処理するコード例です。入力ガードレールは最初のユーザー入力でしか実行されないため、この例では元の入力とコンテキストで実行を再開します。また、保存済み状態を再利用して、モデルを再度呼び出さずに出力ガードレールをリトライする方法も示しています。
import { Agent, GuardrailExecutionError, InputGuardrail, InputGuardrailTripwireTriggered, OutputGuardrail, OutputGuardrailTripwireTriggered, run,} from '@openai/agents';import { z } from 'zod';
// Shared guardrail agent to avoid re-creating it on every fallback run.const guardrailAgent = new Agent({ name: 'Guardrail check', instructions: 'Check if the user is asking you to do their math homework.', outputType: z.object({ isMathHomework: z.boolean(), reasoning: z.string(), }),});
async function main() { const input = 'Hello, can you help me solve for x: 2x + 3 = 11?'; const context = { customerId: '12345' };
// Input guardrail example
const unstableInputGuardrail: InputGuardrail = { name: 'Math Homework Guardrail (unstable)', execute: async () => { throw new Error('Something is wrong!'); }, };
const fallbackInputGuardrail: InputGuardrail = { name: 'Math Homework Guardrail (fallback)', execute: async ({ input, context }) => { const result = await run(guardrailAgent, input, { context }); const isMathHomework = result.finalOutput?.isMathHomework ?? /solve for x|math homework/i.test(JSON.stringify(input)); return { outputInfo: result.finalOutput, tripwireTriggered: isMathHomework, }; }, };
const agent = new Agent({ name: 'Customer support agent', instructions: 'You are a customer support agent. You help customers with their questions.', inputGuardrails: [unstableInputGuardrail], });
try { // Input guardrails only run on the first turn of a run, so retries must start a fresh run. await run(agent, input, { context }); } catch (e) { if (e instanceof GuardrailExecutionError) { console.error(`Guardrail execution failed (input): ${e}`); try { agent.inputGuardrails = [fallbackInputGuardrail]; // Retry from scratch with the original input and context. await run(agent, input, { context }); } catch (ee) { if (ee instanceof InputGuardrailTripwireTriggered) { console.log('Math homework input guardrail tripped on retry'); } else { throw ee; } } } else { throw e; } }
// Output guardrail example
const replyOutputSchema = z.object({ reply: z.string() });
const unstableOutputGuardrail: OutputGuardrail<typeof replyOutputSchema> = { name: 'Answer review (unstable)', execute: async () => { throw new Error('Output guardrail crashed.'); }, };
const fallbackOutputGuardrail: OutputGuardrail<typeof replyOutputSchema> = { name: 'Answer review (fallback)', execute: async ({ agentOutput }) => { const outputText = typeof agentOutput === 'string' ? agentOutput : (agentOutput?.reply ?? JSON.stringify(agentOutput)); const flagged = /math homework|solve for x|x =/i.test(outputText); return { outputInfo: { flaggedOutput: outputText }, tripwireTriggered: flagged, }; }, };
const agent2 = new Agent<unknown, typeof replyOutputSchema>({ name: 'Customer support agent (output check)', instructions: 'You are a customer support agent. Answer briefly.', outputType: replyOutputSchema, outputGuardrails: [unstableOutputGuardrail], });
try { await run(agent2, input, { context }); } catch (e) { if (e instanceof GuardrailExecutionError && e.state) { console.error(`Guardrail execution failed (output): ${e}`); try { agent2.outputGuardrails = [fallbackOutputGuardrail]; // Output guardrails can be retried using the saved state without another model call. await run(agent2, e.state); } catch (ee) { if (ee instanceof OutputGuardrailTripwireTriggered) { console.log('Output guardrail tripped after retry with saved state'); } else { throw ee; } } } else { throw e; } }}
main().catch(console.error);入力と出力のリトライ:
- 入力ガードレールは実行の最初のユーザー入力でしか実行されないため、同じ入力/コンテキストで新しい実行を開始してリトライする必要があります。保存済みの
stateを渡しても、入力ガードレールは再トリガーされません。 - 出力ガードレールはモデルレスポンスの後に実行されるため、
GuardrailExecutionErrorの保存済みstateを再利用して、別のモデル呼び出しなしで出力ガードレールを再実行できます。
上記の例を実行すると、次の出力が表示されます。
Guardrail execution failed (input): Error: Input guardrail failed to complete: Error: Something is wrong!Math homework input guardrail tripped on retryGuardrail execution failed (output): Error: Output guardrail failed to complete: Error: Output guardrail crashed.Output guardrail tripped after retry with saved state