Course Content
AutoGen Essentials
7 sections · 28 lessons
How do you route tasks dynamically to different agents based on intent or confidence?
What you need to know
Three routing styles
| Style | AutoGen 0.4+ | Who decides | Best when |
|---|---|---|---|
| Central router | SelectorGroupChat (+ selector_func, candidate_func) | A selector model or your code | Many possible next steps, one coordinator |
| Handoffs | Swarm with handoffs=[...] | The current agent | The current agent knows who should take over |
| Fixed graph | GraphFlow with conditional edges | Your edges | The paths are known in advance |
Legacy 0.2 used a custom speaker_selection_method callable and allowed_or_disallowed_speaker_transitions.
Code first, model second
1def route(messages):2 last = messages[-1]3 if last.source != "user":4 return None # let the selector model decide5 text = last.to_text().lower()6 if any(w in text for w in ("refund", "chargeback", "money back")):7 return "billing"8 if any(w in text for w in ("router", "no internet", "slow speed")):9 return "tech"10 return None # unclear: model picks1112team = SelectorGroupChat([billing, tech, general], model_client=client,13 selector_func=route, termination_condition=stop)Handoffs with Swarm
1from autogen_agentchat.teams import Swarm2from autogen_agentchat.conditions import HandoffTermination, MaxMessageTermination34triage = AssistantAgent("triage", model_client=client,5 handoffs=["billing", "tech", "user"],6 system_message="Work out the issue. Hand off to billing or tech. "7 "If unsure, hand off to user with one clarifying question.")8team = Swarm([triage, billing, tech],9 termination_condition=HandoffTermination(target="user")10 | MaxMessageTermination(15))Each entry in handoffs becomes a tool like transfer_to_billing. When the model calls it, a HandoffMessage moves control. Handing off to "user" stops the run so your app can ask the customer and resume.
Confidence that means something
A model saying "confidence: 0.9" is not calibrated. Better signals:
- A small intent classifier's probability, and the gap between the top two intents.
- Whether required fields were found (order id, phone number).
- Retrieval scores for the question against each specialist's knowledge base.
High confidence goes straight to the specialist. Low confidence or a narrow gap goes to a generalist that asks one clarifying question, or to a human.
A real-life example
An e-commerce customer-support triage team handled 20,000 chats a day with a plain SelectorGroupChat. The selector call added about 700 ms and ₹0.05 per turn, and 8% of chats went to the wrong specialist first, for example "my refund for the broken phone" went to tech because it mentioned a phone.
They added a keyword selector_func and a small classifier on the first message. Chats where the classifier was above 0.85 and ahead of the runner-up by 0.3 routed directly (72% of traffic). The rest used the LLM selector, and messages with no order id went to general to ask for one. Mis-routes fell to 2.5%, and they added a hop cap: after three handoffs, the chat goes to a human.
Follow-up questions to expect
- "Selector or Swarm?" — Selector when a coordinator should see the whole picture; Swarm when each specialist knows its own limits and the next owner.
- "How do you debug mis-routing?" — Log each selection with the candidates and the last message; most fixes are better
descriptiontext or a new rule inselector_func. - "What stops handoff loops?" — A hop cap, a
MaxMessageTermination, and a fallback to a human after N transfers.