In Swarm and the OpenAI Agents SDK, a handoff is just a tool whose return value is the next Agent. The runtime swaps the active agent and keeps the loop running; no orchestrator graph.
Picture a small restaurant with three specialists, a host, a server, and a chef, but no manager. The host greets you and, if you ask about the menu, hands you a card that says 'Talk to the server.' That card is the entire handoff mechanism. The host did not call a manager, did not send a message through a special channel, did not flag a transfer event. They just used a tool they already had (handing you a card) whose result happened to mean 'now this other person is talking to you.' Swarm bets that the simplest possible primitive, a normal tool that returns a person, is enough to coordinate the whole restaurant.
Concept explanation~2 min read
Everything you need to truly understand this topic: intuition, mechanics, step by step explanation, code, formulas, and worked example. Click to expand.
Concept explanation~2 min read
Everything you need to truly understand this topic: intuition, mechanics, step by step explanation, code, formulas, and worked example. Click to expand.
Swarm is one of the most instructive multi-agent frameworks to study even if you never ship it to production, because its design is a thesis statement: 'the LLM's tool-calling capability is already enough to do orchestration; you do not need to invent new primitives.' Either you agree with that thesis for your workload (Swarm fits) or you disagree (you reach for LangGraph, CrewAI, or AutoGen).
This deep dive covers the handoff mechanism in detail, the four things Swarm intentionally does not have, the design bet that motivates the minimalism, and the relationship between Swarm (the experimental package) and the OpenAI Agents SDK (the production evolution).
The handoff mechanism, in detail
Every Swarm Agent is constructed with name, instructions (which becomes the system prompt), and functions (a list of Python callables the agent can use as tools).
A handoff function is a regular Python function whose return type is Agent. By convention it is named transfer_to_<agent_name> and has a docstring describing when to call it.
The runtime loop
When client.run(agent=greeter, messages=[...]) is called, the loop is:
- The current agent's system prompt + the message history + the current agent's tool schemas are sent to the LLM.
- The LLM emits either a final assistant message (loop ends) or a tool call.
- If the tool call is a handoff (return type is
Agent), the runtime calls the function, gets the returned Agent, and sets it as the new current agent. - The tool call and its return value are appended to the shared message history.
- Loop continues with the new current agent reading the same history.
Why this is so minimal
No branching code in the orchestrator. No explicit edges between agents. No graph compile step. The runtime is roughly 'while current agent has not produced a final message, run the agent's tool-call loop, and swap the current agent if a tool returned one.' That is the entire mechanism.
Situations where this technique stops working.
2–4 min · Everything important, quickly.
from swarm import Swarm, Agent
def transfer_to_billing():
"""Hand off to the billing specialist when the user asks about invoices, refunds, or pricing."""
return billing
def transfer_to_tech():
"""Hand off to the tech specialist when the user reports a bug or asks how to use the product."""
return tech
greeter = Agent(
name="Greeter",
instructions="Greet the user, identify the topic, then hand off.",
functions=[transfer_to_billing, transfer_to_tech],
)
billing = Agent(name="Billing", instructions="Resolve billing questions.")
tech = Agent(name="Tech", instructions="Resolve technical questions.")
client = Swarm()
result = client.run(agent=greeter, messages=[{"role": "user", "content": "I was double-charged."}])
# greeter sees 'double-charged', calls transfer_to_billing(), runtime swaps in billing, loop continues.| Framework | Handoff mechanism | Orchestration primitive |
|---|---|---|
| Swarm / OpenAI Agents SDK | Tool returning an Agent | None. Model picks via tool call |
| LangGraph | Node + conditional edge / Supervisor pattern | StateGraph |
| CrewAI Hierarchical | Manager LLM delegates via `delegate` tool | Crew + manager_llm |
| AutoGen GroupChat | Manager picks via select_speaker | GroupChatManager |
Real products, models, and research that use this idea.
- OpenAI's original Swarm GitHub repository explicitly describes itself as 'educational' and 'experimental'. The design exists to teach a minimal orchestration pattern.
- The OpenAI Agents SDK (the productionised evolution of Swarm) inherits the handoff as tool pattern and adds typed inputs, tracing, and guardrails.
What an interviewer would ask next. Try answering before peeking at the approach.
QHow would you enforce a deterministic routing policy on top of Swarm handoffs?
Wrap the handoff tool in a Python shim that inspects state (intent classifier, rule table) and returns the chosen Agent. The model still calls the tool; the tool's return value is decided in code, not by the model.
Red flags & common mistakes
The phrases that signal junior thinking. Click to expand.
Red flags & common mistakes
The phrases that signal junior thinking. Click to expand.
Assuming Swarm needs an orchestrator graph or a transfer protocol. And missing the point that handoffs reuse the model's existing tool-calling capability with zero new orchestration primitives.
60 second bullets to scan on the way to the call.
The exact mechanism: tool returns Agent, runtime swaps active agent
Four things Swarm explicitly does NOT have (graph, event, role, transport)
Primary sources. Browse if you want the original framing.
Same topic, related formats. Practice these next.