« Phase 22 README · Warmup · Deep Dive · Principal Deep Dive · Core Contributor · Staff Notes
Phase 22 — Hitchhiker's Guide to Google ADK
The compressed practitioner tour. Read the WARMUP for the derivations; this is the stuff you say in the meeting.
30-second mental model
Google ADK is a code-first, model-agnostic agent framework, Gemini/Vertex-optimized. An
agent is an LlmAgent = model + instruction + tools + output_key. A FunctionTool wraps a
Python function and auto-derives its schema from the signature. A Runner drives the loop and
yields Events (model response, tool call, tool result, final). The signature idea: workflow
agents (Sequential/Parallel/Loop) put deterministic, code-defined orchestration around
LLM leaves — as opposed to sub_agents + transfer_to_agent, where the model routes. State
is a scoped dict (user:/app:/temp:) in a SessionService; callbacks (before/after
× agent/model/tool) are the interception layer, and a before_* that returns a value
short-circuits the step (cache / guardrail). Ship it to Vertex AI Agent Engine.
The things to tattoo on your arm
| Thing | What it is |
|---|---|
LlmAgent / Agent | model + instruction + tools + output_key + sub_agents |
FunctionTool | Python function → schema derived from the signature; no default ⇒ required |
Runner.run(...) | drives the loop, yields Events; event.is_final_response() pulls the answer |
output_key | writes the agent's final text to session.state[output_key] — the composition seam |
SequentialAgent | run sub-agents in order, shared state (step 2 sees step 1's output_key) |
ParallelAgent | run sub-agents on the same input, independent branches, merge outputs |
LoopAgent | repeat until a sub-agent **escalate**s OR max_iterations |
sub_agents + transfer | the model picks which child to hand control to (non-deterministic) |
| state scopes | user: (per-user) · app: (whole app) · temp: (this turn) · none (this session) |
| callback short-circuit | a before_* returning a value skips the wrapped step |
| deploy | Vertex AI Agent Engine (managed sessions, scaling, tracing) or Cloud Run |
The one distinction interviewers actually probe
Deterministic workflow agents (order fixed in code) vs LLM-driven
sub_agenttransfer (order chosen by the model at runtime).
Say it as: "ADK's philosophy is deterministic structure around LLM reasoning. If the flow is
knowable, I encode it as a SequentialAgent/ParallelAgent/LoopAgent so it's testable and
replayable; I only use sub_agents + transfer_to_agent when routing genuinely needs to read the
input at runtime. Reliability compounds — I don't spend it on a routing decision I could hard-code."
Framework one-liners
- Google ADK =
LlmAgent+ tools + aRunnerthat yields Events; workflow agents for deterministic orchestration; scopedSessionServicestate; callbacks for guardrails; Vertex deploy. - LangGraph (Phase 18) = you draw the graph (nodes/edges/reducers/checkpoints); max control.
- OpenAI Agents SDK =
Agent+Runner+handoffs; minimal API, OpenAI-centric. - All three = elaborations of
while not done: proposal = model(context); execute.
War stories
- The "AI dispatcher" that flaked 1 in 8 times. A top-level
LlmAgentwith fivesub_agentswas routing a known three-stage pipeline. The model occasionally transferred to the wrong child. Rewriting it as aSequentialAgent(deterministic) killed the flakiness overnight — the routing never needed the model. - The parallel research agent with the heisenbug. Two
ParallelAgentbranches, and branch B's instruction referenced branch A'soutput_key. It "worked" in dev (A happened to finish first) and failed in prod. Branches must be independent; a downstream sequential step combines them. - The $-per-day that wouldn't drop. Same repeated support questions hitting Gemini every time.
A ten-line
before_model_callbackcache (hash the request, return the storedContenton a hit) cut model calls ~40% — the short-circuit contract doing exactly what it's for. - The tool that deleted the wrong thing — once. After that, every mutating tool got a
before_tool_callbackthat checks the args against an allow-list and returns a rejection to block the call. The guardrail is testable: assert the function ran zero times.
Vocabulary
LlmAgent/Agent (reasoning unit) · FunctionTool (function → auto-schema) · Runner
(loop that yields Events) · Event (what happened; carries state_delta, escalate) ·
output_key (final text → state) · workflow agent (Sequential/Parallel/Loop,
deterministic) · sub_agents / transfer_to_agent (LLM-driven delegation) · escalate
(stop-the-loop signal) · SessionService (holds sessions + scoped state) · state scopes
(user:/app:/temp:) · MemoryService (long-term recall) · callbacks (before/after ×
agent/model/tool) · short-circuit (a before_* return skips the step) · Vertex AI Agent
Engine (managed deploy).
Beginner mistakes
- Thinking workflow agents use an LLM to pick the order (they're the deterministic option).
- Letting
ParallelAgentbranches depend on each other's output (race — they're concurrent). - Forgetting
output_key, then wondering why aSequentialAgent's steps can't see each other. - Treating state as one flat dict —
user:tierandtiergo to different stores. - Using callbacks only for logging and missing the
before_*short-circuit (caches/guardrails). - Reaching for
sub_agents+ transfer when aSequentialAgentwould be reliable and testable. - No
max_iterationson aLoopAgentthat relies on a model to escalate — it can spin. - Assuming ADK is Gemini-only (it's model-agnostic via
LiteLlm; just Gemini/Vertex-optimized).