Skip to main content

Lab 19: Building a Collaborative Travel Team

Goalโ€‹

In this lab, you will build a Travel Planning Team consisting of a Coordinator, a Weather Specialist, and a Flight Booker. You will learn how to use the mode parameter to create a system where sub-agents fulfill specific tasks and then automatically return control to the main planner.

The Scenarioโ€‹

  • Coordinator receives the user's travel request.
  • It delegates to the Weather Specialist (in single_turn mode) to get a quick forecast.
  • It then delegates to the Flight Booker (in task mode) to find and "book" a flight (allowing for some back-and-forth about preferences).
  • Finally, the Coordinator synthesizes the plan.

Step 1: Create the Projectโ€‹

Environment setup:

  • Local machine: If you're continuing the course in sequence, cd into the adk-training project you created in Module 2 and skip the block below -- your environment and dependencies already carry forward. If you're starting fresh at this module, create that project first:
    uv init adk-training --python 3.10 && cd adk-training
    uv add "google-adk>=2.1.0" python-dotenv
  • DevContainer / Codespaces (Alternative): If you opened this repository in a DevContainer or GitHub Codespaces, Python, uv, and the core ADK dependencies are already pre-installed in your container environment.
uv run adk create travel_team
cd travel_team

Step 2: Implement the Collaborative Nodesโ€‹

Open agent.py. Your task is to define the team and configure their modes correctly.

Exercise: Complete the agent definitions by setting the appropriate mode for each specialist.

# In agent.py (Starter Code)
from google.adk import Agent

# Note: every agent below needs rerun_on_resume=True. Any node that's part
# of a sub_agents dispatch chain can be "woken up" when a task-mode
# sub-agent pauses and resumes across turns -- without the flag on ALL
# three agents (coordinator included), you'll hit:
# "ValueError: A node must have rerun_on_resume=True."

# 1. Define the Weather Specialist
# Hint: Use 'single_turn' mode for a quick, non-interactive lookup.
weather_agent = Agent(
name="weather_checker",
model="gemini-3.5-flash",
rerun_on_resume=True,
instruction="""
# TODO: Write instructions to provide a brief 3-day forecast
# for the requested destination.
"""
)

# 2. Define the Flight Booker
# Hint: Use 'task' mode to allow the agent to ask the user
# questions about their flight preferences before finishing.
flight_agent = Agent(
name="flight_booker",
model="gemini-3.5-flash",
rerun_on_resume=True,
instruction="""
# TODO: Write instructions to help the user book a flight.
# Ask about preferred airline or time if not provided.
"""
)

# 3. Define the Coordinator
# Hint: Coordinator should NOT have a mode set (it's the root), but it
# still needs rerun_on_resume=True (see note above).
root_agent = Agent(
name="travel_planner",
model="gemini-3.5-flash",
rerun_on_resume=True,
instruction="""
# TODO: Write instructions to coordinate the team.
# 1. Get weather from weather_checker.
# 2. Book flight via flight_booker.
# 3. Present the final cohesive plan.
""",
# TODO: Register your specialists here
sub_agents=[]
)

Step 3: Run and Testโ€‹

  1. Launch the Dev UI:
    uv run adk web .
  2. Verify the Flow:
    • Ask: "I want to go to Tokyo next week."
    • Observe: The travel_planner should call the weather_checker.
    • Observe: Then it should call the flight_booker. The flight booker might ask you "Which airline do you prefer?" or "Do you want a morning flight?". Keep answering -- it may take more than one exchange before it has everything it needs.
    • Final Check: Watch the Trace tab for the turn where flight_booker decides it's done: it calls the framework-injected finish_task tool, and control returns to travel_planner immediately, within that same turn -- not on a separate follow-up turn -- with no "hand-off" code written by you. travel_planner then presents the final combined plan in that same response.

Bonus (optional): Try rewiring weather_checker as an AgentTool instead of a sub_agents entry: drop mode="single_turn", remove it from sub_agents, and instead give travel_planner tools=[AgentTool(agent=weather_agent)] (import from google.adk.tools.agent_tool). Re-run the same request and compare the Trace tab: with AgentTool the whole weather lookup happens inside travel_planner's own function call -- there's no separate weather_checker author entry the way there was with mode="single_turn". Same call-and-return result, different plumbing.

Lab Summaryโ€‹

You have built a Collaborative Agent Team!

  • You used mode="single_turn" for background utility tasks.
  • You used mode="task" for interactive sub-tasks with automatic return.
  • You observed how the ADK 2.0 framework manages the hand-off lifecycle so you can focus on agent logic.

Self-Reflection Questionsโ€‹

  • Why would you use single_turn instead of task for a database lookup node?
  • What happens to the conversation history when a sub-agent is in task mode? (Hint: Check the Trace tab).
  • How does the mode setting improve the reliability of complex, multi-step workflows compared to standard chat mode?
  • In this lab, travel_planner consults two sub-agents (weather_checker, flight_booker) and combines their results, because both use mode="task"/"single_turn", which forces the return to the coordinator. Now imagine weather_checker and flight_booker were both RemoteA2aAgents -- separate services -- registered via a bare sub_agents=[...] with no mode set. What would happen the first time the coordinator delegated? What are two different ways to fix it?

๐Ÿ” Reference Solution Vaultโ€‹

๐Ÿ”

Module 19 Reference Solution Vault

Active Comprehension Gate โ€ข Zero Guessable URLs โ€ข Guided Verification

Step 1/3: Question 1 of 3

In Module 19 (Collaborative Teams), what is the primary role of peer-to-peer agent communication in ADK architectures?