当前背景效果:Frost
返回文章列表

FIELD NOTE

Generative UI 到底交付了什么:Tool Call、JSON Spec 与完整 UI

沿着 Agent 交给宿主的运行时产物,梳理 Generative UI 的三条实现路线,以及 AG-UI、A2UI、json-render、MCP Apps 各自处理的问题。

阅读约 19 分钟
Agent 节点出发,蓝、青、橙三条连线穿过虚线边界,依次接入宿主应用中的工具参数胶囊、组件树和完整仪表盘。

「让 Agent 生成一个界面」至少可以指三件事:从前端已有的组件中挑一张卡片、临时组合一份可渲染的表单描述,或者交付一块带有自身布局和交互的完整面板。它们都被称为 Generative UI,实现方式和风险却不在同一层。

实现路线、界面出现的位置、通信协议、UI 规范和渲染框架也经常被放进同一张对比表。本文先把这些概念归位,再沿着一个具体问题展开:Agent 究竟把什么交给了宿主应用,宿主又保留了哪些决定。

目录

  1. 什么是 Generative UI
  2. 三种实现路线
  3. 代表项目分别解决什么问题
  4. 把这些项目放回一条完整链路
  5. 三条路线怎么比较
  6. 还没有解决的研究问题
  7. 系列路线图

什么是 Generative UI

CopilotKit 的概览将 Generative UI 定义为由 AI Agent 部分或完整产生的用户界面。这个定义覆盖面很大。落到实现里,比较有用的判断方式是看两件事:哪些 UI 决策从开发阶段移到了运行时,以及这些决策以什么形式穿过 Agent 与宿主之间的边界。

Agent 交付的产物宿主应用接手的工作预先划定的边界常见实现
工具名与参数选择并渲染预制组件组件、参数 Schema、状态映射Tool Rendering
组件结构、绑定与动作校验 Spec,映射为本地组件Schema、Catalog、RendererA2UI、json-render
完整 UI surface隔离、挂载并开放有限的宿主能力容器、权限、消息与网络边界MCP Apps、pi-generative-ui

这三行只描述控制权边界。一个产品可以混用三条路线:常见操作走预制组件,临时表单交给声明式 Spec,专业工具再用完整 surface。

三栏极简对比图从左到右依次为受控式(Tool Call→Component)、声明式(JSON Spec→Renderer)和开放式(Full UI→Sandbox);底部单一连续轴从左侧“更多宿主控制”过渡到右侧“更多 Agent 自由度”。

两条容易混淆的分类轴

第一条轴是 generation approach:Agent 交付什么。受控式交出工具名和参数,声明式交出组件结构,开放式交出完整 UI surface。第二条轴是 application surface:界面出现在哪里。

界面出现在哪里(application surface),与 Agent 交付什么(generation approach),是两条独立的分类轴。把它们混在一起会得出「Chatless 比聊天卡片更开放」一类并不成立的推论。

Chat 把卡片、表单或工具结果插入消息流,界面通常跟随某一轮对话出现。Chat+ 在对话旁保留一块持续演化的画布。文档、代码、图表或设计稿要跨多轮保留状态,还会涉及局部更新、撤销、版本和选区。Chatless 将 Agent 生成的模块放回产品原有工作流,例如仪表盘分析、表格筛选器或异常处理建议,界面里可以完全没有聊天框。

三种 surface 都能使用预制组件、声明式 Spec 或完整 UI,界面位置不会替系统决定生成边界。

三种实现路线

受控式、声明式、开放式的分类来自 CopilotKit 的表达自由度划分。沿着本文的主线看,三条路线的变化很具体:Agent 依次交出工具参数、组件结构和完整 surface,宿主预先掌握的 UI 细节随之减少。

受控式:Agent 选择,前端渲染

受控式(Controlled)把组件树留在前端代码里。开发者预先实现天气卡片、数据摘要或参数表单,再将它们注册成工具。Agent 只返回工具名和参数,前端负责匹配组件并处理加载、成功和失败状态。

这条边界可以通过 Schema 校验参数,组件可以单独复现,布局、交互和无障碍细节不受模型输出影响。限制来自同一个地方:Agent 只能使用已经注册的组件;每增加一种表达,开发者都要补上组件、工具定义和渲染逻辑,跨端客户端也要各自实现。

声明式:Agent 组合结构,客户端解释

当预制组件不够用、又希望客户端继续掌握执行边界时,交付物会扩大成一份 UI 描述。Agent 可以组合标题、日期选择器、选项列表和提交按钮;Schema 限制结构,可信组件目录限制可用能力,客户端再将抽象名称映射到本地组件。模型在这条路线里生成结构,不执行任意代码。

