エージェントの実行
エージェントはそれ自体では何もしません。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.エージェントを実行すると、実行の最終出力と完全な履歴を含む 実行結果 オブジェクトを受け取ります。
エージェントループ
Section titled “エージェントループ”Runner の run メソッドを使うときは、開始エージェントと入力を渡します。入力は文字列(ユーザーメッセージと見なされます)か、OpenAI Responses API のアイテムである入力アイテムのリストのいずれかです。
Runner は次のループを実行します。
- 現在の入力で現在のエージェントのモデルを呼び出す
- LLM の応答を検査する
- 最終出力 → 返す
- ハンドオフ → 新しいエージェントに切り替え、蓄積された会話履歴を保持し、1 に戻る
- ツール呼び出し → ツールを実行し、その結果を会話に追加し、1 に戻る
maxTurnsに達したらMaxTurnsExceededErrorをスローする
Runner ライフサイクル
Section titled “Runner ライフサイクル”アプリ起動時に Runner を作成し、リクエスト間で再利用します。このインスタンスは、モデルプロバイダやトレーシングオプションなどのグローバル設定を保持します。まったく異なる設定が必要な場合のみ、別の Runner を作成してください。簡単なスクリプトでは、デフォルト Runner を内部で使う run() を呼ぶこともできます。
run() メソッドへの入力は、実行を開始する初期エージェント、実行の入力、および一連のオプションです。
入力は、文字列(ユーザーメッセージと見なされます)、入力アイテム のリスト、または Human in the loop (人間の介入) エージェントを構築している場合の RunState オブジェクトのいずれかです。
追加オプションは次のとおりです。
| Option | Default | Description |
|---|---|---|
stream | false | true の場合、呼び出しは StreamedRunResult を返し、モデルから到着するイベントを順次発行します |
context | – | すべてのツール / ガードレール / ハンドオフに転送されるコンテキストオブジェクト。コンテキスト管理 を参照 |
maxTurns | 10 | セーフティリミット。到達時に MaxTurnsExceededError をスローします |
signal | – | キャンセル用の AbortSignal |
session | – | セッション永続化の実装。セッション を参照 |
sessionInputCallback | – | モデル呼び出し前に実行される、セッション履歴と新規入力のカスタムマージロジック。セッション を参照 |
callModelInputFilter | – | モデル呼び出し直前に、モデル入力(items + 任意の instructions)を編集するためのフック。Call model input filter を参照 |
toolErrorFormatter | – | モデルに返すツール承認拒否メッセージをカスタマイズするフック。Tool error formatter を参照 |
tracing | – | 実行ごとのトレーシング設定の上書き(例: エクスポート用 API キー) |
errorHandlers | – | サポートされるランタイムエラーのハンドラー(現在は maxTurns)。Error handlers を参照 |
conversationId | – | サーバー側の会話を再利用(OpenAI Responses API + Conversations API のみ) |
previousResponseId | – | 会話を作成せずに前回の Responses API 呼び出しから継続(OpenAI Responses API のみ) |
ストリーミング
Section titled “ストリーミング”ストリーミングを使うと、LLM の実行中にストリーミングイベントも受け取れます。ストリームが開始されると、StreamedRunResult には、新しく生成されたすべての出力を含む、実行に関する完全な情報が含まれます。for await ループを使ってストリーミングイベントを反復処理できます。詳しくは ストリーミング ガイドを参照してください。
独自の Runner インスタンスを作成する場合、RunConfig オブジェクトを渡して Runner を構成できます。
| Field | Type | Purpose |
|---|---|---|
model | string | Model | 実行中の すべての エージェントに特定のモデルを強制します |
modelProvider | ModelProvider | モデル名を解決します。デフォルトは OpenAI プロバイダです |
modelSettings | ModelSettings | エージェントごとの設定を上書きするグローバルなチューニングパラメーター |
handoffInputFilter | HandoffInputFilter | ハンドオフ時に入力アイテムを変更します(ハンドオフ自体で定義されていない場合) |
inputGuardrails | InputGuardrail[] | 最初のユーザー入力に適用されるガードレール |
outputGuardrails | OutputGuardrail[] | 最終出力に適用されるガードレール |
tracingDisabled | boolean | OpenAI トレーシングを完全に無効化 |
traceIncludeSensitiveData | boolean | スパンは出力しつつ、トレースから LLM/ツールの入出力を除外 |
workflowName | string | Traces ダッシュボードに表示。関連する実行をグルーピングするのに役立ちます |
traceId / groupId | string | SDK に生成させる代わりに、トレースまたはグループ ID を手動指定 |
traceMetadata | Record<string, string> | すべてのスパンに付与する任意のメタデータ |
tracing | TracingConfig | 実行ごとのトレーシング上書き(例: エクスポート用 API キー) |
sessionInputCallback | SessionInputCallback | この Runner 上のすべての実行に対するデフォルトの履歴マージ戦略 |
callModelInputFilter | CallModelInputFilter | 各モデル呼び出しの直前にモデル入力を編集するグローバルフック |
toolErrorFormatter | ToolErrorFormatter | モデルに返すツール承認拒否メッセージをカスタマイズするグローバルフック |
会話 / チャットスレッド
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 に会話履歴を保持させることで、毎ターンごとにローカルの全トランスクリプトを送信する代わりにできます。これは長い会話や複数サービスの調整に便利です。詳細は Conversation state guide を参照してください。
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);Call model input filter
Section titled “Call model input filter”callModelInputFilter を使って、モデルが呼び出される直前にモデル入力を編集します。このフックは現在のエージェント、コンテキスト、(セッション履歴がある場合はそれを含む)結合済みの入力アイテムを受け取ります。機密データのマスキング、古いメッセージのドロップ、追加のシステムガイダンスの注入のために、更新した input 配列と任意の instructions を返します。
runner.run(..., { callModelInputFilter }) で実行ごとに設定するか、Runner の設定(RunConfig の callModelInputFilter)としてデフォルトを設定します。
Tool error formatter
Section titled “Tool error formatter”toolErrorFormatter を使うと、ツール呼び出しが拒否された際にモデルへ返す承認拒否メッセージをカスタマイズできます。これにより、SDK のデフォルトメッセージではなく、(たとえばコンプライアンス指針のような)ドメイン固有の文言を返せます。
フォーマッタは実行ごと(runner.run(..., { toolErrorFormatter }))にも、RunConfig(new Runner(...) の toolErrorFormatter)でグローバルにも設定できます。
Error handlers
Section titled “Error handlers”errorHandlers を使うと、サポートされるランタイムエラーをスローする代わりに最終出力へ変換できます。現在は maxTurns のみサポートしています。
errorHandlers.maxTurnsは最大ターンのエラーのみを処理しますerrorHandlers.defaultはサポートされる種類のフォールバックとして使われます- ハンドラーは
{ error, context, runData }を受け取り、{ finalOutput, includeInHistory? }を返せます
SDK はキャッチ可能な少数のエラーをスローします。
MaxTurnsExceededError–maxTurnsに到達ModelBehaviorError– モデルが無効な出力を生成(例: 不正な JSON、未知のツール)InputGuardrailTripwireTriggered/OutputGuardrailTripwireTriggered– ガードレール違反GuardrailExecutionError– ガードレールの実行失敗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