首页 › AI Agent › Agent100道面试题 › 多 Agentmulti-agent › 如何实现 Agent 间的 Handoff(任务交接)?

如何实现 Agent 间的 Handoff(任务交接)?

难度:中级 分类:Multi-Agent​

简短回答​

Agent Handoff 是多 Agent 系统中一个 Agent 将控制权、任务和对话上下文转交给另一个 Agent 的过程。最常用的实现是 OpenAI 提出的 transfer_to_XXX 模式——将 Handoff 包装为工具调用,当 Agent 判断任务超出自身能力时,调用 transfer_to_specialist_agent 函数触发交接。关键挑战不在于触发 Handoff,而在于上下文传递的可靠性——大多数"Agent 失败"实际上是 Handoff 时的上下文丢失或格式错误。最佳实践是使用结构化的 Handoff 数据(JSON Schema),而非自由文本。​

详细解析​

为什么需要 Handoff?​

单个 Agent 配备太多工具或过大的上下文时,决策质量会下降。Handoff 允许将任务路由给专精的 Agent:​

​

飞书文档 - 图片

​

Handoff 是控制权转移而非工具借用:路由 Agent 判断超纲即 transfer,退货完成后再交接给财务 Agent,全程传递对话上下文。​

实现方式 1:Tool-Based Handoff(OpenAI 模式)​

将 Handoff 作为工具暴露给 LLM:​

​

代码块​

Python

# OpenAI Agents SDK 风格​

from agents import Agent, handoff​

​

# 定义专家 Agent​

refund_agent = Agent(​

name="Refund Agent",​

instructions="你负责处理退款请求...",​

tools=[execute_refund, check_refund_status],​

)​

​

shipping_agent = Agent(​

name="Shipping Agent",​

instructions="你负责处理物流问题...",​

tools=[track_package, update_address],​

)​

​

# 路由 Agent 有 Handoff 能力​

