A2UI v0.8 JSON Schema 全解析:消息协议、组件目录与 LLM 友好的解析式 Schema
【免费下载链接】a2ui项目地址: https://gitcode.com/GitHub_Trending/a2/a2ui
A2UI(Agent to UI)v0.8 协议的核心资产是一组形式化的 JSON Schema 文件,它们共同定义了"服务端如何向客户端推送 UI"与"客户端如何向服务端回传事件"的完整契约。本指南以 specification/v0_8/json/README.md 为骨架,逐一拆解这六类 Schema 的字段语义、设计动机与解析方式,并结合仓库中的渲染器源码与示例消息,帮助你掌握如何基于这些 Schema 构建 Agent UI、自定义组件目录,或开发全新的渲染器实现。
一、Schema 家族总览
specification/v0_8/json/目录存放的是 A2UI v0.8 协议的正式 JSON Schema 定义,整个目录结构如下:
specification/v0_8/json/ ├── README.md # 本文关联文档 ├── server_to_client.json # 服务端→客户端消息(抽象、与目录无关) ├── client_to_server.json # 客户端→服务端事件 ├── catalog_description_schema.json # 组件目录的元模式(meta-schema) ├── standard_catalog_definition.json # 标准组件目录(具体实现) ├── server_to_client_with_standard_catalog.json# 解析后的 LLM 友好版本 ├── a2ui_client_capabilities_schema.json # 客户端能力声明 └── catalogs/ ├── basic/ # 标准目录的示例消息(31 个场景) │ ├── examples/*.json │ └── ... └── minimal/ # 最小目录(渲染器测试床) ├── minimal_catalog.json ├── README.md └── examples/*.json六个核心文件的定位可以先用一张表概括:
| Schema 文件 | 角色 | 关键作用 |
|---|---|---|
server_to_client.json | 抽象线协议 | 定义beginRendering、surfaceUpdate、dataModelUpdate、deleteSurface四种消息,component字段保持通配(additionalProperties: true) |
client_to_server.json | 事件协议 | 定义userAction与error两类客户端回传消息 |
catalog_description_schema.json | 元模式 | 定义组件目录的结构(catalogId+components+styles),允许创建任意自定义组件集 |
standard_catalog_definition.json | 具体目录 | 标准组件集的落地实现(Text、Image、Row、Card 等) |
server_to_client_with_standard_catalog.json | 解析模式 | 将标准目录替换进server_to_client.json,把通配的component变为严格的oneOf/属性枚举,供 LLM 直接生成合法消息 |
a2ui_client_capabilities_schema.json | 能力协商 | 客户端声明支持的目录集合,供服务端选择catalogId |
二、server_to_client.json:四种服务端消息的线协议
server_to_client.json是整组 Schema 中"目录无关(catalog-agnostic)"的核心。它位于 specification/v0_8/json/server_to_client.json,顶层约束additionalProperties: false,即一条消息必须且只能包含beginRendering、surfaceUpdate、dataModelUpdate、deleteSurface四个动作属性之一。
这四种消息承载了 A2UI 的核心理念:UI 结构(组件树)与应用数据(数据模型)严格分离。组件结构通过surfaceUpdate一次性下发,之后的数据刷新只需发送轻量的dataModelUpdate,无需重传整棵 UI 树。渲染器源码印证了这一点——renderers/web_core/src/v0_8/schema/server-to-client.ts 使用 Zod 对同一结构做了逐字段等价建模,并额外实现了"组件 ID 去重""引用完整性校验"等 Schema 本身无法表达的约束。
2.1 beginRendering:首帧渲染信号
beginRendering通知客户端"可以开始渲染某个 surface",防止出现"内容不完整闪烁"(flash of incomplete content)。客户端会先缓冲surfaceUpdate与dataModelUpdate消息,直到收到该信号后才执行首次渲染。
{ "beginRendering": { "surfaceId": "unique-surface-1", "root": "root-component-id" } }字段说明:
surfaceId(必填,string):要渲染的 UI surface 唯一标识。root(必填,string):根组件 ID,客户端从该组件出发遍历组件树完成渲染。catalogId(可选,string):本次 surface 使用的组件目录标识;省略时客户端必须回退到本版本的默认标准目录。每个 surface 可以使用不同的目录,这在多 Agent 系统中尤其灵活——不同 Agent 可以支持不同的组件目录。styles(可选,object):UI 的样式信息。在通配版中additionalProperties: true,在解析版中则被约束为目录styles所定义的字段(如font、primaryColor)。
2.2 surfaceUpdate:组件树的主要载体
surfaceUpdate是定义 UI 结构的主要消息,包含surfaceId与components数组。每个数组元素是一个"组件实例",结构如下:
{ "surfaceUpdate": { "surfaceId": "main_content_area", "components": [ { "id": "unique-component-id", "component": { "Text": { "text": { "literalString": "Hello, A2UI" }, "usageHint": "h1" } } } ] } }组件实例的三个字段:
id(必填,string):组件唯一标识,被布局容器(Row/Column/List 等)通过字符串 ID 引用。weight(可选,number):组件在 Row/Column 内的相对权重,对应 CSS 的flex-grow;仅当组件是 Row/Column 的直接子节点时才能设置。component(必填,object):包装对象,必须且只能包含一个键,键名即组件类型名(如Heading、Text),键值为该组件的属性对象。
关键设计:整个组件列表是扁平的邻接表,而不是嵌套 JSON 树。各组件之间的父子关系通过字符串 ID 互相引用。这样设计的原因在 specification/v0_8/docs/a2ui_protocol.md 中有明确阐述:要求 LLM 一次性生成完美嵌套的 JSON 树既困难又易错,而"先想一个组件、给它一个 ID、之后再用 ID 引用它"的方式更符合生成式模型的思维方式。组件可以按任意顺序下发,只要在beginRendering之前所有被引用的组件都已到位即可。
2.3 dataModelUpdate:动态数据与状态管理
dataModelUpdate负责更新 surface 的数据模型,是"状态与结构分离"设计的具体实现:
{ "dataModelUpdate": { "surfaceId": "main_content_area", "path": "/user/name", "contents": [ { "key": "username", "valueString": "a2a_fan" }, { "key": "age", "valueNumber": 30 }, { "key": "active", "valueBoolean": true } ] } }字段说明:
surfaceId(必填,string):本次数据更新作用的 surface。path(可选,string):数据模型内的目标路径(如/user/name);省略或设为/时,整个数据模型将被整体替换。contents(必填,array):数据条目数组,每条必须包含key,并恰好提供一个带类型的value*属性。可用类型有valueString、valueNumber、valueBoolean,以及表示"邻接表形式映射"的valueMap(其内部条目同样遵循"一个 key 加恰好一个 value*"规则)。
Zod 实现中对"恰好一个 value* 属性"的校验非常直接(renderers/web_core/src/v0_8/schema/server-to-client.ts#L40-L52):依次统计valueString、valueNumber、valueBoolean、valueMap的出现次数,若总数不等于 1 则校验失败。
数据绑定(data binding)方面,协议只支持 1:1 的直接绑定,不包含格式化器、条件等转换器——任何数据变换都必须在服务端完成后再通过dataModelUpdate下发。
2.4 deleteSurface:销毁 surface
deleteSurface显式移除某个 surface 及其全部内容:
{ "deleteSurface": { "surfaceId": "surface-to-remove" } }仅一个必填字段surfaceId,用于标识要删除的 UI surface。
三、client_to_server.json:客户端事件回传
客户端向服务端回传事件使用独立的 client_to_server.json。它通过minProperties: 1、maxProperties: 1与oneOf: [{required: ["userAction"]}, {required: ["error"]}]双重约束,保证每条消息只能携带一个事件。保持数据流单向(SSE 单向推送 UI),事件通过独立的 A2A 消息回传,是协议"健壮且可扩展"设计原则的一部分。
3.1 userAction:用户交互事件
用户触发组件上的动作时上报,其字段全部来自组件定义中的action:
{ "userAction": { "name": "login_submitted", "surfaceId": "gallery-simple-login-form", "sourceComponentId": "submit_button", "timestamp": "2025-09-19T10:30:00Z", "context": { "user": "a2a_fan", "pass": "s3cret" } } }字段说明:
name(必填,string):动作名称,取自组件action.name属性。surfaceId(必填,string):事件来源 surface 的 ID。sourceComponentId(必填,string):触发事件的组件 ID。timestamp(必填,string,format: "date-time"):ISO 8601 格式的事件发生时间。context(必填,object):组件action.context中定义的数据绑定,解析全部绑定后的键值对。
注意context中携带的是"解析数据绑定之后"的值:组件定义里value可以写成{"path": "/username"},客户端解释器会在事件触发时把该路径解析为数据模型中的实际值再回传。
3.2 error:客户端错误上报
{ "error": { "message": "Failed to load font resource", "code": "FONT_LOAD_ERROR" } }error对象内容完全灵活(additionalProperties: true),用于向服务端报告客户端侧错误。
四、catalog_description_schema.json:自定义目录的元模式
A2UI 的可扩展性根植于目录机制:协议本身不固定组件集合,组件集由独立的Catalog定义。catalog_description_schema.json 是描述"一个目录长什么样"的元模式,仅要求三个字段:
catalogId(必填,string):目录唯一标识。文档建议用自己拥有的互联网域名做前缀以避免冲突,例如mycompany.com:somecatalog。components(必填,object):键为组件名、值为该组件属性的 JSON Schema(引用 draft 2020-12)。styles(必填,object):键为样式名、值为该样式属性的 JSON Schema。
这意味着任何团队都可以构建自己的组件集——签名面板、报表卡片、专用图表等——而协议本身无需改动。styles对象是beginRendering消息中styles字段的取值约束来源。
五、standard_catalog_definition.json:标准组件目录
standard_catalog_definition.json 是符合上述元模式的标准目录实现,定义了 A2UI v0.8 基线所包含的组件与样式,它是beginRendering省略catalogId时的默认回退目录。
5.1 标准组件清单
标准目录共 20 个组件,分为展示类、布局类、容器类与输入类:
| 类别 | 组件 | 核心属性 |
|---|---|---|
| 展示 | Text | text(字面量或数据路径)、usageHint(h1~h5/caption/body) |
| 展示 | Image | url、altText、fit(对应 CSSobject-fit)、usageHint(icon/avatar/smallFeature/mediumFeature/largeFeature/header) |
| 展示 | Icon | name(约 50 个枚举图标名,或数据路径) |
| 展示 | Video | url |
| 展示 | AudioPlayer | url、description |
| 布局 | Row | children(explicitList或template)、distribution(对应justify-content)、alignment(对应align-items) |
| 布局 | Column | 同Row,主轴方向为垂直 |
| 布局 | List | children、direction(vertical/horizontal)、alignment |
| 容器 | Card | child(容器内渲染的组件 ID) |
| 容器 | Tabs | tabItems(每个 tab 含title与child) |
| 容器 | Divider | axis(horizontal/vertical) |
| 容器 | Modal | entryPointChild(触发打开的组件)、contentChild(弹窗内组件) |
| 输入 | Button | child、primary、action(name+context键值数组) |
| 输入 | CheckBox | label、value(字面量布尔或数据路径) |
| 输入 | TextField | label、text、textFieldType(date/longText/number/shortText/obscured)、validationRegexp |
| 输入 | DateTimeInput | value(ISO 8601)、enableDate、enableTime |
| 输入 | MultipleChoice | selections、options、maxAllowedSelections、variant(checkbox/chips)、filterable |
| 输入 | Slider | label、value、minValue、maxValue |
要点:
- 动态列表:
Row/Column/List的children支持两种形态——explicitList(显式固定子组件 ID 数组)与template(由数据模型中的列表动态生成,template.componentId指定模板组件,template.dataBinding指定数据路径)。 - 字面量 vs 数据绑定:几乎所有取值属性(文本、URL、图标名、标签等)都支持"字面量(
literalString/literalNumber/literalBoolean/literalArray)或数据路径(path,如/user/name)"二选一的结构。客户端解释器负责在渲染前解析这些路径。 - 样式:标准目录只定义两个样式——
font(string)与primaryColor(string,必须匹配^#[0-9a-fA-F]{6}$十六进制格式)。
5.2 标准目录示例:登录表单
仓库在 specification/v0_8/json/catalogs/basic/examples/ 提供了 31 个标准目录示例,涵盖简单文本、航班状态、邮箱撰写、音乐播放器、商品卡片、聊天消息、咖啡点单、运动详情、健身汇总等真实场景。以00_simple-login-form.json为例,它完整演示了"数据先行 → 结构后置 → 信号渲染"的典型消息序列:
[ { "dataModelUpdate": { "surfaceId": "gallery-simple-login-form", "path": "/", "contents": [ { "key": "username", "valueString": "" }, { "key": "password", "valueString": "" } ] } }, { "surfaceUpdate": { "surfaceId": "gallery-simple-login-form", "components": [ { "id": "root", "component": { "Column": { "children": { "explicitList": ["form_title", "username_field", "password_field", "submit_button"] }, "distribution": "start", "alignment": "stretch" } } }, { "id": "submit_button", "component": { "Button": { "child": "submit_label", "primary": true, "action": { "name": "login_submitted", "context": [ { "key": "user", "value": { "path": "/username" } }, { "key": "pass", "value": { "path": "/password" } } ] } } } } ] } }, { "beginRendering": { "surfaceId": "gallery-simple-login-form", "root": "root" } } ]这段示例展示了三个关键手法:
- 先发
dataModelUpdate初始化空表单数据; surfaceUpdate用扁平列表描述整棵组件树(Column 根节点通过explicitList引用子组件 ID),TextField 的text与 Button 的action.context都通过path绑定数据模型;- 最后发
beginRendering指定根组件root,客户端才开始渲染。
六、server_to_client_with_standard_catalog.json:LLM 友好的解析模式
通配版server_to_client.json中,surfaceUpdate.components[].component是开放的(additionalProperties: true),虽然协议灵活,但对 LLM 来说"可以放任何东西"意味着"不知道该放什么"。
server_to_client_with_standard_catalog.json正是为解决这个问题而生的解析后(resolved)版本:它把standard_catalog_definition.json的组件定义替换进server_to_client.json,将通配的component对象变成严格的属性枚举(Text、Image、Row、Card……每个键的值都是对应组件的严格属性 Schema),同时把beginRendering.styles替换为目录中的styles定义(font与primaryColor)。这样 LLM 拿到的是一份"完整、严格类型、零歧义"的 Schema,可以直接用于生成合法 A2UI 消息。
6.1 自己生成解析模式
文档 specification/v0_8/docs/a2ui_protocol.md#L269-L285 给出了基于任意自定义目录生成解析模式的 Python 逻辑,核心只有三步替换:
import copy component_properties = custom_catalog_definition["components"] style_properties = custom_catalog_definition["styles"] resolved_schema = copy.deepcopy(server_to_client_schema) resolved_schema["properties"]["surfaceUpdate"]["properties"]["components"]["items"]["properties"]["component"]["properties"] = component_properties resolved_schema["properties"]["beginRendering"]["properties"]["styles"]["properties"] = style_properties换句话说,server_to_client.json是抽象的线协议(wire protocol),server_to_client_with_standard_catalog.json是具体的生成工具(generation tool)。构建 Agent 时,官方建议使用面向目标目录的解析模式,以显著提升 UI 生成的可靠性。
6.2 渲染器侧的 Schema 消费
在渲染器实现侧,解析模式同样被直接使用。例如 renderers/web_core/src/v0_8/index.ts#L25-L32 既导出了基于 Zod 手写的A2uiMessageSchema,也直接以 JSON 模块方式引入解析模式文件并对外暴露为Schemas.A2UIClientEventMessage。而verify-schema.test.ts(renderers/web_core/src/v0_8/schema/verify-schema.test.ts)则验证手写 Zod 模式与官方 JSON Schema 的一致性——这说明 JSON Schema 文件不仅是文档,还是各语言渲染器实现正确性的对照基准。
七、minimal_catalog.json:渲染器开发的测试床
标准目录功能全面,但对于从零实现一个渲染器而言负担过重。catalogs/minimal/minimal_catalog.json 将组件面收敛到五个基础组件:
- Text:渲染文本字符串;
- Row:水平 flex 布局;
- Column:垂直 flex 布局;
- Button:基础交互与动作派发;
- TextField:用户输入。
它的catalogId为https://a2ui.org/specification/v0_8/catalogs/minimal/minimal_catalog.json。根据 catalogs/minimal/README.md 的说明,最小目录是标准目录的严格子集(strict subset):任何对该最小目录合法(valid)的 A2UI 消息,对标准目录同样合法。这意味着开发者可以用最小目录的示例(catalogs/minimal/examples/下的 5 个场景)去测试那些硬编码使用标准目录的既有 v0.8 渲染器,也可以先围绕布局算法、组件嵌套、数据绑定、事件处理四个核心能力打好地基,再扩展到完整标准目录。
八、配套:a2ui_client_capabilities_schema.json 与能力协商
能力协商机制使"平台无关"成为可能:协议定义的是抽象组件树("我需要一个 Card 里面放一个 Row"),由客户端负责把这些抽象类型映射到原生控件。为此,客户端需要告诉服务端"我支持哪些目录"。a2ui_client_capabilities_schema.json 定义了a2uiClientCapabilities对象:
supportedCatalogIds(必填,string[]):客户端支持的每个目录的 URI,v0.8 标准目录为https://a2ui.org/specification/v0_8/standard_catalog_definition.json。inlineCatalogs(可选,array):内联目录定义数组,元素引用catalog_description_schema.json;仅当服务端在能力声明中标记了acceptsInlineCatalogs: true时才应提供。
服务端收到客户端能力后,在beginRendering.catalogId中指定所选目录(必须是supportedCatalogIds之一,或某个inlineCatalogs的catalogId)。省略则客户端回退到标准目录。
九、实践要点与使用建议
围绕这组 Schema 的典型开发场景与要点总结如下:
- Agent 生成 UI:优先使用解析模式(如
server_to_client_with_standard_catalog.json,或按 6.1 节逻辑基于自有目录生成的解析模式)作为 LLM 的工具/约束输入,而不是通配版线协议。 - 消息序列习惯:按"
dataModelUpdate(数据)→surfaceUpdate(结构)→beginRendering(渲染信号)"的顺序发送;后续状态变化只需小体积的dataModelUpdate,避免重传整个组件树。 - 组件 ID 纪律:
id在整个 surface 内必须唯一;Row/Column/List引用不存在的组件 ID 会导致渲染失败。Zod 实现(server-to-client.ts)的superRefine会对重复 ID 与悬空引用给出显式错误。 - 数据绑定约定:只支持 1:1 直接绑定,无转换器;格式化、条件等逻辑必须在服务端完成。
- 自定义目录:以
catalog_description_schema.json为元模式定义组件与样式 Schema,用域名前缀的catalogId避免冲突,并通过inlineCatalogs或客户端能力声明提供给服务端。 - 渲染器开发入门:先以
minimal_catalog.json为靶子跑通五个基础组件与catalogs/minimal/examples/示例,再逐步逼近标准目录,同时可复用 web_core 的 Schema 一致性测试思路验证自己的实现。
这组 JSON Schema 既是协议的事实规范,也是所有语言 SDK 与渲染器实现的"单一事实来源";深入理解它们的层次关系(抽象线协议 / 具体目录 / 解析模式),是使用 A2UI 或为其贡献实现的关键起点。
【免费下载链接】a2ui项目地址: https://gitcode.com/GitHub_Trending/a2/a2ui
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考