1. Tổng quan
Hầu hết các ứng dụng đại lý đều trả về văn bản thuần tuý. A2UI sẽ thay đổi điều đó. Đây là một giao thức có 18 thành phần cơ bản khai báo giao diện người dùng, cho phép tác nhân của bạn tạo ra các giao diện phong phú, có tính tương tác. Ứng dụng sẽ hiển thị các thành phần này một cách tự nhiên. Bạn không cần mã giao diện người dùng mới cho mỗi bố cục.
Lớp học lập trình này sử dụng Bộ công cụ phát triển tác nhân (ADK) để xây dựng tác nhân và A2UI để tạo giao diện người dùng.
Sản phẩm bạn sẽ tạo ra
Bảng điều khiển cơ sở hạ tầng đám mây theo 3 giai đoạn:
- Một tác nhân tiêu chuẩn trả về dữ liệu tài nguyên dưới dạng văn bản thuần tuý
- Một tác nhân A2UI trả về dữ liệu giống như JSON A2UI có cấu trúc
- Một tác nhân được kết xuất hiển thị JSON A2UI dưới dạng các thành phần giao diện người dùng tương tác trong giao diện người dùng dành cho nhà phát triển ADK

Kiến thức bạn sẽ học được
- Cách A2UI hoạt động: 18 thành phần cơ bản, 3 loại thông báo, mô hình thành phần phẳng
- Cách sử dụng A2UI SDK để nhắc một tác nhân ADK tạo JSON A2UI
- Cách kết xuất các thành phần A2UI trong
adk web
Bạn cần có
- Một dự án trên Google Cloud đã bật tính năng thanh toán
- Một trình duyệt web như Chrome
- Python 3.12 trở lên
Lớp học lập trình này dành cho các nhà phát triển có trình độ trung cấp và đã quen thuộc với Python và Google Cloud.
Bạn sẽ mất khoảng 15 đến 20 phút để hoàn thành lớp học lập trình này.
Các tài nguyên được tạo trong lớp học lập trình này sẽ có chi phí dưới 5 USD.
2. Thiết lập môi trường
Tạo một dự án trên Google Cloud
- Trong Google Cloud Console, trên trang chọn dự án, hãy chọn hoặc tạo một dự án trên Google Cloud.
- Đảm bảo bạn đã bật tính năng thanh toán cho dự án trên Cloud. Tìm hiểu cách kiểm tra xem tính năng thanh toán có được bật trên một dự án hay không.
Khởi động Trình chỉnh sửa Cloud Shell
Để chạy một phiên Cloud Shell từ bảng điều khiển Google Cloud, hãy nhấp vào Kích hoạt Cloud Shell trong bảng điều khiển Google Cloud.
Thao tác này sẽ khởi chạy một phiên trong ngăn dưới cùng của bảng điều khiển Cloud của bạn.
Để khởi chạy trình chỉnh sửa, hãy nhấp vào Open Editor (Mở trình chỉnh sửa) trên thanh công cụ của cửa sổ Cloud Shell.
Đặt các biến môi trường
Trong thanh công cụ Cloud Shell Editor, hãy nhấp vào Terminal (Thiết bị đầu cuối) và New Terminal (Thiết bị đầu cuối mới), sau đó chạy các lệnh sau để thiết lập dự án, vị trí và định cấu hình ADK để sử dụng Gemini trong Vertex AI.
export GOOGLE_CLOUD_PROJECT=<INSERT_YOUR_GCP_PROJECT_HERE> export GOOGLE_CLOUD_LOCATION=global export GOOGLE_GENAI_USE_VERTEXAI=True
Bật API
Trong dòng lệnh, hãy chạy lệnh sau để bật các API cần thiết:
gcloud services enable aiplatform.googleapis.com
Cài đặt các phần phụ thuộc
Trong cửa sổ dòng lệnh, hãy chạy lệnh sau để cài đặt phiên bản mới nhất của Bộ phát triển tác nhân (ADK):
pip install -U google-adk a2ui-agent-sdk export PATH="$HOME/.local/bin:$PATH"
3. Tạo tác nhân
Bắt đầu bằng một tác nhân ADK tiêu chuẩn trả về văn bản thuần tuý. Đây là giao diện của hầu hết các ứng dụng tác nhân hiện nay.
Tạo thư mục nhân viên hỗ trợ
Tạo một thư mục có tên là a2ui_agent. Thư mục này sẽ chứa mã nguồn cho tác nhân và các công cụ của bạn.
Xác định công cụ và dữ liệu mô phỏng
Tạo a2ui_agent/resources.py với nội dung sau. Công cụ này trả về danh sách các tài nguyên trên đám mây cùng với trạng thái của chúng.
RESOURCES = [
{
"name": "auth-service",
"type": "Cloud Run",
"region": "us-west1",
"status": "healthy",
"cpu": "2 vCPU",
"memory": "1 GiB",
"instances": 3,
"url": "https://auth-service-abc123.run.app",
"last_deployed": "2026-04-18T14:22:00Z",
},
{
"name": "events-db",
"type": "Cloud SQL",
"region": "us-east1",
"status": "warning",
"tier": "db-custom-8-32768",
"storage": "500 GB SSD",
"connections": 195,
"version": "PostgreSQL 16",
"issue": "Storage usage at 92%",
},
{
"name": "analytics-pipeline",
"type": "Cloud Run",
"region": "us-west1",
"status": "error",
"cpu": "2 vCPU",
"memory": "4 GiB",
"instances": 0,
"url": "https://analytics-pipeline-ghi789.run.app",
"last_deployed": "2026-04-10T16:45:00Z",
"issue": "CrashLoopBackOff: OOM killed",
},
]
def get_resources() -> list[dict]:
"""Get all cloud resources in the current project.
Returns a list of cloud infrastructure resources including their
name, type, region, status, and type-specific details.
Status is one of: healthy, warning, error. Resources with
warning or error status include an 'issue' field describing
the problem.
"""
return RESOURCES
Xác định nhân viên hỗ trợ
Tạo a2ui_agent/agent.py có nội dung sau:
from google.adk.agents import Agent
from .resources import get_resources
root_agent = Agent(
model="gemini-3-flash-preview",
name="cloud_dashboard",
description="A cloud infrastructure assistant that reports on project resources.",
instruction=(
"You are a cloud infrastructure assistant. When users ask about their "
"cloud resources, use the get_resources tool to fetch the current state. "
"Summarize the results clearly in plain text."
),
tools=[get_resources],
)
4. Kiểm thử nhân viên hỗ trợ
ADK có một giao diện người dùng dành cho nhà phát triển mà bạn có thể dùng để tương tác và gửi câu lệnh cho tác nhân trong trình duyệt để kiểm thử.
Khởi động giao diện người dùng dành cho nhà phát triển ADK
Trong cửa sổ dòng lệnh của Cloud Shell Editor, hãy chạy lệnh sau để khởi động giao diện người dùng dành cho nhà phát triển ADK:
adk web --port 8080 --allow_origins "*" --reload_agents
Bạn sẽ thấy một thông báo tương tự như sau:
+-----------------------------------------------------------------------------+ | ADK Web Server started | | | | For local testing, access at http://127.0.0.1:8080. | +-----------------------------------------------------------------------------+
Mở giao diện người dùng dành cho nhà phát triển ADK
Bạn có thể mở giao diện người dùng dành cho nhà phát triển ADK trong trình duyệt bằng cách nhấp vào URL kiểm thử cục bộ bằng tổ hợp phím Ctrl hoặc Cmd, hoặc bằng cách nhấp vào nút Web Preview (Xem trước trên web) rồi chọn Preview on Port 8080 (Xem trước trên cổng 8080).
Sau khi bạn xem giao diện người dùng dành cho nhà phát triển ADK, hãy chọn a2ui_agent trong trình đơn thả xuống.
Gửi câu lệnh mẫu
Gửi một câu lệnh mẫu cho tác nhân:
What's running in my project?
Bây giờ, hãy thử một câu lệnh mẫu khác và bạn sẽ nhận được nhiều kết quả văn bản hơn:
Does anything need my attention?
Cuộc trò chuyện của bạn sẽ có dạng như sau:

