コンテンツにスキップ

エージェントの実行

エージェントはそれ自体では何もしません。Runner クラスまたは run() ユーティリティで 実行 します。

ターンの実行、イベントのストリーミング、会話状態の管理を行いたい場合は、まず エージェント を読んだあとにこのページを読んでください。エージェントの定義方法をまだ検討中なら、先に エージェント から始めてください。

Simple 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 が不要な場合は、run() ユーティリティも使えます。これはシングルトンのデフォルト Runner インスタンスを実行します。

または、独自の runner インスタンスを作成することもできます。

Simple run
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 runner
const 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 の run メソッドを使うときは、開始エージェントと入力を渡します。入力は文字列(ユーザーメッセージとして扱われます)か、OpenAI Responses API の項目である入力項目のリストのいずれかです。

その後、runner は次のループを実行します。

  1. 現在の入力で、現在のエージェントのモデルを呼び出す
  2. LLM の応答を検査する
    • 最終出力 → 返す
    • ハンドオフ → 新しいエージェントに切り替え、蓄積済みの会話履歴を保持し、1 へ戻る
    • ツール呼び出し → ツールを実行し、結果を会話に追加し、1 へ戻る
  3. maxTurns に達したら MaxTurnsExceededError を投げる

アプリ起動時に Runner を作成し、リクエスト間で再利用してください。インスタンスには、モデルプロバイダーやトレーシングオプションなどのグローバル設定が保持されます。まったく異なる設定が必要な場合にのみ、別の Runner を作成してください。単純なスクリプトなら、内部でデフォルト runner を使う run() を呼ぶこともできます。

run() メソッドへの入力は、実行開始に使う初期エージェント、実行入力、オプションのセットです。

入力は、文字列(ユーザーメッセージとして扱われます)、入力項目 のリスト、または 人間の介入(HITL) エージェントを構築している場合は RunState オブジェクトのいずれかです。

追加オプションは次のとおりです。

OptionDefaultDescription
streamfalsetrue の場合、呼び出しは StreamedRunResult を返し、モデルから到着したイベントを逐次発行します
contextすべてのツール / ガードレール / ハンドオフに渡されるコンテキストオブジェクト。詳細は コンテキスト管理ガイド を参照してください
maxTurns10安全上限。到達すると MaxTurnsExceededError を投げます
signalキャンセル用の AbortSignal
sessionセッション永続化実装。セッションガイド を参照してください
sessionInputCallbackセッション履歴と新規入力のカスタムマージロジック。モデル呼び出し前に実行されます。セッション を参照してください
callModelInputFilterモデル呼び出し直前にモデル入力(項目 + 任意の instructions)を編集するフック。Call model input filter を参照してください
toolErrorFormatterモデルに返すツール承認拒否メッセージをカスタマイズするフック。Tool error formatter を参照してください
reasoningItemIdPolicy以前の実行項目をモデル入力に戻す際、reasoning-item の id を保持するか省略するかを制御します。Reasoning item ID policy を参照してください
tracing実行単位のトレーシング設定上書き(例: export API key)
errorHandlersサポートされる実行時エラー(現在は maxTurns)のハンドラー。Error handlers を参照してください
conversationIdサーバー側会話を再利用します(OpenAI Responses API + Conversations API のみ)
previousResponseId会話を作らずに前回の Responses API 呼び出しから継続します(OpenAI Responses API のみ)

ストリーミングを使うと、LLM 実行中のイベントも受け取れます。ストリーム開始後、StreamedRunResult には生成された新規出力を含む実行の完全情報が入ります。ストリーミングイベントは for await ループで反復できます。詳細は ストリーミングガイド を参照してください。

独自の Runner インスタンスを作る場合は、runner を設定するために RunConfig オブジェクトを渡せます。

