Google把生成式UI关进组件目录,A2UI 1.0想替前端收拾烂账
A2UI 1.0发布,Apache 2.0,跨Web、移动、手表和电视。它不让模型直接吐HTML,改用catalog.json约束组件和函数。安全、iframe税、Express DSL和wire协议都值得看。
Google Cloud Tech 发布了 A2UI 1.0,Apache 2.0 协议,定位是稳定、开放的生成式 UI 协议和框架。支持 Web 端 React、Angular、Lit,移动和桌面端 Flutter、SwiftUI、Jetpack Compose、Lynx 等渲染器,也提供 Python、TypeScript、Dart 的 Agent SDK,并集成到 AGUI 等系统里。作者 Alan Blount 在原文里解释了 6 个常见问题,核心都指向一件事:模型可以生成界面,但界面不能变成一坨没人管得住的字符串。
直接让模型写 HTML,问题不在灵活性
开发房间里问什么是生成式 UI,一半人会想到语言模型把 raw HTML 和 Tailwind class 流式吐进浏览器。真要让这套东西符合设计系统,还能在 Web、移动、手表、TUI 上表现一致,基本做不到。
Google Stitch 和 Vercel 推过 DESIGN.md,把字体比例、间距 token、布局规则写进 markdown,让 coding agent 少在每次 PR 里发明紫色渐变。Vercel 的案例很具体:文件构建跑了 200 多轮,包含完整轮次、定向检查和 dry run,还有模型 judge 每轮写批评,反馈进入下一轮。带 design.md 生成的页面有 39 个失败,不带有 91 个,测试里少了 57%。这算成功故事,但原文也点出它脆弱:错误要被人抓出来补进 DESIGN.md,DESIGN.md 和真实设计系统之间还会漂移。
更尴尬的是,前端和移动团队可能花了好几年打磨暗色模式对比度、RTL 布局、本地化日期选择器、WAI-ARIA 屏幕阅读器属性、触控目标,这些已经躺在 React、Angular、Lit、Flutter、SwiftUI、Jetpack Compose 组件库里。运行时让模型再写一遍,纯属重复劳动。A2UI 的做法是给 agent 一份预构建组件契约 catalog.json,agent 只能引用允许的组件。设计师控制灵活性,比如 6 个大 widget、20 个小 widget、50 个原子组件。
流式 HTML 和 JS,会把 prompt injection 变成 XSS
原文举了个直白的场景:agent 读未读日历邀请,然后把原始 HTML、CSS、JavaScript 流进主应用 DOM。某条外部邀请在会议描述里藏了 prompt injection,这段不可信文本就在已认证会话里写入了可执行标记。用 HTML sanitizer 剥掉 script 标签不够。构造过的 CSS 可以把不可见点击目标用 position: fixed 浮在真实审批按钮上,可以通过 background URL 请求外泄 token,也可以污染 DOM 全局变量。安全工程师不会把概率模型的输出当可信客户端代码。
A2UI 1.0 里,UI 消息是纯声明式数据,不是可执行脚本或 raw CSS。agent 只能引用组件名和 catalog.json 里 allowlist 的函数。1.0 还加了 allowedCallers 和 requiresUserActivation 标记,后台流不能随便触发外部导航或剪贴板操作,除非用户真的点了。
iframe 不是免费沙箱,它有税
排除 raw HTML 进主 DOM 后,很多团队会选沙箱 iframe。MCP Apps 用双 iframe,外层代理 sandbox.html 把不可信 HTML 喂给内层 srcdoc frame,sandbox 设为 allow-scripts,origin 是 null。对 3D WebGL 查看器或自定义 Kanban 这种独立第三方画布,这笔交易合理,A2UI 1.0 也通过 @a2ui/catalog-mcp 嵌入 MCP Apps。
但聊天流里放 15 张交互卡,iframe 就开始和浏览器物理规律打架。15 张卡起 15 个 document context,框架 JS 在内存里重复。origin 是 null,localStorage 和 cookies 直接抛 SecurityError。下拉菜单在矩形框边缘被裁剪,Tab 焦点被困住,通过 postMessage 异步调整高度会让移动端滚动卡顿。自己控制 UI 就尽量原生渲染,用自家设计系统,不交 iframe 税。iframe 留给真正需要隔离像素画布的那 10%,或者别人完全可信的 UI。
生成式 UI 是一条光谱,不是一种答案
原文把 agent 给用户送 UI 的方式列成光谱:预构建 UI,agent 只挑一个屏幕;在你的页面里注入来自别处的 widget;声明式 UI,从组件目录组合;完全在运行时编码或渲染 UI。四种都能用,A2UI 也从第三种起步,同时发布了 MCP Apps 加 A2UI 的三种方法,也有 iframe 内自定义 HTML 模板的工作版本。
LLM 更喜欢 Express DSL,不想吐嵌套 JSON
早期 server-driven UI 原型常让模型直接输出 wire JSON。看 token 流就知道,raw UI JSON 很啰嗦,token 花在 component、children、id、引号和嵌套括号上,600 token 处一个逗号就能让解析崩掉。Rabi Shanker Guha 和 OpenUI 项目用 OpenUI Lang 展示过:raw UI JSON 最多浪费三分之二输出 token 在结构仪式上,流式还得等外层括号闭合;行导向的位置 DSL,形如 identifier = Component(...),更贴近代码训练过的模型生成结构的方式。
这个洞察启发了 A2UI Express,现在是 1.0 的 Python、TypeScript、Dart Agent SDK 默认推理格式。模型在 a2ui 标签里写简洁位置调用和 $/path 绑定。原文给了 54 个样本的 core_v1_0 benchmark,用 gemini-3.8-flash,temperature 设 0.0:Express 把中位 prompt token 减少 45.4%,从 10980 降到 6000;生成 UI 代码 token 降 63.2%,无 thinking 时 2.7 倍,有 unbounded thinking 时降 67.3%,3.1 倍。客户用 Express 把临床仪表盘延迟从 10 秒压到 5 秒,Soverius AI 微调本地 Gemma 4,在浏览器里直接流式输出 Express。
推理格式和 wire 格式必须切开
看到位置 DSL 流得快,很容易想在每个 iOS、Android、Web 客户端里直接解析它。这是个陷阱。六个客户端渲染 SDK 耦合一种 LLM 语法,以后每次 prompt 格式升级都要等移动应用商店发版。等过三周 iOS 二进制更新的人知道有多疼。
A2UI 1.0 在服务端推理格式和传输 wire 协议之间画了硬边界。服务端 A2uiGenerator 把 Express 块编译成标准 A2UI 1.0 JSON 和 JSONL envelope。同一个 wire 格式也接受服务端 @macro 展开,把私有数据库查询留在 LLM prompt 外面,或者接受 System 1 决策模型的结构化选择,比如 ByteDance Lynx playground 里的 Jev。createSurface 打开 surface,可以一条消息内联初始 components 和 dataModel。updateComponents 流式发送平铺、按 ID 寻址的组件列表,更新时不用 diff 深层树。updateDataModel 通过 RFC 6901 JSON Pointer 发小更新,走 SSE、WebSockets、A2A、AG-UI 或 MCP。客户端渲染器只解析验证过的 JSON。换模型、改推理语法、把难处理的卡片搬进确定性 Python @macro,都不用发客户端更新。
生态和上手
原文提到 OpenUI 做了位置 DSL 和 React catalog,ByteDance 为 Lynx 做了流式原生生成式 UI,Alation 为 AIOS 做了声明式 SQL 后端 feed,要同时渲染在 Alation 的 Data Products App 和 Claude 里。Atlassian 在 Jira 里做交互 agent 卡片。Bloomberg、CommerceTools、CopilotKit,以及 Google 内部的 Gemini Notebook 和 Gemini Enterprise,都在让 agent 用 UI 回应。
安装方式原文给了几条:npx skills add a2ui-project/a2ui,把 A2UI 1.0 skill 加给 Antigravity、Claude Code、Codex、Cursor 等 coding agent;pip install a2ui-agent-sdk;npm install @a2ui/agent @a2ui/react @a2ui/web_core。文档、quickstart、spec 在 a2ui.org,浏览器实验在 A2UI Playground。原文链接在这里。
社区追问比发布稿更有意思
Invariant 问 1.0 会不会破坏旧版本构建,还是直接 drop-in。Ruslan 关心旧 app 收到 catalog 里没有的组件时,能不能让屏幕其余部分继续工作,只停掉那个不支持的组件。Juliano 在手动 playground 里试了搜索 Northwind:从第 2 页搜索正确返回第 1 页的一行,无匹配后 clear 也能恢复,他问这个筛选能不能扛住无关的流式组件更新。S4ck3 说原生 SwiftUI 渲染器会让 Mac 和 iOS 开发者更容易买账。nick 的评论很短:协议胜过 demo,A2UI 押注的是契约。Wei Sun 问能不能用它实现 MCP App。Amy 对 15 张卡 15 个 iframe 的手机体验表示难受。Raúl 认为生成式 UI 让 agent 从报告结果走到为任务搭界面,标准重要,因为同一个 agent 输出应该在任意 app 里合理渲染,不只在自己生成它的那个 app。will 问它是不是能重定义 AI coding 的 UI 框架。Agentik 则想看 agent 到底会在手表上渲染什么。
A2UI 1.0 的价值不在让模型更会写界面,而在给运行时 UI 上一份合同。普通用户可能只会感知到 agent 回复从文字墙变成能点的卡片。开发者得到的是复用现有设计系统、安全边界清楚、客户端不被推理语法绑架。风险也摆在那:catalog 怎么治理,旧客户端怎么降级,跨端细节能不能真的对齐。协议能不能赢,看生态愿不愿意把组件目录当成公共契约,而不是又一个内部 JSON 字段表。
发布时间: 2026-11-12 02:32