Bạn sẽ thấy một màn hình thông báo. Chính xác nhưng không mang lại trải nghiệm tốt cho người dùng.
5. Tạo JSON A2UI
Điều gì sẽ xảy ra nếu tác nhân có thể mô tả một giao diện người dùng thay vì chỉ xuất văn bản? A2UI là một giao thức cho phép các tác nhân tạo ra giao diện tương tác từ danh mục gồm 18 thành phần cơ bản. Ứng dụng sẽ hiển thị các thành phần này một cách tự nhiên.
A2UI Python SDK bao gồm trình quản lý lược đồ giúp tạo lời nhắc hệ thống cho bạn. Thư viện này hướng dẫn LLM về danh mục thành phần A2UI đầy đủ, tên và loại thuộc tính chính xác cũng như cấu trúc JSON.
Cập nhật tác nhân
Thay thế nội dung của a2ui_agent/agent.py bằng nội dung sau:
from google.adk.agents import Agent
from a2ui.schema.manager import A2uiSchemaManager
from a2ui.basic_catalog.provider import BasicCatalog
from .resources import get_resources
schema_manager = A2uiSchemaManager(
version="0.8",
catalogs=[BasicCatalog.get_config("0.8")],
)
instruction = schema_manager.generate_system_prompt(
role_description=(
"You are a cloud infrastructure assistant. When users ask about "
"their cloud resources, use the get_resources tool to fetch the "
"current state."
),
workflow_description=(
"Analyze the user's request and return structured UI when appropriate."
),
ui_description=(
"Use cards for resource summaries, rows and columns for comparisons, "
"icons for status indicators, and buttons for drill-down actions. "
"Do NOT use markdown formatting in text values. Use the usageHint "
"property for heading levels instead. "
"Respond ONLY with the A2UI JSON array. Do NOT include any text "
"outside the JSON. Put all explanations into Text components."
),
include_schema=True,
include_examples=True,
)
root_agent = Agent(
model="gemini-3-flash-preview",
name="cloud_dashboard",
description="A cloud infrastructure assistant that renders rich A2UI interfaces.",
instruction=instruction,
tools=[get_resources],
)
Phương thức generate_system_prompt() kết hợp nội dung mô tả vai trò của bạn với giản đồ JSON A2UI đầy đủ và một số ví dụ ít lần, nhờ đó LLM biết chính xác cách định dạng đầu ra. Bạn không cần phải viết danh mục thành phần theo cách thủ công.
6. Kiểm thử đầu ra JSON
Nếu bạn vẫn đang chạy giao diện người dùng dành cho nhà phát triển ADK từ trước đó, thì giao diện này sẽ tự động tải lại những thay đổi mà bạn đã thực hiện đối với tác nhân.
Chọn a2ui_agent, bắt đầu một phiên mới bằng cách nhấp vào +New Session (Phiên mới) ở trên cùng bên phải của giao diện người dùng dành cho nhà phát triển ADK, sau đó gửi cùng một câu lệnh như trước:
What's running in my project?
Lần này, tác nhân sẽ phản hồi bằng JSON A2UI thay vì văn bản thuần tuý. Bạn sẽ thấy các tin nhắn có cấu trúc chứa beginRendering, surfaceUpdate và dataModelUpdate trong đầu ra của cuộc trò chuyện.