声明式 UI 的五个构件

声明式链路中,Agent 生成的具体 JSON 是 SpecSchema 校验组件引用、属性类型、数据绑定和动作格式,Catalog 列出当前可用的组件与动作。通过校验后,Registry 将抽象名称映射到平台组件,Renderer 才能遍历 Spec、解析绑定并构造真实界面。

声明式路线把新的压力集中到了 UI 语言本身。Catalog 太小,Agent 很快碰到表达上限;组件与嵌套规则铺得太开,模型又更容易生成无效结构。跨端 Renderer 还可能对同一份 Spec 作出不同解释。调试一张动态表单时需要同时看 Agent 输出、Schema 校验、状态更新和最终渲染,问题已经超出普通组件调试的范围。

开放式:交付完整的 UI surface

交付物继续扩大,就会越过宿主的组件目录。Agent 或远端工具返回一块完整界面,宿主应用提供容器和通信能力。界面可以是模型当场生成的 HTML,也可以是工具开发者提前构建、由 Agent 在合适时机调出的专业应用。

分类走到这里会碰到一个边界案例:从调用入口看,工具名、参数和触发方式都是预先定义的;从 UI 表达看,参数内部又是一块可以自由组织的开放式界面。路线归类取决于交付物的表达边界,Tool Call 只是交付通道。

完整 surface 能容纳复杂图表、画布、编辑器和第三方专业工具,也把更多执行能力带进宿主。安全性取决于隔离源、sandbox 权限、CSP、消息白名单、Host 能力授权、网络访问限制和审计。iframe 只是其中一层。移动端和桌面原生容器还要另行处理可移植性与体验一致性。

代表项目分别解决什么问题

下表概述各项目在 Generative UI 生态中的角色。

项目类型解决的问题主要输出
A2UI声明式 UI 规范Agent 生成的结构化 UI 如何在不同客户端间安全复用surfaceUpdatedataModelUpdatebeginRendering 等消息与抽象组件表示
json-render实现框架从 Spec 到原生组件的转换缺少标准构件Schema/Catalog/Registry/Renderer 运行时,React Schema,JSONL Patch 支持
AG-UI通信协议Agent 与前端之间的事件流没有统一消息格式Tool Call、状态快照与增量、运行生命周期事件
MCP Apps / MCP-UI标准化 surface 交付工具需要返回完整 UI 时如何安全隔离消息定义(初始化、输入/结果、尺寸、Host Context、销毁)、iframe 沙箱
pi-generative-ui实证性实现通过 Tool Call 交付开放式 HTML 如何流式渲染morphdom 增量更新、WebView 窗口、display-only Widget

A2UI

Google 的 A2UI 是声明式 UI 规范。截至 2026 年 7 月,A2UI 官方仓库将项目标记为 v0.8 Public Preview:格式和渲染器已经可用,但仍在向 v1.0 演进。它使用声明式 JSON 表达可增量更新的 UI,把抽象组件映射到 Web、Flutter 等客户端的本地实现,并通过可信组件目录限制 Agent 能调用的能力。仓库将这套思路概括为「像数据一样安全,像代码一样有表现力」。

CopilotKit 的生态说明还把 Open-JSON-UI 列为一条声明式路线,描述为对 OpenAI 内部声明式 UI Schema 的开放标准化。目前公开信息主要来自 CopilotKit,尚未看到像 A2UI 那样清晰、独立的官方规范入口。本文将它保留为待核实的生态名称,不把它当成与 A2UI 成熟度相同的标准。

json-render

json-render 把 Schema、Catalog、Registry、Renderer 等构件集中到一个实现框架中。它自带的 React Schema 使用 root + elements 表示一棵通过 ID 引用的扁平组件树,也支持 JSONL Patch 增量补全。@json-render/core 同时保持 Schema-agnostic,应用可以换用其他 Spec 结构。Schema 文档将 Schema 比作语法,将 Catalog 比作词汇。

A2UI 与 json-render 可以接在一起。A2UI 定义可交换的 UI 消息和组件表示;json-render 提供 Catalog、校验、Registry 与 Renderer 等实现构件。按照 A2UI 集成说明,开发者可以定义符合 A2UI 格式的 Catalog 和 Renderer,直接处理 surfaceUpdatedataModelUpdatebeginRendering 等消息,无需先转换成 json-render 的默认 Spec。文档将这段实现标为示意性集成,展示适配方法,并未提供封装完成的 A2UI Adapter。json-render 与 Open-JSON-UI 也没有公开的继承或改名关系,共同点只到「用 JSON 描述 UI」为止。

