1. 概要
ほとんどのエージェント アプリはプレーン テキストを返します。A2UI はそれを変えます。これは、エージェントがリッチでインタラクティブなインターフェースを構成できるようにする 18 個の宣言型 UI プリミティブを備えたプロトコルです。クライアントはそれらをネイティブにレンダリングします。レイアウトごとに新しいフロントエンド コードは必要ありません。
この Codelab では、Agent Development Kit(ADK)を使用してエージェントを構築し、A2UIを使用して UI を生成します。
作成するアプリの概要
3 つのステージで構成されるクラウド インフラストラクチャ ダッシュボード:
- リソースデータをプレーン テキストとして返す標準エージェント
- 同じデータを構造化された A2UI JSON として返すA2UI エージェント
- A2UI JSON を ADK 開発 UI のインタラクティブな UI コンポーネントとして表示するレンダリングされたエージェント

学習内容
- A2UI の仕組み: 18 個のプリミティブ、3 つのメッセージ タイプ、フラット コンポーネント モデル
- A2UI SDK を使用して ADK エージェントに A2UI JSON を生成させる方法
adk webで A2UI コンポーネントをレンダリングする方法
必要なもの
- 課金を有効にした Google Cloud プロジェクト
- ウェブブラウザ(Chrome など)
- Python 3.12 以降
この Codelab は、Python と Google Cloud にある程度精通している中級レベルのデベロッパーを対象としています。
この Codelab を完了するまでに約 15 ~ 20 分かかります。
この Codelab で作成するリソースの費用は 5 ドル未満です。
2. 環境を設定する
Google Cloud プロジェクトの作成
- Google Cloud コンソールのプロジェクト選択ページで、Google Cloud プロジェクトを選択または作成します。
- Cloud プロジェクトに対して課金が有効になっていることを確認します。プロジェクトで課金が有効になっているかどうかを確認する方法をご覧ください。
Cloud Shell エディタを起動する
Google Cloud コンソールから Cloud Shell セッションを起動するには、Google Cloud コンソールで [Cloud Shell をアクティブにする] をクリックします。
これにより、Google Cloud コンソールの下部ペインでセッションが起動します。
エディタを起動するには、Cloud Shell ウィンドウのツールバーにある [エディタを開く] をクリックします。
環境変数を設定する
Cloud Shell エディタのツールバーで、[**ターミナル**]、[**新しいターミナル**] をクリックし、次のコマンドを実行してプロジェクトとロケーションを設定し、Vertex AI で Gemini を使用するように ADK を構成します。
export GOOGLE_CLOUD_PROJECT=<INSERT_YOUR_GCP_PROJECT_HERE> export GOOGLE_CLOUD_LOCATION=global export GOOGLE_GENAI_USE_VERTEXAI=True
API を有効にする
ターミナルで次のコマンドを実行して、必要な API を有効にします。
gcloud services enable aiplatform.googleapis.com
依存関係のインストール
ターミナルで次のコマンドを実行して、Agent Development Kit(ADK)の最新バージョンをインストールします。
pip install -U google-adk a2ui-agent-sdk export PATH="$HOME/.local/bin:$PATH"
3. エージェントを作成する
プレーン テキストを返す標準の ADK エージェントから始めます。これが、現在のほとんどのエージェント アプリの外観です。
エージェント フォルダを作成する
エージェントとツールのソースコードを格納する a2ui_agent というフォルダを作成します。
ツールとモックデータを定義する
次の内容で a2ui_agent/resources.py を作成します。このツールは、ステータスを含むクラウド リソースのリストを返します。
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
エージェントを定義する
次の内容で a2ui_agent/agent.py を作成します。
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. エージェントをテストする
ADK には、ブラウザでエージェントを操作してプロンプトを送信し、テストに使用できる開発 UI が含まれています。
ADK 開発 UI を起動する
Cloud Shell エディタのターミナルで、次のコマンドを実行して ADK 開発 UI を起動します。
adk web --port 8080 --allow_origins "*" --reload_agents
次のようなメッセージが表示されます。
+-----------------------------------------------------------------------------+ | ADK Web Server started | | | | For local testing, access at http://127.0.0.1:8080. | +-----------------------------------------------------------------------------+
ADK 開発 UI を開く
ADK 開発 UI をブラウザで開くには、ローカル テスト URL を Ctrl キーまたは Cmd キーを押しながらクリックするか、[ウェブでプレビュー] ボタンをクリックして [ポート 8080 でプレビュー] を選択します。
ADK 開発 UI が表示されたら、プルダウン メニューから a2ui_agent を選択します。
サンプル プロンプトを送信する
エージェントにサンプル プロンプトを送信します。
What's running in my project?
別のサンプル プロンプトを試すと、より多くのテキスト出力が得られます。
Does anything need my attention?
会話は次のようになります。

テキストの壁が表示されます。正確ですが、優れたユーザー エクスペリエンスとは言えません。
5. A2UI JSON を生成する
エージェントがテキストをダンプするのではなく、UI を記述できるとしたらどうでしょうか。A2UI は、エージェントが 18 個のプリミティブのカタログからインタラクティブなインターフェースを構成できるようにするプロトコルです。クライアントはそれらをネイティブにレンダリングします。
A2UI Python SDK には、システム プロンプトを生成するスキーマ マネージャーが含まれています。LLM に、完全な A2UI コンポーネント カタログ、正しいプロパティ名とタイプ、JSON 構造を学習させます。
エージェントを更新する
a2ui_agent/agent.py の内容を次のように置き換えます。
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],
)
generate_system_prompt() メソッドは、ロールの説明を完全な A2UI JSON スキーマとフューショットの例と組み合わせるため、LLM は出力のフォーマット方法を正確に把握できます。コンポーネント カタログを手動で作成する必要はありません。
6. JSON 出力をテストする
以前から ADK 開発 UI が実行されている場合は、エージェントに加えた変更が自動的に再読み込みされます。
a2ui_agent を選択し、ADK 開発 UI の右上にある [+New Session] をクリックして新しいセッションを開始し、以前と同じプロンプトを送信します。
What's running in my project?
今回は、エージェントはプレーン テキストではなく A2UI JSON で応答します。チャット出力に beginRendering、surfaceUpdate、dataModelUpdate を含む構造化メッセージが表示されます。