JSON mô tả một giao diện người dùng phong phú với thẻ, biểu tượng và nút, nhưng adk web hiển thị giao diện này dưới dạng văn bản thô. Trong bước tiếp theo, bạn sẽ kết xuất thành phần này dưới dạng các thành phần giao diện người dùng thực tế.
7. Tìm hiểu về A2UI
Xem tệp JSON mà tác nhân của bạn vừa tạo. Bạn sẽ nhận thấy rằng tệp này chứa 3 loại thông báo. Mọi phản hồi A2UI đều tuân theo cấu trúc tương tự như sau:
1. beginRendering
Tạo một bề mặt kết xuất và đặt tên cho thành phần gốc:
{"beginRendering": {"surfaceId": "default", "root": "main-column"}}
2. surfaceUpdate
Gửi cây thành phần dưới dạng danh sách phẳng có các giá trị nhận dạng tham chiếu (không lồng nhau):
{"surfaceUpdate": {"surfaceId": "default", "components": [
{"id": "main-column", "component": {"Column": {"children": {"explicitList": ["title", "card1"]}}}},
{"id": "title", "component": {"Text": {"text": {"literalString": "My Resources"}, "usageHint": "h1"}}},
{"id": "card1", "component": {"Card": {"child": "card1-content"}}},
{"id": "card1-content", "component": {"Text": {"text": {"path": "service_name"}}}}
]}}
3. dataModelUpdate
Gửi dữ liệu riêng biệt với cấu trúc:
{"dataModelUpdate": {"surfaceId": "default", "contents": [
{"key": "service_name", "valueString": "auth-service"},
{"key": "status", "valueString": "healthy"}
]}}
Các thành phần liên kết với dữ liệu bằng {"path": "key"}. Bạn có thể cập nhật dữ liệu mà không cần gửi lại cây thành phần.
18 thành phần cơ bản
Danh mục | Thành phần |
Bố cục | Thẻ, Cột, Hàng, Danh sách, Thẻ, Đường phân chia, Phương thức |
Hiển thị | Văn bản, Hình ảnh, Biểu tượng, Video, Trình phát âm thanh |
Input | TextField, DateTimeInput, MultipleChoice, CheckBox, Slider |
Hành động | Nút |
Đại lý tạo nhiều bố cục từ cùng một danh mục. Hãy xem tài liệu tham khảo về thành phần để biết toàn bộ thông tin chi tiết về từng thành phần cơ bản. Chế độ xem duyệt qua, trang tổng quan Mức độ ưu tiên và biểu mẫu cấu hình đều sử dụng 18 thành phần cơ bản này. Bạn không cần thành phần giao diện người dùng mới.
8. Kết xuất các thành phần A2UI
Tác nhân tạo ra JSON A2UI hợp lệ, nhưng adk web hiển thị JSON này dưới dạng văn bản thô. Để kết xuất thành phần này dưới dạng các thành phần thực tế trên giao diện người dùng, bạn cần một tiện ích nhỏ để chuyển đổi đầu ra JSON A2UI của tác nhân thành định dạng mà trình kết xuất tích hợp của adk web mong đợi.
Tạo tiện ích kết xuất A2UI
Tạo a2ui_agent/a2ui_utils.py có nội dung sau:
import json
import re
from google.genai import types
from google.adk.agents.callback_context import CallbackContext
from google.adk.models.llm_response import LlmResponse
def _wrap_a2ui_part(a2ui_message: dict) -> types.Part:
"""Wrap a single A2UI message for rendering in adk web."""
datapart_json = json.dumps({
"kind": "data",
"metadata": {"mimeType": "application/json+a2ui"},
"data": a2ui_message,
})
blob_data = (
b"<a2a_datapart_json>"
+ datapart_json.encode("utf-8")
+ b"</a2a_datapart_json>"
)
return types.Part(
inline_data=types.Blob(
data=blob_data,
mime_type="text/plain",
)
)
def a2ui_callback(
callback_context: CallbackContext,
llm_response: LlmResponse,
) -> LlmResponse | None:
"""Convert A2UI JSON in text output to rendered components."""
if not llm_response.content or not llm_response.content.parts:
return None
for part in llm_response.content.parts:
if not part.text:
continue
text = part.text.strip()
if not text:
continue
if not any(k in text for k in ("beginRendering", "surfaceUpdate", "dataModelUpdate")):
continue
# Strip markdown fences
if text.startswith("```"):
text = text.split("\n", 1)[-1]
if text.endswith("```"):
text = text[:-3].strip()
# Find where JSON starts (skip conversational prefix)
json_start = None
for i, ch in enumerate(text):
if ch in ("[", "{"):
json_start = i
break
if json_start is None:
continue
json_text = text[json_start:]
# raw_decode parses JSON and ignores trailing text
try:
parsed, _ = json.JSONDecoder().raw_decode(json_text)
except json.JSONDecodeError:
# Handle concatenated JSON objects: {"a":1} {"b":2}
try:
fixed = "[" + re.sub(r'\}\s*\{', '},{', json_text) + "]"
parsed, _ = json.JSONDecoder().raw_decode(fixed)
except json.JSONDecodeError:
continue
if not isinstance(parsed, list):
parsed = [parsed]
a2ui_keys = {"beginRendering", "surfaceUpdate", "dataModelUpdate", "deleteSurface"}
a2ui_messages = [msg for msg in parsed if isinstance(msg, dict) and any(k in msg for k in a2ui_keys)]
if not a2ui_messages:
continue
new_parts = [_wrap_a2ui_part(msg) for msg in a2ui_messages]
return LlmResponse(
content=types.Content(role="model", parts=new_parts),
custom_metadata={"a2a:response": "true"},
)
return None
Tiện ích này thực hiện 2 việc:
- Trích xuất JSON A2UI từ đầu ra văn bản của tác nhân
- Bao bọc từng thông báo A2UI theo định dạng mà trình kết xuất A2UI tích hợp của
adk webmong đợi
Cập nhật tác nhân
Thay thế nội dung của a2ui_agent/agent.py bằng nội dung sau. Thay đổi duy nhất so với bước trước là việc nhập a2ui_callback và tham số after_model_callback trên tác nhân:
from google.adk.agents import Agent
from a2ui.schema.manager import A2uiSchemaManager
from a2ui.basic_catalog.provider import BasicCatalog
from .resources import get_resources
from .a2ui_utils import a2ui_callback
schema_manager = A2uiSchemaManager(
version="0.8",
catalogs=[BasicCatalog.get_config("0.8")],
)
instruction = schema_manager.generate_system_prompt(
role_description=(
"You are a cloud infrastructure assistant. When users ask about "
"their cloud resources, use the get_resources tool to fetch the "
"current state."
),
workflow_description=(
"Analyze the user's request and return structured UI when appropriate."
),
ui_description=(
"Use cards for resource summaries, rows and columns for comparisons, "
"icons for status indicators, and buttons for drill-down actions. "
"Do NOT use markdown formatting in text values. Use the usageHint "
"property for heading levels instead. "
"Respond ONLY with the A2UI JSON array. Do NOT include any text "
"outside the JSON. Put all explanations into Text components."
),
include_schema=True,
include_examples=True,
)
root_agent = Agent(
model="gemini-3-flash-preview",
name="cloud_dashboard",
description="A cloud infrastructure assistant that renders rich A2UI interfaces.",
instruction=instruction,
tools=[get_resources],
after_model_callback=a2ui_callback,
)
9. Kiểm thử giao diện người dùng được kết xuất
Nếu bạn vẫn đang chạy giao diện người dùng dành cho nhà phát triển ADK từ trước đó, thì giao diện này sẽ tự động tải lại những thay đổi mà bạn đã thực hiện đối với tác nhân.
Làm mới thẻ trình duyệt, chọn a2ui_agent, sau đó bắt đầu một phiên mới bằng cách nhấp vào +New Session (Phiên mới) ở trên cùng bên phải của giao diện người dùng dành cho nhà phát triển ADK và gửi cùng một câu lệnh như trước:
What's running in my project?
Lần này, adk web kết xuất các thành phần A2UI dưới dạng giao diện người dùng thực tế: thẻ có chỉ báo trạng thái, thông tin chi tiết về tài nguyên và nút thao tác.