AG-UI

AG-UI 是 Agent 与前端的通信协议,负责双向事件流,覆盖消息、工具调用、状态快照与增量、运行生命周期等内容。它不是 UI Schema 或 Renderer。详见 AG-UI 文档架构说明CopilotKit 的对比说明也采用了这一区分。

MCP Apps 与 MCP-UI

MCP Apps 给开放式交付提供了标准化路径。它把工具与 UI 资源关联起来,让 Host 在 iframe 中显示交互界面,并定义初始化、工具输入与结果、尺寸变化、Host Context 和销毁等消息。MCP Apps 规范还为 Web Host 规定了不同源 sandbox、CSP 和消息转发边界。

早期材料常使用 MCP-UI 这个名字。截至 2026 年 7 月,MCP-UI 项目说明其客户端和服务端包实现 MCP Apps 标准,同时保留对旧版 MCP-UI Host 的兼容。本文用「MCP Apps」指标准,用「MCP-UI」指相关实现与兼容层。

pi-generative-ui 与逆向案例

pi-generative-ui 把一个边界案例实现成了可运行的 Pi Extension:通过预先定义的 show_widget 工具,把完整的 HTML、CSS 和 JavaScript 放进 Tool Call 参数,流式输出来交付开放式界面。其五步流程如下:

  1. Agent 调用 visualize_read_me,按需加载图表、交互、Mockup 等设计指南;
  2. 再调用 show_widget,把生成的 HTML 作为 Tool Call 参数流式输出;
  3. Extension 拦截 toolcall_start / toolcall_delta / toolcall_end
  4. Glimpse 提供 WebView 窗口,morphdom 负责把不断增长的 HTML 更新为稳定 DOM;
  5. 完整内容到达后再执行脚本,启用图表和界面内部交互。

这里的设计指南是一种 Prompt 层面的软约束,与 json-render 的 Schema 和 Catalog 不同:它能引导模型生成更一致的界面,却不能从结构上保证输出只使用某组组件。当前仓库还说明,Widget 对 Agent 主要是 display-only;界面内部可以响应滑块、Hover 和动画,Host RPC 则承担 SVG 保存等少量宿主能力。

Michael Livs 的逆向分析关于 Claude.ai 直接注入 DOM、具体沙箱方式等判断,来自作者对 Tool Call 数据和界面表现的推测,Anthropic 没有公布相应架构。这里引用它来观察设计空间,不将这些推测写成 Claude 的已证实实现。

把这些项目放回一条完整链路

A2UI 和 AG-UI 只差一个字母,放到一条请求链路里却相隔一层。CopilotKit 对两者的说明也采用了这个区分。

MCP 把工具和数据源接给 Agent,A2A 负责 Agent 之间的协作。Agent 决定返回声明式界面后,A2UI 描述组件、数据与增量更新;AG-UI 负责 Agent 与前端之间的双向事件流,覆盖消息、工具调用、状态快照与增量、运行生命周期等内容,详见 AG-UI 文档架构说明。到了客户端,json-render 或专用 Renderer 才把 Spec 解释成真实组件。

一条可能的组合链路如下:

工具 / 数据 -- MCP --> Agent <-- A2A --> 其他 Agent
                         |
                  AG-UI 或应用 API
                         |
                         v
             A2UI / 其他 JSON Spec
                         |
              json-render / 专用 Renderer
                         |
                         v
                    原生组件树

角色分层图中通信层展示 MCP(工具与 Agent 之间)、A2A(Agent 之间)、AG-UI(Agent 与宿主之间)三条连线;UI 交付层展示两条独立路径:A2UI Spec 经 json-render 到原生组件,以及 MCP Apps UI Resource 经沙箱到嵌入式界面。

图中的连接都可以替换。应用可以用自己的 API 传递 A2UI,json-render 也不绑定 AG-UI。json-render 的 AG-UI 集成页展示了 Tool Call、State 和 Custom Event 的接法,页面明确把示例标为 illustrative,实际项目仍需补全。

MCP Apps 走另一条分支:工具返回 UI Resource,Host 挂载隔离界面,不经过本地 JSON 组件 Renderer。json-render 则属于实现框架,不承担 Agent 通信协议的职责。

以上是本文使用的教学分层,各项目没有共同发布对应的标准栈。

三条路线怎么比较

