从2024年底开始,围绕 AI Agent(智能体)的一系列开放协议开始密集出现。它们的共同目标很明确:为不断“生长”的 Agent 生态建立一套可通用、可协作的语言与标准。Google 最新开源的A2UI(Agent to UI)协议提出了一个新思路—让 AI Agent 学会“说 UI 的语言”。通过一种安全、声明式的格式,将UI需求发送给前端应用,用来渲染与交互。本文将深入解读这个新协议。特别是,它与我们曾介绍过的AG-UI、CopilotKit(回顾:一步步实战 CopilotKit(AG-UI协议))是什么关系?而与MCP、A2A等协议又是怎样的协作方式?传统的 Agent 与用户交互,主要依赖文本或语音,尤其是在对话式 AI Agent 中更为常见。但正如我们之前强调的那样,自然语言交互只是最简单的方式,并不总是最高效的方式。在日常的个人助手场景中,用聊天完成简单问答当然没有问题;但一旦进入企业级场景,单纯靠对话,效率就会迅速下降。比如,你想让 AI 帮你预订一家心仪的餐厅:日期、时间、人数,需要一轮一轮地来回确认。每增加一个约束条件,就多一次对话往返,整个过程既冗长又容易出错,用户体验并不理想。在这种情况下,更合理的方式是:直接呈现一个交互式表单,让用户选择日期、时间、人数,点击提交即可完成预订。相比反复“聊天确认”,一个清晰、聚焦的 UI 往往高效得多。目前,大多数 Agent 应用的 UI,仍然是由前端工程师使用 React、Vue、Flutter 等框架提前构建,整体交互流程相对固定。也有一些探索性的方案。例如我们之前介绍过的CopilotKit,具有“生成式 UI”的能力:前端根据 Agent 返回的状态或数据,动态生成并渲染相应的UI。比如将Agent调用的天气查询结果渲染成前端的卡片:但这里的“生成式UI”,其交互形态、组件结构,仍然是在前端提前定义好的;框架只是提供了更方便的机制(如 hooks),帮助在 UI 与后端 Agent 之间同步状态和数据。或者说: UI 的主导权依然在前端,Agent 并不“理解”或“描述”界面本身。 相比传统应用 UI,对话式 Agent 的界面其实有着特殊的需求:- 动态性:UI元素需要随着上下文即时生成或调整,某种程度上应该由 AI 来“决定该出现什么”。
- 安全性:但你又不能直接执行 AI 输出的前端代码,否则极易引入 XSS、代码注入等风险。AI应该“描述UI”,而不是“构建UI”。
- 跨平台:同一个 Agent,可能服务于Web/App/桌面等多种前端,各UI 技术栈并不相同。能否做到“一次UI生成,多端呈现”?
- 流式交互:正如文本的流式输出,能否让用户也能实时看到 UI 的生成和变化,而不是长时间等待一次性“憋”出完整的UI?
- 状态同步:UI的表单数据、进度状态、临时输入,往往需要与后端 Agent 状态保持同步。能否根据状态变化局部更新UI?
如何让 AI 以安全、可控、跨平台的方式,驱动交互界面的生成与更新? 在 A2UI 协议出现之前,这一领域还缺乏统一标准。OpenAI、Anthropic 等厂商,都定义了各自生成 UI 的方式,彼此之间并不兼容。显然,这正是一个开放的Agent UI协议真正有价值的地方。现在让我们进入A2UI的世界,A2UI目前还处于预览阶段(稳定版0.8,草稿版0.9),在消息格式等方面会不断优化,但核心思想会保持稳定。简而言之,A2UI(Agent-to-User Interface)是一种声明式的生成式 UI 规范。它允许 AI Agent 使用 JSON 数据来描述UI布局与组件,应该“长什么样、能做什么”。Agent 不再局限于输出字符串,而是可以返回一份”UI 组件树的描述“。前端应用接收到描述后,再使用本地已有的组件库,将其渲染成真正可交互的界面。Agent(AI)负责“描述 UI”,前端负责“绘制 UI”。本质上,就是给 Agent 配备一门“UI 语言”,而前端负责把其翻译成你看到的交互界面。A2UI 背后有一组非常明确的设计原则,使其特别适合由 LLM 生成、并在多平台上稳定运行。A2UI 定义的是纯数据格式,而不是可执行代码。正如官方文档中所强调的:“Running arbitrary code generated by an LLM may present security risk. A2UI is declarative data format, not executable code…” 为此,A2UI 引入了一个可信组件库(catalog)的概念:所有可渲染的 UI 组件(如 Button、Card、Text 等),都需要事先在组件库中注册。Agent 只能“请求使用”这些白名单组件,而无法注入任意脚本或超出范围的元素。所以,A2UI 传递的并不是“如何操作 DOM”,而是一张UI 蓝图:它告诉前端应该使用哪些已核准的组件,以及它们的属性和布局关系,而具体怎么渲染、怎么执行,始终由宿主前端应用掌控。A2UI 的协议结构在设计时,明确考虑了LLM的生成特性:UI的描述采用了扁平化的 JSON 列表结构(在最新的0.9版进一步完善),而不是深度嵌套的树形结构。它让 LLM 更容易进行逐步、流式的生成:LLM可以先输出一个根组件的“占位描述”,再在后续的输出中补充子组件或细节;也可以只对 UI 的某一部分进行增量更新。 用户能够看到界面逐步成形,而不是等待输出完整 JSON 后才开始渲染。A2UI 的另一个核心设计,是彻底解耦界面结构与具体实现。Agent 发送的只是UI组件结构和必要的绑定数据,不包含任何与 React、Flutter等具体框架绑定的细节。真正的组件映射和渲染完全由客户端负责。也就是:同一份 A2UI JSON,可以被不同平台的渲染器解释为各自原生的 UI 组件。 比如,同一个“A2UI 按钮”,在 Web 环境中可能渲染为 HTML Button,在 Flutter 中映射为 RaisedButton,在 iOS 上则对应 SwiftUI 的 Button:各端既能复用统一的 Agent 输出,又能保持与宿主应用一致的原生体验,而无需让 AI 关心任何平台差异。除了界面结构,还需要一个机制把必要的数据绑定到组件上:比如在一个列表组件上展示Agent检索到的多个餐厅名称。A2UI 因此引入了dataModel消息机制,以支持UI组件与数据之间的绑定。一方面,Agent 可以发送单独的数据更新消息(类似”某个Button上要显示xxx文字“),前端渲染器据此刷新UI,避免每次重发整份 UI 描述。另一方面,当用户点击按钮、填写表单触发交互时,前端将事件以标准化消息的形式送回 Agent,Agent 再根据这些事件触发流程、更新数据或UI。由此,A2UI 在 Agent 与 UI 之间,形成了一个完整、可控的交互闭环。为了更直观地理解 A2UI,我们不妨通过一个完整的场景来走一遍工作流程。假设有一个 Agent,负责帮用户查找与预订餐厅。当用户输入“帮我预订 2 人的餐厅桌位”时,Agent 并不需要再通过多轮对话去反复确认日期、时间等细节,而是可以直接通过 A2UI,生成一个可交互的预订界面。这来自官方的一个A2UI的Demo,先了解它的简单架构:- 后端的Agent利用LLM动态生成结构化的A2UI JSON 消息(包含界面结构和数据)。
- 消息通过A2A 流式协议(SSE)实时传输到Web 前端。
- 前端接收并解析这些流数据,安全地渲染出用户界面(如预订表单)。
- 当用户在界面上进行操作(如点击“确认预订”)时,前端会将交互转化为标准化的用户操作事件(UserAction Event),回传给 Agent。
在这个场景中,我们让Agent 向用户展示一个小型表单,包括:在传统对话模式下,Agent 只能回复类似「请问您想预订哪天几点?」这样的文本。但在 A2UI 模式下,Agent 会构造一系列结构化的 JSON 消息,用来描述这个UI的组成,并通过流式发送消息给前端。{ "surfaceUpdate": { "surfaceId":"main",# 指定界面区域(surface),支持一个对话有多个界面区域 "components": [ { "id":"root", "component": { "Column": { "children": { "explicitList": [ "header", "date_input", "confirm_btn" ] }, "distribution":"start", "alignment":"stretch" } } }, {"id":"header","component": {"Text": {"text": {"literalString":"预订餐厅桌位"},"usageHint":"h1"} } }, {"id":"date_input","component": {"DateTimeInput": {"label": {"literalString":"选择日期和时间"},"value": {"path":"/reservation/datetime"},"enableDate":true,"enableTime":true} } }, {"id":"confirm_btn","component": {"Button": {"child":"confirm_text","action": {"name":"confirm_reservation"},"primary":true} } }, {"id":"confirm_text","component": {"Text": {"text": {"literalString":"确认预订"} } } } ] } } 这条surfaceUpdate消息,表示 Agent 希望创建或更新一块名为main的界面区域。其中包含了标题、日期时间选择器以及确认按钮等组件。- 组件 ID:每个组件都有一个唯一的id(如header、date_input)。后续如果 Agent 需要更新某个组件,或引用其内容,会依赖这个 ID。
- 组件类型:在component字段中,通过对象键指定组件类型,例如Text、DateTimeInput、Button。有前端经验的读者对此应该并不陌生。
- 数据绑定:在DateTimeInput中,value: {"path": "/reservation/datetime"}表示该控件绑定到数据模型中的某个字段。
Agent接着通过发送 dataModelUpdate 消息把数据绑定到UI组件:{ "dataModelUpdate": { "surfaceId":"main", "contents": [ {"key":"reservation","valueMap": [ {"key":"datetime","valueString":"2025-12-18T19:00"} ]} ] } } 前端接收到这条消息后,日期时间选择器会直接显示为「2025/12/18 19:00」。这种模式使界面与数据更新彻底分离,避免了频繁重发整棵组件树。Agent 可以流式发送多个surfaceUpdate消息,但前端并不会立即渲染界面,而是等待 Agent 明确发出”可以开始渲染“的信号消息:{ "beginRendering": { "surfaceId":"main", "root":"root", "catalogId":"https://my-company.com/a2ui/v0.8/my_custom_catalog.json" } } 这条消息的含义是:UI 描述已经足够完整(但不一定全部结束),可以安全地进行首次渲染。由于 A2UI 采用的是 JSON Lines 格式,每条消息独立成行,前端可以边接收、边解析,生成”流式的 UI “。假设前端是一个 Web 应用,并集成了 A2UI 提供的渲染库(例如基于 Lit 的 Web Components 渲染器)。当前端收到surfaceUpdate和beginRendering后,就会将这些UI描述映射为浏览器中的原生组件或自定义组件,并生成对应的 DOM 结构。整个过程中,并没有执行任何 AI 生成的、不受信任的代码。Agent 给出的只是“UI蓝图”,而真正的组件实现,来自开发者事先审核过的组件库或成熟的 UI 框架,安全边界始终掌握在客户端。实际运行中,渲染过程接受到的消息可能是这样不断推送的:{"surfaceUpdate":{"surfaceId":"main","components":[...]}}//Header{"surfaceUpdate":{"surfaceId":"main","components":[...]}}//Body{"beginRendering":{"surfaceId":"main","root":"root-id"}}//Initialrender{"surfaceUpdate":{"surfaceId":"main","components":[...]}}//Footer(afterinitialrender){"dataModelUpdate":{"surfaceId":"main","contents":{...}}}//PopulatedataUI可以先出现主体,再逐步补充细节元素和数据,用户无需等待一次性完成。当用户在UI上选择日期时间,并点击「确认预订」按钮时,前端会将这些操作转换为标准化的userAction消息发送给 Agent:{ "userAction": { "name":"confirm", "surfaceId":"main", "context": { "details": { "datetime":"2025-12-16T19:00:00Z", } } } } Agent 收到该事件后,便可以调用相应的业务工具完成预订。如果预订成功,Agent 可以再次通过 A2UI 返回一个成功提示的UI描述;如果需要补充信息,也可以更新现有UI,引导用户继续操作。可以看到,A2UI 让 Agent 直接参与到了 UI 的构建过程中。它能够基于对话上下文,即时“设计”出一个UI,让用户用点击和填写来完成复杂操作。技术上,A2UI 通过声明式 JSON、数据绑定以及事件机制,优雅地解决了”AI 如何安全地驱动前端 UI“的问题,也显著提升了应用的可扩展性与用户体验。理解 A2UI,容易联想到AG-UI和CopilotKit。它们并不是彼此替代的关系,而是处在不同层级、分工清晰的一套组合。AG-UI 全称Agent–User Interaction Protocol。它关注的重点并不是 UI 本身,而是Agent 与前端UI之间如何进行可靠、实时的交互。AG-UI 由 CopilotKit 团队发起,并在 2025 年中正式推出,目标是建立一条标准化的双向通信通道,让 Agent 后端与前端 UI 能够持续交换消息、事件与上下文状态。从定位上看,AG-UI 更像是“通信层协议”:但它不限定 UI 的具体表达。只要是 JSON 事件流,AG-UI 都可以承载。因为 AG-UI 不关心“你传的是什么”,它可以承载各种生成式 UI 规范,不管是A2UI,还是OpenAI之前的Open-JSON-UI,甚至是你自己定义的一套 UI 描述格式。所以:- AG-UI 定义的是这些描述如何以事件流的方式,在 Agent 与前端之间安全、实时地传输。
CopilotKit 是 AG-UI 协议的主要实现之一。它提供了一整套前后端集成方案,帮助开发者将 AI Agent 快速嵌入现有前端应用,而无需自己处理复杂的通信、状态同步和事件分发逻辑,使开发者可以把注意力集中在两件事上:值得一提的是,CopilotKit 团队本身也参与了 A2UI 规范的共建,并且是 A2UI 的首批合作伙伴之一。因此,在 CopilotKit 的最新版本中,已经对 A2UI 提供了完整支持。在实际开发中,使用 CopilotKit 时,可以让后端 Agent 直接产出 A2UI JSON 描述,再通过 AG-UI 管道传输到前端,由 CopilotKit 提供的渲染器进行渲染。CopilotKit 还提供了一个非常实用的工具:A2UI Composer。https://a2ui-editor.copilotkit.ai/ 通过可视化方式创建 UI 组件,Composer 会自动生成 A2UI 规范的 JSON。你可以将生成的 JSON 复制到 Agent 的提示词或输出中使用:在前端CopilotKit 已经为 A2UI 消息准备好了渲染器。开发者只需通过简单的集成,即可完成从协议到界面的整条链路。我们总结 A2UI、AG-UI、MCP、A2A 等协议在 Agent 应用中的定位与分工:在真实的企业级 Agent 应用中,这些协议往往是组合使用的。以一个智能客服系统为例:它可能通过MCP访问客户数据库查询订单信息,通过A2A协同外部数据分析 Agent,再借助AG-UI保持前端 Copilot 应用与后端 Agent 之间的状态同步,并由A2UI将复杂流程呈现为可交互的界面,供用户操作和反馈。 总之,A2UI 让 Agent 不再只会“说话”,而是开始学会“表达UI”。通过与 AG-UI、MCP、A2A 等协议的分层协作,它补齐了 Agent 应用栈中的关键一环,使 AI 的输出可以以更直观、更友好的交互形式呈现出来。当然,目前 A2UI 仍处在早期阶段(v0.8),生态也在快速演进中。对于开发者而言,理解并实践这些协议的组合,将是构建下一代 AI 应用的关键。正如当年 Web 标准催生了创新浪潮,在这些 Agent 协议的推动下,AI 应用同样有望迎来新的爆发期。
|