핸드오프
핸드오프를 사용하면 에이전트가 대화의 일부를 다른 에이전트에 위임할 수 있습니다. 이는 서로 다른 에이전트가 특정 영역에 특화되어 있을 때 유용합니다. 예를 들어 고객 지원 앱에서는 예약, 환불, FAQ를 처리하는 에이전트를 둘 수 있습니다.
핸드오프는 LLM에 도구로 표현됩니다. Refund Agent라는 에이전트로 핸드오프하면 도구 이름은 transfer_to_refund_agent가 됩니다.
전문 에이전트가 대화를 이어받아야 한다는 것을 알게 된 뒤에 에이전트 페이지를 읽으세요. 전문 에이전트가 원래 에이전트 뒤에서 동작해야 한다면 대신 agents as tools을 사용하세요.
핸드오프 생성
섹션 제목: “핸드오프 생성”모든 에이전트는 handoffs 옵션을 받습니다. 여기에는 다른 Agent 인스턴스나 handoff() 헬퍼가 반환한 Handoff 객체를 넣을 수 있습니다.
일반 Agent 인스턴스를 전달하면 해당 handoffDescription(제공된 경우)이 기본 도구 설명에 추가됩니다. 모델이 언제 해당 핸드오프를 선택해야 하는지 명확히 할 때 사용하세요.
기본 사용법
섹션 제목: “기본 사용법”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()를 통한 핸드오프 사용자 지정
섹션 제목: “handoff()를 통한 핸드오프 사용자 지정”handoff() 함수로 생성된 도구를 조정할 수 있습니다.
agent– 핸드오프할 대상 에이전트toolNameOverride– 기본transfer_to_<agent_name>도구 이름 재정의toolDescriptionOverride– 기본 도구 설명 재정의onHandoff– 핸드오프가 발생할 때의 콜백.RunContext를 받고,inputType이 설정된 경우 파싱된 핸드오프 페이로드도 받음inputType– 핸드오프 도구 호출 인자용 스키마inputFilter– 다음 에이전트로 전달할 히스토리 필터isEnabled– 일치하는 실행에서만 핸드오프를 노출하는 boolean 또는 조건 함수
handoff() 헬퍼는 항상 전달한 특정 agent로 제어를 넘깁니다. 가능한 목적지가 여러 개라면 목적지마다 하나의 핸드오프를 등록하고, 모델이 그중에서 선택하게 하세요. 핸드오프 호출 시점에 어떤 에이전트를 반환할지 직접 결정해야 한다면 커스텀 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',});핸드오프 입력
섹션 제목: “핸드오프 입력”모델이 핸드오프를 선택할 때 작은 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 사용 시점
섹션 제목: “inputType 사용 시점”핸드오프에 reason, language, priority, summary 같은 모델 생성 라우팅 메타데이터가 조금 필요할 때 inputType을 사용하세요. 예를 들어 분류 에이전트가 { reason: 'duplicate_charge', priority: 'high' }와 함께 환불 에이전트로 핸드오프할 수 있고, 환불 에이전트가 이어받기 전에 onHandoff에서 해당 메타데이터를 로깅하거나 저장할 수 있습니다.
목적이 다르면 다른 메커니즘을 선택하세요.
- 기존 애플리케이션 상태는
RunContext에 넣기 - 수신 에이전트가 보는 히스토리를 바꾸고 싶다면
inputFilter사용 - 가능한 전문 에이전트가 여러 명이면 목적지마다 핸드오프 하나씩 등록.
inputType은 선택된 핸드오프에 메타데이터를 추가할 수 있지만 목적지 간 디스패치는 하지 않음 onHandoff실행 전에 SDK가 파싱된 페이로드를 검증하길 원하면 원문 JSON Schema보다 Zod 스키마를 우선 사용. 원문 JSON Schema는 모델에 전송되는 도구 계약만 정의함
입력 필터
섹션 제목: “입력 필터”기본적으로 핸드오프는 전체 대화 히스토리를 받습니다. 다음 에이전트로 전달되는 내용을 수정하려면 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가 우선합니다.
권장 프롬프트
섹션 제목: “권장 프롬프트”프롬프트에 핸드오프를 언급하면 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은 실행 결과를 참고하세요