Agent Development Guide¶
Build AI agents that generate A2UI interfaces. This guide covers generating and streaming UI messages from LLMs.
Quick Overview¶
Building an A2UI agent:
- Understand user intent → Decide what UI to show
- Generate A2UI JSON → Use LLM structured output or prompts
- Validate & stream → Check schema, send to client
- Handle actions → Respond to user interactions
Start with a simple agent¶
We will use the ADK to build a simple agent. We will start with text and eventually upgrade it to A2UI.
See step by step instructions at the ADK quickstart.
Then edit the my_agent/agent.py file with a very simple agent for restaurant recommendations.
import json
from google.adk.agents.llm_agent import Agent
from google.adk.tools.tool_context import ToolContext
def get_restaurants(tool_context: ToolContext) -> str:
"""Call this tool to get a list of restaurants."""
return json.dumps([
{
"name": "Xi'an Famous Foods",
"detail": "Spicy and savory hand-pulled noodles.",
"imageUrl": "http://localhost:10002/static/shrimpchowmein.jpeg",
"rating": "★★★★☆",
"infoLink": "[More Info](https://www.xianfoods.com/)",
"address": "81 St Marks Pl, New York, NY 10003"
},
{
"name": "Han Dynasty",
"detail": "Authentic Szechuan cuisine.",
"imageUrl": "http://localhost:10002/static/mapotofu.jpeg",
"rating": "★★★★☆",
"infoLink": "[More Info](https://www.handynasty.net/)",
"address": "90 3rd Ave, New York, NY 10003"
},
{
"name": "RedFarm",
"detail": "Modern Chinese with a farm-to-table approach.",
"imageUrl": "http://localhost:10002/static/beefbroccoli.jpeg",
"rating": "★★★★☆",
"infoLink": "[More Info](https://www.redfarmnyc.com/)",
"address": "529 Hudson St, New York, NY 10014"
},
])
AGENT_INSTRUCTION="""
You are a helpful restaurant finding assistant. Your goal is to help users find and book restaurants using a rich UI.
To achieve this, you MUST follow this logic:
1. **For finding restaurants:**
a. You MUST call the `get_restaurants` tool. Extract the cuisine, location, and a specific number (`count`) of restaurants from the user's query (e.g., for "top 5 chinese places", count is 5).
b. After receiving the data, you MUST follow the instructions precisely to generate the final a2ui UI JSON, using the appropriate UI example from the `prompt_builder.py` based on the number of restaurants."""
root_agent = Agent(
model='gemini-2.5-flash',
name="restaurant_agent",
description="An agent that finds restaurants and helps book tables.",
instruction=AGENT_INSTRUCTION,
tools=[get_restaurants],
)
Don't forget to set the GOOGLE_API_KEY environment variable to run this example.
You can test out this agent with the ADK web interface:
Select my_agent from the list, and ask questions about restaurants in new york. You should see a list of restaurants in the UI as plain text.
Generating A2UI Messages¶
Getting the LLM to generate A2UI messages requires some prompt engineering.
Attention
This is an area we are still designing. The developer ergonomics of this are not yet finalized.
For now, let's copy the a2ui_schema.py from the contact lookup example. This is the easiest way to get the A2UI schema and examples for your agent (subject to change).
First lets add the new imports to the agent.py file:
Now we will modify the agent instructions to generate A2UI messages instead of plain text. We will leave a placeholder for future UI examples.
# Eventually you can copy & paste some UI examples here, for few-shot in context learning
RESTAURANT_UI_EXAMPLES = """
"""
# Construct the full prompt with UI instructions, examples, and schema
A2UI_AND_AGENT_INSTRUCTION = AGENT_INSTRUCTION + f"""
Your final output MUST be a a2ui UI JSON response.
To generate the response, you MUST follow these rules:
1. Your response MUST be in two parts, separated by the delimiter: `---a2ui_JSON---`.
2. The first part is your conversational text response.
3. The second part is a single, raw JSON object which is a list of A2UI messages.
4. The JSON part MUST validate against the A2UI JSON SCHEMA provided below.
--- UI TEMPLATE RULES ---
- If the query is for a list of restaurants, use the restaurant data you have already received from the `get_restaurants` tool to populate the `dataModelUpdate.contents` array (e.g., as a `valueMap` for the "items" key).
- If the number of restaurants is 5 or fewer, you MUST use the `SINGLE_COLUMN_LIST_EXAMPLE` template.
- If the number of restaurants is more than 5, you MUST use the `TWO_COLUMN_LIST_EXAMPLE` template.
- If the query is to book a restaurant (e.g., "USER_WANTS_TO_BOOK..."), you MUST use the `BOOKING_FORM_EXAMPLE` template.
- If the query is a booking submission (e.g., "User submitted a booking..."), you MUST use the `CONFIRMATION_EXAMPLE` template.
{RESTAURANT_UI_EXAMPLES}
---BEGIN A2UI JSON SCHEMA---
{A2UI_SCHEMA}
---END A2UI JSON SCHEMA---
"""
root_agent = Agent(
model='gemini-2.5-flash',
name="restaurant_agent",
description="An agent that finds restaurants and helps book tables.",
instruction=A2UI_AND_AGENT_INSTRUCTION,
tools=[get_restaurants],
)
Understanding the Output¶
Your agent will no longer strictly output text. Instead, it will output text and a JSON list of A2UI messages.
The A2UI_SCHEMA that we imported is a standard JSON schema that defines valid operations like:
render(displaying a UI)update(changing data in an existing UI)
Because the output is structured JSON, you may parse and validate it before sending it to the client.
# 1. Parse the JSON
# Warning: Parsing the output as JSON is a fragile implementation useful for documentation.
# LLMs often put Markdown fences around JSON output, and can make other mistakes.
# Rely on frameworks to parse the JSON for you.
parsed_json_data = json.loads(json_string_cleaned)
# 2. Validate against A2UI_SCHEMA
# This ensures the LLM generated valid A2UI commands
jsonschema.validate(
instance=parsed_json_data, schema=self.a2ui_schema_object
)
By validating the output against A2UI_SCHEMA, you ensure that your client never receives malformed UI instructions.
TODO: Continue this guide with examples of how to parse, validate, and send the output to the client renderer without the A2A extension.