ハンドオフ
ハンドオフを使用すると、エージェントは会話の一部を別のエージェントに委任できます。これは、異なるエージェントが特定の領域を専門としている場合に便利です。たとえば、カスタマーサポートアプリでは、予約、返金、よくある質問をそれぞれ担当するエージェントを用意できます。
ハンドオフは、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– 条件に一致する実行に対してのみハンドオフを公開する真偽値または述語
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 “ハンドオフ入力”モデルがハンドオフを選択するときに、小さな構造化ペイロードを付加させたい場合があります。その場合は、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 に渡します。
isEnabled は、モデルがハンドオフ引数を返す前に、SDK がモデルで利用可能なハンドオフを準備する時点で評価されます。そのため、引数を伴うハンドオフ内の値を認可することはできません。認可が解析済みフィールドに依存する場合は、アプリケーションで副作用が発生する前に、onHandoff の冒頭で確認してください。認可に失敗した場合は、値を返すのではなく例外をスローしてください。onHandoff が正常に値を返すと、SDK は転送を続行します。ツール入力ガードレールは関数ツールに適用され、ハンドオフには適用されません。
これは次のエージェントのメイン入力を置き換えるものではなく、別のハンドオフ先を選択するものでもありません。handoff() ヘルパーは引き続き、ラップした特定のエージェントに転送します。また、inputFilter で変更しない限り、受信側のエージェントには引き続き会話履歴が表示されます。
inputType は RunContext とも別のものです。ローカルにすでに存在するアプリケーションの状態や依存関係ではなく、ハンドオフ時にモデルが決定するメタデータに使用してください。
inputType の使用場面
Section titled “inputType の使用場面”ハンドオフで、reason、language、priority、summary など、モデルが生成する小さなルーティング用メタデータが必要な場合に inputType を使用します。たとえば、トリアージエージェントは { reason: 'duplicate_charge', priority: 'high' } を付けて返金エージェントにハンドオフでき、返金エージェントが引き継ぐ前に onHandoff でそのメタデータをログに記録したり、永続化したりできます。
目的が異なる場合は、別の仕組みを選択してください。
- 既存のアプリケーション状態は
RunContextに格納します。 - 受信側のエージェントに表示される履歴を変更する場合は、
inputFilterを使用します。 - スペシャリストの候補が複数ある場合は、ハンドオフ先ごとに 1 つずつハンドオフを登録します。
inputTypeは選択されたハンドオフにメタデータを追加できますが、ハンドオフ先の振り分けは行いません。 onHandoffの実行前に SDK で解析済みペイロードを検証する場合は、Zod スキーマまたはサポートされている Standard Schema 値を使用してください。元の JSON Schema は、モデルに送信されるツールのコントラクトを定義するだけです。Standard 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– ハンドオフの呼び出し項目と出力項目を含む、現在のターン中に生成された項目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については、エージェントの実行結果を参照してください。