Hãy thử một câu lệnh khác để xem cách tác nhân tạo ra một giao diện người dùng khác từ cùng một nhóm thành phần cơ bản:
Does anything need my attention?
Cuối cùng, hãy thử một câu lệnh khác để tạo một giao diện người dùng khác nhằm triển khai một dịch vụ mới:
I need to deploy a new service
Mỗi câu lệnh đều được gửi đến cùng một tác nhân, cùng một công cụ và cùng 18 nguyên tắc cơ bản. Nhưng mỗi câu lệnh sẽ tạo ra một giao diện người dùng khác nhau cho một ý định khác nhau.
10. Dọn dẹp
Để tránh để máy chủ cục bộ chạy, hãy dọn dẹp các tài nguyên:
- Trong dòng lệnh đang chạy
adk web, hãy nhấn tổ hợp phím Ctrl+C để dừng máy chủ tác nhân.
Nếu đã tạo một dự án dành riêng cho lớp học lập trình này, bạn có thể xoá toàn bộ dự án:
gcloud projects delete ${GOOGLE_CLOUD_PROJECT}
11. Xin chúc mừng
Bạn đã tạo một tác nhân ADK tạo giao diện người dùng phong phú, mang tính tương tác bằng A2UI.
Kiến thức bạn học được
- A2UI là một giao thức có 18 nguyên tắc khai báo và 3 loại thông báo
- A2UI SDK tạo ra các câu lệnh hệ thống hướng dẫn LLM về danh mục thành phần
- Cùng một tác nhân, công cụ và các thành phần cơ bản tạo nên nhiều giao diện người dùng cho nhiều ý định
- Bạn có thể kết xuất trực tiếp các thành phần A2UI trong
adk webtrong quá trình phát triển
Tạo giao diện người dùng sản xuất
Trong lớp học lập trình này, bạn đã kết xuất A2UI bên trong adk web để phát triển và kiểm thử.
Đối với bản phát hành công khai, bạn sẽ tạo một giao diện người dùng bằng một trong các trình kết xuất A2UI chính thức:
Nền tảng | Trình kết xuất đồ hoạ | Cài đặt |
Web (React) |
|
|
Web (Lit) |
|
|
Web (Angular) |
|
|
Thiết bị di động/Máy tính | Flutter GenUI SDK |