Skip to lesson

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 agent

How it works

For a text request, the runtime follows a cooperative event loop:

  1. The caller invokes Runner.run_async() with the user, session, and message. The runner resolves the session and creates an invocation context.
  2. The runner starts the root agent. Agent logic may call a model, execute a tool, or transfer control to another agent.
  3. Execution yields an Event for model content, a function call or response, a state delta, or a control signal.
  4. The runner processes the event and its actions, records it through the configured services, and yields it to the caller.
  5. 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.

The runner drives one invocation through a yield-process-resume loopRead top to bottom. The caller sends the user, session, and message to the runner, which resolves the session and starts the root agent. Inside a loop that runs until the invocation reaches its stopping condition, agent execution yields an event, the runner processes the event and its actions and records it through the configured services, the runner yields the event to the caller, and agent execution resumes. The caller receives events while the invocation is still running, not only at its end.Root agentRunnerCallerresolves the sessionprocesses the eventresumesloop[until the stopping condition]user, session, and messagestarts the root agentyields an Eventyields it to the caller

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 familyBoundaryTypical use
AgentBefore or after an agent runValidate context, initialize data, or record agent-level telemetry
ModelBefore or after an LLM callApply input policy, cache a result, or filter a model response
ToolBefore or after tool executionValidate 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

ConceptMeaningDesign consequence
InvocationOne runner-managed request-response executionBudget and correlate work at this boundary
EventOne structured occurrence within the invocationPreserve intermediate events for debugging and auditing
CallbackCode invoked at a named lifecycle boundaryKeep it fast and predictable because it is on the execution path
Final responseAn event classified for user-facing outputDo not confuse it with every text or tool-result event
LLM-call limitA cap on model calls in one runCombine 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_calls limits 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

References