FieldTypePurpose
modelstring | Model実行内の すべて のエージェントに特定モデルを強制します
modelProviderModelProviderモデル名を解決します。デフォルトは OpenAI provider です
modelSettingsModelSettingsエージェント単位設定を上書きするグローバル調整パラメーター。オプトインのリトライ設定を含む詳細は モデルガイド を参照してください
handoffInputFilterHandoffInputFilterハンドオフ実行時に入力項目を変更します(ハンドオフ側で未定義の場合)
inputGuardrailsInputGuardrail[]初期 ユーザー入力に適用されるガードレール
outputGuardrailsOutputGuardrail[]最終 出力に適用されるガードレール
tracingDisabledbooleanOpenAI Tracing を完全に無効化します
traceIncludeSensitiveDatabooleanspan は送信しつつ、トレースから LLM / ツールの入力と出力を除外します
workflowNamestringTraces ダッシュボードに表示され、関連実行のグルーピングに役立ちます
traceId / groupIdstringSDK に生成させず、trace または group ID を手動指定します
traceMetadataRecord<string, string>すべての span に付与する任意メタデータ
tracingTracingConfig実行単位のトレーシング上書き(例: export API key)
sessionInputCallbackSessionInputCallbackこの runner 上の全実行に対するデフォルト履歴マージ戦略
callModelInputFilterCallModelInputFilter各モデル呼び出し前にモデル入力を編集するグローバルフック
toolErrorFormatterToolErrorFormatterモデルに返すツール承認拒否メッセージをカスタマイズするグローバルフック
reasoningItemIdPolicyReasoningItemIdPolicy生成済み項目を後続モデル呼び出しへ再投入する際、reasoning-item の id を保持または省略するデフォルトポリシー

状態を次ターンへ持ち越す一般的な方法は 4 つあります。

StrategyWhere state livesBest forWhat you pass on the next turn
result.historyアプリのメモリ小規模チャットループ、完全な手動制御、任意のプロバイダーresult.history
sessionストレージ + SDK永続チャット状態、再開可能実行、カスタムストア同じ session インスタンス(またはストアバックドなもの)
conversationIdOpenAI Conversations APIworker / サービス間で共有するサーバー側状態同じ conversationId と新しいユーザーターンのみ
previousResponseIdOpenAI Responses API のみ会話を作らない最小構成のサーバー管理継続result.lastResponseId と新しいユーザーターンのみ

result.historysession はクライアント管理です。conversationIdpreviousResponseId は OpenAI 管理で、OpenAI Responses API 使用時のみ適用されます。ほとんどのアプリでは、会話ごとに永続化戦略を 1 つ選んでください。クライアント管理履歴とサーバー管理状態を混在させると、意図的に統合しない限りコンテキストが重複する可能性があります。

runner.run()(または run() ユーティリティ)の各呼び出しは、アプリレベル会話の 1 ターン を表します。RunResult のどこまでをエンドユーザーに見せるかは選べます。finalOutput のみの場合もあれば、生成項目すべての場合もあります。

Example of carrying over the conversation history
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"

対話版は chat example を参照してください。

毎ターンでローカル会話履歴全体を送る代わりに、OpenAI Responses API に会話履歴を永続化させることができます。これは長い会話や複数サービスを調整する場合に有用です。以下のいずれのサーバー管理方式でも、各リクエストでは新しいターンの入力だけを渡します。API が過去状態を再利用します。詳細は Conversation state guide を参照してください。

OpenAI はサーバー側状態再利用の方法を 2 つ提供します。

1. 会話全体に対する conversationId
Section titled “1. 会話全体に対する conversationId”

Conversations API で一度会話を作成し、すべてのターンでその ID を再利用できます。SDK は新規生成項目のみを自動的に含めます。

Reusing a server conversation
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 を使って各リクエストを連結できます。これにより、完全な会話リソースを作らずにターン間コンテキストを維持できます。

Chaining with previousResponseId
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);

conversationIdpreviousResponseId は同時に使えません。システム間で共有できる名前付き会話リソースが必要なら conversationId、応答から次の応答へ最小コストで SDK レベル継続したいだけなら previousResponseId を使ってください。

callModelInputFilter は、モデル呼び出しの 直前 にモデル入力を編集するために使います。このフックは現在のエージェント、コンテキスト、結合済み入力項目(存在する場合はセッション履歴を含む)を受け取ります。更新した input 配列と任意の instructions を返し、機密データのマスキング、古いメッセージの削除、追加のシステムガイダンス注入を行えます。

runner.run(..., { callModelInputFilter }) で実行単位に設定するか、Runner 設定(RunConfigcallModelInputFilter)でデフォルト設定します。

戻り値は ModelInputData オブジェクト { input: AgentInputItem[], instructions? } である必要があります。input フィールドは必須で、配列でなければなりません。これ以外の形を返すと UserError が投げられます。

SDK はフィルター呼び出し前に、準備済みターン入力を clone します。session も使っている場合、永続化されるのはこの filtered clone なので、ここで適用したマスキングや切り詰めは保存済みセッション履歴にも反映されます。

conversationId または previousResponseId では、このフックは次の Responses API 呼び出し用に準備された payload に対して実行されます。過去のサーバー管理コンテキストは API 側で復元されるため、その呼び出しの filtered 配列は過去履歴の完全再生ではなく、新ターン差分のみをすでに表している場合があります。この最終フィルター手順の前に保存履歴と現在ターンのマージ方法を変更したい場合は、sessionInputCallback を使ってください。

