核心摘要 — A2UI(Agent-to-UI)是 Google 开源的声明式 UI 协议(Declarative UI Protocol),让 AI Agent 通过发送声明式 JSON 来生成富交互界面——而非可执行代码。客户端使用自有的原生组件库(React、Flutter、Lit)渲染这些 JSON 描述,并严格执行数据与代码的安全隔离。2026 年初发布的 v0.9 版本引入了 Prompt 优先架构、官方 React 渲染器和 Python Agent SDK,使 A2UI 成为 Agent 驱动 UI 领域的新兴标准。

核心要点

  • 声明式,非可执行 — A2UI Agent 以 JSON 描述 UI 意图,客户端使用预先审批的可信组件进行渲染。没有 eval(),没有注入脚本,没有服务端渲染的 HTML 片段。
  • 一套协议,多端运行 — 官方渲染器覆盖 React、Lit、Angular 和 Flutter。SwiftUI 和 Jetpack Compose 渲染器列入 2026 Q2 路线图。
  • 架构级安全 — 数据与代码分离不是一条策略建议,而是协议层面的结构性保证。Agent 无法逃出组件目录,也无法在客户端执行任意逻辑。
  • 补全协议栈 — A2UI 处理 Agent → 用户界面,A2A 处理 Agent → Agent 通信,MCP 处理 Agent → 工具连接。三者共同覆盖全部交互层面。
  • v0.9 采用 Prompt 优先架构 — Schema 嵌入模型的系统提示中,解锁更丰富的布局表达,摆脱了结构化输出(Structured Output)模式的限制。

"聊天墙"困境

过去两年,AI Agent 的主流交互界面一直是聊天对话流:一个纵向滚动的文本气泡列表。这种形式适合对话式问答,但当 Agent 需要展示结构化信息时,体验就会急剧恶化。

假设一个机票预订 Agent,用户问:"帮我查下周四从旧金山飞东京成田的航班。"

没有 A2UI(纯文本聊天):

code
Agent: 以下是可用航班:

1. JAL 002 — 出发 11:30 AM,到达次日 3:30 PM — 经济舱 $1,240
2. ANA 008 — 出发 5:15 PM,到达次日 9:20 PM — 经济舱 $1,180
3. United 837 — 出发 1:45 PM,到达次日 5:50 PM — 经济舱 $980

需要预订哪个?请回复对应编号。

用户需要逐行解析这堵文字墙,在脑中对比三个选项,然后输入一个数字。没有筛选,没有排序,也无法并排比较。

有了 A2UI(原生 UI):

Agent 发送一段 JSON 描述,为每个航班指定 FlightCard 组件,附加 SortDropdown 排序控件和绑定了操作的 BookButton。客户端渲染出带有航空公司 Logo、价格高亮和一键预订流程的原生卡片——而 Agent 没有输出任何一行 HTML 或 JavaScript。

sequenceDiagram participant User participant Client as "Client (React App)" participant Agent as "AI Agent" User->>Agent: "Flights SFO→NRT Thu" Agent->>Client: createSurface (JSON) Agent->>Client: updateComponents (FlightCard × 3) Client->>User: Native flight cards rendered User->>Client: Taps "Book" on ANA 008 Client->>Agent: action event (book, flightId=ANA008)

这就是 A2UI 的核心价值:Agent 不再与聊天墙搏斗,转而直接生成真正的用户界面。

什么是 A2UI?

A2UI(Agent-to-UI)是 Google 以 Apache 2.0 许可证发布的开源协议。它定义了一种声明式 JSON 格式(Declarative JSON Format),供 AI Agent 描述用户界面。Agent 不生成渲染代码——它生成的是 UI 的描述:界面长什么样、有什么行为。客户端解析这份描述,用自有的可信组件库进行渲染。

该协议有两个规范版本:

版本 状态 架构 适用场景
v0.8 稳定 结构化输出(约束解码) 原生支持 JSON 模式的模型
v0.9 草案 Prompt 优先(Schema 嵌入系统提示) 更丰富的布局、更灵活的模型

A2UI 位于 Agent 技术栈的特定层级。它不替代 MCP(负责连接 Agent 与工具和数据源),也不替代 A2A(负责多 Agent 协调)。它专门处理 Agent 到用户的界面层——Agent 输出转化为可视化、可交互体验的"最后一公里"。

