A useful agent has to do more than produce a good answer. It needs to find the right data, call tools, recover from failures, and let someone understand what happened. Choosing the model solves only part of that problem.
My work at Google includes agentic AI tools for research and data exploration. The architectural question I keep returning to is where a decision belongs. Which decisions need a model? Which can ordinary code make? Which require a person to review the evidence?
Gemini, the Agent Development Kit (ADK), A2A, and A2UI address different parts of that design. They can work together, but you do not need all four for every application. The diagram shows one possible arrangement. The pipeline example later in this post is illustrative, rather than a description of an internal system.
Gemini: choosing the next step
A model can help when the next step depends on interpreting a question or unfamiliar evidence. For a research request, that might mean choosing which reports to read, then deciding whether they support an answer or leave a gap.
With Gemini function calling (opens in a new tab), the model returns a function name and arguments. The application executes the function and returns its result to the model. That distinction matters: a proposed tool call is input to your code, and your code still owns authorization, argument validation, timeouts, and error handling. Independent calls can run in parallel; dependent calls have to wait for the data they need.
A large context window helps fit more evidence into a request. It does not preserve state across a restart or guarantee that the model will use every detail correctly. Decide what belongs in the active context, what should be retrieved on demand, and what must be stored as an explicit fact about the task.
Make a run inspectable
When a result is wrong, I want to follow the sequence of inputs, tool calls, responses, and decisions that produced it. A final answer alone cannot show whether the agent searched the wrong dataset, misread a tool error, or calculated the wrong metric.
Record observable actions and the evidence behind them. You do not need the model’s private reasoning to inspect whether it called the correct tool with valid arguments. Put limits on calls, elapsed time, and retries, and return a useful partial result when a task reaches those limits.
ADK: coordinating the work
ADK provides the runtime and abstractions for agents, tools, and workflows. Its workflow documentation (opens in a new tab) describes sequential, parallel, and loop execution. The available APIs differ across SDK languages and versions, so use the docs for the version you install.
Use code for known sequences
Suppose a research task needs three reports before it can compare them. Fetch those reports concurrently when the requests are independent, wait for the results, and then ask the model to compare them. There is no benefit in asking the model to rediscover that dependency on every run.
Leave room for decisions that depend on the content. If a report contradicts the others, the model might request another source. That additional search should still have a budget and a stopping condition. A loop that produces more text is not necessarily making progress.
Split work into separate agents when the responsibilities or permissions differ enough to justify it. A writer and a database operator may need different tools. Two agents with the same instructions and access may only add latency and another place for context to be lost.
Save state and handle retries
ADK distinguishes sessions, state, and memory (opens in a new tab). A session records an interaction, state holds values used during it, and memory supports retrieval across interactions. An in-memory service loses its contents when the process stops; persistence needs a suitable storage backend.
Saving a conversation is different from safely resuming an operation. If a process dies after submitting a job but before recording the response, a retry can submit it again. Store the operation ID and check its status, or use an idempotency key supported by the service. Test that failure window explicitly.
The framework also does not decide which data a user may access. Enforce that in the service handling the request, using the caller’s identity and the operation being requested. Instructions to the model can describe the rule, but cannot enforce it.
A2A: delegating to another service
An agent in the same process can often be called directly. A2A becomes useful when an independently deployed agent needs to accept work and report progress through a shared protocol. It can expose that interface without exposing its prompts or internal tools. MCP serves a related purpose for connecting applications to tools and resources.
Discover capabilities
The A2A specification (opens in a new tab) defines
an Agent Card describing supported capabilities, interfaces, and authentication
requirements. Its well-known discovery path is /.well-known/agent-card.json.
Read the card before assuming a service supports a particular interaction, and
pin the protocol version in your integration.
A description of a capability is not permission to use it. Authenticate the remote service, authorize requests on the server, and treat descriptions and returned text as external data. They should not be able to override your application’s instructions.
Track work that takes time
A2A supports immediate messages and tasks with a lifecycle. A task can report progress, request input, fail, or complete. Clients can retrieve status; streaming and push notifications depend on the capabilities a service supports. The official task lifecycle guide (opens in a new tab) explains those distinctions.
Design the user experience for interrupted work too. A closed browser tab should not leave someone wondering whether the task is still running. Keep the task ID, show the last known status, and distinguish a failed connection from a failed task.
A2UI: showing the result
A paragraph works for an explanation. Comparing report findings may need a table; choosing a date may need a form. A2UI lets an agent describe an interface that the host application renders using its own components.
Keep rendering in the application
The A2UI design (opens in a new tab) uses declarative component descriptions and a catalog of supported components. The application maps those descriptions to its renderer. The agent does not need to supply executable HTML or JavaScript to request a table, a button, or a form.
That reduces what model output can do, but the component catalog still needs careful implementation. Validate properties, handle links safely, and authorize actions on the server. A button labeled “Approve” should invoke a defined operation; its presence in a generated interface must not grant new permissions.
Update the interface in pieces
A2UI describes components using IDs and references between them. That allows incremental updates: a result table can change without replacing the rest of the screen. The project documentation (opens in a new tab) explains the component model and provides renderer examples. Use the schema for your chosen version; message names from older examples may no longer match it.
Incremental rendering also needs deliberate interaction design. Keep keyboard focus stable, announce meaningful status changes, and preserve entered values while results arrive. A stream of valid UI messages can still produce a frustrating interface if it keeps moving the control someone is trying to use.
Example: a failed data pipeline
Consider a fictional daily orders job that has failed. An engineer asks the agent what happened. The agent retrieves the failed run’s logs, input-volume measurements, and job configuration. Those read-only lookups can run concurrently if they are independent.
The logs show an out-of-memory error and the input volume is larger than usual. More memory is one possible response, but data skew or a changed join could also explain the failure. The answer should state the evidence, the uncertainty, and what the proposed retry would help establish.
Separate diagnosis from execution
The model can propose an operation with structured arguments. This is an illustrative application payload, not an ADK or A2A protocol message:
{
"action": "retry_batch",
"job_id": "orders_daily",
"failed_run_id": "run_2026_04_24",
"requested_memory_gib": 16,
"evidence": ["log:worker-oom", "metric:input-volume"],
"reason": "The worker ran out of memory during the failed run."
}Before running it, the service checks that the job exists, that the failed run belongs to it, that the caller may retry it, and that the requested resources are within policy. It also checks for a retry already in progress. Those decisions should not depend on whether the model sounds confident.
The interface can then show the engineer the affected job, evidence, resource change, and expected cost implications. If approval is required, bind it to that specific proposal. Changing the job or its parameters after approval must not reuse the same authorization.
Once authorized, a predefined operation submits the retry and records its ID. The agent monitors the result and reports whether it succeeded. Completion needs evidence from the job service, not a prediction made when the retry was submitted.
Corrections can improve the next diagnosis. Keep the explanation and the conditions under which it applies, then evaluate it against other cases. One successful retry does not establish that doubling memory is the right answer to every memory error.
Start with a task you can evaluate
I would start with one useful task, a small set of tools, and examples of acceptable and unacceptable results. Make that path observable before adding more agents or protocols.
For the pipeline assistant, test missing logs, conflicting evidence, rejected permissions, duplicate requests, and a restart during submission. Measure whether it reaches the correct result, how often a person must intervene, and what each completed task costs. Those answers tell you where another model, a new tool, or a separate agent would actually help.
Continue reading
More from the journal.
AI Development
6 min read
AI Agents in the Enterprise: Where to Start
A practical approach to enterprise AI agents: tool access, memory, orchestration, evaluation, and a bounded first deployment.
AI Development
7 min read
MCP Servers: Connecting AI Assistants to Your Tools
A practical guide to MCP architecture, local server setup, useful integrations, tool design, permissions, and troubleshooting.