A2UI初想
起因是一个问题:LLM 能不能读用户所处的 context,直接生成贴合业务的 UI?从一个 text2SQL demo 出发,我一度以为答案是"让 LLM 输出 HTML"——哪怕只做 dashboard 也要 LLM 知道整个故事、生成 HTML、再照 API 文档接后端。可这本质上不就是在用 LLM 做一个 Web App?那如果限定在 chatbox 内、按情境渲染不同组件,是不是该落到 React 的动态加载上?
A2UI
喝着咖啡跟Deepseek等模型聊了一下,就发现我之前的理解太肤浅了,架构师们并不这样设计的,它们会考虑不是什么component都能被render ... 于是我让Grok 4.5 写了个小demo看看 BTW Grok 写后端似乎真不太行,之前让它写flutter解决了一些GLM 5.2也没法解决的问题。
1)A2UI 是一套协议(protocol) ,不是某个具体的库、框架或产品。定义了服务端(agent)和客户端(renderer)之间 怎么用消息描述界面 。
2)它规定的是 消息契约 :server→client 只有 4 种消息( createSurface / updateComponents / updateDataModel / deleteSurface )
3)一个 surface = 一块画板,里面装着一棵树(forest of components)。 这块画板(surface)是稳定的容器,而里面的 components 可以千变万化。
Jsonl
Json line
JSONL(JSON Lines)是每行一个独立、完整的 JSON 值、行与行用 \n 分隔的格式。它通常由多个 JSON 值逐个紧凑序列化(每个值压成一行、内部不留裸换行)后拼接而成,而不是把一个 JSON array join 成一行。
对 A2UI 来说,一条消息(如 createSurface)就是一个 JSON 对象,紧凑序列化为一行 JSONL。这条 JSONL 行可以通过 SSE 的 data 字段传输,也可以走纯 JSONL 流(NDJSON)。
todo list
概念
后文都会简单用todo list作为案例看如何使用A2UI
从消息契约上看,Surface生命周期挺明显的:
createSurface / updateComponents / updateDataModel / deleteSurface
其中 只要还没执行deleteSurface,就可以updateComponents & updateDataModel
而一个session里面可能会同时管理多个Surface,可以想象:
- 某个场景,弹出window是一个Surface,弹出window后面的page可能有多个Surface
- 一般来说例如做一个dashboard,一个component对应一个图表,而整个page就是一个Surface
- Catalog-白名单:所有渲染的component都必须在这个Catalog里面,它完全没有任何样式/布局字段,但它会规定例如是不是必填,必选之类的
下面这个是default的Catalog :
a2ui.org/specificati… 是 A2UI 官方 v0.9.1 版本的 basic(基础)组件目录 ,它声明了某个 Surface 被允许渲染哪些组件以及各自支持的属性,developer可以自定义。
用hy3生成了一段复杂的component,它可以让我们脑补一下todo APP里面复杂组件大概是怎样的
Column (root)
├── Tabs // 全部/进行中/已完成
│ ├── List (进行中)
│ │ ├── Card (item_0) → Row[ CheckBox, Text, Icon(star), Icon(delete) ]
│ │ ├── Card (item_1) → ...
│ └── ...
├── Row (底部操作栏)
│ ├── Button(添加)
│ ├── Button(筛选) → Modal(筛选表单: Dropdown优先级 + DatePicker)
│ └── ProgressBar(今日完成度)
└── Modal (编辑) → Column[ TextField(标题), DatePicker, Button(保存) ]