生成式 UI 是新的前端

生成式 UI 是新的前端

生成式 UI 是新的前端 生成式 UI 是新的前端 Modified June 5 Code block Plain Text "a2ui operations": [ {"type": "create surface", "surfaceId": SURFACE ID, "catalogId": CATALOG ID}, {"type": "update components", "surfaceId": SURFACE ID, "components": FLIGHT SCHEMA}, {"type": "update data model", "surfaceId": SURFACE ID, "data": {"flights": flights}}, ] } 这是真实函数,不是伪代码。runtime middleware 会识别工具结果里的 a2ui operations 容器,并把 surface 转发给前端。要加酒店?新增一个 schema 文件,再写一个带不同 surface ID 的函数。前端零额外工作。 固定 schema 与动态 schema 上面的组件树存在 flights.json 里,是你写好的。agent 只负责填数据。这就是固定 schema。 动态 schema 则反过来:每一轮由一个辅助 LLM 根据对话上下文编写组件树。最后仍然返回同一个 a2ui operations 容器。Google ADK showcase 同时提供了这两种方式。 catalog 是契约 定义里列出 agent 允许输出的组件,并用 Zod schema 描述属性。renderer 负责补上 React。拼写错误会变成构建错误,而不是空白屏幕。 Code block TypeScript const renderers: CatalogRenderers<TravelDefinitions = { FlightCard: ({ props }) = ( <article className="rounded xl border p 4" <header className="flex justify between" <span {(props as any).airline}</span <span {(props as any).price}</span </header <div className="text sm text muted foreground" {(props as any).origin} → {(props as any).destination} · {(props as any).departureTime} </div </article ), }; export const travelCatalog = createCatalog(travelDefinitions, renderers, { catalogId: "copilotkit://travel catalog", includeBasicCatalog: true, }); 两部分都在 Generative UI Starter Project 里,已经接好并互相匹配。a2ui fixed schema.py 里有 search flights,renderers.tsx 里有 FlightCard catalog。问航班,卡片就会流式进入聊天窗口。 按钮和其他交互组件会在 schema 里携带 action。basic catalog 会把它接到 onClick。点击之后,事件通过 AG UI 发回 agent。agent 决定下一步渲染什么。不需要写 click handler。 token 账 不管是 50 种卡片还是 500 种,agent 看到的都是一个函数。组件库增长时,每一轮的 token 仍然保持平稳。 因为本质上只是 JSON,所以它可以扩展到任何渲染框架。任何已经会说 AG UI 的 agent,从第一天就可以驱动 A2UI。不需要改 agent 代码来接这套东西。 取舍: LLM 掌控布局。在你的 catalog 范围内,输出会随运行而变化。如果你要发布法律披露、营销页面,或者任何需要精确像素位置的界面,这不是该用的模式。 声明式模式适合长尾场景:dashboard、结果页、表单、卡片、widget。 适合发布声明式的场景: 用例数量超过你能逐个预构建的时间。你在 prototype 阶段之后开始关心 token 经济性。 会出问题的地方: 你构建了自定义 FlightCard,但所有航班都渲染成 basic catalog 的通用卡片。控制台没有报错。原因是 agent 上的 CATALOG ID 和前端 createCatalog 里的 catalogId 不匹配。前端无法识别 agent 指向的 catalog,就会回退到 basic。两边的字符串必须完全一致。 模式 3:开放式,没有 catalog,也没有规则 第三种模式位于另一个极端。没有 catalog,没有 schema,只有一块空白画布。 这个类型里有两种子模式。 MCP Apps MCP server 暴露 UI surface,agent 负责驱动它。让我印象最深的例子是 Excalidraw。agent 拥有画布的完整控制权,可以基于你的上下文绘制图表,并掌控画板上的每一个像素。 从零实现客户端协议会很痛苦,所以 CopilotKit 提供了 MCPAppsMiddleware。把它挂到你的 agent 上,然后指向任意 MCP Apps server。 Code block TypeScript const agent = new BuiltInAgent({ model: "openai/gpt 5.5", prompt: "You are a helpful assistant.", }).use( new MCPAppsMiddleware({ mcpServers: [{ type: "http", url: "https://mcp.excalidraw.com/mcp", serverId: "my server" }], }), ); 启动 MCP Apps Showcase 后,你可以在聊天窗口里订航班、订酒店。同一套 middleware,真实 MCP server。或者再进一步。 AI MCP App Builder 可以让 agent 在 E2B sandbox 里写出一个全新的 app,然后实时渲染出来。 沙盒 HTML agent 编写原始 HTML。你的应用把它渲染到沙盒 iframe 里,这样它不能劫持当前 session。 runtime 会注册一个 HTML 渲染工具,并通过 AG UI 发送给 agent。agent 可以用任何想要的 markup 调用它。agent 侧不需要定义 HTML 工具,runtime 会注入进去。 agent 侧 instruction 在这里真的很关键: Code block Python canvas agent = LlmAgent( name="canvas agent", model="gemini 3.5 flash", instruction=( "You are a visualization assistant. When the user asks to see, " "draw, or visualize anything, generate an interactive HTML UI. " "Use Tailwind classes only. No external fonts. Stick to neutral " "colors unless the user names one." ), ) 如果没有这些风格规则,模型会默认采用它训练数据里当周最“响亮”的审美。有这些规则后,大多数时候它会接近你的品牌风格,但不是每一次都能做到。 品牌一致性问题 我试过把开放式模式作为某个 agent 的主界面发布。一周后就撤掉了。 周二是“Neo brutalist”,周三变成 “iOS 4 clone”。prompt 里的风格规则能把 agent 推向你的品牌方向,但不能保证结果。品牌一直在变,产品显得不严肃。 开放式不是没用,而是经常被用错。 它适合一类事情:一次性互动。用户不关心界面长什么样,而且以后也不会再看到它。“给我展示电子是怎么工作的。”“把我最近 10 次查询画成一个怪一点的柱状图。”“把这个 API 响应可视化。”类似 Google AI Overviews 里会出现的那类东西。 适合发布开放式的场景: 一次性查询、用后即弃的可视化、沙盒实验。不要把它当成主界面。 会出问题的地方: iframe 渲染了,但按钮点不了,表单也提交不了。sandbox flags 可能太严格,也可能宽到浏览器拒绝执行。把 iframe sandbox 设为允许 scripts 和 forms,别的都不要开。永远不要允许 allow same origin。 如何选择 写代码之前,先跑一遍这个决策树。 设计师已经为这个流程给出像素级 mockup?用受控式。 要发布几十种卡片类型或 widget?用声明式。 用户只会看一次、用完就丢的一次性可视化?用开放式。 拿不准?默认选声明式。对最重要的前三个流程升级成受控式。永远不要把开放式当默认方案。 如果你已经在发布产品,但不确定自己落在哪种模式里,数一数 render tools。超过 15 个,就说明你在受控式里,而且墙已经很近了。这周就开始接 A2UI。 三种模式,三种取舍 受控式押注在你身上。预构建组件,像素级精确。超过 25 个后成本很高。 声明式押注在 schema 上。schema 是契约,agent 负责填充。扩展成本保持平稳。 开放式押注在模型上。没有 catalog,没有 schema,原始 HTML。适合用完即弃的场景,但面对会反复发布的功能很脆。 真正的问题不是选错模式,而是不知道自己已经选了一种。 多数团队默认走向受控式,因为框架默认就是受控式。到了 25 个组件时撞墙,然后因为开放式在 demo 里看起来很惊艳,就转向开放式。这两者都不是明确决策,而是顺着惯性漂过去的。 要有意识地选择。让模式匹配问题。需要精确的流程用受控式,长尾场景用声明式,用完即弃的内容用开放式。 开源生成式 UI Agent 模板 三种模式的参考实现都在 awesome llm apps 新增的 Generative UI Agents 部分。按需 clone,需要什么就留下什么,不需要的就删掉。 我还会继续发布更多关于生产环境 agent、AG UI 以及可扩展模式的内容。关注 @Saboo Shubham 获取后续更新。 Generative UI Starter Project MCP Apps Showcase AI MCP App Builder Generative UI Agents @Saboo Shubham 这是真实函数,不是伪代码。runtime middleware 会识别工具结果里的 a2ui operations 容器,并把 surface 转发给前端。要加酒店?新增一个 schema 文件,再写一个带不同 surface ID 的函数。前端零额外工作。 固定 schema 与动态 schema 上面的组件树存在 flights.json 里,是你写好的。agent 只负责填数据。这就是固定 schema。 动态 schema 则反过来:每一轮由一个辅助 LLM 根据对话上下文编写组件树。最后仍然返回同一个 a2ui operations 容器。Google ADK showcase 同时提供了这两种方式。 catalog 是契约 定义里列出 agent 允许输出的组件,并用 Zod schema 描述属性。renderer 负责补上 React。拼写错误会变成构建错误,而不是空白屏幕。 两部分都在 Generative UI Starter Project 里,已经接好并互相匹配。a2ui fixed schema.py 里有 search flights,renderers.tsx 里有 FlightCard catalog。问航班,卡片就会流式进入聊天窗口。 Generative UI Starter Project 按钮和其他交互组件会在 schema 里携带 action。basic catalog 会把它接到 onClick。点击之后,事件通过 AG UI 发回 agent。agent 决定下一步渲染什么。不需要写 click handler。 token 账 不管是 50 种卡片还是 500 种,agent 看到的都是一个函数。组件库增长时,每一轮的 token 仍然保持平稳。 因为本质上只是 JSON,所以它可以扩展到任何渲染框架。任何已经会说 AG UI 的 agent,从第一天就可以驱动 A2UI。不需要改 agent 代码来接这套东西。 取舍: LLM 掌控布局。在你的 catalog 范围内,输出会随运行而变化。如果你要发布法律披露、营销页面,或者任何需要精确像素位置的界面,这不是该用的模式。 声明式模式适合长尾场景:dashboard、结果页、表单、卡片、widget。 适合发布声明式的场景: 用例数量超过你能逐个预构建的时间。你在 prototype 阶段之后开始关心 token 经济性。 会出问题的地方: 你构建了自定义 FlightCard,但所有航班都渲染成 basic catalog 的通用卡片。控制台没有报错。原因是 agent 上的 CATALOG ID 和前端 createCatalog 里的 catalogId 不匹配。前端无法识别 agent 指向的 catalog,就会回退到 basic。两边的字符串必须完全一致。 模式 3:开放式,没有 catalog,也没有规则 第三种模式位于另一个极端。没有 catalog,没有 schema,只有一块空白画布。 这个类型里有两种子模式。 MCP Apps MCP server 暴露 UI surface,agent 负责驱动它。让我印象最深的例子是 Excalidraw。agent 拥有画布的完整控制权,可以基于你的上下文绘制图表,并掌控画板上的每一个像素。 从零实现客户端协议会很痛苦,所以 CopilotKit 提供了 MCPAppsMiddleware。把它挂到你的 agent 上,然后指向任意 MCP Apps server。 启动 MCP Apps Showcase 后,你可以在聊天窗口里订航班、订酒店。同一套 middleware,真实 MCP server。或者再进一步。 MCP Apps Showcase AI MCP App Builder 可以让 agent 在 E2B sandbox 里写出一个全新的 app,然后实时渲染出来。 AI MCP App Builder 沙盒 HTML agent 编写原始 HTML。你的应用把它渲染到沙盒 iframe 里,这样它不能劫持当前 session。 runtime 会注册一个 HTML 渲染工具,并通过 AG UI 发送给 agent。agent 可以用任何想要的 markup 调用它。agent 侧不需要定义 HTML 工具,runtime 会注入进去。 agent 侧 instruction 在这里真的很关键: 如果没有这些风格规则,模型会默认采用它训练数据里当周最“响亮”的审美。有这些规则后,大多数时候它会接近你的品牌风格,但不是每一次都能做到。 品牌一致性问题 我试过把开放式模式作为某个 agent 的主界面发布。一周后就撤掉了。 周二是“Neo brutalist”,周三变成 “iOS 4 clone”。prompt 里的风格规则能把 agent 推向你的品牌方向,但不能保证结果。品牌一直在变,产品显得不严肃。 开放式不是没用,而是经常被用错。 它适合一类事情:一次性互动。用户不关心界面长什么样,而且以后也不会再看到它。“给我展示电子是怎么工作的。”“把我最近 10 次查询画成一个怪一点的柱状图。”“把这个 API 响应可视化。”类似 Google AI Overviews 里会出现的那类东西。 适合发布开放式的场景: 一次性查询、用后即弃的可视化、沙盒实验。不要把它当成主界面。 会出问题的地方: iframe 渲染了,但按钮点不了,表单也提交不了。sandbox flags 可能太严格,也可能宽到浏览器拒绝执行。把 iframe sandbox 设为允许 scripts 和 forms,别的都不要开。永远不要允许 allow same origin。 如何选择 写代码之前,先跑一遍这个决策树。 设计师已经为这个流程给出像素级 mockup?用受控式。 要发布几十种卡片类型或 widget?用声明式。 用户只会看一次、用完就丢的一次性可视化?用开放式。 拿不准?默认选声明式。对最重要的前三个流程升级成受控式。永远不要把开放式当默认方案。 如果你已经在发布产品,但不确定自己落在哪种模式里,数一数 render tools。超过 15 个,就说明你在受控式里,而且墙已经很近了。这周就开始接 A2UI。 三种模式,三种取舍 受控式押注在你身上。预构建组件,像素级精确。超过 25 个后成本很高。 声明式押注在 schema 上。schema 是契约,agent 负责填充。扩展成本保持平稳。 开放式押注在模型上。没有 catalog,没有 schema,原始 HTML。适合用完即弃的场景,但面对会反复发布的功能很脆。 真正的问题不是选错模式,而是不知道自己已经选了一种。 多数团队默认走向受控式,因为框架默认就是受控式。到了 25 个组件时撞墙,然后因为开放式在 demo 里看起来很惊艳,就转向开放式。这两者都不是明确决策,而是顺着惯性漂过去的。 要有意识地选择。让模式匹配问题。需要精确的流程用受控式,长尾场景用声明式,用完即弃的内容用开放式。 开源生成式 UI Agent 模板 三种模式的参考实现都在 awesome llm apps 新增的 Generative UI Agents 部分。按需 clone,需要什么就留下什么,不需要的就删掉。 Generative UI Agents 我还会继续发布更多关于生产环境 agent、AG UI 以及可扩展模式的内容。关注 @Saboo Shubham 获取后续更新。 @Saboo Shubham 原帖链接:https://x.com/Saboo Shubham /status/2062220865643982875 原帖链接:https://x.com/Saboo Shubham /status/2062220865643982875 过去,前端是一套固定的东西。设计师画出来,工程师做出来,用户看到的就是最终发布的版本。 这套方式已经结束了。 2026 年正在上线的界面,有一部分是由 agent 根据用户真实提出的需求,在运行时实时绘制出来的。用户要一张表,就给他一张表,而不是给一段“表格说明”。 生成式 UI 这一层,让 agent 不再只是描述,而是开始展示。围绕它已经出现了三种构建模式,而它们之间的差异,比大多数团队意识到的都更重要。 但这件事并不是只有一种做法。它有三种。多数团队其实已经选了一种,只是自己还没意识到。 协议栈 三个协议,各自负责一件事。 MCP 连接 agent 和工具。A2A 连接 agent 与 agent。AG UI 连接 agent 和用户。 AG UI 是流式传输层,承载你下面会看到的一切:工具调用、A2UI schema、MCP App 事件、状态增量。它运行在 SSE 之上。状态在同一条流上双向流动。用户修改,agent 看见;agent 修改,用户看见。 A2UI 是 Google 提出的规范,用于让 agent 以 schema 的形式产出 UI。它跑在 AG UI 之上。CopilotKit 已经把它用于生产环境。 你不需要为这些东西手写解析器。CopilotKit 本身就是 AG UI 客户端,会替你解码这条流。 大多数团队容易混淆的三种模式 问十个开发者什么是生成式 UI,你会得到十个答案。大多数人描述的,其实只是他们当前框架自带的那一种模式。 实际只有三种。这个光谱从“控制力更强”延伸到“灵活性更高”。 • 受控式: 你预先构建组件,agent 选择要渲染哪一个。 • 声明式: agent 输出 schema,你的应用把它映射成组件。 • 开放式: agent 编写原始 HTML,你的应用在沙盒中渲染它。 2026 年的每一个 Gen UI 框架,都位于这条线上某个位置。差异是架构层面的,不是视觉层面的。规模上来以后,每一种模式都会以不同方式让你的应用出问题。 我试过不同的技术栈。大多数栈只能很好覆盖其中一种模式。最后我选了 CopilotKit,因为它能在同一套 runtime 上支持三种模式,并且跑在 AG UI 之上。下面所有内容都基于这套栈。 模式 1:受控式,前端掌控 UI 这是大多数团队的起点,也是大多数团队卡住的地方。 你预先构建一个 React 组件,把它绑定到一个工具名。agent 选择这个工具后,组件就会以内联形式渲染到聊天里,agent 传入的 参数会作为 props 传给组件。 一个前端 hook。零 agent 代码。就是这样。 这个 hook 会把工具注册到 CopilotKit runtime。runtime 通过 AG UI 把它暴露给 agent。当 agent 调用它时,参数会流式传入,你的组件会以内联方式渲染出来。不用写 Python 工具,不用接 schema,不用加 API route。 你的设计系统仍然掌握主导权。 那张支出图不是样本。AI Financial Coach Agent 会把类似卡片真正渲染到预算、储蓄计划和债务还款方案里。 AI Financial Coach Agent 想先看最小版 hook?它在 Generative UI Starter Project 里的 use generative ui examples.tsx。 Generative UI Starter Project token 成本 你注册的每个组件,都会在用户开口之前就进入 agent 的上下文窗口。一个典型工具描述加上 JSON schema,大约会占 400 个 token。25 个组件就是每一轮 10,000 个 token。每次请求都要付这笔成本。 agent 还会选错组件。相似组件太多时尤其如此。饼图和环形图都可以“展示占比”,于是它开始猜。 什么时候要加入 agent 侧状态 共享状态是少数值得写 Python 工具的场景。agent 写入 session state,UI 的其他部分订阅并重新渲染,不需要第二次 LLM 调用。固定一个指标,dashboard 更新;添加一行,表格重绘。 前端通过 CopilotKit 的 shared state hook 读取固定的指标。聊天组件仍然以内联方式渲染,因为同一个工具名也通过前端 hook 接好了。 在聊天里固定一个指标,面板会在没有第二次模型调用的情况下重绘。这就是 AI Dashboard Canvas Agent。 AI Deep Research Agent更进一步。计划、每一次搜索、每一次文件写入,全部以实时卡片的形式流式展示。除此之外,前端 hook 就已经是完整方案。 适合发布受控式的场景:十个以内的高价值流程。设计精度很重要。你清楚知道自己需要哪些 UI。 不适合的场景:你的代码库会随着用例线性增长。25 个组件意味着每一轮 agent 调用里,都放着 25 个工具定义。 会出问题的地方:agent 选错组件。两个工具描述在语义上重叠。超过 15 个工具后,其中两个很可能都像是在“展示数据”。修法:重写描述,写用户意图,而不是写视觉形式。“当用户要求比较整体中的占比时使用”,比“渲染饼图”更好。 AI Dashboard Canvas Agent AI Deep Research Agent 模式 2:声明式(A2UI),agent 输出 schema 这是多数生产级 agent 应用最终会需要的模式。 agent 输出一个描述 UI 的 JSON schema。你的应用有一份组件目录,把 schema 节点映射到 React,也可以映射到 Svelte、Flutter 或任何其他框架。一个工具,多种 UI。 A2UI 是标准规范。CopilotKit 提供 runtime。ADK 运行 agent。AG UI 负责传输。 agent 工具按顺序返回三个操作:创建 surface、推送组件树、推送数据。

在 小宇宙note 阅读完整内容