Lesson 08 A Triage-and-Handoff Agent
Theme:
Lesson 08 · Slide 1

Lesson 08 — A Triage-and-Handoff Agent

The OpenAI Agents SDK at its sweet spot: one triage front door, three specialists, ~120 lines of Python.

Agents Module 4 OpenAI Agents SDK Handoffs

Lesson 08 · Slide 2

Why this is the SDK's sweet spot

Hits every condition on L07 Slide 11's “Pick it when” list.

Lesson 08 · Slide 3

The system we're building

Goal

A customer-support triage agent that classifies an incoming ticket and hands off to one of three specialists — Billing, Technical, or Account — each of whom resolves the request using its own small toolset.

Real example ticket: “My invoice for March is double what I expected and the auto-renewal won't turn off.”

The triage agent reads the ticket once and routes — the work happens inside the specialist that picks it up.

Lesson 08 · Slide 4

The four agents

AgentInstructions in one lineTools
triageRead the ticket, hand off to the best specialist.(none — only handoffs)
billingResolve billing tickets.lookup_invoice, issue_refund
technicalResolve technical / outage tickets.check_service_status, open_incident
accountResolve account / auth tickets.lookup_account, reset_password
Lesson 08 · Slide 5

The mocked toolset

Notes: Keep the tool surface stable; swap implementations later. The handoff topology never has to change.
Lesson 08 · Slide 6

The triage instructions

You are the front-line triage agent for customer support. Read the ticket
and decide which specialist should handle it:
  - billing / refunds / invoices  -> hand off to Billing.
  - outage / errors / "not working" -> hand off to Technical.
  - login / password / account access -> hand off to Account.
Do NOT try to resolve the ticket yourself. Hand off on the first turn.

Triage's only job is routing. It has zero tools — the only thing it can do is call one of the three synthetic transfer_to_* handoff tools.

Lesson 08 · Slide 7

The handoff wiring

triage = Agent(
    name="Triage",
    instructions=TRIAGE_INSTRUCTIONS,
    model="gpt-4o-mini",
    handoffs=[billing, technical, account],
    input_guardrails=[block_pii],
)

Three handoff targets become three synthetic tools on triage: transfer_to_billing, transfer_to_technical, transfer_to_account. The LLM picks one per ticket.

Lesson 08 · Slide 8

The PII input guardrail

Lesson 08 · Slide 9

A real run trace

ticket: "My invoice for March is double what I expected..."
[step 1] agent=Triage     tools=[transfer_to_billing]
[handoff] Triage -> Billing
[step 2] agent=Billing    tools=[lookup_invoice]
[step 3] agent=Billing    tools=[issue_refund]
[step 4] agent=Billing    tools=[]                     (final_output)

Turn 1 is purely a handoff; the work happens in turns 2–4 inside the Billing agent. result.last_agent.name == "Billing".

Lesson 08 · Slide 10

The Pydantic output type

class Resolution(BaseModel):
    ticket_summary: str
    specialist: str          # 'billing' | 'technical' | 'account'
    actions_taken: list[str]
    follow_up_needed: bool

Applied to each specialist agent via output_type=Resolution. Triage doesn't need one — it just hands off; whichever specialist answers fills in the type.

Lesson 08 · Slide 11

The last_agent audit trail

Lesson 08 · Slide 12

Cost and latency profile

Lesson 08 · Slide 13

What's left to wire (Module 6 hook)

Cross-framework scorecard

Plan F (Module 6) wires this exact agent.py into agents/_eval/run_all.py as the OpenAI SDK row of the cross-framework scorecard.

The same shape of agent (triage + 3 specialists) gets rebuilt-in-spirit across the other frameworks: Claude SDK does it with a single-agent + tool-discriminator, LangGraph as a routed DAG, CrewAI as a crew of role-based agents.

Apples-to-apples comparison in Module 6.

Lesson 08 · Slide 14

Recap & what's next

Coming up: Module 5 — CrewAI. Same end-goal as a crew of role-based agents working together, not handing off.
1 / ?