跳至正文
Agents — OpenUI:概念、使用方式与 Generative UI 方案比较

OpenUI:概念、使用方式与 Generative UI 方案比较

OpenUI 官网 · OpenUI 与 shadcn/ui 集成

AI 参与说明(Agent:Codex):本文通过 Context7 CLI、官方文档及固定提交的公开示例源码调研,解释 OpenUI 的概念、shadcn/ui 接入与 Generative UI 方案分工;资料核验日期为 2026-10-22。最小示例实际运行了组件注册、解析、分块输入和服务端 HTML 渲染,未调用真实 LLM。选型建议属于基于这些证据的工程判断。中文正文按 humanizer-zh 编辑。运行记录:模型 gpt-6.1-sol,reasoning effort ultra,执行入口 Codex Desktop。

主题修订(2026-10-22,Agent:Codex):标题、导语和导航以 OpenUI 的概念、使用方式与同类方案为主线;shadcn/ui 保留为 integration 扩展示例。

OpenUI 让模型在应用运行时,用开发者提供的组件组合界面,并提供组件描述、模型输出语言和流式渲染。 当用户的问题适合用卡片、表格、图表或表单回答时,它可以减少逐种手写回答布局的工作。

理解同类方案,要分清三个问题:模型描述什么界面、Agent 与前端怎样交换事件,以及人怎样参与正在进行的任务。OpenUI、json-render 与 A2UI 主要回答第一个问题;AG-UI 主要回答第二个;Agentic UI 描述第三个层面的产品交互。

shadcn/ui 是本文采用的 integration 案例,用来说明 OpenUI 怎样接入已有组件和设计系统;OpenUI 的核心机制不依赖这一套组件。

先认识这些名称

英文术语中文名称简要解释
Generative UI生成式用户界面模型参与选择、配置或组合界面,回答形式随任务改变
Agentic UI智能体用户界面让人与运行中的 Agent 共同完成任务,包含进度、状态和人工干预等交互
OpenUI保留原名本文指 Thesys 维护的 Generative UI 框架
OpenUI Lang保留原名用语句描述组件、数据和交互的语言,由 OpenUI 运行时解析
Component Library组件库OpenUI 中登记的组件定义及其渲染实现,不等于项目内所有 React 组件
Catalog组件目录在 A2UI、json-render 等方案中声明可用组件及相关约束的集合
Renderer渲染器把界面描述映射成应用中的实际组件
A2UIAgent to UI,智能体到界面Agent 发送声明式界面消息,客户端用自己的组件呈现
AG-UIAgent–User Interaction,智能体与用户交互规范 Agent 与前端之间的运行事件、消息及状态交换
MCP Apps保留原名把工具关联的 HTML 界面交给支持它的 MCP 宿主展示

这里将问题中的 AUI 按 Agentic UI 的含义讨论。AUI 单独出现时不能确定指向哪套方案,集成时应核对完整名称;A2UI、AG-UI 和 assistant-ui 是不同项目,不能互换名称。

Generative UI 到底改变了什么

以“比较三家酒店,筛选有早餐且预算合适的选项”为例,可以有三种实现:

做法开发者预先写什么模型决定什么
固定 Tool UI酒店查询结果统一用 HotelResults 显示是否调用工具与查询参数;结果数据由工具返回
受约束的组合式 Generative UI卡片、比较表、筛选控件及允许的组合规则本次用哪些组件、怎样组合、填入哪些属性
生成完整页面代码代码运行与隔离环境、依赖和可调用能力HTML、CSS、JavaScript 或应用源码

这是按控制范围整理的工程分类,不是互斥的行业标准。固定 Tool UI 也常被归入 Generative UI;需要比较的是模型实际能改变哪些部分。assistant-ui 的模式区分、json-render Introduction

OpenUI 的核心路径属于第二类:应用仍然持有组件实现,模型用 OpenUI Lang 描述一次界面。旅行比较可以出现表格,缺少出行信息时可以出现表单,查询执行完后也可以出现摘要卡片。OpenUI Introduction

这与让 Coding Agent 在开发阶段写一份 shadcn JSX 有不同的交付时刻:前者服务正在使用应用的最终用户,后者修改供开发者构建和发布的源代码。一个产品可以同时采用这两种方式。

