콘텐츠로 이동

핸드오프

핸드오프를 사용하면 에이전트가 다른 에이전트에게 작업을 위임할 수 있습니다. 이는 서로 다른 에이전트가 각기 다른 영역에 특화된 시나리오에서 특히 유용합니다. 예를 들어 고객 지원 앱에는 주문 상태, 환불, FAQ 등과 같은 작업을 각각 전담하는 에이전트가 있을 수 있습니다.

핸드오프는 LLM에 도구로 표현됩니다. 따라서 Refund Agent라는 에이전트로 핸드오프가 있다면, 도구 이름은 transfer_to_refund_agent가 됩니다.

핸드오프 생성

모든 에이전트에는 handoffs 매개변수가 있으며, 여기에 Agent를 직접 전달하거나 핸드오프를 커스터마이즈하는 Handoff 객체를 전달할 수 있습니다.

일반 Agent 인스턴스를 전달하면, 해당 에이전트의 handoff_description(설정된 경우)이 기본 도구 설명에 추가됩니다. 전체 handoff() 객체를 작성하지 않고도, 모델이 언제 해당 핸드오프를 선택해야 하는지 힌트를 주는 데 사용할 수 있습니다.

Agents SDK에서 제공하는 handoff() 함수를 사용해 핸드오프를 생성할 수 있습니다. 이 함수로 핸드오프 대상 에이전트를 지정하고, 선택적으로 오버라이드와 입력 필터를 지정할 수 있습니다.

기본 사용법

다음은 간단한 핸드오프를 만드는 방법입니다:

from agents import Agent, handoff

billing_agent = Agent(name="Billing agent")
refund_agent = Agent(name="Refund agent")

# (1)!
triage_agent = Agent(name="Triage agent", handoffs=[billing_agent, handoff(refund_agent)])
  1. 에이전트를 직접 사용할 수도 있고(billing_agent처럼), handoff() 함수를 사용할 수도 있습니다.

handoff() 함수를 통한 핸드오프 커스터마이즈

handoff() 함수로 다양한 항목을 커스터마이즈할 수 있습니다.

  • agent: 작업이 핸드오프될 대상 에이전트입니다.
  • tool_name_override: 기본값으로 Handoff.default_tool_name() 함수가 사용되며, 이는 transfer_to_<agent_name>으로 해석됩니다. 이를 오버라이드할 수 있습니다.
  • tool_description_override: Handoff.default_tool_description()의 기본 도구 설명을 오버라이드합니다
  • on_handoff: 핸드오프가 호출될 때 실행되는 콜백 함수입니다. 핸드오프가 호출된다는 사실을 알자마자 데이터 페칭을 시작하는 등의 용도에 유용합니다. 이 함수는 에이전트 컨텍스트를 받으며, 선택적으로 LLM이 생성한 입력도 받을 수 있습니다. 입력 데이터는 input_type 매개변수로 제어됩니다.
  • input_type: 핸드오프가 기대하는 입력 타입(선택 사항)입니다.
  • input_filter: 다음 에이전트가 받는 입력을 필터링할 수 있습니다. 자세한 내용은 아래를 참고하세요.
  • is_enabled: 핸드오프 활성화 여부입니다. boolean 또는 boolean을 반환하는 함수가 될 수 있어, 런타임에 동적으로 핸드오프를 활성화/비활성화할 수 있습니다.
from agents import Agent, handoff, RunContextWrapper

def on_handoff(ctx: RunContextWrapper[None]):
    print("Handoff called")

agent = Agent(name="My agent")

handoff_obj = handoff(
    agent=agent,
    on_handoff=on_handoff,
    tool_name_override="custom_handoff_tool",
    tool_description_override="Custom description",
)

핸드오프 입력

일부 상황에서는 LLM이 핸드오프를 호출할 때 특정 데이터를 제공하길 원할 수 있습니다. 예를 들어 "Escalation agent"로 핸드오프하는 상황을 생각해 보세요. 로그를 남길 수 있도록 사유가 함께 제공되길 원할 수 있습니다.

from pydantic import BaseModel

from agents import Agent, handoff, RunContextWrapper

class EscalationData(BaseModel):
    reason: str

async def on_handoff(ctx: RunContextWrapper[None], input_data: EscalationData):
    print(f"Escalation agent called with reason: {input_data.reason}")

agent = Agent(name="Escalation agent")

handoff_obj = handoff(
    agent=agent,
    on_handoff=on_handoff,
    input_type=EscalationData,
)

입력 필터

핸드오프가 발생하면 새 에이전트가 대화를 이어받아 이전의 전체 대화 기록을 볼 수 있는 것과 같습니다. 이를 변경하고 싶다면 input_filter를 설정할 수 있습니다. 입력 필터는 HandoffInputData를 통해 기존 입력을 받아, 새로운 HandoffInputData를 반환해야 하는 함수입니다.

중첩 핸드오프는 옵트인 베타로 제공되며, 안정화하는 동안 기본적으로 비활성화되어 있습니다. RunConfig.nest_handoff_history를 활성화하면, 러너가 이전 대화 기록을 단일 어시스턴트 요약 메시지로 축약하고 <CONVERSATION HISTORY> 블록으로 감싸며, 동일한 실행 중 여러 핸드오프가 발생할 때 새로운 턴을 계속 덧붙입니다. 전체 input_filter를 작성하지 않고도 생성된 메시지를 대체하려면 RunConfig.handoff_history_mapper를 통해 자체 매핑 함수를 제공할 수 있습니다. 이 옵트인은 핸드오프나 실행에서 명시적인 input_filter를 제공하지 않는 경우에만 적용되므로, 이미 페이로드를 커스터마이즈하는 기존 코드(이 저장소의 예제 포함)는 변경 없이 현재 동작을 유지합니다. 단일 핸드오프에 대해 중첩 동작을 오버라이드하려면 handoff(...)nest_handoff_history=True 또는 False를 전달하면 되며, 이는 Handoff.nest_handoff_history를 설정합니다. 생성된 요약의 래퍼 텍스트만 변경하면 된다면, 에이전트를 실행하기 전에 set_conversation_history_wrappers(그리고 선택적으로 reset_conversation_history_wrappers)를 호출하세요.

일부 공통 패턴(예: 기록에서 모든 도구 호출 제거)은 agents.extensions.handoff_filters에 이미 구현되어 있습니다

from agents import Agent, handoff
from agents.extensions import handoff_filters

agent = Agent(name="FAQ agent")

handoff_obj = handoff(
    agent=agent,
    input_filter=handoff_filters.remove_all_tools, # (1)!
)
  1. 이는 FAQ agent가 호출될 때 기록에서 모든 도구를 자동으로 제거합니다.

권장 프롬프트

LLM이 핸드오프를 올바르게 이해하도록 하려면, 에이전트에 핸드오프 관련 정보를 포함하는 것을 권장합니다. agents.extensions.handoff_prompt.RECOMMENDED_PROMPT_PREFIX에 권장 프리픽스가 있으며, 또는 agents.extensions.handoff_prompt.prompt_with_handoff_instructions를 호출해 권장 데이터를 프롬프트에 자동으로 추가할 수 있습니다.

from agents import Agent
from agents.extensions.handoff_prompt import RECOMMENDED_PROMPT_PREFIX

billing_agent = Agent(
    name="Billing agent",
    instructions=f"""{RECOMMENDED_PROMPT_PREFIX}
    <Fill in the rest of your prompt here>.""",
)