返回博客列表

A2UI 协议深度解析:让 AI Agent 动态生成可视化界面的新范式

2026-07-18
A2UIAgentGenerative UIA2AAG-UI数据可视化

一、问题:Agent 只会"说"不会"画"

传统 AI Agent 的输出方式有一个根本局限:它只会返回文本。

用户问"这个月的销售数据怎么样",Agent 返回一段 JSON 或 Markdown 文字——用户得自己去解读。哪怕 Agent 调了工具拿到了结构化数据,最终展示给用户的仍然是一坨文本。

这就像一个分析师写了一份完美的报告,但只能用电话念给你听。

Generative UI(生成式 UI) 就是解决这个问题的方向:让 Agent 不仅返回文本,还能返回可交互的界面——图表、表单、卡片、仪表盘。

2026 年,这个领域已经形成了清晰的协议生态。Google 主导的 A2UI(Agent to UI)是其中最系统化、跨平台能力最强的方案,此外还有 CopilotKit 的 AG-UI、Vercel AI SDK 的 Generative UI(streamUI)、OpenAI 的 Open-JSON-UI、以及基于 MCP 扩展的 MCP-UI

本文从 A2UI 切入,全面解析这些协议如何让 Agent 把数据变成可视化界面。

二、A2UI:Agent 的通用 UI 语言

2.1 核心思想

A2UI 由 Google 创建,Apache 2.0 开源,CopilotKit 作为联合发布伙伴。它的核心命题是:

如何让 AI Agent 安全地跨越信任边界发送富 UI?

答案是:不让 Agent 发送可执行代码(HTML/JS/React),而是发送声明式的组件描述(JSON),由客户端用原生组件渲染。

传统方式: Agent → HTML/JS 代码 → 客户端执行 → 安全风险高
A2UI 方式: Agent → JSON 组件蓝图 → 客户端原生渲染 → 安全且跨平台

这就像 Agent 说的是一种"UI 通用语言"——它描述"我要一个按钮,文字是'提交',点击时触发 submit 动作",而具体长什么样、用什么框架渲染,完全由客户端决定。

2.2 协议架构:三层分离

A2UI 的架构设计有三个关键分离:

职责 消息类型
UI 结构层 定义组件树(按钮、卡片、列表的布局) createSurface / updateComponents
应用状态层 管理数据模型(组件引用的数据) updateDataModel
客户端渲染层 原生组件映射和渲染 各渲染器自行实现

这种分离意味着:UI 结构和数据可以独立更新。当数据变了,只需要发一条 updateDataModel 消息,绑定了该数据路径的组件会自动刷新——不需要重新生成整个 UI 树。

2.3 四种核心消息

A2UI v1.0(候选版)定义了四种消息类型,构成完整的 UI 生命周期:

// 1. 创建 Surface — 初始化一个 UI 画布
{
  "createSurface": {
    "surfaceId": "dashboard-1",
    "root": "main-column",
    "catalogId": "standard"
  }
}

// 2. 更新组件 — 在 Surface 上放置/更新组件
{
  "updateComponents": {
    "surfaceId": "dashboard-1",
    "components": [
      {
        "componentId": "title",
        "type": "Text",
        "parentId": "main-column",
        "properties": {
          "text": { "literalString": "销售仪表盘" },
          "usageHint": "h1"
        }
      },
      {
        "componentId": "sales-chart",
        "type": "Chart",
        "parentId": "main-column",
        "properties": {
          "dataRef": "/data/sales",
          "chartType": "bar"
        }
      }
    ]
  }
}

// 3. 更新数据模型 — 填充/更新数据
{
  "updateDataModel": {
    "surfaceId": "dashboard-1",
    "path": "/data/sales",
    "contents": [
      { "key": "Q1", "valueNumber": 125000 },
      { "key": "Q2", "valueNumber": 180000 },
      { "key": "Q3", "valueNumber": 210000 }
    ]
  }
}

// 4. 删除 Surface — 清理 UI
{
  "deleteSurface": {
    "surfaceId": "dashboard-1"
  }
}

2.4 邻接表模型:为 LLM 而生

A2UI 没有使用传统的嵌套 JSON 树来描述 UI 结构,而是用了邻接表模型(Adjacency List)——所有组件是平面列表,通过 parentIdchildren 引用建立关系。

这个设计不是偶然的,而是专门为 LLM 优化的:

传统嵌套 JSON:
{
  "type": "Column",
  "children": [
    { "type": "Text", "text": "标题" },
    { "type": "Button", "label": "提交" }
  ]
}
→ 必须一次性生成完整结构,无法增量更新

A2UI 邻接表:
[
  { "id": "root", "type": "Column", "children": ["title", "btn"] },
  { "id": "title", "type": "Text", "text": "标题" },
  { "id": "btn", "type": "Button", "label": "提交" }
]
→ 可以逐条流式发送,LLM 不需要完美的 JSON