JSON はカード、アイコン、ボタンを含むリッチな UI を記述しますが、adk web はそれを未加工テキストとして表示します。次のステップでは、実際の UI コンポーネントとしてレンダリングします。
7. A2UI を理解する
エージェントが生成した JSON を確認します。3 種類のメッセージが含まれています。すべての A2UI レスポンスは同じ構造に従います。
1. beginRendering
レンダリング サーフェスを作成し、ルート コンポーネントに名前を付けます。
{"beginRendering": {"surfaceId": "default", "root": "main-column"}}
2. surfaceUpdate
コンポーネント ツリーを ID 参照(ネストされていない)を含むフラット リスト として送信します。
{"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
構造とは別にデータを送信します。
{"dataModelUpdate": {"surfaceId": "default", "contents": [
{"key": "service_name", "valueString": "auth-service"},
{"key": "status", "valueString": "healthy"}
]}}
コンポーネントは {"path": "key"} を使用してデータにバインドされます。コンポーネント ツリーを再送信せずにデータを更新できます。
18 個のプリミティブ
カテゴリ | コンポーネント |
レイアウト | カード、列、行、リスト、タブ、区切り線、モーダル |
ディスプレイ | テキスト、画像、アイコン、動画、オーディオ プレーヤー |
入力 | テキスト フィールド、日付 / 時刻入力、複数選択、チェックボックス、スライダー |
アクション | ボタン |
エージェントは同じカタログからさまざまなレイアウトを構成します。各コンポーネント リファレンスの詳細については、コンポーネント リファレンスをご覧ください。ブラウズビュー、優先度ダッシュボード、構成フォームはすべて同じ 18 個のプリミティブを使用します。新しいフロントエンド コンポーネントは必要ありません。
8. A2UI コンポーネントをレンダリングする
エージェントは有効な A2UI JSON を生成しますが、adk web はそれを未加工テキストとして表示します。実際の UI コンポーネントとしてレンダリングするには、エージェントの A2UI JSON 出力を adk web の組み込みレンダラが想定する形式に変換する小さなユーティリティが必要です。
A2UI レンダリング ユーティリティを作成する
次の内容で a2ui_agent/a2ui_utils.py を作成します。
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
このユーティリティは次の 2 つの処理を行います。
- エージェントのテキスト出力から A2UI JSON を抽出する
adk webの組み込み A2UI レンダラが想定する形式で各 A2UI メッセージをラップする
エージェントを更新する
a2ui_agent/agent.py の内容を次のように置き換えます。前のステップからの唯一の変更点は、a2ui_callback のインポートとエージェントの after_model_callback パラメータです。
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. レンダリングされた UI をテストする
以前から ADK 開発 UI が実行されている場合は、エージェントに加えた変更が自動的に再読み込みされます。
ブラウザタブを更新し、a2ui_agent を選択して、ADK 開発 UI の右上にある [+New Session] をクリックして新しいセッションを開始し、以前と同じプロンプトを送信します。
What's running in my project?
今回は、adk web は A2UI コンポーネントを実際の UI としてレンダリングします。ステータス インジケーター、リソースの詳細、操作ボタンを含むカードです。

別のプロンプトを試して、エージェントが同じプリミティブ セットから別の UI を構成する方法を確認します。
Does anything need my attention?
最後に、別のプロンプトを試して、新しいサービスをデプロイするための別の UI を生成します。
I need to deploy a new service
各プロンプトは、同じエージェント、同じツール、同じ 18 個のプリミティブに送信されます。ただし、プロンプトごとに、インテントが異なる UI が生成されます。
10. クリーンアップ
ローカル サーバーが実行されたままにならないように、リソースをクリーンアップします。
adk webを実行しているターミナルで、Ctrl+C キーを押してエージェント サーバーを停止します。
この Codelab 専用のプロジェクトを作成した場合は、プロジェクト全体を削除できます。
gcloud projects delete ${GOOGLE_CLOUD_PROJECT}
11. 完了
A2UI を使用してリッチでインタラクティブな UI を生成する ADK エージェントを作成しました。
学習した内容
- A2UI は、18 個の宣言型プリミティブ と 3 つのメッセージ タイプ を備えたプロトコルです。
- A2UI SDK は、LLM にコンポーネント カタログを学習させるシステム プロンプトを生成します。
- 同じエージェント、ツール、プリミティブで、インテントが異なる UI を構成します。
- A2UI コンポーネントは、開発中に
adk webで直接レンダリングできます。
本番環境のフロントエンドを構築する
この Codelab では、開発とテストのために adk web 内で A2UI をレンダリングしました。
本番環境では、公式の A2UI レンダラを使用してフロントエンドを構築します。
プラットフォーム | レンダリング | インストール |
ウェブ(React) |
|
|
ウェブ(Lit) |
|
|
ウェブ(Angular) |
|
|
モバイル/デスクトップ | Flutter GenUI SDK |