可以这样理解:MCP 是 Agent 读取数据库的方式,A2A 是两个 Agent 协调任务交接的方式,A2UI 则是 Agent 向人类展示结果的方式。

A2UI 架构:工作原理

消息流

A2UI 会话是 Agent 与客户端之间的一串 JSONL 消息流。协议定义了四种核心消息类型:

消息类型 方向 用途
createSurface Agent → 客户端 打开一个新的 UI 表面(面板、弹窗、内嵌卡片)
updateComponents Agent → 客户端 在表面上添加或替换组件
updateDataModel Agent → 客户端 更新组件绑定的数据
deleteSurface Agent → 客户端 关闭并清理一个表面
graph LR Start(("Start")) -->|"createSurface"| SC["Surface Created"] SC -->|"updateComponents"| CR["Components Rendered"] CR -->|"updateDataModel"| DU["Data Updated"] DU -->|"updateComponents"| CR CR -->|"deleteSurface"| End(("End")) DU -->|"deleteSurface"| End

组件树:邻接表模型

A2UI 不使用嵌套 JSON 来描述组件层级关系。它采用扁平邻接表(Flat Adjacency List)——每个组件都是顶层条目,通过显式的 parentId 指针建立父子关系。这一设计基于两个原因:(1)LLM 生成扁平数组比深层嵌套结构更可靠;(2)它支持增量更新——Agent 可以只添加一个组件,而不必重发整棵树。

json
{
  "type": "updateComponents",
  "surfaceId": "flight-results",
  "components": [
    {
      "componentId": "root",
      "type": "Container",
      "parentId": null,
      "properties": { "direction": "column", "gap": "16px" }
    },
    {
      "componentId": "header",
      "type": "Text",
      "parentId": "root",
      "properties": { "content": "Flights: SFO → NRT", "variant": "h2" }
    },
    {
      "componentId": "sort",
      "type": "Dropdown",
      "parentId": "root",
      "properties": {
        "label": "Sort by",
        "options": ["Price", "Duration", "Departure"],
        "dataRef": "/ui/sortField"
      }
    },
    {
      "componentId": "flight-list",
      "type": "List",
      "parentId": "root",
      "properties": { "dataRef": "/flights", "itemTemplate": "flight-card-tmpl" }
    }
  ]
}

如果你经常处理 JSON 数据,可以使用我们的 JSON 格式化工具 来美化和检查类似上面这样的 A2UI 载荷。

数据绑定:JSON 指针(RFC 6901)

组件不直接内嵌数据。它们通过 JSON 指针(JSON Pointer,RFC 6901)引用独立数据模型中的路径。上例中的 dataRef 属性 /flights 指向由 Agent 通过 updateDataModel 消息维护的数组。

json
{
  "type": "updateDataModel",
  "surfaceId": "flight-results",
  "operations": [
    {
      "op": "replace",
      "path": "/flights",
      "value": [
        { "id": "JAL002", "airline": "JAL", "price": 1240, "depart": "11:30" },
        { "id": "ANA008", "airline": "ANA", "price": 1180, "depart": "17:15" },
        { "id": "UA837", "airline": "United", "price": 980, "depart": "13:45" }
      ]
    },
    {
      "op": "replace",
      "path": "/ui/sortField",
      "value": "Price"
    }
  ]
}

这种分离至关重要。组件树定义结构与行为,数据模型定义内容。Agent 可以更新价格(数据模型)而无需重发 UI 结构,也可以调整布局(组件)而无需重发数据。

安全模型:数据与代码分离

A2UI 的核心安全哲学可以用一句话概括:Agent 发送数据,客户端执行代码。这不是一条指导原则——它是在协议层面强制执行的架构约束。

A2UI 如何防止代码注入

在传统方案中,AI Agent 可能生成 React 组件、HTML 片段或 JavaScript 回调。这些输出中任何一个都可能包含恶意代码——无论是来自提示注入攻击(Prompt Injection)还是模型幻觉。A2UI 从根本上消除了这一攻击面:

