Skip to content

Multi-Agent Handoff

%%{init: {'look': 'handDrawn', 'theme': 'base', 'themeVariables': {'primaryColor': '#eef2ff', 'primaryBorderColor': '#1e40af', 'primaryTextColor': '#1e293b', 'lineColor': '#1e3a8a', 'edgeLabelBackground': '#ffffff', 'clusterBkg': '#fbfcff', 'clusterBorder': '#2563eb', 'fontFamily': '-apple-system, system-ui, Segoe UI, Roboto, Helvetica, Arial, sans-serif', 'fontSize': '15px'}, 'flowchart': {'nodeSpacing': 50, 'rankSpacing': 58, 'padding': 14, 'htmlLabels': true, 'curve': 'basis'}}}%%
flowchart LR
  R(["Customer request"]) --> S("Supervisor")

  subgraph team["specialists · the model picks one"]
    direction TB
    B("Billing")
    T("Technical")
    L("Sales")
  end

  S --> B
  S --> T
  S --> L
  B --> O(["Answer"])
  T --> O
  L --> O
  style team stroke-dasharray: 6 5

Outcome: one supervisor agent fronts a team of specialists. The supervisor's model sees each specialist as a callable tool and delegates; each delegation is its own durable execution.

How it works

  • Sub-agents become tools. With Strategy.HANDOFF the supervisor's model chooses one by name.
  • Each specialist keeps its own tools and instructions, so their reach stays separate.
  • Every delegation is a durable execution. A specialist can retry without re-running the routing decision.

Handoff strategies

strategy= accepts any of these. The values come from Strategy in the SDK:

Strategy What the parent does
handoff The model picks one sub-agent and hands the conversation over
router The model classifies the request and routes it, without conversing
sequential Runs sub-agents in order, each seeing the previous output
parallel Runs all sub-agents at once and collects every answer
swarm Sub-agents pass control between themselves until one finishes
round_robin Takes the next sub-agent in rotation
random Picks a sub-agent at random — useful for A/B comparison
plan_execute Plans a sequence of sub-agent calls, then executes and replans
manual You choose the sub-agent in code, not the model

Prerequisites

A Conductor server with an LLM provider, and CONDUCTOR_SERVER_URL set.

The agents

Save this as agent_handoff.py:

"""Multi-agent handoff — a supervisor delegates to the specialist that fits.

Derived from sdk/python-sdk/examples/agents/05_handoffs.py.

With Strategy.HANDOFF the sub-agents are exposed to the supervisor's model as
callable tools, and the model picks one. Each delegation is its own durable
Conductor execution, so a specialist can retry without re-running the router.
"""

from conductor.ai.agents import Agent, AgentRuntime, Strategy, tool

MODEL = "openai/gpt-4o-mini"


@tool
def check_balance(account_id: str) -> dict:
    """Check the balance of a bank account."""
    return {"account_id": account_id, "balance": 5432.10, "currency": "USD"}


@tool
def lookup_order(order_id: str) -> dict:
    """Look up the status of an order."""
    return {"order_id": order_id, "status": "shipped", "eta": "2 days"}


@tool
def get_pricing(product: str) -> dict:
    """Get pricing information for a product."""
    return {"product": product, "price": 99.99, "discount": "10% off"}


billing = Agent(
    name="billing",
    model=MODEL,
    instructions="You handle billing questions: balances, payments, invoices.",
    tools=[check_balance],
)

technical = Agent(
    name="technical",
    model=MODEL,
    instructions="You handle technical questions: order status, shipping, returns.",
    tools=[lookup_order],
)

sales = Agent(
    name="sales",
    model=MODEL,
    instructions="You handle sales questions: pricing, products, promotions.",
    tools=[get_pricing],
)

support = Agent(
    name="support_supervisor",
    model=MODEL,
    instructions="Route each request to the right specialist: billing, technical, or sales.",
    agents=[billing, technical, sales],
    strategy=Strategy.HANDOFF,
)


if __name__ == "__main__":
    with AgentRuntime() as runtime:
        result = runtime.run(support, "What's the balance on account ACC-123?")
        result.print_result()
        print("execution id:", result.execution_id)

Run it

python agent_handoff.py

Asking for an account balance routes to billing, which calls check_balance. Open Executions to see the supervisor and the chosen specialist as separate executions.

The same example in other SDKs

The agent API is the same shape in every SDK. These are the upstream sources this recipe was derived from:

SDK Example
Python 05_handoffs.py
Java Example05Handoffs.java
TypeScript 05-handoffs.ts
C# Program.cs

Production notes

  • Specialist instructions are the routing signal. Overlapping descriptions cause wrong handoffs.
  • Scope each specialist's tools separately. A billing agent should not reach order-fulfilment tools.
  • Pick the strategy for the shape of the problem, not for novelty — router is cheaper than handoff when no conversation is needed.
  • Bound each specialist independently so one can't consume the whole budget.
  • Handoff decisions are model output. Log which specialist ran and why.