triage_agent = Agent(​

name="Triage Agent",​

​

核心 API 参数:​

•

tool_name_override:自定义生成的工具名(默认 transfer_to_<agent_name>)​

•

tool_description_override:自定义工具描述​

•

on_handoff:Handoff 发生时的回调(用于日志、审计、状态注入)​

•

input_filter:过滤传给目标 Agent 的对话历史(OpenAI SDK 提供 handoff_filters.remove_all_tools 等内置 filter)​

•

input_type:用 Pydantic 模型约束 Handoff 的入参,强制结构化​

工作原理: LLM 足够智能,会在合适的时机调用 transfer_to_XXX。当 Handoff 发生时,新 Agent 接管对话并获得完整的对话历史。​

实现方式 2:Supervisor 模式(LangGraph)​

​

代码块​

Python

from langgraph.graph import StateGraph​

​

​

实现方式 3:函数返回 Agent 对象​

​

代码块​

Python

# Swarm 风格:工具函数返回 Agent 对象触发 Handoff​

def handle_refund(order_id: str):​

"""处理退款请求"""​

status = check_order(order_id)​

if status == "delivered":​

# 返回 Agent 对象 = 触发 Handoff​

return refund_agent​

else:​

return f"订单 {order_id} 尚未送达,无法退款"​

​

triage_agent = Agent(​

​

上下文传递策略​

Handoff 最大的挑战是上下文传递。三种策略:​

​

代码块​

Python

# 策略 1:完整历史传递(简单但可能超出上下文窗口)​

def handoff_full_history(target_agent, conversation_history):​

return target_agent.invoke(messages=conversation_history)​

​

# 策略 2:摘要传递(节省 token,但可能丢失细节)​

def handoff_with_summary(target_agent, conversation_history):​

summary = summarize(conversation_history)​

return target_agent.invoke(messages=[​

{"role": "system", "content": f"前序对话摘要:{summary}"},​

conversation_history[-1] # 最新一条用户消息​

])​

​

Input Filter(上下文过滤)​

​

代码块​

Python

# OpenAI Agents SDK 的 input_filter​

from agents import handoff​

​

Handoff 的可靠性设计​

​

代码块​

Python

class ReliableHandoff:​

​

编排模式与 Handoff 的关系​

​

#SyOLoksNGwWt text { white-space: pre; }#SyOLoksNGwWt .fb0 { stroke: var(--N900-FG, 0.15); }#SyOLoksNGwWt .fb0 {stroke: rgba(31,35,41, 0.15)}#SyOLoksNGwWt .fx0 { stroke-miterlimit: 10; }#SyOLoksNGwWt .fx0 {stroke-miterlimit: 10}#SyOLoksNGwWt .fa1 { fill: rgb(187, 191, 196); }#SyOLoksNGwWt .fa1 {fill: rgb(187, 191, 196)}#SyOLoksNGwWt .fx1 { font: 400 12px MonospacedNumber, LarkHackSafariFont, LarkEmojiFont, LarkChineseQuote, -apple-system, BlinkMacSystemFont, "Helvetica Neue", Tahoma, "PingFang SC", "Microsoft Yahei", Arial, "Hiragino Sans GB", sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji"; }#SyOLoksNGwWt .fx1 {font-style: normal}#SyOLoksNGwWt .fx2 { text-anchor: middle; }#SyOLoksNGwWt .fx2 {text-anchor: middle}#SyOLoksNGwWt .fx3 { dominant-baseline: central; }#SyOLoksNGwWt .fx3 {dominant-baseline: central}#SyOLoksNGwWt .fx4 { stroke: none; }#SyOLoksNGwWt .fx4 {stroke: none}#SyOLoksNGwWt .fc0 { fill: var(--text-caption); }#SyOLoksNGwWt .fc0 {fill: #646a73}#SyOLoksNGwWt .fa2 { fill: var(--text-link-disabled); }#SyOLoksNGwWt .fa2 {fill: rgb(187, 191, 196)}#SyOLoksNGwWt .fx5 { font: 400 13px MonospacedNumber, LarkHackSafariFont, LarkEmojiFont, LarkChineseQuote, -apple-system, BlinkMacSystemFont, "Helvetica Neue", Tahoma, "PingFang SC", "Microsoft Yahei", Arial, "Hiragino Sans GB", sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji"; }#SyOLoksNGwWt .fx5 {font-style: normal}#SyOLoksNGwWt .fx6 { text-anchor: start; }#SyOLoksNGwWt .fx6 {text-anchor: start}#SyOLoksNGwWt .fx7 { dominant-baseline: alphabetic; }#SyOLoksNGwWt .fx7 {dominant-baseline: alphabetic}#SyOLoksNGwWt .fc1 { fill: rgb(0, 0, 0); }#SyOLoksNGwWt .fc1 {fill: rgb(0, 0, 0)}#SyOLoksNGwWt .fb1 { fill: var(--N900-FG, 0.15); }#SyOLoksNGwWt .fb1 {fill: rgba(31,35,41, 0.15)}#SyOLoksNGwWt .fb2 { fill: rgb(209, 217, 224); }#SyOLoksNGwWt .fb2 {fill: rgb(209, 217, 224)}#SyOLoksNGwWt .fa3 { fill: var(--bg-body); }#SyOLoksNGwWt .fa3 {fill: #fff}ABC12345编排模式SequentialSupervisorDecentralizedHierarchicalHandoff 方式固定顺序传递Supervisor 决定路由Agent 自主 Handoff层级间逐级传递特点可预测,适合简单流程集中控制,灵活但有瓶颈去中心化,灵活但难追踪结构化,适合大型系统

​

常见误区 / 面试追问​

误区:"Handoff 只是把对话历史复制过去" — 自由文本 Handoff 是上下文丢失的主要原因。应该用结构化数据(JSON Schema)传递上下文,像对待公开 API 一样对待 Agent 间接口。​

误区:"任何 Agent 都可以 Handoff 给任何 Agent" — 应该限制 Handoff 的路径。每个 Agent 只能 Handoff 给预定义的目标 Agent,防止意外的循环 Handoff 或权限升级。​

追问:"如何防止 Handoff 循环?" — 追踪 Handoff 链路,设置最大 Handoff 次数。如果 Agent A → B → A → B 循环出现,触发断路器并升级给人工处理。​

追问:"Handoff 和工具调用有什么区别?" — 工具调用后控制权回到原 Agent;Handoff 后控制权完全转移到新 Agent。工具是"用完即还",Handoff 是"交接班"。​