Handoffs¶
Handoffs allow agents to delegate tasks to specialized sub-agents.
Basic Handoffs¶
from agents import Agent
# Specialist agents
billing_agent = Agent(
name="billing",
instructions="Handle billing inquiries, refunds, and payments.",
handoff_description="Handles billing, payments, and refunds.",
)
tech_agent = Agent(
name="tech_support",
instructions="Help with technical issues and troubleshooting.",
handoff_description="Handles technical support and troubleshooting.",
)
# Main agent with handoffs
main_agent = Agent(
name="support",
instructions="Route customers to the appropriate specialist.",
handoffs=[billing_agent, tech_agent],
)
Handoff Decorator¶
For more control over handoff behavior:
from agents import Agent, handoff, Handoff
@handoff
def to_billing(context) -> Handoff:
"""Transfer to billing specialist."""
return Handoff(
target=billing_agent,
input_filter=lambda items: items[-5:], # Last 5 messages
)
main_agent = Agent(
name="support",
instructions="Route to specialists as needed.",
handoffs=[to_billing],
)
Handoff Input Filter¶
Control what conversation history transfers:
from agents import Handoff, HandoffInputFilter
def last_n_messages(n: int) -> HandoffInputFilter:
"""Only send last N messages to new agent."""
def filter_fn(items):
return items[-n:]
return filter_fn
billing_handoff = Handoff(
target=billing_agent,
input_filter=last_n_messages(3),
)
Conditional Handoffs¶
from agents import Agent, handoff, Handoff, RunContextWrapper
@handoff
def smart_handoff(ctx: RunContextWrapper) -> Handoff | None:
"""Conditionally hand off based on context."""
if ctx.context.get("is_vip"):
return Handoff(target=vip_agent)
elif ctx.context.get("issue_type") == "billing":
return Handoff(target=billing_agent)
return None # No handoff
Handoff Data¶
Pass data to the new agent:
from agents import Handoff, HandoffInputData
handoff = Handoff(
target=specialist_agent,
input_data=HandoffInputData(
summary="Customer needs help with order #12345",
metadata={"order_id": "12345", "priority": "high"},
),
)
Tracking Handoffs¶
from agents import Runner, RunHooks
class HandoffTracker(RunHooks):
async def on_handoff(self, context, from_agent, to_agent):
print(f"Handoff: {from_agent.name} -> {to_agent.name}")
result = await Runner.run(
main_agent,
"I need help with my bill",
run_hooks=HandoffTracker(),
)
# Check which agent completed the run
print(f"Handled by: {result.last_agent.name}")
Recursive Handoffs¶
Agents can hand off to agents that also have handoffs:
level1 = Agent(name="level1", handoffs=[level2])
level2 = Agent(name="level2", handoffs=[level3])
level3 = Agent(name="level3", instructions="Final handler")
Preventing Infinite Loops¶
Use max_turns to prevent circular handoffs:
from agents import Runner, RunConfig
config = RunConfig(max_turns=10)
result = await Runner.run(agent, input_text, run_config=config)
Handoff vs Tools¶
| Feature | Handoffs | Tools |
|---|---|---|
| Control flow | Transfers to new agent | Returns to same agent |
| Context | New agent takes over | Same agent continues |
| Use case | Specialization | Actions/data retrieval |
See Also¶
- Agents - Creating agents
- Multi-Agent - Complex workflows
- Running Agents - Execution