Android 生成式 UI 来了:A2UI 让 Agent 实时构建原生界面

Google 开源 A2UI 协议,让 Agent 用声明式 JSON 描述界面并由原生 Compose 渲染。
A2UI 是 Google Jetpack Compose 团队推出的开放协议,让 AI Agent 以声明式 JSON 描述可交互界面,由客户端用原生 Material 3 Compose 组件渲染。其概念模型仅两件事:Catalog 定义 Agent 可用的组件与函数契约,Surface 是 Agent 控制的一块 UI 区域。Agent 只返回 UI 描述而不返回可执行代码,从机制上规避代码注入风险。集成分三步:创建 Catalog、配置 Message Processor 解析与校验消息、用 A2UI Surface composable 渲染。由于渲染结果是原生组件,性能、深色模式、主题继承与无障碍能力开箱即用;数据绑定基于 Compose snapshot state,本地交互与 Agent 更新都能即时重组,无需往返后端。每条组件消息渲染前对照 schema 校验,错误组件被隔离并回传 Agent 触发自纠正。开发者可通过替换基础组件或新增自定义组件精确划定 Agent 的能力边界。
AI Agent 的回复不再是一堵文字墙。Google Jetpack Compose 团队推出的 A2UI(Agent to UI)库,让 Agent 能够以声明式 JSON 描述界面,由客户端用原生 Compose 组件渲染出来。在最近的技术演讲中,产品经理 Nick Butcher 和工程师 Anton 完整演示了从依赖集成到自定义组件的全流程。
为什么需要生成式 UI
当前多数 Agent 后端的响应被困在纯文本里。你让 Agent 生成一个订票功能,它给出的答案可能相当不错,但你无法直接交互,样式也与应用其余部分格格不入。生成式 UI 的思路是:Agent 在运行时根据动态输入,生成一套全新的、可交互的界面。
自己实现这套机制并非不可能,但你需要定义与后端交换的格式、事件流、函数调用等一整套协议。A2UI 把这层协议标准化了——它是一个开放的 JSON 格式,用声明式方式描述 UI。Agent 只返回 UI 的 JSON 表示,不返回任何需要客户端执行的代码,从源头上规避了代码注入类安全风险。
两个核心概念:Catalog 与 Surface
A2UI 的概念模型很精简。Catalog 是组件与函数的集合,包含 text、button、row、column 等基础组件,以及用于格式化文本、校验输入、打开 URL 的函数。关键点在于:Catalog 是一份契约,定义了你的应用支持什么,Agent 只能在这份契约内构建 UI,绝不能执行任意代码。
Surface 则是 Agent 控制的一块 UI 区域。Agent 通过 create surface、update components 等协议消息,用 Catalog 中的组件描述这块区域长什么样。
A2UI 规范定义了 basic catalog(基础目录),Jetpack Compose 渲染器用 Material 3 组件实现了它。大部分组件开箱即用,但 image、video、audio player 三个媒体组件需要你接入自己的库——比如用 Coil 加载图片。
声明式 UI 与命令式 UI 的区别:声明式 UI(如 Compose、SwiftUI、React)描述的是「界面应该长什么样」,框架负责计算从旧状态到新状态的最小变更集;命令式 UI(如传统 Android View 体系)则要求开发者逐步发出「添加按钮」「修改文字」等指令。A2UI 选择 JSON 声明式描述,意味着 Agent 只需输出目标状态而非操作序列,客户端可以自行决定如何渲染、如何动画、如何复用组件,这也是它能由原生 Compose 组件承载的前提。
JSON Schema 与契约校验:Catalog 之所以能构成「契约」,本质上依赖 JSON Schema 这类结构化校验机制——它为每种组件类型规定必填字段、字段类型与取值范围。Agent 发来的消息在渲染前先做 schema 校验,不符合契约的内容(如未知组件名、类型不匹配的属性)会在进入 UI 树之前被拦截。这既是安全边界,也是错误自纠正循环得以运转的技术基础。
三步接入:Catalog、消息处理器、渲染
演讲中的演示应用展示了完整的集成路径。系统设计分三层:Chat Session 接收 Agent 流式响应并提取原始 A2UI JSON 消息;Message Processor 用 Parser 把 JSON 转成语义表示,对照 Catalog 校验后映射为 Surface 模型;最后由 A2UI Surface composable 渲染成原生 Compose UI。

代码层面,第一步是创建 Catalog。用 material-a2ui-basic-catalog 工厂函数构建实例,把自定义的图片加载、视频音频渲染组件插进去,再提供打开 URI 等标准函数所需的 context。第二步在 ViewModel 中实例化 Catalog 和 Message Processor,把 Chat Session 回调里到达的每条消息交给 processInput,并在 viewModelScope 的后台协程中调用 process 消费消息队列。用户清空聊天记录时,同步调用 clearSurfaces。
第三步最直观:遍历 active surfaces,把每个模型传给 A2UI Surface composable。Agent 可能选择用列表展示大量内容,此时需要给组件设置最大高度限制。
原生组件的天然优势
渲染出来的界面用的是真实 Material 组件——标签页、对话框、日期选择器、滑块一应俱全。因为它们是原生 Compose 组件,所以具备原生性能,能响应深色模式,会自动继承外层 MaterialTheme 定制的颜色、形状与字体。同样因为原生语义,TalkBack、字体缩放、键盘导航等无障碍能力开箱即用。