OpenUI 的组成与运行方式

OpenUI separates the generated interface description from the component implementation. The model writes OpenUI Lang; the application maps it to registered components. OpenUI Lang 与自有组件

接入时主要遇到下面几层:

部分职责本文涉及的入口
@openuidev/lang-core语言核心、组件规格与 system prompt 生成等共用能力generateSystemPrompt
@openuidev/react-langReact 组件注册、解析、渲染与交互接入defineComponent、createLibrary、Renderer
@openuidev/react-ui完整会话界面与模型流适配AgentInterface、fetchLLM
CLI创建应用、导出组件规格等开发步骤create、generate --spec
Gateway、Autofix、Reliability Monitoring模型接入、生成修复与失败观测可按已有推理链路选择接入方式

只想在现有会话界面里显示生成结果,可以接入 Renderer;需要完整聊天入口时再使用 AgentInterface。开源组件渲染路径可以直接连接自己的模型提供方,官方推荐的 Gateway 是另一项接入选择。Getting Started、生产可靠性

组件定义怎样变成模型能写的语言

开发者先定义 Badge 的 text、variant 属性,以及 Card 可以包含哪些节点。OpenUI 从这些定义生成模型使用的签名和说明,再把模型输出映射回组件。

flowchart TB
    D["defineComponent<br/>名称、属性、说明与 React 实现"]
    L["createLibrary<br/>组合 Component Library"]
    S["Library Spec<br/>提供给服务端"]
    P["System Prompt<br/>组件签名与规则"]
    M["LLM<br/>生成 OpenUI Lang"]
    R["Renderer<br/>解析并检查节点"]
    U["已注册 React 组件<br/>呈现实际界面"]
    D --> L
    L --> S --> P --> M --> R --> U
    L -->|客户端组件映射| R

defineComponent 的四个主要字段是 name、props、description 和 component。props 使用 Zod object;字段顺序决定 OpenUI Lang 的位置参数顺序。.ref 指定允许引用的组件类型,renderNode 把子节点继续映射成 React 节点。Defining Components

由此可以看出,安装 OpenUI 并不会自动把项目里全部 shadcn 组件开放给模型。需要为选定组件定义属性、说明、嵌套关系和行为;这些定义也是后续维护的接口。

流式渲染不要求整份回答先结束

下面是一份对应本文最小组件库的有效输入:

text
root = Card([badge])
badge = Badge("已发货", "secondary")

第一行引用了尚未到达的 badge。后续定义到达后,解析器解析引用,Renderer 再把它变成实际 Badge。应用传给 response 的是累计的 OpenUI Lang 文本,并用 isStreaming 表明响应是否仍在继续。The Renderer

语句不是任意 JavaScript,也不能直接换成 JSX。对上面的 schema,Badge("已发货", "secondary") 的第二个参数是 variant;调整 schema 的字段顺序会影响语言契约,因此历史消息重放也应考虑组件库版本。

扩展接入:shadcn/ui integration

shadcn/ui integration 展示的是复用已有设计系统的一条接入路径。下面用它说明 OpenUI 在具体项目中增加了什么能力。

shadcn/ui distributes editable component code. OpenUI adds a runtime contract that lets a model compose selected components for each request. shadcn/ui Introduction、OpenUI shadcn 集成

原有问题只使用 shadcn 时要做什么加入 OpenUI 后的变化
AI 回答总是 Markdown自行识别何时显示卡片、图表或表单模型可以输出已注册组件的组合
每种工具结果对应一套布局为结果类型分别编写布局与条件分支可复用较小的组件集合表达更多组合
模型生成任意页面很难约束处理代码执行、样式与组件一致性用受控属性和组件映射限定可渲染范围
已有设计系统要持续复用手工让每种 AI 回答遵循设计约定包装已有 shadcn 组件,继续使用项目的主题与组件实现
输出逐步到达,界面仍需可用自行编写分块解析和节点更新逻辑Renderer 处理 OpenUI Lang 的渐进解析与呈现

这些收益取决于应用是否确实需要变化多样的回答布局。组件组合仍要设计,业务数据仍要获取,异常结果仍要处理;布局数量固定的表单或后台页面通常直接写 JSX 更容易维护。

