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 是通信媒介,而非仅显示        │
└────────────────────────────────────┘