エージェントの実行
エージェントはそれ自体では何もしません。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 | – | 以前の実行項目をモデル入力に戻すときに、推論アイテムの id を保持するか省略するかを制御します。推論アイテムの ID ポリシーを参照してください。 |
tracing | – | 実行ごとのトレーシング設定の上書きです。デフォルトのタスク/ターンスパン階層を省略するには、includeTaskAndTurnSpans: false を設定します。 |
sandbox | – | SandboxAgent の実行に使用するサンドボックスクライアント、ライブセッション、セッション状態、スナップショット、マニフェストの上書き、または同時実行数の上限です。コンセプトを参照してください。 |
toolExecution | – | ローカルツール呼び出しに対する SDK 側の実行設定です。同時に実行する関数ツールの数を制限するには toolExecution.maxFunctionToolConcurrency を使用し、承認待ちリクエストの前に関数ツールの入力ガードレールを実行するには toolExecution.preApprovalInputGuardrails を使用します。 |
toolNotFoundBehavior | 'raise_error' | モデルが生成した未解決の関数ツール呼び出しの処理を制御します。モデルから確認できるツールエラーを返して実行を継続するには、'return_error_to_model' を使用します。 |
toolNameCollisionPolicy | 'warn' | 有効な関数ツール名とハンドオフ名の衝突を制御します。警告を出して現在のディスパッチ先のみを公開する代わりに、モデルへのリクエスト前に失敗させるには 'error' を使用します。 |
errorHandlers | – | 対応しているランタイムエラーのハンドラーです。エラーハンドラーを参照してください。 |
conversationId | – | サーバー側の会話を再利用します(OpenAI Responses API と Conversations API のみ)。 |
previousResponseId | – | 会話を作成せずに、前回の Responses API 呼び出しから継続します(OpenAI Responses API のみ)。 |
ストリーミング
Section titled “ストリーミング”ストリーミングでは、LLM の実行中にイベントも公開されます。StreamedRunResult には、実行の進行に伴って情報が蓄積されます。実行結果の completed Promise が解決されると、その概要プロパティには新たに生成されたすべての出力が含まれます。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 | Traces ダッシュボードに表示され、関連する実行をグループ化するのに役立ちます。 |
traceId / groupId | string | SDK に生成させる代わりに、トレース ID またはグループ ID を手動で指定します。 |
traceMetadata | Record<string, string> | すべてのスパンに付加する任意のメタデータです。 |
tracing | TracingConfig | エクスポート用 API キーと includeTaskAndTurnSpans を含む、Runner レベルのデフォルトのトレーシング設定です。個々の実行オプションでこれらの値を上書きできます。 |
sessionInputCallback | SessionInputCallback | この Runner 上のすべての実行に使用する、デフォルトの履歴統合戦略です。 |
callModelInputFilter | CallModelInputFilter | 各モデル呼び出しの前にモデル入力を編集するグローバルフックです。 |
toolErrorFormatter | ToolErrorFormatter | モデルに返されるツールエラーメッセージをカスタマイズするグローバルフックです。 |
reasoningItemIdPolicy | ReasoningItemIdPolicy | 生成済み項目を後続のモデル呼び出しに再投入するときに、推論アイテムの id を保持または省略するデフォルトポリシーです。 |
sandbox | SandboxRunConfig | SandboxAgent の実行に使用するデフォルトのサンドボックスランタイム設定です。 |
toolExecution | ToolExecutionConfig | ローカルツール呼び出しに対するデフォルトの SDK 側実行設定です。maxFunctionToolConcurrency は各ターンにおけるローカル関数ツールの同時実行数を制限します。未設定または null の場合、そのターンで生成されたすべての関数ツール呼び出しが開始されます。preApprovalInputGuardrails を使用すると、承認待ちリクエストの前に関数ツールの入力ガードレールを実行できます。 |
toolNotFoundBehavior | ToolNotFoundBehavior | 未解決の関数ツール呼び出しに対するデフォルトの動作です。'raise_error' は ModelBehaviorError を発生させ、'return_error_to_model' はモデルから確認できるツールエラーを返して実行を継続します。 |
toolNameCollisionPolicy | ToolNameCollisionPolicy | 有効な関数ツール名とハンドオフ名に対するデフォルトの衝突ポリシーです。'warn' はログを記録して現在のディスパッチ先を公開し、'error' はモデルが呼び出される前に UserError を発生させます。 |
toolExecution.maxFunctionToolConcurrency には、1 以上の整数を指定する必要があります。この設定で制限されるのは、ローカル関数ツールの SDK 側での実行のみです。プロバイダー側の modelSettings.parallelToolCalls は変更されません。
toolExecution.preApprovalInputGuardrails はデフォルトで無効です。true に設定すると、承認が必要なローカル関数ツールについて、SDK が承認待ちの中断を記録する前に入力ガードレールが実行されます。ガードレールが rejectContent を返した場合、SDK は承認を求める代わりに、その拒否メッセージをツール出力として返します。ガードレールが呼び出しを許可した場合も承認リクエストは発生し、承認が解決された後、ツールの実行直前に同じ入力ガードレールが再度実行されます。
toolNameCollisionPolicy が制御するのは、有効な関数ツールとハンドオフの間の衝突のみです。名前空間付きツール、遅延ツール、重複するローカル MCP ツール名に対する既存の厳密な検証は変更されません。
状態と会話の管理
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 が以前の状態を再利用します。詳細は、会話状態ガイドを参照してください。
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 を使用し、あるレスポンスから次のレスポンスへ継続するための最小限の SDK レベルの基本コンポーネントだけが必要な場合は previousResponseId を使用してください。
フックとカスタマイズ
Section titled “フックとカスタマイズ”モデル入力フィルターの呼び出し
Section titled “モデル入力フィルターの呼び出し”モデルが呼び出される 直前 にモデル入力を編集するには、callModelInputFilter を使用します。このフックは、現在のエージェント、コンテキスト、および統合された入力項目(存在する場合はセッション履歴を含む)を受け取ります。更新した input 配列と任意の instructions を返すことで、機密データの編集、古いメッセージの削除、または追加のシステムガイダンスの挿入ができます。
実行ごとに runner.run(..., { callModelInputFilter }) で設定するか、Runner の設定でデフォルトとして設定します(RunConfig の callModelInputFilter)。
戻り値は ModelInputData オブジェクト、つまり { input: AgentInputItem[], instructions? } である必要があります。input フィールドは必須で、配列でなければなりません。それ以外の形式を返すと UserError がスローされます。
SDK は、フィルターを呼び出す前に準備済みのターン入力を複製します。session も使用している場合、フィルター処理後の複製が永続化されるため、ここで適用した編集や切り詰めは、保存されたセッション履歴にも反映されます。
フィルターがオブジェクトの同一性に基づいて、繰り返されるモデル呼び出し間の処理をメモ化する場合は、フィルターに preserveInputIdentity = true を設定します。これにより SDK は、SDK が準備した各項目が準備済み入力に含まれている間、その項目の同一性を保持します。ただし、フィルターの各呼び出しに渡される配列は新しいものです。このオプションでは、最初に run() に渡された呼び出し元所有のオブジェクトの同一性は保持されません。
import { CallModelInputFilter, Runner } from '@openai/agents';
const inspectedItems = new WeakSet<object>();
const inspectInputOnce: CallModelInputFilter = ({ modelData }) => { for (const item of modelData.input) { if (item && typeof item === 'object' && !inspectedItems.has(item)) { inspectedItems.add(item); recordPreparedItem(item); } }
return modelData;};
// Keep SDK-prepared item identities stable across repeated model calls so the// WeakSet can recognize items that this filter already inspected. Do not mutate// the items or their nested values.inspectInputOnce.preserveInputIdentity = true;
const runner = new Runner({ callModelInputFilter: inspectInputOnce });
declare function recordPreparedItem(item: object): void;
export { runner };SDK は準備済み項目やそのネストされた値を凍結しないため、このモードはオプトインです。フィルターと、フィルターが呼び出すすべてのヘルパーは、項目をイミュータブルとして扱い、変更する代わりに置換値を返す必要があります。フィルターが戻った後も、モデルリクエストとセッション入力は分離された複製のままです。
conversationId または previousResponseId を使用する場合、このフックは次の Responses API 呼び出し用に準備されたペイロードに対して実行されます。以前のサーバー管理コンテキストは API によって復元されるため、その呼び出しのフィルター対象配列は、以前の履歴全体ではなく、新しいターンの差分のみをすでに表している場合があります。この最終的なフィルター処理の前に、保存された履歴と現在のターンを統合する方法を変更する必要がある場合は、sessionInputCallback を使用してください。
ツールエラーフォーマッター
Section titled “ツールエラーフォーマッター”モデルに返されるツールエラーメッセージをカスタマイズするには、toolErrorFormatter を使用します。これにより、SDK のデフォルトメッセージの代わりに、ドメイン固有の文言(コンプライアンスに関するガイダンスなど)を返せます。
フォーマッターは、実行ごとに(runner.run(..., { toolErrorFormatter }))、または RunConfig でグローバルに(new Runner(...) の toolErrorFormatter)設定できます。
このフォーマッターは、承認拒否に対するグローバルなフォールバックです。特定の中断を result.state.reject(interruption, { message: '...' }) で拒否した場合は、その呼び出しの message が toolErrorFormatter より優先されます。どちらも指定されていない場合、SDK はデフォルトの拒否テキスト Tool execution was not approved. にフォールバックします。
toolNotFoundBehavior: 'return_error_to_model' によって未解決の関数ツール呼び出しが、モデルから確認できるツール出力に変換された場合も、フォーマッターが実行されます。この場合、デフォルトメッセージは Tool '<name>' not found. です。
フォーマッターは次の値を受け取ります。
kind('approval_rejected'または'tool_not_found')toolType('function'、'computer'、'shell'、または'apply_patch')toolNamecallIddefaultMessage(現在のエラー種別に対する SDK のフォールバックメッセージ)runContext
メッセージを上書きするには文字列を返し、SDK のデフォルトを維持するには undefined を返します。フォーマッターが例外をスローした場合(または文字列以外の値を返した場合)、SDK は警告をログに記録し、現在のエラー種別に対するデフォルトメッセージにフォールバックします。
推論アイテムの ID ポリシー
Section titled “推論アイテムの ID ポリシー”SDK が以前に生成された実行項目を、後続のモデル入力用の AgentInputItem[] に戻すときに、推論アイテムの id フィールドを保持するかどうかを制御するには、reasoningItemIdPolicy を使用します。
これは、SDK が生成済みのモデル項目を入力として再投入する次のような箇所に影響します。
- 同じ実行内の後続のモデル呼び出し(ツール実行後など)
- 生成済み項目を入力や履歴として再利用する後続のターン
- 保存された
RunStateから再開された実行 result.history/result.outputなどの派生した実行結果ビュー(モデル入力形式の配列)'preserve'(デフォルト)は推論アイテムの ID を保持します。'omit'は、推論アイテムを入力として再送信する前にidフィールドを削除します。- 推論アイテム以外には影響しません。
このポリシーで変更 されない ものは次のとおりです。
- 元のモデルレスポンス(
result.rawResponses) - 実行項目(
result.newItems) - プロバイダーから返される、モデルの現在のターンの出力
つまり、このポリシーは、SDK が以前に生成された項目から 次の入力 を構築するときに適用されます。
ポリシーは、実行ごとに(runner.run(..., { reasoningItemIdPolicy: 'omit' }))、または Runner のデフォルトとして(new Runner({ reasoningItemIdPolicy: 'omit', ... }))設定できます。保存された RunState から再開する場合は、上書きしない限り、以前に解決されたポリシーが再利用されます。
callModelInputFilter との相互作用
Section titled “callModelInputFilter との相互作用”reasoningItemIdPolicy は callModelInputFilter より前に適用されます。カスタム動作が必要な場合も、callModelInputFilter で準備済み入力を確認し、モデル呼び出しの前に推論 ID を手動で再追加または削除できます。
'omit' の使用場面
Section titled “'omit' の使用場面”再投入される推論アイテムを ID なしで正規化する場合(たとえば、転送または再投入されるモデル入力を簡潔に保つ場合や、アプリのパイプラインにおける連携要件に合わせる場合)は、'omit' を使用します。
バックエンドやプロバイダーが、再投入された推論アイテムをリクエスト検証エラーで拒否する場合にも、トラブルシューティングに役立ちます(たとえば、後続の入力に含まれる推論アイテムの ID に関連する HTTP 400 エラー)。このような場合、'omit' で再投入される推論 ID を削除すると、バックエンドが新しいリクエストに対して無効と見なす ID の送信を回避できます。
SDK で推論アイテムの ID を再投入される入力にも引き継ぎ、連携先がそれを受け入れる場合は、'preserve' のままにしてください。
エラーと復旧
Section titled “エラーと復旧”エラーハンドラー
Section titled “エラーハンドラー”対応しているランタイムエラーをスローせずに最終出力へ変換するには、errorHandlers を使用します。対応しているキーは maxTurns、modelRefusal、invalidFinalOutput です。
errorHandlers.maxTurnsは、最大ターン数のエラーのみを処理します。errorHandlers.modelRefusalは、ModelRefusalErrorとして公開されたモデルの拒否を処理します。errorHandlers.invalidFinalOutputは、構造化された最終出力が存在しない場合、または出力スキーマの検証に失敗した場合に発生するModelBehaviorErrorインスタンスを処理します。ハンドラーは、モデルの再試行やツールの副作用の再実行を行わずに、検証済みのフォールバックを返します。errorHandlers.defaultは、対応しているエラー種別のフォールバックとして使用されます。- ハンドラーは
{ error, context, runData }を受け取り、{ finalOutput, includeInHistory? }を返せます。返されるfinalOutputは、現在のエージェントのoutputTypeと一致する必要があります。structured outputs の場合、SDK は実行を完了する前にフォールバックを検証します。そのエラーに対してundefinedを返すと、デフォルトの動作が維持されます。
SDK がスローする、捕捉可能なエラーは次のとおりです。
MaxTurnsExceededError–maxTurnsへの到達ModelBehaviorError– モデルによる無効な出力の生成(不正な形式の JSON、不明なツールなど)ModelRefusalError– リクエストされた出力の生成をモデルが拒否ModelTimeoutError– タイムアウトしたモデルリクエストが、再試行処理後も最終的に失敗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