shadcn 的 Registry、MCP 与 AI Elements 有助于组件分发或 Agent 界面开发,但不能仅因它们对模型友好,就认为应用已经具备 OpenUI 的运行时语言与渲染契约。shadcn Registry、AI Elements

怎么用:完整示例与最小接入

路径一:运行官方 shadcn 示例

从空项目开始,可以按 Getting Started 运行 npx @openuidev/cli@latest create,由 CLI 选择 Agent framework 并创建应用。若重点是研究已有 shadcn 组件怎样接入,下面的固定示例更便于对照源码。

官方示例包含组件包装、聊天页面、服务端模型请求与流适配,比只复制集成页的几个片段完整。本次核验固定在 OpenUI 提交 720b30bffc7eaa0dfcb4639b5437956d2745f27f:

bash
git clone https://github.com/thesysdev/openui.git
cd openui
git checkout 720b30bffc7eaa0dfcb4639b5437956d2745f27f
cd examples/design-systems/shadcn
pnpm install --ignore-workspace

按官方示例说明,在此示例的 .env.local 设置 THESYS_API_KEY,再运行 pnpm dev。密钥仅留在服务端;输入框、组件和页面源代码不应包含它。本文未使用真实密钥运行完整模型请求。

示例中的天气、股价和搜索工具返回模拟数据;接真实业务时需替换这些实现,不能将演示结果用于事实查询。固定 app-tools.ts

这个快照使用 react-lang / lang-core 1.0.1、react-ui / react-headless 0.18.1、CLI 0.6.0、Next.js 16.2.6 和 React 19.2.3。各包版本并不一致,升级时应一起核对示例依赖,不能把语言版本当成全部 SDK 的版本。固定 package.json

路径二:先验证已有组件能否被描述和渲染

下面是 TypeScript / React 最小实验,前置条件是已有 shadcn 项目,且包含 card、badge 组件及正确的 @/ 路径别名。它固定输入,不需要模型密钥。

bash
npm install --save-exact @openuidev/react-lang@1.0.1 zod@4.6.7
npm install --save-dev --save-exact tsx@4.23.15

保存为 src/openui-smoke.tsx,然后运行 npx tsx src/openui-smoke.tsx:

tsx
import React from "react";
import { renderToStaticMarkup } from "react-dom/server";
import { createLibrary, defineComponent, Renderer } from "@openuidev/react-lang";
import { z } from "zod/v4";
import { Badge as ShadcnBadge } from "@/components/ui/badge";
import { Card as ShadcnCard } from "@/components/ui/card";

const Badge = defineComponent({
  name: "Badge",
  description: "Display one short order status.",
  props: z.object({
    text: z.string(),
    variant: z.enum(["default", "secondary"]),
  }),
  component: ({ props }) => (
    <ShadcnBadge variant={props.variant}>{props.text}</ShadcnBadge>
  ),
});

const Card = defineComponent({
  name: "Card",
  description: "Group order status badges.",
  props: z.object({ children: z.array(Badge.ref) }),
  component: ({ props, renderNode }) => (
    <ShadcnCard>{renderNode(props.children)}</ShadcnCard>
  ),
});

const library = createLibrary({ root: "Card", components: [Card, Badge] });
const response = `root = Card([badge])
badge = Badge("已发货", "secondary")`;

console.log(library.prompt({
  preamble: "Render an order status with the registered components.",
  examples: [response],
}));

console.log(renderToStaticMarkup(
  <Renderer library={library} response={response} isStreaming={false} />,
));

预期输出包含 Badge(text: string, variant: "default" | "secondary") 这一组件签名,以及包含“已发货”的 Card / Badge HTML。这里故意只允许两个 variant,没有把底层组件的全部 API 暴露给模型。

本次在 Node.js 26.0.0、React / React DOM 19.3.1 下运行了等价代码,使用固定提交的真实 shadcn Card 与 Badge,仅适配本地 import。严格 TypeScript 检查通过,输出具有 Card、Badge 对应的 data-slot 和 data-variant="secondary"。本实验检查语言与组件映射,没有测试浏览器样式或真实网络流。

额外改变两项输入,观察结果:

输入变化实测结果工程含义
第一块只提供 root,下一块补上 badge未解析引用从 ["badge"] 变成空数组前向引用可以随后续输入补齐
把 secondary 改成 unsupported出现 type-mismatch,无效 Badge 被移除,Card 保留部分界面仍能显示,不代表整份结果完全有效

