Course Content
AutoGen Essentials
7 sections · 28 lessons
How do you implement turn-taking and stopping conditions in AutoGen group chats?
What you need to know
Turn-taking options in 0.4+
| Team | Who speaks next | Extra model call per turn? | Good for |
|---|---|---|---|
RoundRobinGroupChat | Fixed order | No | Writer and reviewer pairs, fixed pipelines |
SelectorGroupChat | An LLM reads descriptions and history | Yes (unless selector_func decides) | Open tasks where the order varies |
Swarm | The current agent hands off with a HandoffMessage | No | Support desks, where the current agent knows who is next |
GraphFlow | Edges in a directed graph, with conditions | No | Known workflows with branches and loops (experimental) |
MagenticOneGroupChat | An orchestrator agent with a plan and progress ledger | Yes | Open-ended web, file and code tasks |
SelectorGroupChat extras: selector_prompt (template with {roles}, {participants}, {history}), allow_repeated_speaker (default False), candidate_func to narrow who may be picked, and selector_func returning an agent name or None to fall back to the model.
Stopping conditions in 0.4+
| Condition | Stops when |
|---|---|
TextMentionTermination("X", sources=[...]) | Text X appears (optionally only from named agents) |
MaxMessageTermination(n) | n messages have been produced |
TokenUsageTermination(max_total_token=...) | Token budget is used |
TimeoutTermination(timeout_seconds=...) | Time runs out |
HandoffTermination(target="user") | An agent hands off to that target |
SourceMatchTermination(["agent"]) | A named agent has spoken |
FunctionCallTermination("fn") | A named tool has run |
ExternalTermination() | Your code calls .set() |
Example: travel team with code-first routing
1from autogen_agentchat.teams import SelectorGroupChat2from autogen_agentchat.conditions import TextMentionTermination, MaxMessageTermination34def route(messages):5 last = messages[-1]6 if last.source == "user":7 return "planner" # planner always starts8 if last.source in ("flights", "hotels"):9 return "planner" # workers report back to the planner10 return None # otherwise let the LLM choose1112team = SelectorGroupChat(13 [planner, flights, hotels],14 model_client=client,15 selector_func=route,16 termination_condition=TextMentionTermination("FINAL PLAN", sources=["planner"])17 | MaxMessageTermination(16),18)The code handles the predictable moves for free; the LLM only chooses when the planner has spoken and could need either worker.
Legacy 0.2
GroupChat(speaker_selection_method=...) took "auto" (the manager's LLM picks), "round_robin", "random", "manual" (a human picks) or a callable f(last_speaker, groupchat). allowed_or_disallowed_speaker_transitions with speaker_transitions_type="allowed" restricted who could follow whom, allow_repeat_speaker controlled repeats, and max_round capped the chat.
A real-life example
The travel startup first used plain SelectorGroupChat for planner, flights and hotels. The selector made one extra model call per turn, about 1,200 tokens each, and sometimes picked hotels right after the user's first message, before any dates were fixed.
Adding the route function above fixed the order for the obvious cases. Selector calls fell by about 60%, runs got 5 seconds faster, and the "hotel before dates" bug disappeared. The termination condition listens only to the planner, so a worker saying "final plan" in passing no longer stops the run.
Follow-up questions to expect
- "When would you choose round robin over a selector?" — When the order is always the same, such as write then review. It is cheaper and fully predictable.
- "How do you pause for a human and resume?" — End the run with
HandoffTermination(target="user")ormax_turns=1, show the output, then callteam.run(task=reply)again. The team keeps its history until you callreset(). - "What happens if the selector returns an invalid name?" —
SelectorGroupChatretries up tomax_selector_attempts(default 3), then falls back to the previous speaker or the first participant.