コンテンツにスキップ

ハンドオフ

ハンドオフを使うと、あるエージェントが会話の一部を別のエージェントに委譲できます。これは、異なるエージェントがそれぞれ特定の領域に特化している場合に便利です。たとえばカスタマーサポートアプリでは、予約、返金、FAQ を扱うエージェントを用意できます。

ハンドオフは、LLM に対してはツールとして表現されます。Refund Agent という名前のエージェントにハンドオフする場合、ツール名は transfer_to_refund_agent になります。

専門担当が会話を引き継ぐべきだとわかったら、このページは エージェント の後に読んでください。専門担当を元のエージェントの背後にとどめるべき場合は、代わりに agents as tools を使ってください。

すべてのエージェントは handoffs オプションを受け取ります。ここには、ほかの Agent インスタンス、または handoff() ヘルパーが返す Handoff オブジェクトを含められます。

単純な Agent インスタンスを渡した場合は、その handoffDescription(指定されていれば)がデフォルトのツール説明に追記されます。モデルがそのハンドオフを選ぶべきタイミングを明確にするために使ってください。

Basic handoffs
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 handoffs
const 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 が設定されている場合は、解析済みのハンドオフ payload も受け取ります
  • inputType – ハンドオフのツール呼び出し引数のスキーマ
  • inputFilter – 次のエージェントに渡す履歴のフィルター
  • isEnabled – 一致する実行に対してのみハンドオフを公開する boolean または述語関数

handoff() ヘルパーは、常に渡された特定の agent に制御を移します。複数の遷移先候補がある場合は、遷移先ごとに 1 つずつハンドオフを登録し、その中からモデルに選ばせてください。呼び出し時にどのエージェントを返すかを独自のハンドオフコードで決定する必要がある場合は、カスタム Handoff を使ってください。

Customized handoffs
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',
});

モデルがハンドオフを選ぶ際に、小さな構造化 payload も付与してほしい場合があります。その場合は inputTypeonHandoff を一緒に定義します。

Handoff inputs
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 で変更しない限り会話履歴を引き続き参照します。

inputTypeRunContext とも別物です。これは、ハンドオフ時にモデルが決定するメタデータのために使ってください。すでにローカルにあるアプリケーション状態や依存関係のためには使いません。

inputType は、ハンドオフに reasonlanguageprioritysummary など、モデル生成の小さなルーティング用メタデータが必要な場合に使ってください。たとえば、トリアージエージェントは { reason: 'duplicate_charge', priority: 'high' } を付けて返金エージェントにハンドオフでき、onHandoff は返金エージェントが引き継ぐ前にそのメタデータを記録または永続化できます。

目的が異なる場合は、別の仕組みを選んでください。

  • 既存のアプリケーション状態は RunContext に入れる
  • 受け取り側のエージェントが見る履歴を変更したい場合は inputFilter を使う
  • 複数の専門担当の候補がある場合は、遷移先ごとに 1 つのハンドオフを登録する。inputType は選ばれたハンドオフにメタデータを追加できますが、遷移先の振り分けはしません
  • onHandoff の実行前に SDK に解析済み payload を検証してほしい場合は、raw な JSON Schema ではなく Zod スキーマを使う。raw な JSON Schema は、モデルに送られるツール契約を定義するだけです

デフォルトでは、ハンドオフは会話履歴全体を受け取ります。次のエージェントに渡す内容を変更するには、inputFilter を指定します。一般的なヘルパーは @openai/agents-core/extensions にあります。

Input filters
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,
});

inputFilterHandoffInputData オブジェクトを受け取り、返します。

  • inputHistory – 実行開始前の入力履歴
  • preHandoffItems – ハンドオフが発生したターンより前に生成された項目
  • newItems – ハンドオフの呼び出し / 出力項目を含む、現在のターン中に生成された項目
  • runContext – アクティブな実行コンテキスト

RunnerhandoffInputFilter も設定している場合、その特定のハンドオフについてはハンドオフごとの inputFilter が優先されます。

プロンプトでハンドオフに言及すると、LLM はより安定して応答します。SDK は RECOMMENDED_PROMPT_PREFIX を通じて推奨プレフィックスを公開しています。

Recommended prompts
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.`,
});