因此生产应用应处理 onError,记录可用性问题并提供重试、修复或固定结果回退。不能只检查“页面上是否有内容”。Renderer 错误处理

路径三:把固定输入换成模型输出

实际接入还需要三个步骤:

  1. 从组件库导出规格,交给服务端生成 system prompt。
  2. 服务端带着规格、问题及可信业务数据请求模型,把结果流传回前端。
  3. 前端累计 OpenUI Lang 文本,传给同一组件库的 Renderer,并处理交互和错误。

官方 CLI 采用下面的形式。src/library.ts 需导出名为 library 的组件库;输出目录应是项目已有的目标目录。

bash
npx @openuidev/cli@0.6.0 generate src/library.ts --spec --out src/openui.spec.json

服务端使用 @openuidev/lang-core 的 generateSystemPrompt({ library: spec }) 生成直接连接模型时的提示词;官方 Gateway 路径使用 generateSystemPrompt({ cloud: true, library: spec })。浏览器只接收响应,不接触提供方密钥。规格变化后要重新生成,并与客户端组件定义一起部署。Getting Started、System Prompts

已有会话组件时,保留原来的发送消息与持久化机制,再接 Renderer。采用完整官方界面时,AgentInterface 通过 componentLibrary 接收自定义库,fetchLLM 配合对应的 stream adapter 读取服务端流;不能把原始 SSE 事件直接当作界面描述塞给 Renderer。固定页面入口

一次请求怎样经过官方示例

官方 shadcn 示例的核心文件和职责如下,可沿它们阅读接入实现:

文件,均相对 examples/design-systems/shadcn/负责什么
src/lib/shadcn-genui/index.tsx用 defineComponent 和 createLibrary 组装组件库
src/library.ts将库导出为 CLI 使用的 library
src/lib/cloud-prompt.ts读取生成的规格,构造 Gateway 的 system prompt
src/app/api/chat/route.ts请求模型、执行示例中的服务端工具循环、返回 SSE
src/app/page.tsx配置流适配,将库交给 AgentInterface

源码基线见官方示例目录。主要数据对象是组件规格、OpenUI Lang 文本、解析后的节点、表单状态与 action event;它们分别承担描述、呈现和用户输入的职责。

sequenceDiagram
    participant C as 应用前端
    participant S as 服务端与模型
    participant R as Renderer
    C->>S: 问题与会话
    Note over S: 组件规格与工具上下文
    S-->>C: SSE / OpenUI Lang
    C->>R: 累计文本与组件库
    R-->>C: shadcn UI
    C->>R: 用户点击或输入
    alt 继续对话
        R->>C: onAction
        C->>S: 后续请求
    else 本地状态或工具运行
        R->>R: 更新状态或调用 toolProvider
    end

图将服务端、Gateway 与模型合并为生成路径,前半段对应官方聊天示例;后半段展示 OpenUI 当前支持的不同交互路径,具体走哪一条由组件定义和应用接线决定。需要进一步区分两种工具调用:服务端 Agent 在生成回答前调用工具,与生成界面之后 Renderer 通过 toolProvider 执行 Query / Mutation,属于不同阶段。Shadcn Chat 架构、OpenUI Architecture

按钮能显示,不等于业务已经接好

本次固定的 AlertDialogBlock 在确认时调用 triggerAction,发出 ContinueConversation。即便按钮写着 Delete,它执行的也只是发送确认文字。分页组件同样只发出前往某页的消息,真实查询仍需要应用实现。

OpenUI Lang 1.0 另外支持 $variables、Query / Mutation、@Set、@Run 等能力:界面生成后,改变筛选条件或执行已注册操作可以由运行时完成,不必每次重新请求 LLM。@ToAssistant 则明确把意图送回对话。Interactivity

这也带来版本边界:通用 1.0 文档用 action() 描述 action 属性,固定的 shadcn 示例里仍可看到 action object。语言表达式和组件的 props 必须匹配,不能把两套例子的 Button 参数直接拼起来。

Runtime validation constrains UI structure; it does not authorize business operations.

