Categories: FAANG

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

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
<ListValue: [StructValue([(‘title’, ‘$300 in free credit to try Google Cloud AI and ML’), (‘body’, <wagtail.rich_text.RichText object at 0x3ec443549820>), (‘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: 

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

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 coordinatorrnroot_agent = LlmAgent(rn model=’gemini-2.0-flash’,rn name=”TripPlanner”,rn instruction=f”””rn Acts as a comprehensive trip planner.rn – Use the FlightAgent to find and book flightsrn – Use the HotelAgent to find and book accommodationrn – Use the SightSeeingAgent to find information on places to visitrn …rn “””,rn sub_agents=[flight_agent, hotel_agent, sightseeing_agent] # The coordinator manages these sub-agentsrn)’), (‘language’, ‘lang-py’), (‘caption’, <wagtail.rich_text.RichText object at 0x3ec443096640>)])]>

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_toolrnrn# Convert specialized agents into AgentToolsrnflight_tool = agent_tool.AgentTool(agent=flight_agent)rnhotel_tool = agent_tool.AgentTool(agent=hotel_agent)rnsightseeing_tool = agent_tool.AgentTool(agent=sightseeing_agent)rnrn# Root agent now uses these agents as toolsrnroot_agent = LlmAgent(rn model=’gemini-2.0-flash’,rn name=”TripPlanner”,rn instruction=f”””Acts as a comprehensive trip planner…rn Based on the user request, sequentially invoke the tools to gather all necessary trip details…”””,rn tools=[flight_tool, hotel_tool, sightseeing_tool] # The root agent can use these toolsrn)’), (‘language’, ‘lang-py’), (‘caption’, <wagtail.rich_text.RichText object at 0x3ec4430969d0>)])]>

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, ParallelAgentrnrn# 1. Create a parallel agent for concurrent tasksrnplan_parallel = ParallelAgent(rn name=”ParallelTripPlanner”,rn sub_agents=[flight_agent, hotel_agent], # These run in parallelrn)rnrn# 2. Create a summary agent to gather resultsrntrip_summary = LlmAgent(rn name=”TripSummaryAgent”,rn instruction=”Summarize the trip details from the flight, hotel, and sightseeing agents…”,rn output_key=”trip_summary”)rnrn# 3. Create a sequential agent to orchestrate the full workflowrnroot_agent = SequentialAgent(rn name=”PlanTripWorkflow”,rn # Run tasks in a specific order, including the parallel steprn sub_agents=[sightseeing_agent, plan_parallel, trip_summary])’), (‘language’, ‘lang-py’), (‘caption’, <wagtail.rich_text.RichText object at 0x3ec4430961c0>)])]>

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:

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 standardsrntrip_summary_reviewer = LlmAgent(rn name=”TripSummaryReviewer”,rn instruction=f”””Review the trip summary in {{trip_summary}}.rn If the summary meets quality standards, output ‘pass’. If not, output ‘fail'”””,rn output_key=”review_status”, # Writes its verdict to a new keyrn)rnrn# Custom agent to check the status and provide feedbackrnrnclass ValidateTripSummary(BaseAgent):rn async def _run_async_impl(self, ctx: InvocationContext) -> AsyncGenerator[Event, None]:rn status = ctx.session.state.get(“review_status”, “fail”)rn review = ctx.session.state.get(“trip_summary”, None)rn if status == “pass”:rn yield Event(author=self.name, content=Content(parts=[Part(text=f”Trip summary review passed: {review}”)]))rn else:rn yield Event(rn content=Content(parts=[Part(author=self.name,rn text=”Trip summary review failed. Please provide a valid requirements”)]))rnValidateTripSummaryAgent = ValidateTripSummary(rn name=”ValidateTripSummary”,rn description=”Validates the trip summary review status and provides feedback based on the review outcome.”,)rnrn# The final, self-regulating workflowrnroot_agent = SequentialAgent(rn name=”PlanTripWorkflow”,rn sub_agents=[rn sightseeing_agent,rn plan_parallel,rn trip_summary,rn trip_summary_reviewer,rn ValidateTripSummaryAgent() # The final validation step rn])’), (‘language’, ”), (‘caption’, <wagtail.rich_text.RichText object at 0x3ec443096df0>)])]>

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:

AI Generated Robotic Content

Recent Posts

Fine-tuning SDXL with childhood pictures → audio-reactive geometries – [Experiment]

After a deeply introspective and emotional journey, I fine-tuned SDXL using old family album pictures…

14 hours ago

Beyond Accuracy: 5 Metrics That Actually Matter for AI Agents

AI agents , or autonomous systems powered by agentic AI, have reshaped the current landscape…

14 hours ago

Apple Workshop on Reasoning and Planning 2025

Reasoning and planning are the bedrock of intelligent AI systems, enabling them to plan, interact,…

14 hours ago

MediaFM: The Multimodal AI Foundation for Media Understanding at Netflix

Avneesh Saluja, Santiago Castro, Bowei Yan, Ashish RastogiIntroductionNetflix’s core mission is to connect millions of members…

14 hours ago

Scaling data annotation using vision-language models to power physical AI systems

Critical labor shortages are constraining growth across manufacturing, logistics, construction, and agriculture. The problem is…

14 hours ago

Start Your Surround Sound Journey With $50 off This Klipsch Soundbar

This soundbar is just the beginning, with the option to add wireless bookshelf speakers or…

15 hours ago