LLM 生成嵌套 JSON 容易出错(括号不匹配、层级混乱),但生成扁平的键值对列表非常稳定。这是 A2UI "LLM-Friendly" 设计的核心。

2.5 数据绑定:响应式更新的关键

组件属性有两种取值方式:

// 字面值 — 固定不变
{
  "text": { "literalString": "欢迎" }
}

// 数据引用 — 指向数据模型中的路径,数据变了自动更新
{
  "text": { "path": "/data/userName" }
}

updateDataModel 更新了 /data/userName 的值,所有引用了这个路径的组件会自动刷新。这就是 A2UI 的响应式机制——组件树不用重新生成,只需要更新数据模型

对于数据可视化场景,这至关重要:Agent 可以先建好图表结构,然后持续推送新数据,图表实时刷新。

2.6 可信组件目录:安全的边界

客户端维护一个组件目录(Component Catalog),定义了 Agent 允许使用的组件类型。如果 Agent 发了一个不在目录里的组件类型,客户端直接忽略或降级渲染。

// 客户端组件目录(React 示例)
const COMPONENT_CATALOG = {
  'Text': TextComponent,
  'Button': ButtonComponent,
  'Chart': ChartComponent,        // 自定义:图表
  'DataTable': TableComponent,    // 自定义:数据表
  'Map': MapComponent,            // 自定义:地图
  'FlightCard': FlightCardComponent  // 自定义:航班卡片
};

function renderA2UIComponent(descriptor) {
  const Component = COMPONENT_CATALOG[descriptor.type];
  if (!Component) return ;
  return ;
}

函数注册表机制进一步保障了交互安全——按钮点击等事件只能调用客户端预注册的命名函数,Agent 不能定义新函数:

{
  "componentId": "submit-btn",
  "type": "Button",
  "properties": {
    "label": "提交订单",
    "action": {
      "functionName": "submitOrder",
      "args": {
        "orderId": { "$dataRef": "/data/orderId" }
      }
    }
  }
}

submitOrder 函数由客户端开发者实现和审计,Agent 只能调用它并传数据引用参数,不能定义它的行为。

三、动态数据可视化的完整流程

将 A2UI 用于数据可视化,典型流程如下:

sequenceDiagram
    participant U as 用户
    participant C as 客户端
    participant A as Agent
    participant T as 数据源

    U->>C: "分析下季度销售趋势"
    C->>A: 用户消息 + 组件目录声明
    A->>T: get_sales_data(Q="Q3")
    T-->>A: 返回销售数据
    A->>C: createSurface("sales-dashboard")
    A->>C: updateComponents(图表+表格+筛选器)
    A->>C: updateDataModel("/data/sales", [...])
    C->>U: 渲染交互式仪表盘
    U->>C: 点击"按地区筛选" → 选"华东"
    C->>A: action("filter", {region: "华东"})
    A->>T: get_sales_data(region="华东")
    T-->>A: 返回筛选后数据
    A->>C: updateDataModel("/data/sales", [filtered])
    C->>U: 图表实时刷新

关键点:

  1. Agent 先拿数据再画 UI — 不是凭空生成,而是调工具获取真实数据后,根据数据特征决定用什么图表
  2. 结构只建一次,数据持续更新 — 首次 updateComponents 建好布局,后续只需 updateDataModel
  3. 用户交互回流到 Agent — 点击、筛选等操作通过 action 事件回到 Agent,Agent 决定如何响应

四、代码实现:用 ADK + A2UI 构建可视化 Agent

以下是基于 Google ADK + A2UI 的关键实现代码:

4.1 Agent 端:生成 A2UI 消息

import json
from google.adk.agents.llm_agent import Agent
from google.adk.tools.tool_context import ToolContext

def get_sales_data(tool_context: ToolContext) -> str:
    """获取销售数据,返回结构化 JSON"""
    # 实际场景中调用数据库或 API
    sales = [
        {"quarter": "Q1", "revenue": 125000, "region": "华东"},
        {"quarter": "Q2", "revenue": 180000, "region": "华东"},
        {"quarter": "Q3", "revenue": 210000, "region": "华东"},
        {"quarter": "Q1", "revenue": 95000, "region": "华北"},
        {"quarter": "Q2", "revenue": 130000, "region": "华北"},
        {"quarter": "Q3", "revenue": 165000, "region": "华北"},
    ]
    return json.dumps(sales)

