Agentic AI in practice, building real agents with Google ADK
What agentic AI actually means in production, and a hands-on walkthrough of building, tooling, and shipping an agent with Google's Agent Development Kit.
Most teams I talk to have shipped a chatbot. Very few have shipped an agent. The difference is not the model, it is the control loop. A chatbot answers. An agent decides, calls tools, observes what happened, and keeps going until a goal is met or a budget runs out.
What makes a system agentic
Strip away the marketing and an agent is four things wired into a loop: a goal, a set of tools, memory of what already happened, and a stopping rule. Everything else, planning, reflection, multi-agent delegation, is an optimization on top of that loop.
- Goal: a task description precise enough that success is checkable.
- Tools: typed functions the model can call, with real side effects and real failure modes.
- Memory: short-term scratchpad for the current run, long-term store for things worth remembering.
- Stopping rule: max steps, cost ceiling, or an explicit done signal. Without this, agents burn money.
Where Google ADK fits
The Agent Development Kit is Google's open-source framework for building and evaluating agents. It gives you the loop, tool registration, session and state handling, streaming, evaluation harnesses, and a local dev UI, so you are not rebuilding orchestration plumbing for the third time. It is model-agnostic in practice, though it is best integrated with Gemini.
A first agent
ADK is Python-first. A minimal agent is a model, an instruction, and a list of tools. Tools are just plain functions, the docstring and type hints become the schema the model sees, which is why writing a good docstring is now an engineering skill.
from google.adk.agents import Agent
def get_order_status(order_id: str) -> dict:
"""Look up the fulfillment status of a customer order.
Args:
order_id: The public order identifier, e.g. "ORD-10422".
"""
record = orders_api.fetch(order_id)
return {"status": record.status, "eta": record.eta_iso}
root_agent = Agent(
name="support_agent",
model="gemini-2.0-flash",
instruction=(
"You help customers with order questions. "
"Always call get_order_status before answering about an order. "
"If the tool fails, say so plainly instead of guessing."
),
tools=[get_order_status],
)Run it locally with the dev UI and you get a trace of every model call, tool invocation, and state mutation. That trace is the single most useful debugging artifact in agent work, more useful than logs.
pip install google-adk
adk web # local UI with full run traces
adk run app # terminal loopMulti-agent, only when it earns its place
ADK lets you compose agents as sub-agents, so a coordinator can delegate to specialists. This is genuinely useful when subtasks need different tools, different instructions, or different models. It is a mistake when you do it because the diagram looks good. Every hop adds latency, cost, and a new place for context to get lost.
from google.adk.agents import Agent
billing = Agent(name="billing", model="gemini-2.0-flash",
instruction="Handle refunds and invoices.", tools=[issue_refund])
shipping = Agent(name="shipping", model="gemini-2.0-flash",
instruction="Handle delivery and tracking.", tools=[get_order_status])
coordinator = Agent(
name="coordinator",
model="gemini-2.0-flash",
instruction="Route the customer to the right specialist. Do not answer directly.",
sub_agents=[billing, shipping],
)Treating agents like distributed systems
This is the part my background keeps pulling me back to. An agent run is a distributed workflow with a non-deterministic scheduler. The same discipline applies.
- Make tools idempotent, the model will retry, sometimes twice in one run.
- Put a hard budget on steps and tokens, and fail closed when it is hit.
- Never let an agent take an irreversible action without a typed confirmation step.
- Log every tool call with inputs, outputs, and latency, and treat evaluation runs as a regression suite.
- Version instructions like code, a prompt change is a deploy.
Evaluation is the whole game
ADK ships an eval harness where you define a set of scenarios and expected tool trajectories, not just expected text. Checking that the agent called the right tools in a sensible order catches far more regressions than string matching on the final answer. Build ten scenarios before you build the eleventh feature.
Where I would start
Pick one workflow that is currently a human copying data between two systems. Wrap those two systems as tools, give the agent a narrow instruction, put a human approval gate on the write path, and measure it for two weeks. That is a far better first project than a general assistant, and it is the kind of thing that actually stays in production.