2026年完全ガイド:A2UI RizzCharts でインタラクティブなダッシュボードを構築する
2026年完全ガイド:A2UI RizzCharts でインタラクティブなダッシュボードを構築する
🎯 核心要点(TL;DR)
- RizzCharts は、A2UI と A2A Protocol を使用してインタラクティブな ecommerce ダッシュボードを構築する方法を示す本番環境対応のサンプルです
- 標準 A2UI カタログを超えた Chart と GoogleMap コンポーネントを含むカスタムコンポーネントカタログを作成する方法を学びます
- リッチな UI をレンダリングするための3メッセージパターン(
beginRendering、surfaceUpdate、dataModelUpdate)を理解します - データバインディングが UI 構造をアプリケーション状態から分離し、リアクティブな更新を可能にする方法を発見します
- Google の Agent Development Kit (ADK) と統合して、ネイティブなクロスプラットフォーム UI を生成する AI エージェントを構築します
目次
- A2UI RizzCharts とは?
- カスタムコンポーネントカタログが重要な理由
- アーキテクチャの詳細
- 実装ステップバイステップ
- カスタムコンポーネント:Chart と GoogleMap
- データバインディングとリアクティブ更新
- RizzCharts サンプルの実行
- ベストプラクティス
- よくある質問
- まとめ
A2UI RizzCharts とは?
RizzCharts は、A2UI(Agent to UI)プロトコルを使用してAI 駆動の ecommerce ダッシュボードを構築する方法を示す公式サンプルアプリケーションです。AI エージェントがリッチなインタラクティブな可視化を作成し、プラットフォーム間でネイティブにレンダリングする宣言的 UI 生成の力を実証しています。
このサンプルは以下を使用します:
- Google の Agent Development Kit (ADK) によるエージェントオーケストレーション
- A2A Protocol によるエージェント間およびエージェントとクライアント間の通信
- 標準 A2UI コンポーネントを拡張するカスタムコンポーネントカタログ
- 柔軟な LLM プロバイダー統合(Gemini、OpenAI など)のためのLiteLLM
💡 プロのヒント
RizzCharts は実世界のパターンを示しています:AI エージェントがドメイン固有の可視化(チャート、マップ)を生成し、これらは汎用的なチャット応答ではなく、アプリケーションのネイティブな機能のように感じられます。
主要機能
| 機能 | 説明 |
|---|---|
| 販売チャート | 製品カテゴリ別の販売内訳を示すインタラクティブなドーナツ/円グラフ |
| 地理的地図 | 店舗の場所とパフォーマンスの外れ値を表示する Google Maps 統合 |
| リアルタイム更新 | データが変更されたときにリアクティブに更新されるデータバインドコンポーネント |
| カスタムカタログ | 標準 A2UI コンポーネントを超えた拡張コンポーネントライブラリ |
カスタムコンポーネントカタログが重要な理由
標準の A2UI カタログは一般的な UI 要素(Text、Button、TextField、Card など)を提供しますが、実世界のアプリケーションではドメイン固有のコンポーネントが必要になることがよくあります:
- 金融ダッシュボードの株価ティッカー
- ヘルスケアアプリケーションの医療チャート
- エンジニアリングツールのCAD ビューア
- 位置ベースサービスのインタラクティブマップ
カスタムカタログの仕組み
graph TD
A[クライアントがカタログを定義] --> B[クライアントがコンポーネントを登録]
B --> C[クライアントがサポートを発表]
C --> D[エージェントがカタログを選択]
D --> E[エージェントが UI を生成]
E --> F[クライアントがネイティブウィジェットをレンダリング]
フロー:
- クライアントがカタログを定義 — 標準コンポーネントとカスタムコンポーネントをリストアップ
- クライアントが実装を登録 — コンポーネントタイプをネイティブウィジェットにマッピング
- クライアントがサポートを発表 — エージェントにサポートするカタログを通知
- エージェントがカタログを選択 — UI サーフェスに適切なカタログを選択
- エージェントが UI を生成 — カタログコンポーネントを使用して
surfaceUpdateメッセージを作成 - クライアントがレンダリング — 任意のコードを実行せずにネイティブウィジェットを表示
アーキテクチャの詳細
プロジェクト構造
samples/agent/adk/rizzcharts/
├── __main__.py # エントリーポイント、サーバー設定
├── agent.py # LLM 指示付きの RizzchartsAgent
├── agent_executor.py # セッション管理付きの A2A エグゼキューター
├── component_catalog_builder.py # カスタムカタログ読み込みロジック
├── tools.py # データ取得ツール
├── rizzcharts_catalog_definition.json # カスタムコンポーネントスキーマ
└── examples/
├── rizzcharts_catalog/ # カスタム Chart/GoogleMap を使用する例
│ ├── chart.json
│ └── map.json
└── standard_catalog/ # 標準コンポーネントを使用するフォールバック
├── chart.json
└── map.json
コアコンポーネント
1. RizzchartsAgent (agent.py)
ユーザーリクエストを処理し、A2UI ペイロードを生成するメインエージェントクラス:
class RizzchartsAgent(LlmAgent):
"""ecommerce ダッシュボードを実行するエージェント"""
def __init__(self, model, a2ui_enabled_provider, a2ui_schema_provider):
super().__init__(
model=model,
name="rizzcharts_agent",
description="販売マネージャーが販売データをリクエストできるエージェント",
instruction=self.get_instructions,
tools=[
get_store_sales, # 地域/店舗データを取得
get_sales_data, # 販売内訳データを取得
SendA2uiToClientToolset(...) # クライアントに A2UI JSON を送信
],
planner=BuiltInPlanner(
thinking_config=types.ThinkingConfig(include_thoughts=True)
),
)
2. Agent Executor (agent_executor.py)
セッション設定と A2UI 拡張機能のアクティベーションを処理:
class RizzchartsAgentExecutor(A2aAgentExecutor):
def get_agent_card(self) -> AgentCard:
return AgentCard(
name="Ecommerce ダッシュボードエージェント",
description="チャートとマップで ecommerce データを可視化",
capabilities=AgentCapabilities(
streaming=True,
extensions=[get_a2ui_agent_extension(
supported_catalog_ids=[STANDARD_CATALOG_ID, RIZZCHARTS_CATALOG_URI]
)],
),
skills=[
AgentSkill(id="view_sales_by_category", ...),
AgentSkill(id="view_regional_outliers", ...),
],
)
3. Component Catalog Builder (component_catalog_builder.py)
コンポーネントスキーマを動的に読み込み、マージ:
class ComponentCatalogBuilder:
def load_a2ui_schema(self, client_ui_capabilities):
# クライアントがサポートするカタログを確認
if RIZZCHARTS_CATALOG_URI in supported_catalog_uris:
catalog_uri = RIZZCHARTS_CATALOG_URI # カスタム Chart/GoogleMap を使用
elif STANDARD_CATALOG_ID in supported_catalog_uris:
catalog_uri = STANDARD_CATALOG_ID # 標準コンポーネントにフォールバック
# カタログを A2UI スキーマにマージ
a2ui_schema_json["properties"]["surfaceUpdate"]
["properties"]["components"]["items"]
["properties"]["component"]["properties"] = catalog_json
return a2ui_schema_json, catalog_uri
実装ステップバイステップ
ステップ 1:カスタムコンポーネントを定義
カスタムコンポーネントを定義する JSON スキーマを作成します。以下が RizzCharts カタログです:
{
"components": {
"$ref": "standard_catalog_definition.json#/components",
"Canvas": {
"type": "object",
"description": "チャットの横のステートフルパネルで UI をレンダリング",
"properties": {
"children": {
"type": "object",
"properties": {
"explicitList": {
"type": "array",
"items": { "type": "string" }
}
}
}
},
"required": ["children"]
},
"Chart": {
"type": "object",
"description": "階層データを持つインタラクティブチャート",
"properties": {
"type": {
"type": "string",
"enum": ["doughnut", "pie"]
},
"title": {
"type": "object",
"properties": {
"literalString": { "type": "string" },
"path": { "type": "string" }
}
},
"chartData": {
"type": "object",
"properties": {
"literalArray": { "type": "array" },
"path": { "type": "string" }
}
}
},
"required": ["type", "chartData"]
},
"GoogleMap": {
"type": "object",
"description": "カスタマイズ可能なピンを持つ Google Map",
"properties": {
"center": { "type": "object" },
"zoom": { "type": "object" },
"pins": { "type": "object" }
},
"required": ["center", "zoom"]
}
}
}
ステップ 2:データ取得ツールを作成
エージェントがデータを取得するために使用するツールを実装:
def get_sales_data(time_period: str = "year", **kwargs) -> dict:
"""製品カテゴリ別の販売内訳を取得"""
return {
"sales_data": [
{"label": "Apparel", "value": 41, "drillDown": [
{"label": "Tops", "value": 31},
{"label": "Bottoms", "value": 38},
{"label": "Outerwear", "value": 20},
]},
{"label": "Electronics", "value": 28, "drillDown": [...]},
{"label": "Home Goods", "value": 15},
{"label": "Health & Beauty", "value": 10},
{"label": "Other", "value": 6},
]
}
def get_store_sales(region: str = "all", **kwargs) -> dict:
"""販売パフォーマンス付きの店舗の場所を取得"""
return {
"center": {"lat": 34, "lng": -118.2437},
"zoom": 10,
"locations": [
{
"lat": 34.0195, "lng": -118.4912,
"name": "Santa Monica Branch",
"description": "高トラフィックの沿岸地域",
"outlier_reason": "はい、ベースラインを 15% 上回る販売",
"background": "#4285F4", # ハイライトされたピン
},
{"lat": 34.0488, "lng": -118.2518, "name": "Downtown Flagship"},
# ... より多くの場所
],
}
ステップ 3:エージェント指示を設定
エージェントは A2UI ペイロードを生成するための詳細な指示を受け取ります:
def get_instructions(self, readonly_context: ReadonlyContext) -> str:
return f"""
### システム指示
あなたは A2UI Ecommerce ダッシュボード分析の専門家です。主な機能は、ユーザーリクエストを A2UI JSON ペイロードに変換することです。
**ワークフロー:**
1. リクエストを分析 - 意図を決定(Chart か Map か)
2. データを取得 - `get_sales_data` または `get_store_sales` を使用
3. テンプレートを選択 - CHART または MAP の例をベースとして使用
4. JSON ペイロードを構築 - 一意の surfaceId を生成し、タイトルを更新
5. ツールを呼び出す - `send_a2ui_json_to_client` を使用
**例:**
- "Q3 のカテゴリ別販売内訳を表示" → Chart
- "外れ値の店舗はありましたか" → Map
---BEGIN CHART EXAMPLE---
{json.dumps(chart_example)}
---END CHART EXAMPLE---
---BEGIN MAP EXAMPLE---
{json.dumps(map_example)}
---END MAP EXAMPLE---
"""
ステップ 4:A2UI メッセージペイロードを作成
完全な A2UI ペイロードは 3 つのメッセージで構成されます:
Chart の例
[
{
"beginRendering": {
"surfaceId": "sales-dashboard",
"root": "root-canvas"
}
},
{
"surfaceUpdate": {
"surfaceId": "sales-dashboard",
"components": [
{
"id": "root-canvas",
"component": {
"Canvas": {
"children": { "explicitList": ["chart-container"] }
}
}
},
{
"id": "chart-container",
"component": {
"Column": {
"children": { "explicitList": ["sales-chart"] },
"alignment": "center"
}
}
},
{
"id": "sales-chart",
"component": {
"Chart": {
"type": "doughnut",
"title": { "path": "chart.title" },
"chartData": { "path": "chart.items" }
}
}
}
]
}
},
{
"dataModelUpdate": {
"surfaceId": "sales-dashboard",
"path": "/",
"contents": [
{ "key": "chart.title", "valueString": "Sales by Category" },
{ "key": "chart.items[0].label", "valueString": "Apparel" },
{ "key": "chart.items[0].value", "valueNumber": 41 },
{ "key": "chart.items[0].drillDown[0].label", "valueString": "Tops" },
{ "key": "chart.items[0].drillDown[0].value", "valueNumber": 31 }
// ... より多くのデータ
]
}
}
]
Map の例
[
{
"beginRendering": {
"surfaceId": "la-map-view",
"root": "root-canvas"
}
},
{
"surfaceUpdate": {
"surfaceId": "la-map-view",
"components": [
{
"id": "root-canvas",
"component": {
"Canvas": { "children": { "explicitList": ["map-layout-container"] } }
}
},
{
"id": "map-header",
"component": {
"Text": {
"text": { "literalString": "Points of Interest in Los Angeles" },
"usageHint": "h2"
}
}
},
{
"id": "location-map",
"component": {
"GoogleMap": {
"center": { "path": "mapConfig.center" },
"zoom": { "path": "mapConfig.zoom" },
"pins": { "path": "mapConfig.locations" }
}
}
}
]
}
},
{
"dataModelUpdate": {
"surfaceId": "la-map-view",
"path": "/",
"contents": [
{ "key": "mapConfig.center.lat", "valueNumber": 34.0522 },
{ "key": "mapConfig.center.lng", "valueNumber": -118.2437 },
{ "key": "mapConfig.zoom", "valueNumber": 11 },
{ "key": "mapConfig.locations[0].lat", "valueNumber": 34.0135 },
{ "key": "mapConfig.locations[0].name", "valueString": "Google Store Santa Monica" }
// ... より多くの場所
]
}
}
]
カスタムコンポーネント:Chart と GoogleMap
Chart コンポーネント
Chart コンポーネントはインタラクティブなドーナツまたは円グラフをレンダリングします:
| プロパティ | タイプ | 説明 |
|---|---|---|
type |
"doughnut" | "pie" |
チャート可視化タイプ |
title |
{literalString} | {path} |
チャートタイトル(リテラルまたはデータバインド) |
chartData |
{literalArray} | {path} |
{label, value, drillDown?} アイテムの配列 |
DrillDown サポート: 各チャートアイテムは、階層的可視化のためのネストされた drillDown データを持つことができます:
{
"label": "Apparel",
"value": 41,
"drillDown": [
{ "label": "Tops", "value": 31 },
{ "label": "Bottoms", "value": 38 },
{ "label": "Outerwear", "value": 20 }
]
}
GoogleMap コンポーネント
GoogleMap コンポーネントは、カスタマイズ可能なピンを持つインタラクティブマップを表示します:
| プロパティ | タイプ | 説明 |
|---|---|---|
center |
{lat, lng} |
マップの中心座標 |
zoom |
number |
ズームレベル(1-20) |
pins |
array |
ピンオブジェクトの配列 |
ピンのプロパティ:
{
"lat": 34.0195,
"lng": -118.4912,
"name": "Santa Monica Branch",
"description": "高トラフィックの沿岸地域",
"background": "#4285F4", // ピンの背景色
"borderColor": "#FFFFFF", // ピンの境界色
"glyphColor": "#FFFFFF" // ピンのアイコン色
}
データバインディングとリアクティブ更新
A2UI は、データバインディングを通じてUI 構造をアプリケーション状態から分離します:
リテラル vs. パス値
// リテラル(固定値)
{"text": {"literalString": "Sales Dashboard"}}
// パス(データバインド、リアクティブ)
{"text": {"path": "chart.title"}}
chart.title のデータが変更されると、コンポーネントは自動的に更新されます—コンポーネントの再生成は不要です。
JSON Pointer パス
A2UI は RFC 6901 JSON Pointer 構文を使用します:
| パス | 解決先 |
|---|---|
/user/name |
オブジェクトプロパティ |
/items/0 |
最初の配列要素 |
/items/0/price |
ネストされたプロパティ |
テンプレート内のスコープパス
動的リストにテンプレートを使用する場合、パスは各配列アイテムに対してスコープされます:
{
"id": "location-name",
"component": {
"Text": {
"text": { "path": "name" } // 現在のアイテムに対して相対的
}
}
}
/mapConfig.locations/0 の場合、パス name は /mapConfig.locations/0/name に解決されます。
RizzCharts サンプルの実行
前提条件
- Python 3.9+
- UV パッケージマネージャー
- LLM API キー(Gemini、OpenAI など)
セットアップ
# サンプルディレクトリに移動
cd samples/agent/adk/rizzcharts
# 環境ファイルを作成
cp .env.example .env
# API キーで .env を編集
# エージェントサーバーを実行
uv run .
サーバーはデフォルトで http://localhost:10002 で起動します。
環境変数
| 変数 | 説明 | デフォルト |
|---|---|---|
GEMINI_API_KEY |
Google AI API キー | 必須 |
GOOGLE_GENAI_USE_VERTEXAI |
代わりに Vertex AI を使用 | FALSE |
LITELLM_MODEL |
LLM モデル識別子 | gemini/gemini-2.5-flash |
サンプルクエリでテスト
実行後、次のようなリクエストを送信します:
- "Q3 の製品カテゴリ別販売内訳を表示" → ドーナツチャートを生成
- "地域に外れ値の店舗はありましたか?" → ハイライトされたピンを持つマップを生成
- "前年比の収益トレンドはどうですか?" → チャート可視化を生成
ベストプラクティス
1. 説明的なコンポーネント ID
// ✅ 良い
{"id": "sales-chart-q3-2026"}
{"id": "store-location-map"}
// ❌ 悪い
{"id": "c1"}
{"id": "component"}
2. 構造とデータを分離
動的コンテンツにはデータバインディングを使用:
// ✅ 推奨 - データバインド
{"title": {"path": "chart.title"}}
// ⚠️ 控えめに使用 - リテラル値
{"title": {"literalString": "Static Title"}}
3. 一意の Surface ID を生成
各リクエストは一意の surfaceId を生成する必要があります:
surface_id = f"sales_breakdown_{time_period}_{uuid.uuid4().hex[:8]}"
4. スキーマに対して検証
生成された JSON を常に A2UI スキーマに対して検証:
jsonschema.validate(instance=example_json, schema=a2ui_schema)
5. セキュリティの考慮事項
⚠️ 重要なセキュリティ注意事項
- エージェントが生成したすべてのコンテンツを信頼できない入力として扱います
- すべてのプロパティ値に対して入力サニタイゼーションを実装します
- クライアントレンダラーでコンテンツセキュリティポリシー (CSP) を使用します
- レンダリング前にデータを厳密に検証します
よくある質問
Q: 標準カタログとカスタムカタログの違いは何ですか?
A: 標準カタログには、すべての A2UI クライアントで機能する一般的な UI コンポーネント(Text、Button、Card、List など)が含まれています。カスタムカタログは、クライアント側の実装を必要とするドメイン固有のコンポーネント(Chart、GoogleMap、StockTicker)でこれを拡張します。RizzCharts は両方のアプローチを示し、フォールバックサポートを提供します。
Q: A2UI は HTML/iframe の送信と比較してどうですか?
A: A2UI は宣言的データであり、コードではありません。クライアントは独自のネイティブウィジェットを使用してコンポーネントをレンダリングし、以下を保証します:
- コード実行リスクなし(セキュリティ)
- ネイティブなルックアンドフィール(UX)
- 一貫したスタイリング(デザイン)
- クロスプラットフォームサポート(移植性)
Q: RizzCharts コンポーネントを他のプロトコルで使用できますか?
A: はい!RizzCharts は A2A Protocol を使用していますが、A2UI メッセージ形式は任意のトランスポートで機能します:SSE、WebSockets、AG UI、または直接 HTTP。AP2 Protocol も、支払い対応のエージェントインターフェース用に A2UI と統合されています。
Q: クライアントでカスタムコンポーネントを実装するにはどうすればよいですか?
A: クライアントフレームワークでコンポーネント実装を登録:
- カタログ JSON でコンポーネントスキーマを定義
- レンダリングロジックを実装(Lit、Angular、React、Flutter)
- A2UI クライアントにカタログを登録
- エージェントにサポートするカタログを発表
参照実装については Lit サンプル を参照してください。
Q: クライアントがカタログをサポートしていない場合はどうなりますか?
A: RizzCharts にはフォールバックサポートが含まれています。ComponentCatalogBuilder はクライアントの機能を確認します:
if RIZZCHARTS_CATALOG_URI in supported_catalog_uris:
catalog_uri = RIZZCHARTS_CATALOG_URI # カスタムコンポーネント
elif STANDARD_CATALOG_ID in supported_catalog_uris:
catalog_uri = STANDARD_CATALOG_ID # 標準コンポーネント
標準カタログの例は、Chart/GoogleMap なしで同じデータを表示するために List と Card コンポーネントを使用します。
まとめ
RizzCharts サンプルは、エージェント駆動のダッシュボードを構築するための A2UI の完全な力を実証しています:
- カスタムコンポーネントカタログが A2UI を基本 UI 要素を超えて拡張
- データバインディングがリアクティブで効率的な更新を可能に
- スキーマ検証が型安全なエージェント出力を保証
- フォールバックサポートが優雅な劣化を提供
- セキュリティ設計がクライアントを制御下に保つ
次のステップ
- コードを探索:GitHub の RizzCharts
- 独自のカタログを構築:カスタムコンポーネントガイド から始める
- A2A 統合を学ぶ:A2A Protocol ドキュメント を確認
- 支払いを追加:AP2 Protocol と統合してコマースフローを実現
最終更新:2026年1月
キーワード:A2UI, Agent to UI, RizzCharts, custom components, declarative UI, A2A Protocol, ecommerce dashboard, data visualization, AI agents, LLM UI generation
Related Articles
Explore more content related to this topic
The Complete Developer Tutorial: Building AI Agent UIs with A2UI and A2A Protocol in 2026
Master A2UI and A2A Protocol development with this complete tutorial. Learn to build AI agent UIs, implement renderers, create custom components, and integrate secure multi-agent communication for cross-platform applications.
A2UI Introduction - Declarative UI Protocol for Agent-Driven Interfaces
Discover A2UI, the declarative UI protocol that enables AI agents to generate rich, interactive user interfaces. Learn how A2UI works, who it's for, how to use it, and see real-world examples from Google Opal, Gemini Enterprise, and Flutter GenUI SDK.
Universal Commerce Protocol (UCP): The Complete 2026 Guide to Agentic Commerce Standards
Discover Universal Commerce Protocol (UCP), the open standard revolutionizing agentic commerce. Learn how UCP enables seamless interoperability between AI platforms, businesses, and payment providers, solving fragmented commerce journeys with standardized APIs for checkout, order management, and payment processing.
The A2UI Protocol: A 2026 Complete Guide to Agent-Driven Interfaces
Discover A2UI, the security-first declarative UI protocol that enables AI agents to generate rich, interactive user interfaces. Learn how A2UI solves the 'Chat Wall' problem, achieves security through data vs. code separation, and enables dynamic cross-platform interfaces. Includes real-world examples and implementation guidance.
The Complete Guide to A2UI Protocol: Building Agent-Driven UIs with Google's A2UI in 2025
A comprehensive guide to A2UI (Agent to UI), a declarative UI protocol for agent-driven interfaces. Learn how AI agents generate rich, interactive UIs that render natively across platforms without executing arbitrary code.