A2UI:Agent 到用户的生成式显示窗口
4.1 通信差距:为什么需要 A2UI?
人类 vs. Agent 的信息传递方式对比:
| 场景 | 人类做法 | Agent 做法 | 问题 |
|---|---|---|---|
| “Q4 按区域表现如何?” | 在白板画柱状图、圈出亮点、添加上下文 | 返回原始 JSON spreadsheet | 用户需手动导入库、配置坐标轴、管理状态 |
结果:context-switching 破坏 vibe coding 流程。
4.2 Generative UI 的概念
Generative UI = LLM 根据用户意图和上下文在运行时动态创建界面,而非开发者预编码所有 UI 状态。
传统方式:
┌────────────────────────────────────┐
│ 开发者预构建所有可能的 UI 状态 │
│ → 硬编码每个按钮、图表、表单 │
│ → 代码量大、维护成本高 │
└────────────────────────────────────┘
Generative UI:
┌────────────────────────────────────┐
│ LLM 根据请求动态生成界面 │
│ → "比较 Q4 销售按区域" │
│ → Agent 生成交互式布局、卡片、过滤器│
│ → 无需预编码 │
└────────────────────────────────────┘
安全挑战:运行 LLM 生成的任意 UI 代码存在 XSS、代码注入风险。
4.3 A2UI:安全的实现方式
A2UI 是 Google 的开源标准,核心设计理念:
┌─────────────────────────────────────────────────────────────┐
│ Sheet Music vs. Recording │
├─────────────────────────────────────────────────────────────┤
│ 作曲家不给音乐家录音 → 给乐谱 │
│ 同一首乐谱可在钢琴、管弦乐队、合成器上演奏 │
│ │
│ A2UI = UI 的乐谱 │
│ ───────────────── │
│ Agent 写意图(what to render) │
│ Renderer(React/Angular/Lit/Flutter/Jetpack/SwiftUI)演奏 │
│ │
│ 关键:Agent 不知道目标平台(Web/Mobile/Wearable/Appliance)│
│ 只知道组件 catalog │
└─────────────────────────────────────────────────────────────┘
安全模型:
传统方式(不安全):
┌────────────────────────────────────┐
│ Agent 生成可执行代码 │
│ → XSS 风险 │
│ → 代码注入 │
│ → 无控制副作用 │
└────────────────────────────────────┘
A2UI 方式(安全):
┌────────────────────────────────────┐
│ Agent 从可信 catalog 请求组件 │
│ → 组件库预先审核 │
│ → 无任意代码执行 │
│ → 客户端用自己的设计系统渲染 │
└────────────────────────────────────┘
类比:LEGO blocks —— Agent 拼装预定义的安全组件块,而非生成任意代码。
4.4 Basic Catalog(基础组件库)
A2UI v0.9 提供的 18 个基础组件:
| 类别 | 组件 |
|---|---|
| Layout | Row, Column, List |
| Display | Text, Image, Icon, Divider |
| Containers | Card, Modal, Tabs |
| Media | Video, AudioPlayer |
| Interactive | Button, TextField, CheckBox, Slider, DateTimeInput, ChoicePicker |
命名变化:v0.8 的 standard 在 v0.9 改为 basic,信号是生产前端应Bring Your Own Catalog(映射自己的设计系统组件到 A2UI 类型)。
4.5 A2UI 消息结构
A2UI 使用flat adjacency list(扁平邻接表),每个组件通过 id 引用:
{
"version": "v0.9",
"updateComponents": {
"surfaceId": "main",
"components": [
{"id": "root", "component": "Column", "children": ["title", "summary", "export"]},
{"id": "title", "component": "Text", "text": "Q4 Sales", "variant": "h1"},
{"id": "summary", "component": "Text", "text": "Revenue grew 12% QoQ"},
{"id": "export", "component": "Button", "child": "export-label", "action": {"event": {"name": "export_csv"}}},
{"id": "export-label", "component": "Text", "text": "Export CSV"}
]
}
}优势: - LLM 可增量生成 - 客户端可局部更新,无需重渲染整个结构
4.6 两种 A2UI 生成模式
| 模式 | 责任归属 | 适用场景 | Token 消耗 |
|---|---|---|---|
| LLM-generates-UI | Agent 动态决定布局 | 意图驱动的灵活请求(“比较这些区域”) | 高(LLM 生成 UI) |
| Tool-as-template | 工具返回固定 A2UI 结构 | 输入驱动的确定性布局(每个区域 dashboard 结构相同) | 低(工具调用一次) |
Tool-as-template 示例:
from google.adk.agents import LlmAgent
from google.adk.models import Gemini
def get_sales_dashboard(region: str) -> dict:
"""Build a data-bound sales dashboard for `region`."""
data = fetch_sales(region)
return {
"version": "v0.9",
"updateComponents": {
"surfaceId": "sales",
"components": [
{"id": "root", "component": "Column", "children": ["title", "total", "drill"]},
{"id": "title", "component": "Text", "text": {"path": "/title"}, "variant": "h1"},
{"id": "total", "component": "Text", "text": {"path": "/total"}},
{"id": "drill", "component": "Button", "child": "drill-label", "action": {"event": {"name": "expand_details"}}},
{"id": "drill-label", "component": "Text", "text": "Drill Down"}
]
}
}
agent = LlmAgent(
name="sales_agent",
model=Gemini(model="gemini-flash-latest"),
tools=[get_sales_dashboard]
)数据绑定:通过 {path: "/title"} 引用,客户端通过 updateDataModel 消息填充实际值。
4.7 Query-to-Output 映射表
| 查询类型 | 返回类型 | 生成模式 |
|---|---|---|
| “平均值是多少?” | Data(text) | 无需 A2UI |
| “比较这些区域” | UI | LLM-generates-UI |
| “显示我的 dashboard” | UI | Tool-as-template |
| API-to-API | Data(JSON) | 无需 A2UI |
4.8 Canvas + A2UI
Canvas 概念:持久化工作空间,Agent 和用户可实时编辑。
传统 Chat Interface:
┌────────────────────────────────────┐
│ 线性、静态 │
│ → 每个响应是固定文本 │
│ → 需滚动历史记录 │
└────────────────────────────────────┘
Canvas Approach:
┌────────────────────────────────────┐
│ 持久化、动态 │
│ → Agent 和用户共同编辑 │
│ → 实时反映变更 │
│ → UI 是通信媒介,而非仅显示 │
└────────────────────────────────────┘