ハンドオフ
ハンドオフを使うと、エージェントは会話の一部を別のエージェントに委任できます。これは、異なるエージェントが特定領域に特化している場合に便利です。たとえばカスタマーサポートアプリでは、予約、返金、FAQ を扱うエージェントを用意できます。
ハンドオフは LLM に対してツールとして表現されます。Refund Agent という名前のエージェントにハンドオフする場合、ツール名は transfer_to_refund_agent になります。
このページは、専門担当が会話を引き継ぐべきだと分かった段階で エージェント の後に読んでください。専門担当を元のエージェントの背後で動かしたい場合は、代わりに Agents as tools を使ってください。
ハンドオフの作成
Section titled “ハンドオフの作成”すべてのエージェントは handoffs オプションを受け取ります。ここには、他の Agent インスタンス、または handoff() ヘルパーが返す Handoff オブジェクトを含められます。
単なる Agent インスタンスを渡すと、その handoffDescription(指定されている場合)がデフォルトのツール説明に追記されます。モデルがそのハンドオフを選ぶべき条件を明確にするために使ってください。
基本的な使い方
Section titled “基本的な使い方”import { Agent, handoff } from '@openai/agents';
const billingAgent = new Agent({ name: 'Billing agent' });const refundAgent = new Agent({ name: 'Refund agent' });
// Use Agent.create method to ensure the finalOutput type considers handoffsconst triageAgent = Agent.create({ name: 'Triage agent', handoffs: [billingAgent, handoff(refundAgent)],});handoff() によるハンドオフのカスタマイズ
Section titled “handoff() によるハンドオフのカスタマイズ”handoff() 関数を使うと、生成されるツールを調整できます。
agent– ハンドオフ先のエージェントtoolNameOverride– デフォルトのtransfer_to_<agent_name>ツール名を上書きtoolDescriptionOverride– デフォルトのツール説明を上書きonHandoff– ハンドオフ発生時のコールバック。RunContextと、inputTypeが設定されている場合はパース済みのハンドオフペイロードを受け取りますinputType– ハンドオフのツールコール引数用スキーマinputFilter– 次のエージェントに渡す履歴をフィルタリングisEnabled– 一致する実行でのみハンドオフを公開する boolean または述語関数
handoff() ヘルパーは、渡された特定の agent に常に制御を移します。行き先候補が複数ある場合は、行き先ごとに 1 つずつハンドオフを登録し、モデルに選択させてください。呼び出し時にどのエージェントを返すかを独自のハンドオフコードで決定する必要がある場合は、カスタム Handoff を使用してください。
import { z } from 'zod';import { Agent, handoff, RunContext } from '@openai/agents';
const FooSchema = z.object({ foo: z.string() });
function onHandoff(ctx: RunContext, input?: { foo: string }) { console.log('Handoff called with:', input?.foo);}
const agent = new Agent({ name: 'My agent' });
const handoffObj = handoff(agent, { onHandoff, inputType: FooSchema, toolNameOverride: 'custom_handoff_tool', toolDescriptionOverride: 'Custom description',});ハンドオフ入力
Section titled “ハンドオフ入力”モデルがハンドオフ選択時に小さな structured outputs ペイロードを添付できるようにしたい場合があります。その場合は inputType と onHandoff を組み合わせて定義します。
import { z } from 'zod';import { Agent, handoff, RunContext } from '@openai/agents';
const EscalationData = z.object({ reason: z.string() });type EscalationData = z.infer<typeof EscalationData>;
async function onHandoff( ctx: RunContext<EscalationData>, input: EscalationData | undefined,) { console.log(`Escalation agent called with reason: ${input?.reason}`);}
const agent = new Agent<EscalationData>({ name: 'Escalation agent' });
const handoffObj = handoff(agent, { onHandoff, inputType: EscalationData,});inputType は、ハンドオフツールコール自体の引数を記述します。SDK はそのスキーマをハンドオフツールの parameters としてモデルに公開し、返された引数をローカルでパースして、パース済みの値を onHandoff に渡します。
これは次のエージェントのメイン入力を置き換えるものではなく、別の行き先を選ぶものでもありません。handoff() ヘルパーは、ラップした特定のエージェントに引き続きハンドオフし、受信側エージェントは inputFilter で変更しない限り会話履歴を受け取ります。
inputType は RunContext とも別物です。ハンドオフ時点でモデルが決定するメタデータに使い、ローカルですでに保持しているアプリケーション状態や依存関係には使わないでください。
inputType の利用場面
Section titled “inputType の利用場面”inputType は、ハンドオフに reason、language、priority、summary などのモデル生成ルーティングメタデータが少量必要な場合に使います。たとえば、トリアージエージェントは { reason: 'duplicate_charge', priority: 'high' } を添えて返金エージェントにハンドオフでき、onHandoff は返金エージェントが引き継ぐ前にそのメタデータをログ出力または永続化できます。
目的が異なる場合は、別の手段を選んでください。
- 既存のアプリケーション状態は
RunContextに入れる - 受信側エージェントが見る履歴を変更したい場合は
inputFilterを使う - 専門エージェントの候補が複数ある場合は、行き先ごとに 1 つずつハンドオフを登録する。
inputTypeは選ばれたハンドオフにメタデータを追加できますが、行き先間の振り分けは行いません onHandoff実行前に SDK にパース済みペイロードを検証させたい場合は、元の JSON Schema より Zod スキーマを優先する。元の JSON Schema は、モデルに送るツール契約を定義するだけです
入力フィルター
Section titled “入力フィルター”デフォルトでは、ハンドオフは会話履歴全体を受け取ります。次のエージェントに渡す内容を変更するには、inputFilter を指定します。よく使うヘルパーは @openai/agents-core/extensions にあります。
import { Agent, handoff } from '@openai/agents';import { removeAllTools } from '@openai/agents-core/extensions';
const agent = new Agent({ name: 'FAQ agent' });
const handoffObj = handoff(agent, { inputFilter: removeAllTools,});inputFilter は HandoffInputData オブジェクトを受け取り、同じ型で返します。
inputHistory– 実行開始前の入力履歴preHandoffItems– ハンドオフが発生したターンより前に生成された項目newItems– 現在のターン中に生成された項目(ハンドオフの call/output 項目を含む)runContext– 現在の実行コンテキスト
Runner 側でも handoffInputFilter を設定している場合、特定のハンドオフでは個別の inputFilter が優先されます。
推奨プロンプト
Section titled “推奨プロンプト”プロンプトでハンドオフに言及すると、LLM はより安定して応答します。SDK は RECOMMENDED_PROMPT_PREFIX として推奨プレフィックスを公開しています。
import { Agent } from '@openai/agents';import { RECOMMENDED_PROMPT_PREFIX } from '@openai/agents-core/extensions';
const billingAgent = new Agent({ name: 'Billing agent', instructions: `${RECOMMENDED_PROMPT_PREFIX}Fill in the rest of your prompt here.`,});- マネージャーとハンドオフの選び方は エージェント
- より広いワークフロー上のトレードオフは エージェントオーケストレーション
agent.asTool()を使うマネージャー方式の代替は ツール- 実行時のハンドオフ動作は エージェントの実行
- ハンドオフグラフ全体での型付き
finalOutputは エージェントの実行結果