Chapter 10 · Team Advanced: Shared State and Member Communication
Learning objectives: Master switching between the four collaboration modes, learn the correct posture for shared session state across members, and observe team-internal division of labor through streaming events.
10.1 Four Collaboration Modes Overview
Last chapter we used mode=TeamMode.coordinate to let the leader dispatch tasks. Agno explicitly exposes four collaboration styles (from agno.team.mode import TeamMode):
| Mode | Config | Behavior |
|---|---|---|
| Coordinate (default) | Omit mode or set coordinate | Leader picks members, rewrites tasks, synthesizes results |
| Route | mode=TeamMode.route | Leader routes to one member, returns that member's reply directly |
| Broadcast | mode=TeamMode.broadcast | Same task sent to all members |
| Tasks | mode=TeamMode.tasks | Leader maintains a shared task list, looping until completion |
On legacy parameters
Old versions' respond_directly=True and delegate_to_all_members=True remain compatible (mapping to route and broadcast respectively), but new code should always use mode= — when both appear, mode overrides the legacy flags.
10.2 Route Mode: Direct-to-Reply
Customer-service triage, language routing — scenarios where the leader doesn't need to process the result further. Route mode has the lowest latency:
import os
from agno.agent import Agent
from agno.models.openai import OpenAIChat
from agno.team import Team, TeamMode
model = OpenAIChat(
id="deepseek-chat",
api_key=os.getenv("DEEPSEEK_API_KEY"),
base_url="https://api.deepseek.com/v1",
)
billing_agent = Agent(name="Billing Agent", role="Handle billing and refund issues", model=model)
tech_agent = Agent(name="Tech Agent", role="Handle technical fault issues", model=model)
router_team = Team(
name="Customer Router",
model=model,
mode=TeamMode.route,
members=[billing_agent, tech_agent],
# Key switch: pass user's original input verbatim to members; don't let the leader rewrite
determine_input_for_members=False,
instructions=["Route the request to the most suitable member; answer yourself if unsure."],
)
router_team.print_response("My order was charged twice", stream=True)determine_input_for_members=False is an important detail in route mode: without it, the leader still "polishes" the task description by default, which introduces distortion in scenarios requiring passthrough.
10.3 Broadcast and Tasks Modes
Broadcast suits "multi-perspective parallel review"; task loops suit goal-driven long flows:
from agno.team import Team, TeamMode
# Broadcast: three reviewers each receive the same draft
review_team = Team(
name="Review Panel",
model=model,
mode=TeamMode.broadcast, # Same task to each member
members=[
Agent(name="Legal Reviewer", role="Review from compliance perspective", model=model),
Agent(name="UX Reviewer", role="Review from user-experience perspective", model=model),
Agent(name="SEO Reviewer", role="Review from search-optimization perspective", model=model),
],
instructions="Synthesize all member opinions into a single merged revision checklist.",
)
# Task loop: leader decomposes a task list and advances item by item
ops_team = Team(
name="Ops Team",
model=model,
mode=TeamMode.tasks,
max_iterations=6, # Cap the task loop iterations to prevent runaway token burn
members=[tech_agent, billing_agent],
)Always set max_iterations in Tasks mode: the task list is generated and checked off by the model; an uncapped loop is equivalent to handing your budget to the model.
10.4 Shared Session State Across Members
To let multiple members collaborate around the same mutable state (e.g., jointly maintaining a shopping list), the core is three things: declare session_state on the team, enable add_session_state_to_context, and share the same database between team and members:
import os
from agno.agent import Agent
from agno.db.sqlite import SqliteDb
from agno.models.openai import OpenAIChat
from agno.team import Team
db = SqliteDb(db_file="tmp/team.db")
model = OpenAIChat(
id="deepseek-chat",
api_key=os.getenv("DEEPSEEK_API_KEY"),
base_url="https://api.deepseek.com/v1",
)
shopping_agent = Agent(
id="shopping-agent",
name="Shopping List Agent",
role="Manage the shopping list",
model=model,
db=db, # Must share the same db as the team to share sessions
add_session_state_to_context=True, # Let members see session state
enable_agentic_state=True, # Allow members to autonomously modify state in conversation
)
team = Team(
name="Household Team",
members=[shopping_agent],
session_state={"shopping_list": []}, # Initial shared state
db=db,
add_session_state_to_context=True,
enable_agentic_state=True,
description="You are a team that manages shopping lists and household tasks",
show_members_responses=True,
)
team.print_response("Add milk, eggs, and bread to the shopping list")
team.print_response("I already bought eggs; what's still on the list?")
print(f"Final state: {team.get_session_state()}")Another lightweight trick is template injection — state variables can be written directly into instructions and are auto-replaced at runtime:
team = Team(
members=[],
session_state={"user_name": "Xiaoming"},
instructions="The user's name is {user_name}; address them by name.",
markdown=True,
)10.5 Observing the Division of Labor: Streaming Events and Member Responses
The key to debugging a team is seeing "who is doing what." Three techniques work together:
team = Team(
name="Research Team",
model=model,
members=[news_agent, finance_agent],
markdown=True,
show_members_responses=True, # Attach each member's raw reply in the final output
)
# With stream=True you can observe the full leader-dispatch → member-execute → leader-synthesize process
for event in team.run("What are the recent AI company moves and NVDA stock performance?", stream=True):
print(event) # Member start, tool calls, content increments all have corresponding eventsThree supporting best practices:
- Set explicit
ids on members: dispatch selection and run tracking both use member id — more stable than relying on name; - Model inheritance: when a member doesn't set
model, it automatically inherits the team's model — letting you "members use small models, leader uses a large model" with a single omission; - Callable factories:
members=can accept functions that dynamically decide the lineup based onsession_stateat each run (remember to setcache_callables=False).
10.6 Chapter Summary
- New code统一用
mode=TeamMode.coordinate/route/broadcast/tasks; legacy flagrespond_directlyis superseded by the override mechanism; - Route mode with
determine_input_for_members=Falsepassthroughs user input verbatim; - Full conditions for shared state: team and members share
db+ both haveadd_session_state_to_context=True+enable_agentic_state=Truewhen autonomous modification is needed; - Instructions support
{var}template injection from session state; show_members_responses+ streaming events + explicit memberids are the three-pronged approach to observing team division of labor.
🧪 随堂测验
点击你认为正确的选项。答错时会展示正确答案与原因解析。
1. In Agno, to have "the leader only pick a member and return that member's reply directly", the recommended写法 is?
2. In route mode, to pass the user's original input through to members without rewriting, you should?
3. The minimal config to let members read and autonomously modify the team session state is?
4. Regarding Tasks mode, which statement is correct?
🛠️ Hands-On Exercises
- Use route mode to build a "Chinese/English/code question" three-way router; compare member input with and without the
determine_input_for_membersswitch. - Add a "cooking suggestion" member to the shopping list team from 10.4; verify both members can read entries written by the other.
- Enable
show_members_responses=Trueand run a coordinate-mode team withstream=True; record the event sequence (leader dispatch → member → synthesis) and write it as an observation note.
Next chapter brings "determinism" back: when the flow should not be improvised by the model on the fly, Workflow is the better orchestration tool.