핸드오프
핸드오프를 사용하면 에이전트가 대화의 일부를 다른 에이전트에게 위임할 수 있습니다. 서로 다른 에이전트가 특정 영역을 전문적으로 처리할 때 유용합니다. 예를 들어 고객 지원 앱에는 예약, 환불 또는 자주 묻는 질문을 처리하는 에이전트가 있을 수 있습니다.
핸드오프는 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– 조건에 맞는 실행에만 핸드오프를 노출하는 불리언 또는 조건자
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',});핸드오프 입력
섹션 제목: “핸드오프 입력”모델이 핸드오프를 선택할 때 작은 구조화된 페이로드를 첨부하게 하려는 경우가 있습니다. 이 경우 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 시작 부분에서 검사하세요. 승인에 실패하면 값을 반환하지 말고 예외를 발생시키세요. SDK는 onHandoff가 성공적으로 반환된 후 이전을 계속합니다. 도구 입력 가드레일은 함수 도구에 적용되며 핸드오프에는 적용되지 않습니다.
이 페이로드는 다음 에이전트의 기본 입력을 대체하지 않으며, 다른 대상을 선택하지도 않습니다. handoff() 헬퍼는 여전히 래핑한 특정 에이전트로 제어권을 이전하며, inputFilter로 변경하지 않는 한 수신 에이전트는 계속 대화 기록을 확인합니다.
inputType은 RunContext와도 별개입니다. 이미 로컬에 있는 애플리케이션 상태나 종속성이 아니라, 모델이 핸드오프 시점에 결정하는 메타데이터에 사용하세요.
inputType 사용 시점
섹션 제목: “inputType 사용 시점”핸드오프에 reason, language, priority 또는 summary와 같이 모델이 생성하는 소량의 라우팅 메타데이터가 필요할 때 inputType을 사용하세요. 예를 들어 분류 에이전트가 { reason: 'duplicate_charge', priority: 'high' }와 함께 환불 에이전트로 핸드오프하면, 환불 에이전트가 제어권을 넘겨받기 전에 onHandoff가 해당 메타데이터를 기록하거나 영구 저장할 수 있습니다.
목적이 다르다면 다른 메커니즘을 선택하세요.
- 기존 애플리케이션 상태는
RunContext에 저장 - 수신 에이전트가 확인하는 기록을 변경하려면
inputFilter사용 - 가능한 전문 에이전트가 여러 명이라면 대상별로 하나의 핸드오프를 등록.
inputType은 선택된 핸드오프에 메타데이터를 추가할 수 있지만 대상 간 디스패치는 수행하지 않음 onHandoff가 실행되기 전에 SDK가 파싱된 페이로드를 검증하게 하려면 Zod 스키마 또는 지원되는 Standard Schema 값을 사용하는 것이 좋음. 원문 JSON Schema는 모델에 전송되는 도구 계약만 정의함. Standard 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은 실행 결과 참조