AGENT_INSTRUCTION = """
你是一个销售数据分析助手。当用户请求分析数据时:

1. 调用 get_sales_data 工具获取数据
2. 生成 A2UI 消息:
   a. createSurface: 创建 "sales-dashboard" 画布
   b. updateComponents: 放置标题、柱状图、数据表
   c. updateDataModel: 填充销售数据到 /data/sales

组件结构(邻接表格式):
- root (Column) → [title, chart, table]
- title (Text): "销售趋势分析"
- chart (Chart): dataRef="/data/sales", chartType="bar"
- table (DataTable): dataRef="/data/sales"

数据路径绑定:所有组件引用 /data/sales,数据更新时自动刷新。
"""

root_agent = Agent(
    model='gemini-2.5-flash',
    name="sales_visualization_agent",
    instruction=AGENT_INSTRUCTION,
    tools=[get_sales_data],
)

4.2 客户端:注册渲染器和组件目录

// React 渲染器 — 注册自定义可视化组件
import { A2UIProvider, Surface } from '@a2ui/react-renderer';

const componentCatalog = {
  Text: ({ text, usageHint }) => {
    const Tag = usageHint === 'h1' ? 'h1' : 'p';
    return {text};
  },
  Chart: ({ dataRef, chartType }) => {
    const data = useDataModel(dataRef); // 响应式读取数据模型
    return ;
  },
  DataTable: ({ dataRef }) => {
    const data = useDataModel(dataRef);
    return ;
  },
  Button: ({ label, action }) => (
    
  ),
};

function App() {
  return (
    
      
    
  );
}

4.3 传输层:通过 A2A 协议传输

# A2A 传输 — A2UI 消息通过 A2A 扩展自动传输
from a2a.server import A2AServer

server = A2AServer(agent=root_agent)
# A2A 扩展会自动:
# 1. 检测 agent 输出中的 A2UI JSON
# 2. 包装为 application/a2ui+json MIME 类型
# 3. 通过 SSE 流式推送给客户端
server.start(port=10002)

4.4 流式渲染体验

A2UI 的流式特性意味着用户能看到界面"逐步构建":

[0.1s] createSurface → 空白画布出现
[0.3s] updateComponents(title) → 标题出现
[0.5s] updateComponents(chart) → 图表骨架出现
[0.8s] updateDataModel → 数据填充,图表渲染完成
[1.0s] updateComponents(table) → 数据表格出现

对比传统方式(等 Agent 生成完整 JSON 再一次性渲染),用户感知延迟从"等待 N 秒看到完整结果"变成"界面实时生长"。

五、协议生态全景:A2UI 不是唯一选择

5.1 三种 Generative UI 模式

2026 年的 Generative UI 领域存在三种模式,从"更多控制"到"更多灵活性":

模式 代表 原理 安全性 灵活性
受控模式 Vercel AI SDK (streamUI) 预建组件,Agent 选择渲染哪个
声明式模式 A2UI、Open-JSON-UI Agent 输出组件 schema,客户端映射
开放模式 MCP-UI Agent 输出 HTML,沙箱 iframe 渲染

5.2 五大协议对比

维度 A2UI AG-UI Vercel AI SDK MCP-UI Open-JSON-UI
发起方 Google CopilotKit Vercel Microsoft + Shopify OpenAI
定位 UI 格式(内容) 传输协议(管道) 全栈 SDK MCP 扩展 UI 格式
渲染方式 原生组件 任意框架 React Server Components 沙箱 iframe 原生组件
跨平台 Web + Mobile + Desktop Web 优先 仅 React/Web Web(iframe) Web
LLM 友好 流式 JSONL,邻接表 不涉及 UI 生成 工具调用路由 HTML 预构建 JSON Schema
安全模型 可信目录 + 函数注册表 信任代码 服务端执行 沙箱隔离 可信目录
多 Agent 跨信任边界 单 Agent 为主 单 Agent 多 MCP Server 单 Agent
开源 Apache 2.0 开源 Apache 2.0 MCP 扩展 开源

5.3 A2UI + AG-UI:黄金组合

A2UI 和 AG-UI 不是竞争关系,而是互补:

AG-UI = 管道(transport)— 负责 Agent 和前端之间的双向通信、状态同步
A2UI  = 内容(content)  — 负责 UI 组件的描述格式

最佳实践是组合使用:AG-UI 作为传输层,A2UI 作为 UI 格式。CopilotKit 已经实现了这个组合的零配置集成。

六、A2UI 的版本演进

版本 状态 核心变化
v0.8 Legacy 结构化输出优先,基线组件 + 数据绑定 + 邻接表
v0.9 Stable 哲学转向 Prompt-First,引入 createSurface、客户端函数、自定义目录、模块化 Schema
v0.9.1 Current 标准化 application/a2ui+json MIME 类型,放宽 surfaceId 约束
v1.0 Candidate 双向 RPC(actionResponse)、单消息 UI 实例化、surfaceProperties 替代 theme

