A2UI (Agent-to-User Interface) 协议详解
A2UI 是一个开放的协议标准,让 AI Agent 能够安全地向客户端发送丰富的交互式用户界面。Agent 发送声明式 JSON 描述 UI 的意图,客户端使用自己的原生组件库渲染出来。
一、原始内容概述
1.1 什么是 A2UI
A2UI(Agent-to-User Interface)是一个开放的协议标准,由 Google 主导开发,CopilotKit 及开源社区共同贡献,Apache 2.0 许可。它的核心使命是:让 AI Agent 能够安全地向客户端发送丰富的交互式用户界面。
一句话概括:A2UI 让 Agent "说 UI 的语言"——Agent 发送声明式 JSON 描述 UI 的意图,客户端使用自己的原生组件库渲染出来。
1.2 核心问题
A2UI 解决的核心问题是:AI Agent 如何在跨信任边界的情况下,安全地发送丰富的用户界面?
- 纯文本响应:体验太差,无法表达复杂 UI
- 执行代码(HTML/JS):安全风险极高,LLM 生成的代码不可信
- 预定义模板:不够灵活,无法适应动态场景
A2UI 的答案:声明式数据格式,不执行任何代码。安全像数据,表达力像代码。
1.3 核心设计哲学
- 安全第一:声明式 JSON 数据格式,客户端维护受信任的"组件目录"(Catalog)
- LLM 友好:扁平组件列表 + ID 引用(邻接表模型),LLM 可以逐步生成、流式渲染
- 框架无关:一套 JSON 同时渲染到 Angular、Flutter、React、Lit 等
- 渐进式渲染:流式更新,用户无需等待完整响应
1.4 协议版本状态
- 当前生产版:v0.9.1
- 候选版:v1.0(增加 actionResponse RPC、action ID、surfaceProperties)
- 稳定版:v0.9(Prompt-First 模式)
- 遗留版:v0.8(Structured Output 模式)
1.5 四类核心消息
A2UI 协议是服务端到客户端的单向 JSON 流,仅四种消息类型:
① createSurface:创建 UI 表面,必须最先发送。包含 surfaceId(唯一标识)、catalogId(组件目录标识)、theme(主题)和 sendDataModel(是否回传数据模型)属性。
② updateComponents:更新组件结构。组件以扁平列表形式发送,通过 ID 引用建立关系(邻接表模型)。每个 surface 必须有一个 id 为 "root" 的根组件。
③ updateDataModel:更新数据模型。使用 JSON Pointer 路径定位更新位置,无需重发整个组件结构。
④ deleteSurface:删除 UI 表面及其所有组件和数据。
1.6 组件目录(Catalog)
- Basic Catalog:内置基础组件(Text, Button, Row, Column, Card, TextField, Icon, Image, Select, Checkbox, Slider, DataTable 等)
- 自定义 Catalog:开发者可定义自己的组件目录,限制 Agent 只能使用你应用中的受信任组件
1.7 数据绑定
使用 JSON Pointer 路径将组件属性绑定到数据模型,支持动态类型。动态类型可以接受字面值、路径绑定或函数调用。
1.8 传输层解耦
A2UI 协议本身是传输无关的,支持多种传输方式:A2A(推荐)、AG-UI、MCP、SSE+JSON-RPC、WebSocket、REST。
每个传输层需要保证:顺序可靠送达、消息分帧、元数据支持。
二、使用场景举例
场景 1:动态表单生成
用户说"帮我预订一间带会议室和投影仪的商务套房"——Agent 即时生成定制表单(日期选择器、房型下拉、设施多选),客户端用原生组件渲染。
场景 2:远程子 Agent UI 注入
主 Agent 委派酒店预订给远程 Agent,远程 Agent 返回 A2UI payload,通过 A2A transport 传回主客户端——酒店 Agent 无需关心用户用的是什么前端框架。
场景 3:自适应审批看板
Agent 根据查询动态生成 DataTable + 审批按钮,用户点击后实时更新面板数据。
场景 4:实时数据监控面板
Agent 先 createSurface 创建面板结构,updateComponents 定义卡片布局,然后持续通过 updateDataModel 推送 CPU/内存/磁盘指标,界面无需重绘。
场景 5:聊天中嵌入地图/图表组件
Agent 在对话流中插入 Google Map 组件或 DataTable 组件,客户端原生渲染。
三、最佳实践
Agent 端
- Prompt-First 设计:把目录 schema 嵌入 prompt
- 渐进式流输出:先 createSurface → updateComponents → updateDataModel
- 先结构后数据:组件结构优先于数据填充
- 利用数据绑定:用 { "path": "/xxx" } 而非硬编码
客户端
- 容错渲染:对缺失引用用占位符兜底
- 自定义 Catalog 做安全边界
- 合理启用 sendDataModel
传输层
- A2A 传输时用 contextId 关联 surfaces
- SSE 一行一个 JSONL
- 消息分帧必须正确
四、避坑指南
- createSurface 之前发 updateComponents:被丢弃
- 重复创建相同 surfaceId:报错
- JSON Pointer 路径错误:必须以 / 开头
- LLM 生成的 JSON 不符合 Catalog:需验证+纠错
- 流式消息乱序:必须顺序送达
- Catalog ID 冲突:用域名前缀
- 忘记 root 组件:必须有一个 id 为 root 的根
- 自定义 Catalog 类型违规:必须用 \$ref
- 单批组件太多:分批 5~15 个
- 频繁整量替换数据:优先局部 path
- 未知组件 fallback:必须忽略
五、集成方需要做的工作
客户端集成
- 选择 Renderer(Lit / Angular / Flutter / React)
- 集成到应用,连接 A2UI 数据流
- 定义自定义 Catalog(强烈推荐)
- 实现 action 回调
- 主题适配
Agent 端集成
- 选择 transport(推荐 A2A 或 AG-UI)
- 将 Catalog schema 加入 prompt
- 实现 createSurface → updateComponents → updateDataModel → deleteSurface
- 处理 action 回调
传输层集成
- 顺序可靠送达
- 消息分帧
- 元数据支持
- 双向通道
官方资源
- 官网:https://a2ui.org
- GitHub:https://github.com/a2ui-project/a2ui
- A2UI Composer:https://a2ui-composer.ag-ui.com/
- A2UI Theater:https://a2ui-composer.ag-ui.com/theater
文章评论