延迟问题由渐进式渲染缓解:根组件一到就开始显示,容器组件对尚未到达的子组件展示加载占位符,子组件到达后用 Material 3 动效方案动画入场。
双向数据绑定与自纠正循环
演示中的订餐场景展示了数据绑定的价值。拖动滑块调整人数时,下方引用同一数据路径的格式化字符串同步更新——这一切在本地完成,不需要往返 Agent。当用户改用文字要求“改成六人”,Agent 只发来一条 update data model 消息更新对应路径,滑块就地跳变,而无需重新描述整个 UI。机制上,每个 Surface 的数据模型建立在 Compose snapshot state 之上,绑定路径的属性是 derived state,任一来源更新都会触发绑定组件自动重组。

用户操作通过 processor 暴露的 outbound events flow 回传。演示中点击确认按钮后,应用把 A2UI action 消息发回 Agent,context 里包含 Agent 事先声明的、在点击时刻根据数据模型解析出的属性值。你也可以在这里接入自有后端或跳转应用内其他页面。
AI 会犯错,所以每条组件消息在到达 UI 前都会对照 Catalog schema 校验。演示里 Agent 故意生成了一个未知组件类型,该组件被标记为错误并隔离,其余 UI 照常显示;渲染器同时向 Agent 发送“component type unknown”错误信息,Agent 随后补发修正消息,界面就地修复。自定义组件时,你完全可以选择在等待修复期间继续显示加载态,把错误对用户完全隐藏。
Compose Snapshot State 与 derivedStateOf:Compose 的 snapshot 系统是一套可观察的状态容器,任何读取 snapshot state 的组合函数都会在状态变化时被标记为需要重组(recomposition)。derivedStateOf 则用于从若干状态派生出计算结果,并缓存该结果——只有派生值真正变化时才触发下游重组,避免无关更新造成的多余渲染。A2UI 把绑定路径上的属性实现为 derived state,因此无论是用户拖动滑块(本地写入)还是 Agent 发来 update data model(远端写入),都会走同一条重组通路,UI 自然保持单一致。
函数调用与 outbound events 的回传语义:Agent 在 Catalog 中声明的函数(如打开 URL、校验输入)不会由 Agent 自己执行,而是以 action 消息的形式回传客户端,由客户端决定如何处理。这种「声明意图、本地执行」的模式把副作用执行权留在应用侧,配合 context 中按点击时刻解析的属性值,Agent 能拿到足够上下文做下一步决策,却始终无法越过客户端直接操纵设备或数据。
定制与扩展 Catalog
基础目录的每个组件参数都有默认值,替换成自有设计系统的按钮只需实现对应接口的 composable 函数,在 onClick 中调用 dispatch action,再用 observe component state 拿到子内容渲染。

新增组件类型则要实现更通用的 A2UI Component 接口:name 和 description 会被序列化进发送给后端的 Catalog schema,是 Agent 判断是否使用该组件的依据,必须写得足够描述性;properties 定义组件处理的数据,区分静态属性(值内联在属性中)与动态属性(引用数据模型路径,通过 bind API 读取订阅、bind updater 写回)。演示中的星级评分组件正是这样实现的——先定义 value 和 max 两个属性,再完成渲染与双向绑定。
最后把新 Catalog 定义为 ID、组件集合、函数集合三部分,用 add 操作符把自定义组件并入基础目录组件,并更新系统指令中的 schema 生成逻辑。重新部署后,Agent 就能使用这个它此前从未见过的星级组件。
控制权始终在开发者手里:给 Agent 最基础的文本和按钮,它自由发挥;给精心设计的复杂组件,它就只能在这些积木内组合。Jetpack Compose A2UI 渲染器目前处于 alpha 阶段,文档与示例已在 developer.android.com 发布。
相关推荐

Claude国内使用与充值全攻略:三种方式对比及防封控指南
整理Claude国内使用与会员充值的三种方式:海外信用卡直充、苹果美区ID与安卓Google Play内购、网站自助充值,对比各自门槛、成本与封控风险,并给出固定设备、稳定IP、不共享账号等五条降低封号概率的使用习惯。

从ChatGPT内容限制到Eval、可观测性与Guardrail实战
通过电子商店订单Agent实战,讲解ChatGPT内容限制背后的工程逻辑,以及Eval评估、Observability可观测性和Guardrail护栏如何协作,避免同名用户数据泄露与提示注入风险。

LangChain4j决策模型:本地校验Java工具调用
LangChain4j社区提出决策模型方案,在本地对Java工具调用进行校验,将控制逻辑从LLM拉回应用侧,提升工具调用的可靠性与可调试性。