toolErrorFormatter は、ツール呼び出しが拒否されたときにモデルへ返す承認拒否メッセージをカスタマイズするために使います。SDK デフォルト文言ではなく、ドメイン固有の文言(例: コンプライアンスガイダンス)を返せます。

formatter は実行単位(runner.run(..., { toolErrorFormatter }))または RunConfignew Runner(...)toolErrorFormatter)でグローバル設定できます。

この formatter は承認拒否時のグローバルフォールバックです。特定 interruption を result.state.reject(interruption, { message: '...' }) で拒否した場合、その呼び出し単位 messagetoolErrorFormatter より優先されます。どちらもない場合、SDK はデフォルト拒否文 Tool execution was not approved. を使います。

現在この formatter は approval_rejected イベントで実行され、以下を受け取ります。

  • kind(現在は常に 'approval_rejected'
  • toolType'function''computer''shell''apply_patch'
  • toolName
  • callId
  • defaultMessage(SDK のフォールバック文。現在は Tool execution was not approved.
  • runContext

メッセージを上書きするには文字列を返し、SDK デフォルトを維持するには undefined を返します。formatter が throw した場合(または文字列以外を返した場合)、SDK は warning を記録し、デフォルト承認拒否メッセージにフォールバックします。

reasoningItemIdPolicy は、SDK が以前生成した実行項目を後続モデル入力用 AgentInputItem[] に変換するとき、reasoning item の id フィールドを保持するかどうかを制御します。

これは、SDK が生成済みモデル項目を入力として再生する場面に影響します。例:

  • 同一実行内のフォローアップモデル呼び出し(例: ツール実行後)

  • 生成済み項目を入力 / 履歴として再利用する後続ターン

  • 保存済み RunState からの実行再開

  • result.history / result.output のような派生結果ビュー(モデル入力形状の配列)

  • 'preserve'(デフォルト): reasoning-item ID を保持

  • 'omit': 入力として再送する前に reasoning item の id フィールドを削除

  • 非 reasoning item は影響なし

変更されない もの:

  • 生のモデル応答(result.rawResponses
  • 実行項目(result.newItems
  • provider が返す現在ターンのモデル出力

つまり、このポリシーは SDK が過去生成項目から 次の入力 を構築するときに適用されます。

ポリシーは実行単位(runner.run(..., { reasoningItemIdPolicy: 'omit' }))または runner デフォルト(new Runner({ reasoningItemIdPolicy: 'omit', ... }))で設定できます。保存済み RunState から再開する場合、上書きしない限り以前に解決されたポリシーが再利用されます。

reasoningItemIdPolicycallModelInputFilter より先に適用されます。カスタム挙動が必要なら、callModelInputFilter で準備済み入力を検査し、モデル呼び出し前に reasoning ID を手動で再追加または削除できます。

再生された reasoning item を ID なしで正規化したい場合(例: 転送 / 再生されるモデル入力を単純化したい、またはアプリパイプラインの統合要件に合わせたい)に 'omit' を使います。

バックエンド / provider が再生 reasoning item をリクエスト検証エラーで拒否する場合(例: フォローアップ入力中の reasoning item ID に関連する HTTP 400 エラー)にも有効なトラブルシュート手段です。その場合、'omit' で再生 reasoning ID を削除すると、新規リクエストで無効と扱われる ID の送信を避けられます。

再生入力でも reasoning-item ID を維持したく、統合先がそれを受け入れるなら 'preserve' を維持してください。

errorHandlers を使うと、サポートされる実行時エラーを throw せず最終出力へ変換できます。現在サポートされるのは maxTurns のみです。

  • errorHandlers.maxTurns は max-turn エラーのみを処理
  • errorHandlers.default はサポート対象種別のフォールバックとして使用
  • ハンドラーは { error, context, runData } を受け取り、{ finalOutput, includeInHistory? } を返せます

SDK は、捕捉可能な少数のエラーを投げます。

すべては基底 AgentsError クラスを継承し、現在の実行状態へアクセスする state プロパティを持つ場合があります。

以下は GuardrailExecutionError を処理するコード例です。入力ガードレールは最初のユーザー入力でのみ実行されるため、この例では元の入力とコンテキストで実行を再開始します。また、保存済み状態を再利用して、モデルを再呼び出しせずに出力ガードレールを再試行する方法も示しています。

Guardrail execution error
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 retry
Guardrail execution failed (output): Error: Output guardrail failed to complete: Error: Output guardrail crashed.
Output guardrail tripped after retry with saved state