维度 传统方案(嵌入代码) A2UI(声明式 JSON)
Agent 输出 HTML/JS/React 代码 JSON 描述
代码执行 Agent 生成的代码在客户端运行 仅运行预先审批的客户端代码
组件集 无限制(任意 HTML 标签) 仅限可信组件目录
事件处理 任意 onClick 函数 注册表中的命名函数
数据访问 完整 DOM/API 权限 仅限作用域内的数据模型
提示注入风险 高——注入的代码会被执行 极低——注入的 JSON 只是数据

可信组件目录

客户端维护一份 Agent 可以请求的组件目录。如果 Agent 发送了一个不在目录中的组件 type,客户端会忽略它或渲染一个降级兜底组件。Agent 无法在运行时发明新的组件类型。

javascript
// 客户端组件目录(React 示例)
const COMPONENT_CATALOG = {
  'Container': ContainerComponent,
  'Text': TextComponent,
  'Button': ButtonComponent,
  'Dropdown': DropdownComponent,
  'List': ListComponent,
  'FlightCard': FlightCardComponent,
  'Image': ImageComponent,
};

function renderA2UIComponent(descriptor) {
  const Component = COMPONENT_CATALOG[descriptor.type];
  if (!Component) {
    console.warn(`Unknown component type: ${descriptor.type}`);
    return <FallbackComponent />;
  }
  return <Component {...descriptor.properties} />;
}

函数注册表

即使是客户端交互(按钮点击、表单提交)也使用预注册目录中的命名函数——而非任意代码:

json
{
  "componentId": "book-btn",
  "type": "Button",
  "parentId": "flight-list",
  "properties": {
    "label": "Book Now",
    "action": {
      "functionName": "bookFlight",
      "args": { "flightId": { "$dataRef": "/selectedFlight/id" } }
    }
  }
}

bookFlight 函数由客户端开发者实现和审计。Agent 可以调用它并传递数据模型引用作为参数,但无法定义这个函数的具体行为。这就是 A2UI 在 UI 层实现工具调用安全性的方式。

A2UI v0.9:有什么变化

v0.8 是为支持结构化输出(约束解码,Constrained Decoding)的模型设计的。JSON Schema 在解码层强制执行,保证了输出有效性,但限制了表达力——Schema 必须足够简单,模型才能追踪。

v0.9 转向Prompt 优先架构(Prompt-First Architecture)。完整的 JSON Schema 嵌入模型的系统提示中,模型自由生成 JSON,客户端在事后进行校验。这带来了多项改进:

