AutoGen Essentials

Course Content

AutoGen Essentials

7 sections · 28 lessons

How do you route tasks dynamically to different agents based on intent or confidence?


Routing a support chat, cheapest check firstselector_funckeyword rulesClassifier:above 0.85and clear gapLLM selectorreads descriptionsGeneralagent asksone questionHuman afterthree handoffs72% of chats never reach the LLM selector.
Each step only sees the chats the cheaper step could not route, so the model's guess is the fallback, not the default.

What you need to know

Three routing styles

StyleAutoGen 0.4+Who decidesBest when
Central routerSelectorGroupChat (+ selector_func, candidate_func)A selector model or your codeMany possible next steps, one coordinator
HandoffsSwarm with handoffs=[...]The current agentThe current agent knows who should take over
Fixed graphGraphFlow with conditional edgesYour edgesThe 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

Python
def route(messages):    last = messages[-1]    if last.source != "user":        return None                          # let the selector model decide    text = last.to_text().lower()    if any(w in text for w in ("refund", "chargeback", "money back")):        return "billing"    if any(w in text for w in ("router", "no internet", "slow speed")):        return "tech"    return None                              # unclear: model picksteam = SelectorGroupChat([billing, tech, general], model_client=client,                         selector_func=route, termination_condition=stop)

Handoffs with Swarm

Python
from autogen_agentchat.teams import Swarmfrom autogen_agentchat.conditions import HandoffTermination, MaxMessageTerminationtriage = AssistantAgent("triage", model_client=client,    handoffs=["billing", "tech", "user"],    system_message="Work out the issue. Hand off to billing or tech. "                   "If unsure, hand off to user with one clarifying question.")team = Swarm([triage, billing, tech],             termination_condition=HandoffTermination(target="user")                                   | 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 description text or a new rule in selector_func.
  • "What stops handoff loops?" — A hop cap, a MaxMessageTermination, and a fallback to a human after N transfers.