Every agent framework eventually confronts the same problem: when you wire five agents together, the wiring itself becomes code that a language model can get wrong. Google’s Agent Development Kit answers with a pattern no other major framework ships as a first-class citizen — workflow agents that compose sub-agents with zero model calls. A SequentialAgent runs its children in order. A ParallelAgent fans out and merges their event streams. A LoopAgent iterates until an escalation event or a max iteration count, with a purpose-built exit tool the inner agent can call. The model never sees the control flow, because the control flow is Python. That idea anchors an Apache-2.0 codebase of unusual industrial polish: a runner that streams every intermediate event, a flow built from composable request processors, toolsets that filter themselves per request, a plugin system hooked into every lifecycle stage, and a fleet of swappable services for sessions, memory, artifacts, and authentication. It is the framework Google ships Gemini in, and reading it explains a lot about how Google thinks agents should be built.

The architecture reads as five strata. At the top, the Runner turns a new or resumed invocation into an event stream, coordinating session, artifact, and memory services as it goes. Agents form a small hierarchy — a base class owning the lifecycle, LlmAgent as the model-driven workhorse, and the workflow agents as deterministic composers — and every agent’s behavior flows through a processor chain in the flows package, where separate processors assemble identity, instructions, and contents, build tool declarations, and execute function calls. The model layer hides Gemini behind an interface that a registry resolves, with a three-thousand-seven-hundred-line LiteLLM bridge and a native Anthropic client standing in for the rest of the market. Services — sessions with state deltas, keyword-searched memory, versioned artifacts, OAuth credential exchange — arrive as interfaces with in-memory, SQLite, database, and Vertex implementations. And the edges are real product surfaces: a CLI that runs agents in the terminal, a FastAPI server behind adk web and adk api_server, an evaluation harness that scores trajectories from case files. As always in this series, what follows is an educational tour of published source code.

Google ADK overview architecture diagram

ADK at a glance: the runner drives the agent hierarchy and its workflow composers, every LLM agent runs through the processor-chain flow, toolsets and the model registry arm it, plugins hook the lifecycle, and session services plus the API server turn it into a deployed product.

Reading the overview from left to right:

  • The runner turns invocations into event streams and coordinates every state service.
  • The agent base owns the lifecycle every agent shares, callbacks included.
  • The LLM agent is the model-driven workhorse with instructions, tools and output schemas.
  • The workflow agents compose sub-agents deterministically as Sequential, Parallel and Loop.
  • The base flow runs the request processors, the model call, then the response processors.
  • The toolset contract groups tools with per-request filtering and auth wiring.
  • The LiteLLM bridge adapts a hundred providers onto the model interface.
  • The API server exposes runs, sessions and live audio over FastAPI.

Why You Need This

The first reason is the workflow agents, because they settle the framework argument about orchestration by refusing to let the model do it. The base class defines one async lifecycle — runAsync with an invocation context — that all agents share, so a ParallelAgent’s children are indistinguishable from a solo LlmAgent to whoever runs them. SequentialAgent is under two hundred lines because composition is genuinely that thin: it iterates children, threading session state between them. ParallelAgent merges child event branches so concurrent sub-agents stay attributable, and LoopAgent iterates until an escalation or cap, with the exit tool as the model’s one deliberate way out. The transfer between model-driven and deterministic layers is itself an interface: the transfer tool and the flow’s transfer processor let an LlmAgent hand control to a sibling, so you can mix “model decides” and “code decides” per subtree. For anyone who has debugged an agent that wander-routed through its own menu, this design is the alternative worth copying.

The second reason is the processor chain, because it decomposes the black box of “what does the model actually see.” The base flow runs a list of request processors before each model call and response processors after, and each processor is a readable module: the basic processors inject identity and static instructions, the functions processor builds tool declarations and executes requested calls, and the transfer processor appends routing instructions. The machinery underneath is honest about the hard parts — declaration building from type hints, argument coercion of model-produced JSON, the ToolContext that gives every tool a handle on state, artifacts, memory, and auth. Events carry the side effects: EventActions bundle state deltas, artifact saves, transfers, and escalations, which is how the runner replays and rewinds sessions deterministically. The plugin system wraps all of it — base_plugin.py exposes callbacks from user input through model calls to tool errors, and the shipped plugins from debug logging to reflect-and-retry are worked examples.

The third reason is the services layer, because deployment is where most agent demos die, and ADK treats it as a first-class surface. The session services come in four grades — in-memory for tests, SQLite and full database for production, Vertex-backed for Google Cloud — all exposing the same state-delta model the events produce. Memory is a searchable bank the agent queries mid-run, and artifacts are versioned binaries in memory, on disk, or in GCS. The auth handler performs OAuth exchanges on tool calls with resume support, so a tool that needs a login token suspends and continues instead of failing. On the model side, the registry resolves names to implementations, the Gemini client ships with a context-cache manager for cost control, a fallback model wraps primaries with ordered backups, and the interface contract is small enough that the bridge is integration, not surgery.

Google ADK detail architecture diagram

The detail view: the runner with its contexts, events and compaction; the flow processors from identity to function calling; tool internals from declarations to the transfer verb; model implementations from Gemini through LiteLLM with fallback and caching; the state services with auth; and the CLI, server, evaluation and agent-to-agent surfaces.

The detail view shows the seams explicitly. The runner threads an invocation context through everything, streams events, and compacts long sessions — while the flow remains a pure function of that context. Tool internals sit one layer below the processor so the model-facing contract (declarations, parsing, confirmation) is separable from the agent-facing verbs (transfer, exit, memory load). The model group is deliberately boring — interface, three implementations, resilience, caching — because the interesting decisions live in the services and the processor chain. The interface stratum on the right is what makes this a product rather than a library: the CLI drives dev loops, the test runner scores evaluation cases against real trajectories, and the remote A2A agent — two thousand lines, marked experimental — wraps external agents speaking the agent-to-agent protocol into the same lifecycle as local ones.

From Install to a Multi-Agent Tree

Installation is pip install google-adk, and the fastest path is a folder with one agent: define an Agent named root with instructions and a tool or two, run adk web in the parent directory, and the dev UI serves the agent at localhost with tracing visible per turn. To feel the workflow-agent idea, split the work — a SequentialAgent whose children are a researcher LlmAgent, a ParallelAgent fanning out three summarizers, and a LoopAgent with a reviewer that escalates when done — then compose them as sub_agents. Run the same tree headlessly with adk api_server for HTTP clients, or adk run root for the terminal. Swap InMemorySessionService for DatabaseSessionService with a connection URL and the conversation state survives restarts; add adk eval with a case file and the trajectories are scored automatically. The evaluation CLI and the deployment helpers (adk deploy) are the bridge from notebook to service, and both read the same agent folder structure you already have.

Honest limits: the docs and defaults are Gemini-first, and the deepest integrations — Vertex session and memory backends, context caching, grounding tools — assume Google Cloud, so a non-GCP deployment is supported but noticeably less paved. The evaluation harness expects its own case-file format, which is an investment in lock-in however well-designed. The agent-to-agent surface is explicitly experimental and its two-thousand-line wrapper is best treated as a preview. And the framework’s breadth is a real cost: the plugin, toolset, and service abstractions are all load-bearing, so new teams should start with the workflow agents and plain function tools before reaching for the customization points that make ADK powerful.

Watch PyShine on YouTube

Contents