Cloud Blog: How to build a simple multi-agentic system using Google’s ADK

Source URL: https://cloud.google.com/blog/products/ai-machine-learning/build-multi-agentic-systems-using-google-adk/
Source: Cloud Blog
Title: How to build a simple multi-agentic system using Google’s ADK

Feedly Summary: Agents are top of mind for enterprises, but often we find customers building one “super” agent – a jack of all trades – instead creating multiple agents that can specialize and work together. Monolithic agents often crumble under their own weight because of instruction overload, inaccurate outputs, and brittle systems that are impossible to scale. 
The good news: A team of specialized AI agents, each an expert in its domain, can deliver higher fidelity, better control, and true scalability.
The challenge: Building robust multi-agent workflows is complex. This is where Google’s Agent Development Kit (ADK) becomes essential. The ADK provides the framework to design, build, and orchestrate these sophisticated agentic systems, leveraging the power of Gemini. In this post, we’ll show you how you can build a multi-agentic workflow using ADK.

aside_block
), (‘btn_text’, ‘Start building for free’), (‘href’, ‘http://console.cloud.google.com/freetrial?redirectPath=/vertex-ai/’), (‘image’, None)])]>

Step 1: Create specialized agents 
Instead of one monolithic agent trying to do everything and getting confused, we’ll break the problem down. We’re building a team of focused specialist agents, each with clear instructions for a single job. In this case, we’ll take a travel example: 

FlightAgent: Knows only about flights.

HotelAgent: An expert in accommodation.

SightseeingAgent: A dedicated tour guide.

code_block
<ListValue: [StructValue([(‘code’, ‘from google.adk.agents import LlmAgent\r\n\r\n# Flight Agent: Specializes in flight booking and information\r\nflight_agent = LlmAgent(\r\n model=\’gemini-2.0-flash\’,\r\n name=”FlightAgent",\r\n description="Flight booking agent",\r\n instruction=f"""You are a flight booking agent… You always return a valid JSON…""")\r\n\r\n# Hotel Agent: Specializes in hotel booking and information\r\nhotel_agent = LlmAgent(\r\n model=\’gemini-2.0-flash\’,\r\n name="HotelAgent",\r\n description="Hotel booking agent",\r\n instruction=f"""You are a hotel booking agent… You always return a valid JSON…""")\r\n\r\n# Sightseeing Agent: Specializes in providing sightseeing recommendations\r\nsightseeing_agent = LlmAgent(\r\n model=\’gemini-2.0-flash\’,\r\n name="SightseeingAgent",\r\n description="Sightseeing information agent",\r\n instruction=f"""You are a sightseeing information agent… You always return a valid JSON…""")’), (‘language’, ‘lang-py’), (‘caption’, <wagtail.rich_text.RichText object at 0x3ebb500b8760>)])]>

To manage these specialists, build a coordinator workflow. Then, create a TripPlanner root agent whose only job is to understand a user’s request and route it to the correct specialist.

code_block
<ListValue: [StructValue([(‘code’, ‘# Root agent acting as a Trip Planner coordinator\r\nroot_agent = LlmAgent(\r\n model=\’gemini-2.0-flash\’,\r\n name="TripPlanner",\r\n instruction=f"""\r\n Acts as a comprehensive trip planner.\r\n – Use the FlightAgent to find and book flights\r\n – Use the HotelAgent to find and book accommodation\r\n – Use the SightSeeingAgent to find information on places to visit\r\n …\r\n """,\r\n sub_agents=[flight_agent, hotel_agent, sightseeing_agent] # The coordinator manages these sub-agents\r\n)’), (‘language’, ‘lang-py’), (‘caption’, <wagtail.rich_text.RichText object at 0x3ebb500b8fd0>)])]>

While this works beautifully for simple queries (e.g., "Find me a flight to Paris" is immediately dispatched to the FlightAgent), a new problem quickly becomes apparent. When asked, "Book a flight to Paris and then find a hotel," the coordinator calls the FlightAgent and stops.  It has done its job of routing the initial request, but it cannot orchestrate a multi-step workflow. The manager is a great receptionist but a poor project manager
This limitation stems from how the system handles sub-agents. When the Root Agent calls the Flight Agent as a sub-agent, the responsibility for answering the user is completely transferred to the Flight Agent. The Root Agent is effectively out of the loop. All subsequent user input will be handled solely by the Flight Agent. This often leads to incomplete or irrelevant answers because the broader context of the initial multi-step request is lost, directly reflecting why the manager struggles as a "project manager" in these scenarios.
Step 2: Give your coordinator tools 
The coordinator needed an upgrade. It shouldn’t just forward a request; it needed the ability to use its specialists to complete a bigger project. This led to the next evolution: the Dispatcher Agent with Agent Tools.
Instead of treating the specialists as destinations, we will treat them as tools in the root agent’s toolbox. The root agent could then reason about a complex query and decide to use multiple tools to get the job done.
Using the ADK, the specialized agents are converted into AgentTools.

code_block
<ListValue: [StructValue([(‘code’, ‘from google.adk.agents import agent_tool\r\n\r\n# Convert specialized agents into AgentTools\r\nflight_tool = agent_tool.AgentTool(agent=flight_agent)\r\nhotel_tool = agent_tool.AgentTool(agent=hotel_agent)\r\nsightseeing_tool = agent_tool.AgentTool(agent=sightseeing_agent)\r\n\r\n# Root agent now uses these agents as tools\r\nroot_agent = LlmAgent(\r\n model=\’gemini-2.0-flash\’,\r\n name="TripPlanner",\r\n instruction=f"""Acts as a comprehensive trip planner…\r\n Based on the user request, sequentially invoke the tools to gather all necessary trip details…""",\r\n tools=[flight_tool, hotel_tool, sightseeing_tool] # The root agent can use these tools\r\n)’), (‘language’, ‘lang-py’), (‘caption’, <wagtail.rich_text.RichText object at 0x3ebb500b8370>)])]>

This is a game-changer. When the complex query "Book a flight to Paris and then find a hotel" is run, the root agent understands and it intelligently calls the flight_tool, gets the result, and then calls the hotel_tool. It can also suggest two top places to visit using Sightseeing_tool. The to-and-fro communication between the root agent and its specialist tools enabled a true multi-step workflow.
However, as the system worked, an inefficiency became noticeable. It found the flight, then it found the hotel. These two tasks are independent. Why couldn’t they be done at the same time?
Step 3: Implement parallel execution 
The system is smart, but it’s not as fast as it could be. For tasks that don’t depend on each other, they can be run concurrently to save time.
The ADK provides a ParallelAgent  for this. We use this to fetch flight and hotel details simultaneously. Then, a SequentialAgent is used to orchestrate the entire workflow. It first gets the sightseeing info , then "fan-out" to the parallel agent for flights and hotels, and finally, "gather" all the results with a TripSummaryAgent.

code_block
<ListValue: [StructValue([(‘code’, ‘from google.adk.agents import SequentialAgent, ParallelAgent\r\n\r\n# 1. Create a parallel agent for concurrent tasks\r\nplan_parallel = ParallelAgent(\r\n name="ParallelTripPlanner",\r\n sub_agents=[flight_agent, hotel_agent], # These run in parallel\r\n)\r\n\r\n# 2. Create a summary agent to gather results\r\ntrip_summary = LlmAgent(\r\n name="TripSummaryAgent",\r\n instruction="Summarize the trip details from the flight, hotel, and sightseeing agents…",\r\n output_key="trip_summary")\r\n\r\n# 3. Create a sequential agent to orchestrate the full workflow\r\nroot_agent = SequentialAgent(\r\n name="PlanTripWorkflow",\r\n # Run tasks in a specific order, including the parallel step\r\n sub_agents=[sightseeing_agent, plan_parallel, trip_summary])’), (‘language’, ‘lang-py’), (‘caption’, <wagtail.rich_text.RichText object at 0x3ebb500b8160>)])]>

We now have an optimized workflow. The system is now not only handling complex queries, but it is doing so efficiently. It is close to the finish line, but one final doubt remains. Is the final summary good? Does it always meet the strict quality guidelines?
Step 4: Create feedback loops 
A feedback loop is needed for the system to review its own work.
The idea is to add two more agents to the sequence:

TripSummaryReviewer: An agent whose only job is to evaluate the summary generated by the TripSummaryAgent. It checks for completeness and structure, outputting a simple "pass" or "fail."

ValidateTripSummaryAgent: A custom agent that checks the reviewer’s status and provides the final, validated output or an error message.

This pattern works by having agents communicate through a shared state. The TripSummaryAgent writes its output to the trip_summary key, and the TripSummaryReviewer reads from that same key to perform its critique.

code_block
<ListValue: [StructValue([(‘code’, ‘# Agent to check if the trip summary meets quality standards\r\ntrip_summary_reviewer = LlmAgent(\r\n name="TripSummaryReviewer",\r\n instruction=f"""Review the trip summary in .\r\n If the summary meets quality standards, output \’pass\’. If not, output \’fail\’""",\r\n output_key="review_status", # Writes its verdict to a new key\r\n)\r\n\r\n# Custom agent to check the status and provide feedback\r\n\r\nclass ValidateTripSummary(BaseAgent):\r\n async def _run_async_impl(self, ctx: InvocationContext) -> AsyncGenerator[Event, None]:\r\n status = ctx.session.state.get("review_status", "fail")\r\n review = ctx.session.state.get("trip_summary", None)\r\n if status == "pass":\r\n yield Event(author=self.name, content=Content(parts=[Part(text=f"Trip summary review passed: {review}")]))\r\n else:\r\n yield Event(\r\n content=Content(parts=[Part(author=self.name,\r\n text="Trip summary review failed. Please provide a valid requirements")]))\r\nValidateTripSummaryAgent = ValidateTripSummary(\r\n name="ValidateTripSummary",\r\n description="Validates the trip summary review status and provides feedback based on the review outcome.",)\r\n\r\n# The final, self-regulating workflow\r\nroot_agent = SequentialAgent(\r\n name="PlanTripWorkflow",\r\n sub_agents=[\r\n sightseeing_agent,\r\n plan_parallel,\r\n trip_summary,\r\n trip_summary_reviewer,\r\n ValidateTripSummaryAgent() # The final validation step \r\n])’), (‘language’, ”), (‘caption’, <wagtail.rich_text.RichText object at 0x3ebb500b8430>)])]>

With this final piece in place,, our AI system is no longer a single, confused genius but a highly efficient, self-regulating team of specialists. It can handle complex, multi-step queries with parallel execution for speed and a final review process for quality assurance.
Get started 
Ready to build your own multi-agent workflows? Here’s how to get started:

Explore project source code

Explore the Agent Development Kit documentation to dive deeper into its capabilities and features. 

Check out more ADK examples and tutorials on GitHub to see practical implementations.

AI Summary and Description: Yes

**Summary:**
The text discusses the development of specialized AI agents for enterprise applications using Google’s Agent Development Kit (ADK). It emphasizes the benefits of a multi-agent architecture over monolithic systems, highlighting how these specialized agents can efficiently handle complex workflows and improve scalability. Furthermore, the text introduces the concept of concurrent and sequential execution of tasks, as well as implementing feedback loops to ensure quality control in operations.

**Detailed Description:**
The content presents a detailed approach to building multi-agent systems tailored for specialized tasks in enterprises, particularly relevant for those involved in AI and infrastructure security.

– **Specialization Over Monoliths**:
– Highlights the issues with creating a single “super” agent that becomes overloaded and inefficient.
– Advocates for multiple focused agents, each responsible for a single aspect of a workflow (e.g., FlightAgent, HotelAgent, SightseeingAgent).

– **Agent Development Kit (ADK)**:
– Introduces Google’s ADK as an essential framework for designing and orchestrating these specialized agents.
– Allows for the construction of workflows that can adapt and expand as required, enhancing flexibility in complex environments.

– **Workflow Management**:
– **Coordinator Role**: The originally proposed root agent struggles with multi-step requests, indicating a need for orchestrating tasks more effectively.
– **Dispatcher Agent**: Defines the evolution from a simple coordinator to a Dispatcher Agent that can reason through complex requests and utilize specialized agent tools.

– **Efficiency Improvements**:
– Explains the implementation of parallel execution, allowing independent tasks (like booking a flight and a hotel) to occur simultaneously using a ParallelAgent to improve response times and overall efficiency.
– Discusses the eventual orchestration of the entire workflow with a SequentialAgent that organizes tasks in a logical sequence, culminating in the integration of a TripSummaryAgent.

– **Quality Assurance**:
– Introduces feedback loops with specific agents tasked to review and validate output after processing to maintain higher standards of accuracy and completeness.
– The final iteration incorporates multiple layers of review and validation ensuring the output meets strict quality criteria.

– **Practical Implementation**:
– Encourages professionals to utilize the ADK for building their own multi-agent systems, referencing resources for guidance and examples.

Overall, the text presents significant insights for professionals in AI development, particularly in the security aspects where reliable and efficient systems are critical. The focus on specialization, efficiency, and quality assurance in AI workflow management provides a roadmap for implementing robust multi-agent architectures in dynamic environments.