特性 v0.8 v0.9
Schema 传递方式 约束解码配置 系统提示嵌入
Schema 复杂度 受解码器约束限制 任意丰富
Web 渲染器 仅 Lit Lit + React + Angular(共享 web-core
Agent SDK 无(原始 JSON) Python SDK(a2ui-agent
Schema 文件 单体规范 按组件模块化
流式传输 JSONL JSONL(不变)

v0.8 与 v0.9 的 JSON 对比

v0.8 — 扁平结构,最简属性:

json
{
  "component": "text-input",
  "id": "email",
  "label": "Email",
  "validation": "email"
}

v0.9 — 更丰富的属性、显式 Surface 绑定、数据引用:

json
{
  "componentId": "email-input",
  "type": "TextInput",
  "parentId": "form-root",
  "surfaceId": "contact-form",
  "properties": {
    "label": "Email Address",
    "placeholder": "you@example.com",
    "dataRef": "/form/email",
    "validation": {
      "pattern": "^[\\w.-]+@[\\w.-]+\\.[a-zA-Z]{2,}$",
      "errorMessage": "Please enter a valid email"
    }
  }
}

v0.9 新增:共享 web-core

v0.9 规范引入了 @anthropic-ai/a2ui-web-core(由 Google 贡献到共享仓库),一个平台无关的 TypeScript 库,负责处理:

  • JSON 指针解析和数据模型管理
  • 组件树协调(差异比对与补丁更新)
  • 根据模块化 Schema 校验 Agent 消息
  • 将 UI 交互事件路由回 Agent

各框架渲染器(React、Lit、Angular)只是 web-core 的轻量封装,减少了代码重复,确保了行为一致性。

渲染器:一套协议,多端运行

A2UI 的平台无关设计意味着任何渲染技术都可以实现渲染器。当前生态如下:

渲染器 平台 状态 包名
React Web ✅ 官方(v0.9) @a2ui/react-renderer
Lit Web ✅ 官方(v0.8+) @a2ui/lit-renderer
Angular Web ✅ 社区维护 a2ui-angular
Flutter 移动端 + 桌面端 ✅ 官方 a2ui_flutter
SwiftUI iOS / macOS 🔜 计划 Q2 2026
Jetpack Compose Android 🔜 计划 Q2 2026

React 渲染器是目前 Web 端功能最完整的实现。它将 A2UI 组件类型映射为 React 组件,将数据模型作为 React 状态管理,并将用户操作以事件形式路由回 Agent。

graph TD A["AI Agent"] -->|"JSONL stream"| B["web-core"] B -->|"Component tree"| C{"Renderer"} C -->|React| D["React App"] C -->|Lit| E["Lit App"] C -->|Flutter| F["Flutter App"] D -->|"User events"| A E -->|"User events"| A F -->|"User events"| A

实战构建:A2UI 完整示例

下面我们来构建一个完整的联系表单——A2UI 的 "Hello World"。Agent 创建一个 Surface,添加表单组件,绑定数据模型,并处理提交操作。

第一步:Agent 发送 JSONL 流

jsonl
{"type":"createSurface","surfaceId":"contact-form","title":"Contact Us","mode":"inline"}
{"type":"updateComponents","surfaceId":"contact-form","components":[{"componentId":"form-root","type":"Container","parentId":null,"properties":{"direction":"column","gap":"12px"}},{"componentId":"name-input","type":"TextInput","parentId":"form-root","properties":{"label":"Full Name","dataRef":"/form/name","required":true}},{"componentId":"email-input","type":"TextInput","parentId":"form-root","properties":{"label":"Email","dataRef":"/form/email","validation":{"pattern":"^[\\w.-]+@[\\w.-]+\\.[a-zA-Z]{2,}$","errorMessage":"Invalid email"}}},{"componentId":"msg-input","type":"TextArea","parentId":"form-root","properties":{"label":"Message","dataRef":"/form/message","rows":4}},{"componentId":"submit-btn","type":"Button","parentId":"form-root","properties":{"label":"Send Message","variant":"primary","action":{"functionName":"submitContact","args":{"data":{"$dataRef":"/form"}}}}}]}
{"type":"updateDataModel","surfaceId":"contact-form","operations":[{"op":"replace","path":"/form","value":{"name":"","email":"","message":""}}]}

可以将每一行粘贴到我们的 JSON 校验工具 中,验证每条消息是否格式正确。

第二步:Python Agent SDK

v0.9 的 Python SDK(a2ui-agent)提供了高级封装,无需手动拼接 JSONL:

python
from a2ui_agent import A2UIAgent, Surface, components as c

agent = A2UIAgent(model="gemini-2.5-pro")

# 定义 UI
surface = Surface(id="contact-form", title="Contact Us", mode="inline")

surface.add(c.Container(id="form-root", direction="column", gap="12px"))
surface.add(c.TextInput(
    id="name-input",
    parent="form-root",
    label="Full Name",
    data_ref="/form/name",
    required=True,
))
surface.add(c.TextInput(
    id="email-input",
    parent="form-root",
    label="Email",
    data_ref="/form/email",
    validation={"pattern": r"^[\w.-]+@[\w.-]+\.[a-zA-Z]{2,}$"},
))
surface.add(c.TextArea(
    id="msg-input",
    parent="form-root",
    label="Message",
    data_ref="/form/message",
    rows=4,
))
surface.add(c.Button(
    id="submit-btn",
    parent="form-root",
    label="Send Message",
    variant="primary",
    action={"functionName": "submitContact", "args": {"data": {"$dataRef": "/form"}}},
))

# 初始化数据模型
surface.set_data("/form", {"name": "", "email": "", "message": ""})

# 发送到客户端
async for message in agent.stream(surface):
    await websocket.send(message)

第三步:React 客户端渲染

jsx
import { A2UIProvider, A2UISurface } from '@a2ui/react-renderer';

const FUNCTION_REGISTRY = {
  submitContact: async ({ data }) => {
    const response = await fetch('/api/contact', {
      method: 'POST',
      headers: { 'Content-Type': 'application/json' },
      body: JSON.stringify(data),
    });
    return response.ok;
  },
};

function App() {
  return (
    <A2UIProvider
      agentUrl="wss://agent.example.com/a2ui"
      functionRegistry={FUNCTION_REGISTRY}
    >
      <A2UISurface surfaceId="contact-form" />
    </A2UIProvider>
  );
}

客户端开发者控制 submitContact 的具体行为,Agent 控制表单的外观和数据流转。双方各司其职,互不越界。

A2UI 在 Agent 协议栈中的位置

现代 Agent 系统不依赖单一协议运行,而是依赖一个协议栈,每一层处理不同类型的交互。以下是 A2UI 与 MCP 和 A2A 的协作关系:

graph TB subgraph "User Layer" U["Human User"] end subgraph "A2UI Layer" A2UI["A2UI Protocol"] end subgraph "Agent Layer" AG1["Agent A"] AG2["Agent B"] end subgraph "A2A Layer" A2A["A2A Protocol"] end subgraph "Tool Layer" MCP["MCP Protocol"] T1["Database"] T2["API"] T3["File System"] end U <-->|"Declarative UI"| A2UI A2UI <-->|"JSON surfaces"| AG1 AG1 <-->|"Agent-to-Agent"| A2A A2A <-->|"Task delegation"| AG2 AG1 <-->|"Tool calls"| MCP AG2 <-->|"Tool calls"| MCP MCP --> T1 MCP --> T2 MCP --> T3
协议 层级 方向 载荷
A2UI Agent ↔ 用户 双向(UI + 事件) 声明式 JSON Surface
A2A Agent ↔ Agent 双向(任务 + 结果) JSON-RPC 任务消息
MCP Agent ↔ 工具 双向(调用 + 响应) JSON-RPC 工具调用

在实际的 Agentic 工作流中,用户可能通过 A2UI Surface 发起一个复杂操作。主 Agent 通过 A2A 将子任务委派给专业 Agent,每个 Agent 通过 MCP 调用工具。结果沿协议栈向上回流,最终以更新后的 A2UI Surface 呈现给用户。关于 Agent 间协作模式的深入探讨,请参阅我们的多 Agent 系统实战指南

最佳实践

1. 保持 Surface 小而专注。 一个 Surface 应当代表一个单一任务或视图——一个表单、一个结果面板、一个确认对话框。不要试图在一个 Surface 内构建完整的单页应用。如果用户的任务发生变化,创建一个新的 Surface。

2. 优先使用数据模型更新,而非重发组件。 当只有内容发生变化(新的搜索结果、更新的价格)时,使用 updateDataModel。只在 UI 结构发生变化时才发送 updateComponents。这可以最小化传输体积,使协议在流式场景下更高效。

3. 对组件目录进行版本管理。 可信组件目录会随时间演进。使用语义化版本,并在 createSurface 消息中包含目录版本号,这样 Agent 就能知道客户端支持哪些组件。

4. 在客户端校验 Agent 输出。 尽管 A2UI 是声明式的,仍然应在渲染前校验传入的 JSON 是否符合 Schema。web-core 库会自动完成这一步,但如果你构建自定义渲染器,务必在消息接入层使用 JSON Schema 校验。

5. 为渐进增强而设计。 并非所有客户端都支持所有组件类型。设计 Agent 时应包含 fallback 属性——例如 FlightCard 可以带一个 fallbackText,在纯文本客户端中也能正常渲染。

常见问题(FAQ)

什么是 A2UI 协议?

A2UI(Agent to UI)是 Google 以 Apache 2.0 许可证发布的开源声明式 UI 协议。它让 AI Agent 通过发送 JSON 描述(而非可执行代码)来生成富交互界面。客户端应用——无论是 React、Flutter、Angular 还是 Lit 构建的——解析这些描述并使用自有的原生组件库进行渲染。

其核心创新在于数据(Agent 发送的内容)与代码(客户端执行的逻辑)的严格分离。Agent 可以描述一个带点击处理器的按钮,但无法定义这个处理器的具体行为。这一架构约束从根本上消除了一整类安全漏洞,包括试图通过 UI 层执行恶意代码的提示注入攻击。

A2UI 如何保证安全性?

A2UI 的安全模型是结构性的,而非流程性的。三重机制协同发挥作用。首先,Agent 输出始终是声明式 JSON——协议中没有嵌入可执行代码的语法。其次,客户端维护一份可信组件目录:Agent 被允许请求的组件类型白名单,任何未知的组件类型会被拒绝或渲染为安全的降级组件。第三,客户端交互(按钮点击、表单提交、页面导航)使用函数注册表中预审计的命名函数。Agent 通过函数名引用函数并传递数据,但无法定义或修改函数行为。

这意味着即使是精心设计的提示注入攻击——成功说服 Agent 发出恶意指令——也只能请求客户端开发者已经审批过的组件和函数。

A2UI v0.8 和 v0.9 有什么区别?

v0.8 为具备约束解码能力(结构化输出)的 LLM 设计。JSON Schema 在解码器层面强制执行,保证模型生成的每个 token 都符合 Schema。缺点是 Schema 必须保持精简——复杂布局可能超出解码器的追踪能力。

v0.9 采用Prompt 优先方案。完整的 JSON Schema 嵌入模型的系统提示中,模型自由生成 JSON,校验在客户端事后进行。这使得组件 Schema 可以包含嵌套属性、条件校验和复杂数据绑定,表达力大幅提升。v0.9 还附带了共享的 web-core TypeScript 库、官方 React 渲染器以及 Python Agent SDK(a2ui-agent),简化了服务端 Surface 的构建流程。

A2UI 支持哪些平台?

A2UI 在设计上是平台无关的——任何渲染技术都可以实现渲染器。截至 2026 年 4 月,官方渲染器覆盖 React(Web)、Lit(Web)和 Flutter(移动端 + 桌面端)。社区维护的 Angular 渲染器也已可用。Google 已宣布 SwiftUI(iOS/macOS)和 Jetpack Compose(Android)渲染器将在 2026 Q2 发布。

共享的 web-core 库负责处理协议层逻辑(消息解析、数据模型管理、组件树协调),因此构建新渲染器的主要工作是将 A2UI 组件类型映射到目标平台的原生组件。

A2UI 与 A2A 和 MCP 协议的关系是什么?

三套协议共同构成现代 Agent 系统的完整交互栈。MCP(Model Context Protocol,模型上下文协议)处理 Agent 到工具层——定义 Agent 如何调用数据库、API、文件系统等外部资源。A2A(Agent-to-Agent)处理 Agent 到 Agent 层——支持多 Agent 协调、任务委派和结果聚合。A2UI 处理 Agent 到用户层——定义 Agent 如何通过可视化界面展示信息和收集输入。

在生产级 Agentic 工作流中,三套协议通常同时运行。用户通过 A2UI Surface 发起交互,触发主 Agent。主 Agent 可能通过 A2A 委派给其他 Agent,并通过 MCP 调用工具。结果沿协议栈回流,最终以更新后的 A2UI Surface 呈现。关于框架对比,请参阅我们的 2026 年 AI Agent 框架全面对比

总结

A2UI 解决了 Agent 生态中一个根本性缺口:AI Agent 无法生成安全、丰富、跨平台的用户界面。通过将声明式 JSON 作为唯一通信格式,并维持严格的数据与代码边界,该协议让 Agent 无需承担代码生成的安全风险即可创建交互式体验。

v0.9 标志着一个成熟度拐点。Prompt 优先架构、共享 web-core 库和官方 React 渲染器使 A2UI 在 Web 端已经具备生产就绪能力。Flutter 覆盖了移动端和桌面端,SwiftUI/Compose 渲染器即将到来,该协议有望成为与 MCP 和 A2A 并列的 Agent 到用户界面标准层。

如果你正在构建 Agent 驱动的产品,现在就是评估 A2UI 的最佳时机。从官方 React 渲染器起步,定义你的可信组件目录,亲身体验"能聊天的 Agent"和"能交付界面的 Agent"之间的差距。

更多 Agent 生态的深度解析,请阅读我们的 AI Agent 开发实战指南MCP 协议深度解析

相关资源