Google CloudProfessional Agentic Architect2026-093.1 Designing and building agentic workflows in code
Understand ADK execution
Completed by the knowledge check
Learning objective
Explain how the Agent Development Kit (ADK) executes one request through a runner and an event stream, where callbacks intercept that execution, and how to bound the work performed during the request. This lesson covers runtime execution, not session-storage or long-term-memory design.
Core idea
Treat ADK execution as a bounded, event-driven invocation. The Runner drives the invocation. Agents, models, tools, and callbacks perform the work and communicate progress or control decisions as Event objects. Runtime limits prevent a faulty reasoning path from consuming work without bound.
One user message does not necessarily cause one model call. An invocation can cross agents, call tools, and return tool results to a model for another step. The ADK invocation context defines this hierarchy:
invocation
agent call
step: one LLM call, optionally followed by tool calls and results
step: another LLM call to continue or summarize
optional transfer to another agentHow it works
For a text request, the runtime follows a cooperative event loop:
- The caller invokes
Runner.run_async()with the user, session, and message. The runner resolves the session and creates an invocation context. - The runner starts the root agent. Agent logic may call a model, execute a tool, or transfer control to another agent.
- Execution yields an
Eventfor model content, a function call or response, a state delta, or a control signal. - The runner processes the event and its actions, records it through the configured services, and yields it to the caller.
- Agent execution resumes after event processing. The cycle ends when the invocation reaches its stopping condition.
This yield-process-resume relationship is the central mental model in the ADK runtime event loop.
An event is more than a text chunk. It carries content plus metadata such as its author, event ID, invocation ID, and actions. Actions can represent state or artifact deltas and control signals. Applications should inspect structured fields and use event.is_final_response() instead of assuming that every event is the user-facing answer. See the ADK events guide.
Given an initialized runner and existing session, the following Python fragment budgets one invocation and selects final responses from its event stream:
from google.adk.agents.run_config import RunConfig
run_config = RunConfig(max_llm_calls=8)
async for event in runner.run_async(
user_id=user_id,
session_id=session_id,
new_message=user_message,
run_config=run_config,
):
if event.is_final_response() and event.content:
render(event.content)max_llm_calls caps total LLM calls for that run, including continuation calls after tool results. It does not cap tokens, tool executions, or elapsed time. The default is 500; zero or a negative value disables enforcement, which the runtime configuration guide does not recommend for production. Choose a bound from the workflow’s valid path, latency objective, and cost budget. Add application deadlines and tool-specific retry limits for risks that an LLM-call cap does not cover.
Callbacks as execution interceptors
Callbacks run at named lifecycle points:
| Callback family | Boundary | Typical use |
|---|---|---|
| Agent | Before or after an agent run | Validate context, initialize data, or record agent-level telemetry |
| Model | Before or after an LLM call | Apply input policy, cache a result, or filter a model response |
| Tool | Before or after tool execution | Validate arguments, enforce a policy, or normalize a tool result |
In Python, returning None normally continues the default path or preserves a result. A value from a before_* callback can skip the wrapped operation; values from after_model_callback and after_tool_callback can replace their results. after_agent_callback has distinct semantics. Return types and parameter names depend on the callback and SDK language; use the ADK callback type reference.
A callback is an in-process interception point, not an event consumer. Use a callback when a check must run at a specific execution boundary. Consume the event stream when the application needs to render output, trace the invocation, or react to structured results. Callbacks can enforce deterministic code at their boundary, but they do not make the model’s future choices deterministic.
Key distinctions and trade-offs
| Concept | Meaning | Design consequence |
|---|---|---|
| Invocation | One runner-managed request-response execution | Budget and correlate work at this boundary |
| Event | One structured occurrence within the invocation | Preserve intermediate events for debugging and auditing |
| Callback | Code invoked at a named lifecycle boundary | Keep it fast and predictable because it is on the execution path |
| Final response | An event classified for user-facing output | Do not confuse it with every text or tool-result event |
| LLM-call limit | A cap on model calls in one run | Combine it with timeouts and retry limits; it is not a full resource budget |
Callbacks improve enforcement and observability, but they add latency and hidden control flow. Keep each callback focused and log overrides. A low LLM-call cap controls cost and runaway reasoning, but it can reject valid tool-rich requests. Size it from measured event traces, not from visible turns.
Architecture / decision scenario
A payment-support agent may look up a case, inspect policy, and propose a refund. It must not execute the refund without an approval token.
The architect runs each user request through Runner.run_async() with an explicit max_llm_calls value. A before_tool_callback checks both the refund tool name and the approval token before any side effect. Returning a documented tool result blocks an unauthorized call while allowing the agent to explain the denial. An after_tool_callback records the tool outcome with the invocation ID. The application consumes every event for tracing but displays only content-bearing events for which is_final_response() is true.
The design uses separate bounds for separate failure modes: the LLM-call cap limits reasoning steps, the tool client limits retries and elapsed time, and the approval callback protects the side-effect boundary. Raising the LLM-call cap alone would not improve authorization or stop a hanging payment API.
Common exam traps
- Treating a runner as the agent itself. The runner coordinates execution; agents and tools contain execution logic.
- Assuming one user turn equals one LLM call. Tool use, summarization, and transfers can require additional calls within the same invocation.
- Treating events as text messages only. Events also carry tool activity, deltas, metadata, and control signals.
- Using an event consumer where a deterministic pre-tool policy check is required. The event may describe a call after the relevant interception point.
- Assuming
max_llm_callslimits tokens, tool retries, or wall-clock time. - Assuming a callback makes all later model behavior deterministic. It controls only the lifecycle boundary where it runs.
What to remember
- The runner drives one invocation through a yield-process-resume event loop.
- One invocation can contain several agents, LLM calls, and tool events.
- Events are structured runtime records; use
is_final_response()for display. - Callbacks observe or override execution at agent, model, and tool boundaries.
- Bound model calls explicitly, then add deadlines and retry limits for other resources.
Knowledge check
An ADK invocation makes only two model calls but hangs on a slow tool. max_llm_calls is set to eight. Which change addresses the unbounded elapsed time?
An interface displays every text-bearing event, including intermediate tool activity. Which selection should it use for user-facing final answers?
An approval check must reject a refund before the tool executes. Which ADK integration supplies the required interception point?
before_tool_callback checking the concrete proposalafter_tool_callback that replaces the displayed resultReferences
- Google, Runtime event loop
- Google, Events
- Google, Callbacks
- Google, Types of callbacks
- Google, Runtime configuration
- Google, ADK Python invocation context