0%
1
Curious builder0 XP earned · 300 to level 2
0 daysFinish a lesson to begin
Badge collection0 of 6 unlocked
27 small wins to finish your pathNext lesson →

A refund specialist by handoff

A handoff is a tool call that passes the whole conversation to another agent, so a refund is handed to a specialist agent and the run continues there.

Last updated: 28 Sep, 2026 · openai-agents 0.22.3

The desk from The desk agent and its tools answers order questions. A refund is a different job, so it belongs to a different agent. Handoffs, from the lesson on Handoffs: passing control to another agent, move the run there.

The pieces, and where each came from

PieceFrom lesson
The desk with its lookup toolThe desk agent and its tools
A second Agent, the refund specialistAgent: name, instructions and tools
handoffs=[refund] on the deskHandoffs: passing control to another agent
result.last_agent to read who answeredRunner and the RunResult object

The refund specialist

The specialist is a second Agent. It only handles refunds, so its instructions say so.

python
refund = Agent(
    name="Refund specialist",
    instructions="Handle refund requests.",
    model=ShopModel(),
)

The desk that can hand off

The desk lists the specialist in handoffs. That turns the specialist into a transfer target the model can pick.

python
desk = Agent(
    name="Shop desk",
    instructions="Help shoppers; send refunds to the specialist.",
    tools=[lookup_order],
    handoffs=[refund],   # the desk may transfer to this agent
    model=ShopModel(),
)

Reading who answered

After the run, result.last_agent is whichever agent produced the final answer.

python
result = Runner.run_sync(desk, "I want a refund")
print("Answered by:", result.last_agent.name)
print("Reply:", result.final_output)

The desk handing a refund to the specialist

The desk starts the run, the word refund triggers the transfer, and the specialist finishes it.

Example
from agents import Agent, Runner, function_tool, set_tracing_disabled
from shop_model import ShopModel
set_tracing_disabled(True)

@function_tool
def lookup_order(order_id: str) -> str:
    "Look up an order by its id."
    return f"Order {order_id}: shipped on 3 March, arriving 7 March."

refund = Agent(
    name="Refund specialist",
    instructions="Handle refund requests.",
    model=ShopModel(),
)
desk = Agent(
    name="Shop desk",
    instructions="Help shoppers; send refunds to the specialist.",
    tools=[lookup_order],
    handoffs=[refund],
    model=ShopModel(),
)
result = Runner.run_sync(desk, "I want a refund")
print("Answered by:", result.last_agent.name)
print("Reply:", result.final_output)

What the handoff produced

  • The stand-in saw the word refund and returned a call to the specialist's transfer tool rather than a reply.
  • result.last_agent.name is Refund specialist, so control moved off the desk for the rest of the run.
  • The reply was composed by the specialist after the transfer, from its own refund instructions, so it reads as a refund answer and not as the desk's; Swapping in a real model puts a real model behind the same specialist.

Handoff vs one agent for everything

ApproachWhat happens
One desk handles refunds tooRefund rules crowd the desk's instructions and every tool sits on one agent
Handoff to a specialistEach agent stays focused; result.last_agent tells you who took over

When to hand off

  • A task with its own rules or tools, a refund, a cancellation, a fraud check, is cleaner as a separate agent.
  • You want the transcript to show which agent handled a request.
Watch out. A handoff hands over the whole conversation, not one message. After the transfer the specialist owns every following turn until it hands back or the run ends.
Try it yourself
  • Send an order question instead and confirm last_agent.name stays Shop desk.
  • Rename the specialist and watch the printed agent name change.
  • Add a second specialist to handoffs and see the stand-in still picks the first on the word refund.

Little by little, you're building something great.