从 v0.8 到 v1.0 的演进方向很清晰:

  1. 从结构化输出到 Prompt-First — 不再依赖解码层约束 JSON,而是把 Schema 嵌入系统提示,让 LLM 自由生成后验证
  2. 从单向到双向 — v1.0 新增 actionResponse,支持客户端→服务器的同步 RPC 调用
  3. 从硬编码到可扩展 — theme 被替换为 surfaceProperties,视觉样式完全交给客户端原生主题

七、渲染器生态

A2UI 的跨平台能力依赖于多端渲染器:

渲染器 平台 状态 包名
Lit Web ✅ 稳定 @a2ui/web-lib
Angular Web ✅ 稳定 @a2ui/angular
React Web ✅ 官方 @a2ui/react-renderer
Flutter Mobile + Desktop ✅ 稳定 flutter_genui
SwiftUI iOS / macOS 🔜 2026 Q2
Jetpack Compose Android 🔜 2026 Q2

v0.9 引入的 @anthropic-ai/a2ui-web-core 共享库统一了 Web 渲染器的核心逻辑——JSON Pointer 解析、组件树 diff/patch、Schema 验证——React/Lit/Angular 渲染器只是薄封装层。

八、实际应用场景

8.1 数据分析仪表盘

Agent 接收"分析销售数据"的请求 → 调工具获取数据 → 生成包含图表 + 筛选器 + 数据表的 A2UI 界面。用户点击筛选器,action 事件回到 Agent,Agent 重新获取数据并更新数据模型,图表实时刷新。

8.2 表单生成

Agent 根据上下文动态生成表单——不同场景的表单字段不同。通过 A2UI 的数据绑定,表单提交后数据自动写入数据模型,Agent 收到结构化数据而非文本。

8.3 多 Agent 协作 UI

多个 Agent 各自负责不同 UI 区域(一个管图表,一个管地图,一个管表单),通过 A2A 协议将各自的 A2UI 消息发送到同一个 Surface。这是 Google 内部多 Agent 工作流的典型模式。

8.4 自定义组件目录扩展

标准目录提供 18 个组件(Text、Button、Card、List 等),但真实场景需要领域组件:

// 金融仪表盘:注册 K 线图组件
const financialCatalog = {
  ...standardCatalog,
  'CandlestickChart': CandlestickChartComponent,
  'StockTicker': StockTickerComponent,
  'OrderBook': OrderBookComponent,
};

// 医疗应用:注册医疗时间线
const medicalCatalog = {
  ...standardCatalog,
  'MedicalTimeline': MedicalTimelineComponent,
  'PatientVitals': PatientVitalsComponent,
};

客户端声明支持哪些目录,Agent 就知道可以用哪些组件来构建 UI。

九、A2UI 的局限与思考

A2UI 解决的是"最后一英里"——从 Agent 到屏幕的 UI 传输。但完整的可视化工作流还需要:

  1. 数据理解 — 解析 CSV/Excel/JSON,推断 Schema,检测列类型
  2. 数据清洗 — 标准化日期,处理空值,处理异常值
  3. 统计分析 — 分布、相关性、趋势、异常检测,决定什么值得展示
  4. 图表选择 — 匹配图表类型与分析意图,调色板,视觉层次
  5. 交互生成 — 筛选器、下钻、提示
  6. 导出展示 — PPT、PDF、PNG

A2UI 只覆盖第 5 步的传输环节。步骤 1-4 的"智能层"和步骤 6 的"导出层"需要额外的 Agent 或工具完成。

这也是为什么 A2UI 的定位是协议而非产品——它定义了"怎么传",不定义"传什么"和"为什么传"。

十、总结:Generative UI 的范式转移

A2UI 代表了一个正在发生的范式转移:

从"Agent 描述界面"到"Agent 生成界面"

  • 传统:Agent 返回文本 → 用户自己理解 → 自己操作
  • Generative UI:Agent 返回可交互的界面 → 用户直接探索

对于数据可视化场景,这意味着:

传统 Agent A2UI 驱动的 Agent
"销售数据如下:Q1: 12.5万, Q2: 18万..." 直接渲染柱状图,可点击下钻
"建议填写以下信息" 直接生成表单,带验证和联动
"已为您预订航班" 直接渲染航班卡片,可改签/取消

A2UI + AG-UI 的组合正在成为 2026 年 Agent 应用的事实标准:AG-UI 负责管道和状态同步,A2UI 负责 UI 内容描述。加上 A2A 协议处理 Agent 间通信,三者构成了完整的 Agent 驱动界面协议栈。

随着 v1.0 候选版的发布和 SwiftUI/Compose 渲染器即将上线,A2UI 正在从"实验性协议"走向"生产级标准"。对于需要跨平台、高安全、多 Agent 协作的企业级 Agent 应用,A2UI 值得认真评估。


参考链接:

分享给朋友