比较维度受控式声明式开放式
Agent 交付物工具名与参数组件结构、绑定与动作(Spec)完整 UI surface
宿主责任选择并渲染预制组件校验 Spec,映射为本地组件隔离、挂载,开放有限宿主能力
表达自由度低(受限于已注册组件)中(可组合多种组件)高(任意界面)
可测试性容易(参数校验、独立组件)中等(需同时检查 Agent 输出、Schema 校验、状态和渲染)低(依赖隔离沙箱与安全性测试)
主要代价每增一种表达需添加组件、工具定义、跨端实现UI 语言设计(Catalog 范围与生成可靠性权衡)、跨端语义一致性安全隔离(sandbox、CSP、消息白名单)、跨端可移植性
适合的问题已知界面模式、频繁使用的小组件动态表单、临时布局复杂工具、画布、第三方专业界面

实际产品常混用三条路线,因为不同场景需要不同的控制权边界:常见操作走受控式(高效可靠),临时表单走声明式(灵活但可控),专业工具走开放式(完全自由)。界面的生成方式与界面出现的位置(Chat/Chat+/Chatless)是两条独立轴,组合使用不会冲突。

还没有解决的研究问题

现有项目已经能演示 Spec 如何生成、传输和渲染。对 Generative UI 的研究还要追问两段链路:第一帧出现之前,模型输出能否稳定成立;第一帧出现之后,这张界面是否真的完成了任务。

以「第一帧」为分界线的从左到右评估流程:前半段依次为有效 Spec、语义匹配、流式稳定性;后半段依次为动作成功、任务成功、可访问性、用户修正;设有虚线反馈回路从用户修正返回至有效 Spec。

第一帧之前

Schema 的表达能力与生成可靠性互相牵制。组件和组合规则越丰富,模型需要同时满足的约束越多;Catalog 收得太窄,Agent 又很快碰到表达上限。A2UI 与 json-render 都采用扁平、ID 引用的结构,其中包含对增量生成和局部更新的考虑。这种设计究竟能把有效生成率提高多少,仍需要测试。

通过 Schema 校验只说明 JSON 结构合法。信息层级、按钮文案和任务流程还可能出错,评估时要分别记录语法正确、语义正确和交互有效。

流式生成又增加了时间维度。文本少一个结尾通常仍可阅读,组件树缺少一个引用就可能无法渲染。JSONL Patch、Snapshot / Delta 和 A2UI 消息对顺序、原子性、回滚与恢复的定义,共同决定中间状态能否显示。

pi-generative-ui 给出了流式 HTML 的另一种压力。每个 Token 都替换完整文档会造成闪烁和滚动位置丢失;反复设置 innerHTML 会销毁已有节点;直接追加节点又会受到浏览器自动修复未闭合标签的影响。它最后用 morphdom 比较新旧 DOM,只更新变化节点。A2UI 和 json-render 可以围绕稳定 ID 表达局部更新,流式 HTML 则要把不完整字符序列持续恢复成 DOM。两条路线处理的输入不同,更新算法复杂度无法单独证明哪条路线更好。

第一帧之后

跨端 Renderer 首先要守住语义。同一个日期选择器在 Web、Flutter 和原生平台可以使用不同外观,但提交数据、触发动作和可访问性语义应当等价。

用户点击、输入和局部状态变化随后要回到 Agent 上下文。系统需要决定回传哪些状态,怎样引用产生事件的 surface 与组件,以及何时局部更新、何时重新生成。否则一张能点击的界面仍然接不上下一轮推理。

评估指标还没有形成稳定做法。JSON 有效率和渲染成功率只覆盖链路前半段;任务完成率、用户修正次数、布局稳定性、动作成功率、信息查找时间,以及键盘和辅助技术可用性,才会显示生成界面是否改善了交互。


目前的工程方案已经能回答「界面怎样送到 Host 并被渲染」。证据最薄的一段发生在渲染成功之后:如果实验只报告 JSON 通过率和首屏成功率,我们还无法判断这张界面是否比文本更快完成任务,或是否给用户制造了新的修正成本。

系列路线图

后续文章会沿着同一条交付链路拆解实现,并把生成正确性、流式一致性和交互评估单独展开。

  • 00|综述:Generative UI 到底交付了什么(本文)
  • 01|受控式 Generative UI:预制组件、工具调用与状态映射(待更新)
  • 02|声明式 Generative UI(一):A2UI 的 Schema、组件目录与流式更新(待更新)
  • 03|声明式 Generative UI(二):json-render 的 Catalog、Spec 与跨端 Renderer(待更新)
  • 04|开放式 Generative UI:MCP Apps、流式 HTML 与沙箱边界(待更新)
  • 05|AG-UI:消息、状态与用户交互怎样形成运行时闭环(待更新)
  • 06|研究专题:Schema 生成正确性、流式一致性与 Generative UI 评估(待更新)

DISCUSSION

评论

正在加载评论…