调用工具的函数仍需指向应用自己的可信 API,并由服务端检查当前用户、资源权限和参数。重试可能重复执行的写入还需按业务设计幂等。Gateway 能修复格式和 schema 问题,不会因此知道某个用户是否有权删除订单,或模型展示的金额是否真实。工具连接的边界、Reliability

AUI、A2UI、AG-UI:分别在说什么

Agentic UI:人与 Agent 协作的交互方式

Agentic UI describes how humans supervise, steer, and collaborate with running agents. Generative UI is one capability within that experience. CopilotKit 的概念说明

例如旅行应用中,Agent 搜索时展示进展,人可以修改预算,双方看见同一份行程,预订前再由人确认。这些交互可以出现在聊天窗口、聊天加画布,或直接嵌入原来的业务页面。仅让模型生成一张漂亮的卡片,还没有解决共享状态、任务恢复与中途干预。

这里采用 CopilotKit 对 Agentic UI 的解释来建立比较框架,不把某家产品的能力清单当作所有实现必须遵循的标准。

A2UI:描述可交换的界面消息

A2UI uses declarative JSON messages to describe interfaces that a client renders with its own components. Its UI description is separate from its transport. A2UI、Transports

它由 Google 发起,关注 Agent 跨边界发送界面描述:Catalog 约定组件能力,Surface 标识界面实例,消息更新组件及数据,客户端再把用户 action 回传。相同语义可以映射到不同客户端的组件实现;这不意味着任意 schema 都能被任意客户端直接渲染。Data Flow

2026-10-22 官网将 v0.9.1 标为 Current、v1.0 标为 Candidate。早期 surfaceUpdate / beginRendering 与较新版本的 createSurface / updateComponents 不应混用;还要核对具体 Renderer 的协议版本与成熟度。版本清单、Renderers

相较 OpenUI,A2UI 更适合放在“多个 Agent、不同客户端如何交换一份声明”的问题下评估。已有 React / shadcn 应用仍需要合适的 Renderer 和组件映射,协议本身不提供项目的视觉设计。

AG-UI:连接 Agent 与前端的事件协议

AG-UI is a bidirectional agent–application interaction protocol, not a Generative UI specification. AG-UI Overview

它关心运行开始与结束、文本增量、工具调用、状态快照与增量等事件怎样传递。前端因此能区分 Agent 仍在执行、工具有结果、状态发生变化等情况;卡片叫什么、按钮允许哪些属性,则交给另一个 UI 契约。AG-UI Events

因此 A2UI 可以经 AG-UI 传输。OpenUI 也有对应集成路径;是否采用 AG-UI,要看现有后端与前端是否需要这层事件连接,简单应用不必为了显示 Card 再引入全部协议设施。A2UI Transports、OpenUI AG-UI 集成

同类方案怎样比较

下面按主要职责比较;同一项目可能跨越多层,表格不是互斥分类。

方案核心产物或契约适合解决的问题与 OpenUI 的关系
OpenUIOpenUI Lang、组件规格、Renderer从自有组件组合流式 UI,并接入状态、工具和生成修复包装已有 shadcn 组件;可只接 Renderer
json-renderCatalog、JSON spec、Registry用受约束 JSON 描述组件树、绑定数据及动作与 OpenUI 最接近的比较对象;提供 @json-render/shadcn
A2UI声明式 JSON 消息、Catalog、Surface在不同 Agent 与客户端之间交换界面描述需要兼容的 Renderer 与自有组件映射
AG-UI运行、消息、工具、状态等事件连接 Agent backend 与交互前端可以承载 UI 描述,通常与 Renderer 配合
CopilotKit应用 SDK、Runtime 与 Agent 接入让应用支持前端工具、共享状态、人工参与及 Generative UI范围比单个 UI 语言更广,可采用受控组件与 A2UI 等模式
assistant-ui会话 Runtime、Tool UI、present 等生成能力构建会话体验并连接已有后端自带 JSON 组件树方案,也可以接 OpenUI
MCP Apps工具关联的 HTML 资源及宿主通信把完整工具界面交付给支持它的聊天客户端内部可用 shadcn;通常由宿主在沙箱 iframe 展示

对应的一手入口:json-render、shadcn API、CopilotKit 组件注册、assistant-ui Generative UI、MCP Apps。A2UI、AG-UI 的契约和版本见上一节。

