コンテンツにスキップ

エージェントの実行

エージェントはそれ自体では何もしません。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 が不要な場合は、シングルトンのデフォルト Runner インスタンスを実行する run() ユーティリティも使えます。

または、独自の 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() メソッドへの入力は、実行を開始する初期エージェント、実行の入力、および一連のオプションです。

入力は、文字列(ユーザーメッセージと見なされます)、入力アイテム のリスト、または Human in the loop (人間の介入) エージェントを構築している場合の RunState オブジェクトのいずれかです。

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

OptionDefaultDescription
streamfalsetrue の場合、呼び出しは StreamedRunResult を返し、モデルから到着するイベントを順次発行します
contextすべてのツール / ガードレール / ハンドオフに転送されるコンテキストオブジェクト。コンテキスト管理 を参照
maxTurns10セーフティリミット。到達時に 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 のみ)

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

独自の Runner インスタンスを作成する場合、RunConfig オブジェクトを渡して Runner を構成できます。

FieldTypePurpose
modelstring | Model実行中の すべての エージェントに特定のモデルを強制します
modelProviderModelProviderモデル名を解決します。デフォルトは OpenAI プロバイダです
modelSettingsModelSettingsエージェントごとの設定を上書きするグローバルなチューニングパラメーター
handoffInputFilterHandoffInputFilterハンドオフ時に入力アイテムを変更します(ハンドオフ自体で定義されていない場合)
inputGuardrailsInputGuardrail[]最初のユーザー入力に適用されるガードレール
outputGuardrailsOutputGuardrail[]最終出力に適用されるガードレール
tracingDisabledbooleanOpenAI トレーシングを完全に無効化
traceIncludeSensitiveDatabooleanスパンは出力しつつ、トレースから LLM/ツールの入出力を除外
workflowNamestringTraces ダッシュボードに表示。関連する実行をグルーピングするのに役立ちます
traceId / groupIdstringSDK に生成させる代わりに、トレースまたはグループ ID を手動指定
traceMetadataRecord<string, string>すべてのスパンに付与する任意のメタデータ
tracingTracingConfig実行ごとのトレーシング上書き(例: エクスポート用 API キー)
sessionInputCallbackSessionInputCallbackこの Runner 上のすべての実行に対するデフォルトの履歴マージ戦略
callModelInputFilterCallModelInputFilter各モデル呼び出しの直前にモデル入力を編集するグローバルフック
toolErrorFormatterToolErrorFormatterモデルに返すツール承認拒否メッセージをカスタマイズするグローバルフック

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"

インタラクティブ版は チャットの例 を参照してください。

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

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);

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

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

toolErrorFormatter を使うと、ツール呼び出しが拒否された際にモデルへ返す承認拒否メッセージをカスタマイズできます。これにより、SDK のデフォルトメッセージではなく、(たとえばコンプライアンス指針のような)ドメイン固有の文言を返せます。

フォーマッタは実行ごと(runner.run(..., { toolErrorFormatter }))にも、RunConfignew Runner(...)toolErrorFormatter)でグローバルにも設定できます。

errorHandlers を使うと、サポートされるランタイムエラーをスローする代わりに最終出力へ変換できます。現在は maxTurns のみサポートしています。

  • errorHandlers.maxTurns は最大ターンのエラーのみを処理します
  • 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