本文是对生成式 UI 概念和 Google 开源项目 A2UI 的入门介绍。资料主要来自 Google Developers Blog 的 A2UI 系列文章(文末附链接),内容由笔者重新组织和改写,并加入了个人理解。文中代码为简化的示意代码,具体字段和接口以 a2ui.org 官方文档为准。
一、先看一个场景:订餐厅的尴尬对话
假设你让 AI 助手帮忙订一张明晚的两人桌。纯文字的对话大概是这样的:
你:帮我订一张两人桌。
AI:好的,哪一天?
你:明天。
AI:几点?
你:7 点左右吧。
AI:7 点没有空位了,其他时间可以吗?
你:那你们什么时候有位?
AI:5:00、5:30、6:00、8:30、9:00、9:30、10:00 有空位,您看哪个合适?
来回七八轮,用户一直在打字。其实这件事用一个小表单就能解决:一个日期选择器、一排可选时间段、一个"确认预订"按钮,点三下就完事。
问题是:这个表单从哪来?
- 如果由开发者提前写好,那 AI 只能处理开发者预想到的场景;
- 如果能让 AI 根据当前对话,现场"拼"出最合适的界面,体验就完全不一样了。
后一种思路就叫生成式 UI(Generative UI)。
二、什么是生成式 UI?
1. 一句话定义
生成式 UI:由 AI 根据用户的意图和上下文,实时决定展示什么界面,而不是只回复一段文字。
大模型已经很擅长生成文字、图片和代码,生成式 UI 是把"生成"的对象扩展到了交互界面。
2. 和传统 UI 的区别
| 维度 | 传统 UI | 聊天式 AI | 生成式 UI |
|---|---|---|---|
| 界面由谁决定 | 开发者提前设计 | 基本只有聊天框 | AI 按需组合 |
| 适应新需求 | 要改代码、发版 | 只能用文字回答 | 现场生成合适的界面 |
| 交互方式 | 点击、表单 | 打字 | 点击、表单、图表,加上对话 |
| 典型例子 | 普通 App 页面 | 早期聊天机器人 | AI 助手直接弹出预订卡片、数据图表 |
可以这样理解:传统 UI 是"套餐",聊天式 AI 是"只能口述的菜",生成式 UI 是"现点现做的菜"。
3. 生成式 UI 要解决的难题
想法很美好,落地却有几个绕不开的问题:
- 安全:AI 生成的东西能直接在用户设备上运行吗?如果 AI 输出一段 JavaScript,被提示词注入攻击了怎么办?
- 风格一致:AI 生成的界面能不能和 App 原有的设计风格保持一致,而不是看起来像"外来的"?
- 跨平台:同一个 AI,能不能同时给 Web、iOS、Android、Flutter 应用生成界面?
- 远程 Agent:在多 Agent 协作的场景里,干活的 Agent 可能运行在另一台服务器上,甚至属于另一家公司。它根本碰不到你的前端代码,只能"发消息"。
三、常见的几种实现思路
在 A2UI 出现之前,业界大致有以下几种做法:
思路 A:让 AI 直接生成 HTML/JS,放进 iframe 沙箱
- 优点:自由度极高,想画什么画什么。
- 缺点:iframe 比较重;样式很难和宿主 App 统一,容易出现双滚动条、风格突兀;执行 AI 生成的代码存在安全隐患;而且原生 App(比如 Flutter、SwiftUI)没法直接用。
MCP Apps 走的就是"把 UI 当成资源、在沙箱 iframe 里渲染"的路线,适合需要复杂前端逻辑的场景。
思路 B:预先写好模板,AI 只负责填数据
- 优点:安全、稳定。
- 缺点:灵活性差,AI 只能在开发者准备好的几个模板里选。
思路 C:声明式 UI 描述(A2UI 的路线)
AI 不输出代码,而是输出一份**“界面说明书”**:用哪些组件、怎么排列、显示什么数据。客户端拿到说明书后,用自己的原生组件去渲染。
Google 在介绍 A2UI 时有一句话概括得很到位,笔者意译为:
像数据一样安全,像代码一样有表达力。
四、A2UI 是什么?
1. 基本信息
- 全称:Agent-to-User Interface,可以理解为"Agent 与用户之间的界面协议";
- 发布:Google 于 2025 年 12 月开源,后续经历了 v0.9(2026 年 4 月)、与 MCP 结合(2026 年 6 月)、推理格式可替换和 Express 格式(2026 年 10 月)等更新;
- 定位:一种面向 Agent 优化的、跨平台的声明式 UI 协议,加上一套配套的渲染器和 Agent SDK;
- 官方渲染器:Lit、Angular、Flutter、React 等,社区也在贡献更多实现。
2. 核心机制:用"点菜"来理解
A2UI 的工作方式可以类比为餐厅点菜:
┌──────────────┐ ① 公布菜单(组件目录 Catalog) ┌──────────────┐
│ │ ───────────────────────────────▶ │ │
│ 客户端 │ │ Agent │
│ (Web/App) │ ② 按菜单点菜(A2UI 消息) │ (大模型) │
│ │ ◀─────────────────────────────── │ │
│ ③ 用自家 │ │ │
│ 原生组件上菜 │ ④ 用户点击按钮 → 事件回传 │ │
│ │ ───────────────────────────────▶ │ │
└──────────────┘ └──────────────┘
- 客户端公布"菜单":也就是组件目录(Catalog),列出它信任、能渲染的组件,比如 Card、Text、Button、TextField、Row、Column,也可以是自定义的图表、地图组件;
- Agent 按菜单"点菜":根据对话内容,用目录里的组件组合出界面,以 A2UI 消息的形式发出;
- 客户端"上菜":渲染器把消息映射成自己的原生组件,比如 React 组件或 Flutter Widget,样式完全沿用 App 自己的设计系统;
- 交互回传:用户点击按钮、提交表单时,事件被发回给 Agent,Agent 可以继续更新界面。
关键点在于:Agent 只能点菜单上有的菜。 菜单之外的东西它没法要求客户端渲染,这就是 A2UI 安全性的基础。
3. 三条设计原则
根据官方介绍,A2UI 围绕三条原则设计:
① 安全优先
A2UI 是声明式的数据格式,不是可执行代码。客户端只渲染目录里预先批准的组件,降低了 UI 注入等风险。
笔者理解:这相当于把"信任边界"放在了客户端。无论 Agent 是自家的还是第三方的,无论它有没有被提示词注入攻击,它最多只能"点错菜",没法"往厨房里塞东西"。
② 对大模型友好,支持增量更新
界面被表示为一个扁平的组件列表,组件之间通过 ID 引用,而不是一棵层层嵌套的树。这样做有两个好处:
- 大模型可以一个组件一个组件地生成,客户端可以边收边渲染;
- 后续对话中要修改界面时,只需要更新对应 ID 的组件,不用整页重来。
③ 与框架无关,可移植
A2UI 把"界面结构"和"界面实现"分开。Agent 只描述"要一个卡片,里面有标题和按钮",至于这个卡片在 Web 上是 <div>,在 Flutter 里是 Card Widget,由客户端决定。同一份 A2UI 消息可以在不同框架的客户端上渲染。
五、A2UI 消息长什么样?
在 v0.9 中,Agent 发给客户端的主要是几类消息,从官方文章中可以看到这几个名字:
| 消息 | 作用 |
|---|---|
createSurface | 创建一块界面区域(Surface),可以理解为"开一张新画布" |
updateComponents | 添加或更新这块界面上的组件 |
updateDataModel | 更新界面绑定的数据,比如标题文字、价格、状态 |
注意这里组件和数据是分开的:组件描述"长什么样",数据模型描述"显示什么内容"。组件通过路径(比如 /title)绑定到数据模型上。这样数据变化时,只需要发一条 updateDataModel,界面结构不用动。
下面是一个简化的示意,帮助理解扁平列表和 ID 引用的概念(字段名不代表真实规范,请以官方 Schema 为准):
[
{ "id": "root", "component": "Card", "child": "col" },
{ "id": "col", "component": "Column", "children": ["title", "slots", "submit"] },
{ "id": "title", "component": "Text", "text": { "path": "/title" } },
{ "id": "slots", "component": "Row", "children": ["t1", "t2", "t3"] },
{ "id": "t1", "component": "Button", "label": "18:00" },
{ "id": "t2", "component": "Button", "label": "20:30" },
{ "id": "t3", "component": "Button", "label": "21:00" },
{ "id": "submit", "component": "Button", "label": "确认预订",
"action": { "event": "book_table" } }
]
可以看到:
- 每个组件都有唯一的
id; - 父组件通过 ID 引用子组件,而不是把子组件直接嵌套在自己内部;
title的文字绑定到数据模型的/title路径;- 按钮声明了一个事件,用户点击后会通知 Agent。
开头那个订餐厅的例子,用这样一份消息就能变成一张可以点选的卡片。
六、A2UI 在生态中的位置
生成式 UI 领域的工具很多,容易混淆。下面这张表帮你理清关系:
| 技术 | 解决什么问题 | 与 A2UI 的关系 |
|---|---|---|
| A2A(Agent-to-Agent 协议) | Agent 之间如何通信 | 可以作为 A2UI 消息的传输通道 |
| AG-UI / CopilotKit | Agent 后端和前端应用之间的连接、状态同步 | 互补,AG-UI 负责"管道",A2UI 负责"界面内容" |
| MCP(模型上下文协议) | Agent 如何调用工具和数据 | MCP 工具可以返回 A2UI 消息(MIME 类型 application/a2ui+json) |
| MCP Apps | 以资源形式提供交互界面,通常在 iframe 中渲染 HTML | 互补:标准界面用 A2UI 原生渲染,高度定制的复杂界面用 MCP Apps |
一句话总结:A2A、AG-UI、MCP 管"怎么传",A2UI 管"传什么界面"。
v0.9 之后,A2UI 支持的传输方式包括 MCP、WebSocket、REST、AG-UI、A2A 等,基本不挑通道。
七、快速上手:给 Agent 加上 A2UI
以 Python SDK 为例,接入流程大致分为几步(示意代码,具体 API 以官方文档为准):
pip install a2ui-agent-sdk
# 第 1 步:定义组件目录(可用官方的 Basic 组件集,也可以用自己的)
catalog = CatalogConfig.from_path("catalog.json")
# 第 2 步:用目录生成系统提示词,告诉大模型"菜单上有哪些菜"
system_prompt = build_prompt_with_catalog(catalog)
# 第 3 步:用任意 Agent 框架调用大模型
reply = my_agent.respond(user_query, system_prompt=system_prompt)
# 第 4 步:SDK 解析模型输出,校验并修复成合法的 A2UI 消息
messages = parse_and_validate(reply, catalog)
# 第 5 步:通过 A2A / AG-UI / MCP 等通道发送给客户端渲染
send_to_client(messages)
如果你的前端用的是 CopilotKit,官方提供了现成的模板:
npx copilotkit@latest create my-app --framework a2ui
TypeScript 和 Dart 也有对应的 Agent SDK(@a2ui/agent、a2ui_agent)。
八、最新进展:解决"慢"的问题
生成式 UI 被吐槽最多的一点是慢:用户要等大模型把整个界面一个 Token 一个 Token 地"写"出来。
2026 年 10 月的更新给出了两个方案:
1. A2UI Express:更省 Token 的"简写语法"
不再让模型直接写冗长的 JSON,而是写一种类似 Python 的简洁语法,再由 SDK 编译成标准 A2UI 消息。示意:
root=Card(col)
col=Column([title, submit])
title=Text($/title)
submit=Button(submit_label, _, Event("book_table", {}))
据官方在 gemini-3.5-flash 上的评测,生成同类界面时,Express 的 Token 数大约只有直接写 JSON 的三分之一,有效率和 JSON 持平。
2. 决策模型:固定结构的界面"做选择题"
对于设置页、结账页这类结构固定的界面,可以用专门的决策模型从预定义布局中做选择,再由代码拼装界面,大模型只负责填文字。官方示例中,组件骨架在几百毫秒内就能上屏。
这部分内容的详细解读,可以参考笔者的另一篇文章《生成式 UI 太慢?Google A2UI 新版本让 Token 消耗降到三分之一》。
九、适合哪些场景?
结合官方案例和笔者的理解,以下场景比较适合尝试 A2UI:
| 场景 | 举例 |
|---|---|
| AI 助手中的结构化交互 | 订餐、订票、预约,用表单代替多轮问答 |
| 数据展示 | 根据问题动态生成图表、表格、指标卡片 |
| 个性化界面 | 健康助手根据用户的检查结果展示相关卡片;理财助手根据人生目标生成模拟器 |
| 多 Agent 系统 | 第三方远程 Agent 安全地把界面"送"到你的 App 里 |
| 跨端产品 | 一个 Agent 同时服务 Web、iOS、Android、Flutter 客户端 |
官方博客中提到的案例包括:基于 Flutter 的个人健康助手(把分散的病历、可穿戴设备数据整合成按需生成的卡片),以及个人理财规划模拟器(用滑块、柱状图等组件生成实时界面)。
不太适合的场景
- 需要大量复杂客户端逻辑的界面,比如在线编辑器、游戏。A2UI 受限于组件目录,这类需求更适合 MCP Apps 或传统开发;
- 完全固定、几乎不变的页面。直接写死就好,没必要引入 AI。
十、笔者的几点思考
1. "组件目录"是整个设计的灵魂
A2UI 最聪明的地方,是把控制权交给了客户端。Agent 很强大,但它只能使用客户端公布的组件。这带来三个直接收益:
- 安全:信任边界清晰;
- 品牌一致:界面永远是自家设计系统的样子;
- 复用:前端团队已有的组件库可以直接注册成目录,不用为 AI 另起炉灶。v0.9 把可选的官方组件集从 “Standard” 改名为 “Basic”,传递的也是这个意思:鼓励用你已有的组件,而不是用官方的。
2. 对前端开发者意味着什么?
有人担心"AI 都能生成界面了,前端还有饭吃吗"。笔者的看法是,前端的工作重心会发生转移:
- 从"写一个个页面"转向**“设计和维护高质量的组件目录”**;
- 组件的命名、属性设计、文档描述会直接影响 AI 的使用效果。组件设计得越清晰,AI 拼出来的界面越好;
- 渲染器、交互事件处理、性能优化依然需要专业的前端能力。
换句话说,前端从"做菜的人"变成了"设计菜单和厨房的人"。
3. 落地前需要想清楚的问题
- 可预测性:同一个问题,AI 每次生成的界面可能不一样。对于需要一致体验的核心流程,要考虑用 few-shot 示例或固定模板约束;
- 测试:动态生成的界面怎么做 UI 测试和回归测试,目前还没有成熟方案;
- 可访问性:原生组件天然继承了 App 的无障碍能力,这是 A2UI 相比 iframe 方案的优势,但组件目录本身要先做好无障碍支持;
- 版本演进:A2UI 仍处于 0.x 阶段,规范还在变化,生产使用要留意版本兼容。
4. 生成式 UI 是交互方式的一次升级
过去两年,AI 应用的主流交互几乎都是聊天框。但并不是所有任务都适合用文字完成,选日期、比价格、看趋势,图形界面的效率远高于打字。
生成式 UI 让 AI 应用可以在对话和图形界面之间自由切换:需要理解意图时用对话,需要操作时直接给你一个界面。笔者认为,这会是下一代 AI 应用的标配能力,而 A2UI 提供了一套开放、跨平台的标准,值得持续关注。
总结
| 要点 | 内容 |
|---|---|
| 生成式 UI | AI 根据上下文实时生成交互界面,而不只是回复文字 |
| 核心难题 | 安全、风格一致、跨平台、远程 Agent 无法直接操作前端 |
| A2UI 的方案 | 声明式消息 + 客户端组件目录 + 原生渲染 |
| 三条原则 | 安全优先;对大模型友好、可增量更新;与框架无关 |
| 生态关系 | A2A / AG-UI / MCP 负责传输,A2UI 负责界面内容,MCP Apps 负责复杂定制界面 |
| 最新进展 | Express 格式减少约三分之二的 Token;决策模型加速固定结构界面 |
参考资料
- Introducing A2UI: An open project for agent-driven interfaces(2025-12-15)
- A2UI v0.9: The New Standard for Portable, Framework-Agnostic Generative UI(2026-04-17)
- A2UI + MCP Apps: Combining the best of declarative and custom agentic UIs(2026-06-17)
- Fast, reliable A2UI, with swappable inference formats(2026-10-27)
- A2UI 官方文档:a2ui.org
声明:本文为学习笔记和个人观点,内容基于上述公开资料重新组织和改写,示例代码为笔者编写的简化示意。如有理解偏差,欢迎评论区指正。
本文系统介绍生成式UI的核心理念及其典型实现——Google开源的A2UI协议。重点阐述A2UI作为声明式、跨平台、安全优先的Agent-to-User界面协议,如何通过组件目录机制、扁平化ID引用结构和框架无关设计,解决AI动态生成界面时的安全、一致性与可移植难题;并涵盖A2UI Express、决策模型等最新优化方案,及其在健康助手、理财模拟等场景的适用性分析。
1237

被折叠的 条评论
为什么被折叠?