最接近的比较:OpenUI 与 json-render

两者都允许模型从受控组件集合生成 UI,重点比较应放在描述格式、流式处理、数据绑定、动作和错误恢复。OpenUI 使用紧凑语句及位置参数;json-render 的 React schema 以 root、elements 等字段表示元素及引用,通过 Registry 连接实际组件。OpenUI 组件定义、json-render 核心流程

OpenUI Lang 的紧凑性可能减少重复 JSON 字段,但不能只按格式长度决定采用。官方首页的 token 和速度数字来自其特定 benchmark;在自己的组件库里,还应同时比较首次可用界面的时间、生成失败率、修复次数和完整交互结果。本文未复现跨框架性能排名。

已有 shadcn 项目也应实际比较两种接入:OpenUI 的组件包装方式,以及 json-render 的 shadcn schemas / 实现映射。主题复用、组件覆盖与 API 可控程度,比某个演示页面的精致程度更能决定维护成本。

会话 SDK 与 UI 语言可以组合

assistant-ui 当前的 present 路径让模型输出 JSON 组件树,同时保留固定 Tool UI 和后端 UI part 等方式,并明确列出 OpenUI 集成。因此“已经用了 assistant-ui,还要不要 OpenUI”取决于是否需要 OpenUI Lang 及其运行能力;不能假设前者只提供聊天外壳。assistant-ui 的模式表

CopilotKit 的评估范围则应包括 Agent 接入、共享状态、人工参与及前端工具。它能注册组件供 Agent 使用,也支持声明式方案;选用它通常是在解决整段人与 Agent 的交互,而不只是替换回答的渲染器。组件注册、Agentic UI

MCP Apps:交付一整个工具界面

MCP Apps links a tool to a ui:// HTML resource. A compatible host renders the view and mediates communication between the view and tools. MCP Apps Overview

例如工具自带一个排期编辑器、地图或 PDF 查看器,宿主把它嵌入当前对话。开发者可以预先用 shadcn 写好界面,也可以在内部采用其他 UI 生成机制;模型现场生成组件树并不是前提。采用时要核对宿主支持、沙箱和通信权限,普通 MCP 工具被成功调用不意味着宿主一定能展示它的界面。

选型时先做一个有边界的小实验

以下是基于上述职责的工程建议:

当前目标优先验证什么
一个查询工具只需显示固定结果先用固定 Tool UI,确认是否真的需要动态布局
已有 shadcn,希望回答能组合表格、卡片和表单对比 OpenUI 与 json-render 的组件契约及流式表现
同一远程 Agent 要服务多个客户端评估 A2UI 的 Catalog、版本和各端 Renderer
已有 Agent backend,需要展示过程、共享状态并接受人工干预评估 AG-UI 与 CopilotKit 等应用接入设施
需要完整会话界面并接现有后端比较 assistant-ui 与 OpenUI AgentInterface 等路径
要把完整工具界面放进不同聊天宿主核对 MCP Apps 支持及宿主通信能力

一个可执行的试点是只开放三种结果:只读订单摘要、订单列表、补充查询条件的表单。先接一个只读业务工具,再让同一组问题分别经过固定 Tool UI 和动态组合路径。输入中加入空结果、很长的文本、无权访问的订单和中断的响应;验收时检查:

  • 数据是否来自可信工具,界面是否正确表达空值、金额与时间。
  • 未注册组件、错误枚举、引用缺失是否被记录并给出可读回退。
  • 变化的是布局还是业务语义,关键行动是否仍然清楚。
  • 提交表单、刷新页面与重新打开历史消息后,状态是否符合应用约定。
  • 动态组合是否确实减少布局代码,且没有增加难以接受的延迟与失败处理成本。

当流程转向支付、删除或其他写入时,再增加明确操作入口、后端权限校验和重复提交处理。先测读取与表单收集,可以更清楚地判断 Generative UI 的表达价值,避免把尚未接好的业务能力误算成框架收益。

对于已有 React / HeroUI 技术栈,评估方法相同:OpenUI 不要求使用 shadcn,可以包装自有组件。若现有 Agent、模型网关或数据后端已能工作,先检查最小 Renderer 接入能否满足需求,再决定是否增加另一套会话 Runtime 或托管服务。

关联阅读

博客助手

正在打开博客助手…