Generative UI:当 AI Agent 开始画界面——深度解析 CopilotKit 的生成式 UI 革命

想象一下,你走进一家餐厅,服务员不是递给你一本固定的菜单,而是问你:"今天想吃什么类型的菜?"然后根据你的回答,当场为你生成一张完全符合你口味和饮食偏好的菜单。这张菜单不是预先印好的,而是为你一个人、在这一刻、基于你的具体需求实时创造的。

引言:从静态到自适应

想象一下,你走进一家餐厅,服务员不是递给你一本固定的菜单,而是问你:"今天想吃什么类型的菜?"然后根据你的回答,当场为你生成一张完全符合你口味和饮食偏好的菜单。这张菜单不是预先印好的,而是为你一个人、在这一刻、基于你的具体需求实时创造的。

这就是 Generative UI(生成式用户界面)的核心理念。

在传统的软件开发中,UI 是静态的。开发者预设好所有的按钮、表单、图表,用户只能在这些固定的选项中操作。就像一家餐厅只有一本固定的菜单,不管谁来、什么时候来、有什么特殊需求,看到的都是同样的东西。

但世界不是这样的。每个用户的需求都是独特的,每个场景都是动态变化的。

Generative UI 改变了这个范式。在这种新模式下,AI Agent 不再只是生成文字回复,它可以生成、选择或控制用户界面的部分或全部。Agent 可以发送 UI 状态、结构化的 UI 规范,甚至是完整的交互式 UI 块,前端实时渲染。界面从"开发者预定义的固定屏幕"变成了"随 Agent 工作和上下文变化而自适应的活界面"。

这不是科幻。CopilotKit 的 generative-ui 项目已经在 GitHub 上开源( https://github.com/CopilotKit/generative-ui ),他们的口号很直白:"Build apps that adapt to your users"(构建自适应用户的应用)。

但这里有一个关键问题:如果让 AI 完全自由地生成界面,会不会像给一个小孩一把油漆刷让他刷墙一样——虽然很有创造力,但结果可能难以预料?

答案是:控制与自由之间需要一个光谱。CopilotKit 将这个光谱划分为三种实践模式,每种模式对应不同的控制程度和应用场景。

让我带你一步步理解这三种模式,以及支撑它们的协议栈。这不是一个关于未来技术的遥想,而是正在发生的界面革命。


第一章:三种控制光谱——乐高、3D打印与自由雕塑

理解 Generative UI 的最佳方式,是把它想象成一个从"完全控制"到"完全自由"的光谱。在这个光谱上,CopilotKit 定义了三个主要位置,分别用三种制作物品的方式来比喻:乐高积木、3D打印和自由雕塑。

1.1 Controlled Generative UI:乐高积木模式

想象你在玩乐高。所有的积木块都是预先设计好的——红色的方块、蓝色的长条、绿色的平板,形状固定,颜色确定。你的创造力体现在选择哪些积木和如何组合它们,而不是发明新的积木形状。

这就是 Controlled Generative UI(受控生成式 UI) 的工作方式。

在这种模式下,开发者预先构建好所有的 UI 组件——天气卡片、股票行情图、审批流程表单。Agent 的工作不是"创造"组件,而是选择在此时此刻显示哪个组件,并传递它需要的数据。

举个例子。假设你正在开发一个天气助手应用。你预先设计了三个组件:

  • WeatherLoadingState:显示"正在获取天气..."的加载动画
  • WeatherCard:显示温度、湿度、风速的精美卡片
  • WeatherError:显示错误信息和重试按钮
Agent 不需要知道这些组件长什么样、用什么颜色、字体多大。它只需要知道:当用户问"北京天气怎么样"时,调用 get_weather 工具,把"北京"作为参数传进去。剩下的——显示加载状态、展示结果、处理错误——都由前端根据组件定义自动处理。

代码长这样:

useFrontendTool({
  name: "get_weather",
  description: "获取指定位置的天气信息",
  parameters: z.object({ 
    location: z.string().describe("要查询天气的城市或位置") 
  }),
  handler: async ({ location }) => {
    // 调用天气 API
    return getWeatherData(location);
  },
  render: ({ status, args, result }) => {
    // 根据状态渲染不同的预定义组件
    if (status === "inProgress") {
      return <WeatherLoadingState location={args?.location} />;
    }
    if (status === "complete" && result) {
      const data = JSON.parse(result);
      return (
        <WeatherCard
          location={data.location}
          temperature={data.temperature}
          conditions={data.conditions}
          humidity={data.humidity}
        />
      );
    }
    if (status === "error") {
      return <WeatherError />;
    }
  },
});

这种模式的优势很明显:

  • 完全控制:开发者决定用户可以看到的所有界面元素
  • 品牌一致性:所有组件都遵循统一的设计系统
  • 安全性高:没有执行任意代码的风险
  • 性能可预测:预编译的组件,渲染速度有保障
代价是自由度低。Agent 只能在开发者预设的选项中选择,不能创造新的界面形式。如果用户问了一个你没想到的问题,Agent 可能只能回复纯文本,而不是一个精心设计的可视化组件。

这就像是乐高说明书上的模型——如果你只有这些积木,就只能拼出说明书上的东西。想拼一只长颈鹿但说明书上没有?抱歉,只能近似模拟。

适用场景:天气卡片、股票行情、审批流、任何需要严格控制品牌体验的场景。

1.2 Declarative Generative UI:3D打印模式

现在想象 3D 打印。你不是从固定的积木中选择,而是有一个设计文件(比如一个 .stl 文件),描述了一个物体的三维结构。3D 打印机读取这个文件,逐层构建出物体。你可以打印任何形状——只要设计文件描述得出来。

这就是 Declarative Generative UI(声明式生成式 UI) 的工作方式。

在这种模式下,Agent 不再只是选择预定义的组件,而是生成一个结构化的 UI 描述——用 JSON 或类似的格式,描述"这里应该有一个卡片,卡片里有一个标题、一段文字和一个按钮"。前端读取这个描述,用本地的组件库把它渲染出来。

关键的协议有两个:

A2UI(Agent-to-User Interface):Google 提出的基于 JSONL(JSON Lines)的声明式 UI 规范。它定义了一套组件词汇表——Card、Text、Button、TextField、List 等等。Agent 用这些词汇来描述界面,但不涉及具体的样式和实现细节。

举个例子,A2UI 的描述可能是这样的:

{"surfaceUpdate": {"surfaceId": "review-form", "components": [
  {"id": "title", "component": {"Text": {
    "usageHint": "h2",
    "text": {"literalString": "请评价您的体验"}
  }}},
  {"id": "rating", "component": {"TextField": {
    "label": "评分 (1-5)",
    "inputType": "NUMBER"
  }}},
  {"id": "submit", "component": {"Button": {
    "text": "提交评价",
    "action": {"name": "submit_review"}
  }}}
]}}

这段 JSON 没有说"用蓝色背景、圆角 8px、字体大小 16px"。它只是说:"这里有一个表单,包含一个标题、一个数字输入框和一个提交按钮。"具体长什么样,由前端决定——React 用 React 组件渲染,Flutter 用 Flutter widget 渲染,SwiftUI 用 SwiftUI 视图渲染。

Open-JSON-UI:OpenAI 内部声明式 UI 模式的标准化版本。原理类似,也是用 JSON 描述界面结构。

这种模式的优势:

  • 平衡灵活:Agent 可以创建动态界面,不需要为每个场景预定义组件
  • 跨平台:同一个描述可以在 Web、iOS、Android 上渲染出原生风格的界面
  • 安全可控:只是数据描述,没有代码执行风险
  • LLM 友好:JSON 结构对语言模型来说很容易生成
代价是 需要更多协调。Agent 需要知道有哪些组件可用(组件目录),前端需要实现这些组件的渲染逻辑。如果 Agent 描述了一个前端不认识的组件类型,就会失败或降级。

适用场景:餐厅查找器(根据搜索结果动态生成卡片列表)、动态表单(根据对话上下文生成不同的输入字段)、数据可视化(根据数据类型选择图表类型)。

1.3 Open-ended Generative UI:自由雕塑模式

最后想象自由雕塑。你有一团黏土,可以捏成任何形状。没有预设的积木,没有设计文件的约束,只有你的想象力和双手的限制。

这就是 Open-ended Generative UI(开放式生成式 UI) 的工作方式。

在这种模式下,Agent(或 Agent 调用的服务)返回完整的 UI 表面——通常是 HTML,有时是一个 iframe 的 URL。前端基本上只是一个容器,负责把这个外部提供的界面显示出来。

这种模式的核心协议是 MCP Apps(Model Context Protocol Apps)。MCP 原本是一个让 AI 模型调用外部工具的协议(比如让 Claude 查询数据库、操作文件系统)。MCP Apps 扩展了这个协议,允许 MCP 服务器"运送"交互式 HTML UI。

流程是这样的: 1. Agent 决定调用一个工具(比如"创建 Excalidraw 图表") 2. 这个工具声明了一个 UI 资源(通过 ui:// URI 方案) 3. 前端从服务器获取这个 UI 资源(一个 HTML 页面) 4. 前端在一个沙箱化的 iframe 中渲染这个 HTML 5. 用户可以与这个 iframe 中的界面交互(比如编辑图表) 6. iframe 通过 JSON-RPC 与宿主应用双向通信

代码示例:

const agent = new BuiltInAgent({
  model: "openai/gpt-5",
  prompt: "你是一个有用的助手,可以帮用户创建图表。",
}).use(
  new MCPAppsMiddleware({
    mcpServers: [{
      type: "http",
      url: "https://mcp.excalidraw.com/mcp",
      serverId: "excalidraw",
    }],
  }),
);

当 Agent 调用 create_view 工具时,Excalidraw MCP 服务器返回一个交互式的图表编辑器界面,用户可以直接在聊天窗口中编辑图表。

这种模式的优势:

  • 极高自由度:可以创建任何类型的界面,包括复杂的交互式模拟、3D 可视化、自定义控件
  • 服务器端控制:服务器可以完全控制 UI 的外观和行为
  • 快速迭代:不需要更新客户端,服务器端的 UI 可以随时更新
代价是安全风险和性能考虑:
  • 安全性:虽然 iframe 是沙箱化的,但运行外部 HTML 总是有风险的。CSP(内容安全策略)和权限控制至关重要。
  • 性能:iframe 加载需要时间,可能比本地组件慢
  • 一致性:外部 UI 可能与宿主应用的设计风格不一致
  • 可移植性:高度依赖 Web 技术,在非 Web 平台(如原生移动应用)上实现更复杂
适用场景:航班预订(复杂的日期选择、座位图)、交易模拟器(实时图表、下单界面)、Excalidraw 图表编辑、任何需要高度定制化界面且无法被预定义组件覆盖的场景。

1.4 三种模式的对比

维度Controlled (乐高)Declarative (3D打印)Open-ended (自由雕塑)
控制方开发者完全控制共享控制服务器/Agent 控制
自由度低中高
协议AG-UIA2UI, Open-JSON-UIMCP Apps
输出形式预定义组件JSON 描述HTML / iframe
安全性高高中(需要沙箱)
性能最优好中(iframe 加载)
适用场景天气、股票、审批动态表单、列表复杂交互、可视化

1.5 第四种模式:Open Generative UI(补充说明)

CopilotKit 还提到了第四种模式,叫做 Open Generative UI,通过 useComponent hook 实现。

这种模式与 MCP Apps 类似,都是 Agent 生成 HTML,但有一个关键区别:没有服务器往返。在 MCP Apps 中,Agent 调用远程服务器的工具,服务器返回 UI。而在 Open Generative UI 中,LangGraph Agent 直接生成原始 HTML/SVG/Canvas 字符串,通过工具调用直接传递给前端。

这就像是即兴表演——演员(Agent)直接创造内容,不需要舞台工作人员(服务器)的帮助。适合算法可视化、数学绘图、简单的交互式模拟等场景。


第二章:协议栈解剖——神经系统、表现形式与事件流

理解了三种 Generative UI 模式后,我们需要深入底层,看看这些模式是如何实际运作的。这就像是了解汽车的发动机——你不需要成为机械师才能开车,但了解发动机会让你成为更好的司机。

2.1 协议生态系统全景

在 Generative UI 的世界里,有多个协议协同工作,每个协议负责不同的层次。想象一个交响乐团的结构:

协议层级作用比喻
AG-UI交互层Agent ↔ 用户 ↔ 应用的双向同步神经系统
MCP工具层上下文和模型通信手和工具
A2A编排层Agent 间协调乐团指挥
A2UI表现层Agent 生成 UI 规范乐谱
让我逐一解释。

2.2 AG-UI:神经系统

AG-UI(Agent-User Interaction Protocol) 是 CopilotKit 提出的开放协议,它是整个 Generative UI 生态的"神经系统"。

想象你的身体。神经系统不负责思考(那是大脑的工作),也不负责运动(那是肌肉的工作)。神经系统的职责是在大脑和身体各部分之间传递信号——感觉信号从皮肤传向大脑,运动指令从大脑传向肌肉。

AG-UI 做的就是类似的事情。它不关心 Agent 如何思考,也不关心 UI 如何渲染。它只关心一件事:Agent 和前端之间的实时双向通信。

AG-UI 定义了大约 16 种标准事件类型,涵盖:

  • 消息事件:Agent 说的话、用户的输入
  • 工具调用事件:工具开始执行、执行进度、执行完成
  • 状态更新事件:共享状态的快照(STATE_SNAPSHOT)、增量更新(STATE_DELTA,使用 JSON Patch 格式)
  • UI 表面事件:渲染某个 UI、更新 UI 数据
这些事件通过标准化的方式传输——可以是 Server-Sent Events (SSE)、WebSockets、webhooks,甚至是 HTTP 轮询。AG-UI 的设计是传输无关的,只要能把事件从 A 点送到 B 点,用什么方式都可以。

一个典型的 AG-UI 事件流可能是这样的:

// 1. 用户发送消息
{"type": "MESSAGE", "role": "user", "content": "北京天气怎么样?"}

// 2. Agent 决定调用天气工具
{"type": "TOOL_CALL_START", "toolName": "get_weather", "args": {"location": "北京"}}

// 3. 前端渲染加载状态(通过 Controlled GenUI)
{"type": "RENDER", "component": "WeatherLoadingState", "props": {"location": "北京"}}

// 4. 工具执行完成,返回结果
{"type": "TOOL_CALL_COMPLETE", "toolName": "get_weather", "result": {"temp": 22, "humidity": 45}}

// 5. 前端渲染结果卡片
{"type": "RENDER", "component": "WeatherCard", "props": {"temp": 22, "humidity": 45}}

AG-UI 的美妙之处在于它的 统一性。不管你是用 LangGraph、CrewAI、Pydantic AI 还是任何其他 Agent 框架,只要它能发出 AG-UI 兼容的事件,就能连接到任何 AG-UI 兼容的前端(比如 CopilotKit 的 React 组件)。

这就像是 USB 接口——不管是哪个品牌的键盘,只要接口匹配,插上就能用。

2.3 A2UI vs AG-UI:乐谱 vs 演奏

很多人容易混淆 A2UI 和 AG-UI,因为它们的名字很像。但它们的角色完全不同。

A2UI 是乐谱。它定义了"演奏什么音符"——用什么组件、怎么排列、显示什么数据。A2UI 的输出是 JSON 描述,比如:

{"surfaceUpdate": {"components": [
  {"id": "title", "component": {"Text": {"text": {"literalString": "Hello"}}}}
]}}

AG-UI 是演奏过程。它定义了"乐谱如何在音乐家和听众之间流动"——什么时候开始演奏、如何同步多个乐手、如何处理即兴发挥。AG-UI 的输出是事件流,比如:

{"type": "RENDER", "surfaceId": "main", "a2uiPayload": {...}}

关键区别:

  • A2UI 定义"显示什么 UI"(What)
  • AG-UI 定义"UI 如何在前后端流动"(How)
它们可以独立工作,也可以协同工作。AG-UI 可以承载 A2UI 作为其事件的内容——AG-UI 负责传输,A2UI 负责描述要渲染的界面。

2.4 MCP:手和工具

MCP(Model Context Protocol) 是 Anthropic 提出的开放标准,最初目的是让 AI 模型能够调用外部工具和数据源。

想象一个工匠。工匠有手(模型)和工具箱(各种工具)。MCP 定义了手如何握持工具、如何传递指令、如何接收结果。它不关心工具内部是如何工作的(那是工具制造商的事),只关心接口标准化。

MCP 的核心概念:

  • Tools(工具):模型可以调用的功能(如"查询数据库"、"发送邮件")
  • Resources(资源):模型可以读取的数据(如文件内容、数据库记录)
  • Prompts(提示):预定义的提示模板
MCP Apps 扩展了这个协议,增加了 UI Resources(UI 资源)。现在工具不仅可以返回文本或数据,还可以返回一个指向交互式 UI 的引用(通过 ui:// URI)。

2.5 A2A:乐团指挥

A2A(Agent-to-Agent) 是另一个新兴协议,专注于 Agent 之间的协调。

想象一个交响乐团。每个乐手(Agent)都是专家——小提琴手、大提琴手、钢琴家。但他们需要协调,否则就是噪音。乐团指挥(A2A)负责:

  • 决定谁来演奏(哪个 Agent 处理当前任务)
  • 协调节奏和时机(Agent A 完成后 Agent B 开始)
  • 处理交接(Agent A 的输出作为 Agent B 的输入)
A2A 协议定义了 Agent 之间如何发现彼此、如何协商任务、如何传递状态和结果。在复杂的 Generative UI 场景中,可能有多个 Agent 协同工作——一个负责理解用户意图,一个负责查询数据,一个负责生成可视化。A2A 让它们能够无缝协作。

2.6 事件流的生命周期

让我们通过一个完整的例子,看看这些协议如何协同工作。

场景:用户说"帮我规划一次去东京的旅行",Agent 需要一个多步骤的界面来收集偏好(预算、日期、兴趣点)。

步骤 1:用户输入(AG-UI MESSAGE 事件)

{"type": "MESSAGE", "role": "user", "content": "帮我规划一次去东京的旅行"}

步骤 2:Agent 思考并决定启动旅行规划工作流(可能是 A2A 协调多个 Agent)

步骤 3:Agent 生成 UI 描述(A2UI)

{"surfaceUpdate": {"surfaceId": "travel-planner", "components": [
  {"id": "title", "component": {"Text": {"text": {"literalString": "东京旅行规划"}}}},
  {"id": "budget", "component": {"TextField": {"label": "预算(人民币)"}}},
  {"id": "dates", "component": {"DateRangePicker": {"label": "旅行日期"}}},
  {"id": "interests", "component": {"CheckboxGroup": {
    "label": "兴趣",
    "options": ["美食", "购物", "文化", "自然"]
  }}},
  {"id": "next", "component": {"Button": {"text": "下一步", "action": {"name": "plan_trip"}}}}
]}}

步骤 4:通过 AG-UI 传输到前端

{"type": "RENDER", "surfaceId": "travel-planner", "a2uiPayload": {...}}

步骤 5:用户填写表单并点击"下一步"(AG-UI ACTION 事件)

{"type": "ACTION", "surfaceId": "travel-planner", "action": "plan_trip", "data": {"budget": 10000, "dates": {...}, "interests": ["美食", "文化"]}}

步骤 6:Agent 调用工具查询航班和酒店(MCP 工具调用)

步骤 7:Agent 生成结果界面(可能是更复杂的 MCP Apps UI)

整个流程中:

  • AG-UI 负责所有实时通信
  • A2UI 负责描述表单界面
  • MCP 负责调用外部工具(航班查询、酒店预订)
  • A2A(如果使用)负责协调多个 Agent
这就是现代 Generative UI 的协议栈——不是单一协议解决所有问题,而是多个专业化协议分工协作。


第三章:实战案例——Excalidraw 与 OpenGenerativeUI

理论讲完了,让我们看看实际应用。CopilotKit 的 generative-ui 仓库包含两个精彩的实战案例,完美展示了不同模式的应用。

3.1 Excalidraw MCP Apps:开放式 Generative UI 的典范

Excalidraw 是一个流行的开源手绘风格图表工具。CopilotKit 团队与 Excalidraw 合作,创建了一个 MCP Apps 集成,让用户可以通过自然语言描述,在几秒钟内生成可编辑的图表。

用户体验: 1. 用户在聊天窗口中说:"画一个展示客户端-服务器架构的图" 2. Agent 调用 Excalidraw MCP 服务器的 create_view 工具 3. 工具返回一个交互式的 Excalidraw 编辑器界面,嵌入在聊天窗口中 4. 界面上已经有一个根据描述生成的架构图 5. 用户可以直接在界面中编辑图表、添加元素、调整布局 6. 一键点击,图表可以推送到 Excalidraw 主站保存

技术实现:

后端代码(Next.js API 路由):

import { CopilotRuntime, ExperimentalEmptyAdapter, copilotRuntimeNextJSAppRouterEndpoint } from "@copilotkit/runtime";
import { BuiltInAgent } from "@copilotkit/runtime/v2";
import { MCPAppsMiddleware } from "@ag-ui/mcp-apps-middleware";
import { NextRequest } from "next/server";

// 创建 Agent,接入 Excalidraw MCP 服务器
const agent = new BuiltInAgent({
  model: "openai/gpt-5",
  prompt: `你是一个 AI 图表助手,由 Excalidraw 驱动。
  用户描述任何东西,你都要生成对应的图表。
  调用 create_view 工具,传入 Excalidraw 元素数组。`,
}).use(
  new MCPAppsMiddleware({
    mcpServers: [{
      type: "http",
      url: process.env.MCP_SERVER_URL ?? "http://localhost:3001/mcp",
      serverId: "excalidraw",
    }],
  }),
);

const serviceAdapter = new ExperimentalEmptyAdapter();

const runtime = new CopilotRuntime({
  agents: { default: agent },
});

export const POST = async (req: NextRequest) => {
  const { handleRequest } = copilotRuntimeNextJSAppRouterEndpoint({
    runtime,
    serviceAdapter,
    endpoint: "/api/copilotkit",
  });
  return handleRequest(req);
};

当 Agent 调用 create_view 时,它实际上传递的是这样一个 JSON 数组:

[
  {
    "type": "rectangle",
    "x": 100,
    "y": 100,
    "width": 150,
    "height": 80,
    "strokeColor": "#000000",
    "backgroundColor": "transparent"
  },
  {
    "type": "text",
    "x": 125,
    "y": 130,
    "text": "客户端",
    "fontSize": 20
  },
  {
    "type": "arrow",
    "x": 250,
    "y": 140,
    "points": [[0, 0], [100, 0]]
  }
]

Excalidraw MCP 服务器接收这些元素,创建一个可编辑的图表视图,然后通过 MCP Apps 协议返回一个 URL。前端在一个沙箱化的 iframe 中加载这个 URL,用户看到的就是一个完整的 Excalidraw 编辑器。

为什么这个案例重要:

它展示了 Open-ended Generative UI 的强大之处。Agent 不需要知道如何绘制图形、如何处理用户交互、如何保存文件——这些复杂的工作都由 Excalidraw MCP 服务器处理。Agent 只需要"指挥":"我要一个这样的图表"。

这就像是请了一个专业的图表设计师。你告诉他你想要什么,他给你成品,你可以在他的工作室里现场修改,最后带走最终版本。你不需要自己学会设计软件。

3.2 OpenGenerativeUI:探索 Generative UI 的可能性边界

OpenGenerativeUI 是 CopilotKit 的另一个开源展示项目,它使用 useComponent hook 来实现开放式 Generative UI。

与 Excalidraw 案例不同,OpenGenerativeUI 不需要外部 MCP 服务器。LangGraph Agent 直接生成 HTML/SVG/Canvas 代码,前端直接渲染。

支持的内容类型:

  • 算法可视化:排序算法、图遍历、动态规划的逐步演示
  • 3D 动画:Three.js、WebGL 驱动的交互式 3D 场景
  • 交互式模拟:物理模拟、生态系统模拟、经济模型
  • 数学绘图:函数图像、几何图形、统计图表
  • D3 力导向图:网络关系可视化
技术实现:

import { useComponent } from "@copilotkit/react-core/v2";
import { WidgetRenderer, WidgetRendererProps } from "@/components/generative-ui/widget-renderer";

// 注册一个名为 "widgetRenderer" 的组件
useComponent({
  name: "widgetRenderer",
  description: `在沙箱化 iframe 中渲染交互式 HTML/SVG 可视化。
  用于算法可视化、图表、控件和模拟。`,
  parameters: WidgetRendererProps,
  render: WidgetRenderer,
});

当 Agent 需要展示一个可视化时,它直接生成 HTML 字符串:

<!DOCTYPE html>
<html>
<head>
  <script src="https://cdnjs.cloudflare.com/ajax/libs/three.js/r128/three.min.js"></script>
</head>
<body>
  <div id="canvas"></div>
  <script>
    // Three.js 3D 场景代码
    const scene = new THREE.Scene();
    const camera = new THREE.PerspectiveCamera(75, 1, 0.1, 1000);
    const renderer = new THREE.WebGLRenderer();
    // ... 更多 3D 渲染代码
  </script>
</body>
</html>

这个 HTML 字符串通过 AG-UI 协议传输到前端,WidgetRenderer 组件把它放进一个沙箱化的 iframe 中渲染。

与 MCP Apps 的区别:

维度MCP Apps (Excalidraw)useComponent (OpenGenerativeUI)
服务器往返需要(调用远程 MCP 服务器)不需要(Agent 直接生成)
延迟较高(网络请求)较低(本地生成)
能力范围取决于 MCP 服务器的功能取决于 Agent 生成代码的能力
安全性依赖 iframe 沙箱依赖 iframe 沙箱
适用场景调用外部专业服务快速原型、代码生成类任务
为什么这个案例重要:

它展示了 Generative UI 的极限可能性。如果 Agent 能够生成有效的 HTML/JavaScript 代码,那么理论上它可以创建任何类型的界面——从简单的图表到复杂的 3D 游戏。

当然,这也带来了挑战:

  • 代码质量:Agent 生成的代码可能有 bug
  • 安全性:需要严格的沙箱隔离
  • 性能:复杂的可视化可能消耗大量资源
但作为一种探索性工具,OpenGenerativeUI 展示了 Generative UI 的未来方向:Agent 不仅是信息的提供者,更是体验的创造者。


第四章:协议生态的未来——为什么没有唯一的"赢家"

在 Generative UI 的生态系统中,我们有多个协议:AG-UI、A2UI、MCP、A2A。一个自然的疑问是:会不会最终只有一个协议胜出?其他都被淘汰?

答案是:不会。这些协议不是竞争者,而是协作者。

4.1 协议分工的必然性

想象城市交通系统。我们有:

  • 地铁:大运量、固定路线、站点之间快速移动
  • 公交:灵活路线、覆盖面广、门到门服务
  • 出租车/网约车:个性化、随叫随到、点对点
  • 自行车/步行:短距离、灵活、健康
这些交通方式不是竞争关系,而是互补关系。你不会用地铁完成最后一公里的送货,也不会用出租车横跨整个城市上下班(除非你很富有)。

Generative UI 的协议生态也是如此。

4.2 每个协议的核心价值

AG-UI:通用传输层

AG-UI 的目标是成为"神经系统"——不管大脑(Agent)和肌肉(UI)如何变化,神经系统负责传递信号的工作是永恒的。

AG-UI 的价值在于:

  • 框架无关:任何 Agent 框架、任何前端框架都可以使用
  • 实时双向:支持流式响应、状态同步、人机协作
  • 事件标准化:统一的事件类型让调试和监控更容易
A2UI:声明式 UI 标准

A2UI 的目标是成为"乐谱标准"——就像五线谱让不同乐器的演奏者能够理解同一首曲子,A2UI 让不同平台的 UI 能够渲染同一个描述。

A2UI 的价值在于:

  • 跨平台:Web、iOS、Android、桌面,同一套描述
  • LLM 友好:JSON 结构对语言模型来说很容易生成
  • 安全声明式:数据不是代码,没有执行风险
MCP:工具生态系统

MCP 的目标是成为"工具市场"——标准化让工具制造商(MCP 服务器开发者)和工具使用者(Agent 开发者)能够无缝对接。

MCP 的价值在于:

  • 即插即用:连接一个 MCP 服务器,立即获得新能力
  • 安全隔离:工具运行在独立的上下文中
  • 生态丰富:越来越多的服务提供 MCP 接口
A2A:Agent 协作网络

A2A 的目标是成为"Agent 社交协议"——让不同的 Agent 能够发现彼此、协商任务、协同工作。

A2A 的价值在于:

  • 专业化:每个 Agent 专注于自己的领域
  • 组合性:简单的 Agent 组合成复杂的系统
  • 可扩展性:新的 Agent 可以无缝加入网络

4.3 为什么不会有一个"赢家"

技术原因:

每个协议解决的问题本质不同。AG-UI 解决"如何通信",A2UI 解决"描述什么",MCP 解决"调用工具",A2A 解决"Agent 协作"。这就像问"螺丝刀和锤子哪个更好"——取决于你要做什么。

社会原因:

协议的背后是组织。AG-UI 由 CopilotKit 主导,A2UI 由 Google 主导,MCP 由 Anthropic 发起,A2A 是多个组织的协作。这些组织有不同的利益、不同的技术栈、不同的用户群体。强制统一既不现实,也不必要。

历史原因:

技术史告诉我们,开放标准往往比单一垄断更持久。TCP/IP 不是唯一的网络协议,但它是最通用的,所以其他协议(HTTP、FTP、WebSocket)都建立在它之上。Generative UI 的生态也在走向同样的方向——AG-UI 正在成为底层传输标准,而其他协议在其之上各显神通。

4.4 可组合性的重要性

未来的 Generative UI 应用,很可能是多协议组合的:

┌─────────────────────────────────────────────────────────┐
│                    用户界面层                            │
│         (React / Vue / Flutter / SwiftUI)               │
├─────────────────────────────────────────────────────────┤
│              AG-UI 传输层(事件流)                      │
├─────────────────────────────────────────────────────────┤
│  A2UI 渲染器  │  MCP Apps 容器  │  Controlled 组件      │
├─────────────────────────────────────────────────────────┤
│              Agent 运行时层                              │
│    (LangGraph / CrewAI / Pydantic AI / AutoGen)        │
├─────────────────────────────────────────────────────────┤
│  MCP 工具层(数据库、API、文件系统)                      │
├─────────────────────────────────────────────────────────┤
│              A2A 协调层(多 Agent 协作)                 │
└─────────────────────────────────────────────────────────┘

这种分层架构的好处是:

  • 每一层可以独立演进:升级 React 不需要改动 LangGraph
  • 每一层可以替换:不喜欢 LangGraph?换成 CrewAI,其他层不受影响
  • 每一层可以组合:根据需求选择不同的技术栈

4.5 开源生态的合作

令人鼓舞的是,这个生态的主要玩家正在走向合作而非对抗:

  • Oracle:Open Agent Specification,定义可移植的 Agent 描述
  • Google:A2UI 规范,声明式 UI 标准
  • CopilotKit:AG-UI 协议 + 实现框架
  • Anthropic:MCP 协议
  • OpenAI:支持 MCP Apps
  • Microsoft:Azure Agent Framework 支持 AG-UI
  • AWS:AgentCore 提供 AG-UI 端点
这些合作的目标很明确:即插即用可移植性。开发者应该能够: 1. 用任何框架编写 Agent 2. 连接到任何支持 AG-UI 的前端 3. 使用任何 MCP 服务器提供的工具 4. 让 Agent 生成符合 A2UI 的界面 5. 在不同平台(Web、iOS、Android)上获得一致的体验

这不是一个公司的愿景,而是整个行业的方向。


第五章:开发者视角——选择、安全与性能

如果你是开发者,想要在自己的项目中使用 Generative UI,应该怎么做?这一章提供实用的指导。

5.1 如何选择合适的模式

选择 Generative UI 模式,就像选择交通工具——取决于你的目的地、预算和时间。

选择 Controlled Generative UI(乐高模式)如果:

  • ✅ 你需要严格控制品牌体验
  • ✅ 你的应用场景有限且明确(天气、股票、特定审批流)
  • ✅ 你想要最高的性能和安全性
  • ✅ 你的团队有前端开发能力,可以预构建组件
选择 Declarative Generative UI(3D 打印模式)如果:
  • ✅ 你需要动态界面,但不想为每种可能预定义组件
  • ✅ 你需要跨平台支持(Web + 移动端)
  • ✅ 你想要平衡灵活性和安全性
  • ✅ 你的 Agent 需要生成表单、列表、简单图表
选择 Open-ended Generative UI(自由雕塑模式)如果:
  • ✅ 你需要高度定制化的交互体验
  • ✅ 你在调用外部专业服务(如 Excalidraw、复杂数据可视化)
  • ✅ 你可以接受 iframe 的性能和安全权衡
  • ✅ 你的应用场景无法被预定义组件覆盖
决策流程图:

开始
  │
  ├─ 是否需要严格控制 UI 外观?
  │     ├─ 是 → Controlled GenUI
  │     └─ 否
  │           │
  │           ├─ 是否需要调用外部专业服务?
  │                 ├─ 是 → MCP Apps (Open-ended)
  │                 └─ 否
  │                       │
  │                       ├─ 是否需要动态生成界面?
  │                             ├─ 是 → Declarative GenUI (A2UI)
  │                             └─ 否 → 传统 UI 即可

5.2 安全考虑

Generative UI 引入了新的安全挑战,尤其是当 Agent 生成的内容可能包含代码时。

沙箱隔离(针对 MCP Apps 和 Open-ended GenUI):

所有外部 UI 内容都应该在沙箱化的 iframe 中运行。现代浏览器的 iframe sandbox 属性提供了强大的隔离:

<iframe 
  sandbox="allow-scripts allow-same-origin"
  src="..."
></iframe>

推荐的沙箱配置:

  • allow-scripts:允许执行 JavaScript(否则界面无法交互)
  • 不要 allow-top-navigation:防止 iframe 导航父页面到钓鱼网站
  • 不要 allow-forms(除非必要):防止表单提交到恶意地址
  • 使用 CSP(Content Security Policy)限制可加载的资源来源
内容安全策略(CSP)示例:

Content-Security-Policy: 
  default-src 'self';
  script-src 'self' 'unsafe-inline';
  style-src 'self' 'unsafe-inline';
  connect-src 'self' https://api.yourservice.com;

权限控制:

MCP Apps 允许 UI 请求额外权限(如麦克风、摄像头)。这些权限应该:

  • 明确显示给用户,获得用户同意
  • 仅在必要时授予
  • 可以随时撤销
代码注入防护:

对于 Agent 直接生成 HTML 的模式(Open Generative UI),需要防范 XSS 攻击:

  • 使用 DOMPurify 等库清理 HTML
  • 禁止 eval()、new Function() 等动态代码执行
  • 对所有的用户输入进行转义

5.3 性能权衡

不同的 Generative UI 模式有不同的性能特征。

渲染性能:

模式首次渲染更新渲染内存占用
Controlled极快(预编译组件)极快低
Declarative快(JSON 解析 + 组件映射)快中
Open-ended慢(iframe 加载)中(iframe 通信开销)高(独立上下文)
网络开销:
  • Controlled:无额外网络开销(组件已在客户端)
  • Declarative:低(JSON 文本传输)
  • Open-ended:高(HTML/JS/CSS 资源加载,可能需要多次往返)
优化建议:

1. 预加载:对于 MCP Apps,可以在用户可能调用工具前就预加载 UI 资源 2. 懒加载:对于不常用的组件,使用动态导入(dynamic import) 3. 缓存:缓存 MCP 服务器的 UI 资源,避免重复下载 4. 降级策略:如果 iframe 加载失败,提供纯文本或简化 UI 的降级方案 5. 流式渲染:对于 A2UI,支持渐进式渲染,不要等到整个 JSON 完成再显示

5.4 开发工具与调试

调试 Generative UI 应用比普通应用更复杂,因为涉及前后端、多个协议的交互。

推荐工具:

1. AG-UI DevTools:查看事件流、检查状态更新 2. MCP Inspector:测试 MCP 服务器和工具调用 3. 浏览器开发者工具:

  • Network 面板:检查协议传输
  • Performance 面板:分析渲染性能
  • Console 面板:查看日志和错误
调试技巧:
  • 在 AG-UI 事件中添加唯一的 traceId,跟踪一个用户请求的全链路
  • 使用 console.group() 组织相关的日志输出
  • 在 iframe 中使用 postMessage 进行跨窗口调试

结论:UI 的新纪元

让我们回到文章的开头。

传统的 UI 是静态的、预定义的、为"平均用户"设计的。就像一本固定的菜单,不管谁来、什么时候来、有什么特殊需求,看到的都是同样的选项。

Generative UI 改变了这个范式。界面不再是固定的,而是 活的——它随着用户的需求、Agent 的理解、上下文的变化而动态生成。

这不是关于技术的炫技,而是关于 人机交互的本质转变。

在旧范式中,用户必须学习软件的"语言"——菜单在哪里、按钮是什么意思、如何完成一个任务。软件是主人,用户是客人,必须遵循主人的规则。

在新范式中,软件学习用户的语言——用户用自己的话描述需求,Agent 生成适合当下需求的界面。用户是主人,软件是工具,随叫随到,按需变形。

这是从"为所有用户设计一个界面"到"为每个用户、在每个时刻、生成专属界面"的转变。

展望未来

Generative UI 还处于早期阶段。2026 年,我们看到了 AG-UI、A2UI、MCP Apps 等协议的初步标准化,看到了 CopilotKit、Google Opal、Claude 等产品的实践探索。

未来会怎样?我不知道确切的答案,但有一些方向是明确的:

更智能的界面生成:随着多模态模型的发展,Agent 不仅能生成结构化 UI,还能生成像素级精准的视觉设计。

更深入的个性化:界面不仅根据任务生成,还根据用户的偏好、习惯、能力水平动态调整。色盲用户看到高对比度配色,老年用户看到大字体,专家用户看到高级选项。

更无缝的跨平台:同一份 A2UI 描述,在手机上自动适配小屏幕,在 VR 设备上变成 3D 界面,在汽车中控屏上变成语音优先的交互。

更强大的 Agent 协作:通过 A2A 协议,多个专业 Agent 协同为用户服务。一个 Agent 负责理解需求,一个负责查询数据,一个负责生成可视化,一个负责优化性能——它们协同生成一个统一的界面。

最后的思考

费曼曾经说过:"如果你认为你理解了某样东西,试着把它解释给一个大一新生听。如果你做不到,说明你没有真正理解。"

Generative UI 的概念听起来很复杂——协议栈、事件流、声明式描述、沙箱隔离。但核心的 idea 其实很简单:

让软件界面像人类服务一样,根据每个用户的独特需求动态调整。

这不是终点,而是开始。我们站在 UI 新纪元的门槛上,前方是未知但令人兴奋的可能性。

正如 CopilotKit 的口号所说:"Build apps that adapt to your users."

让我们开始构建吧。


附录:参考资源

官方资源:

  • CopilotKit generative-ui GitHub:https://github.com/CopilotKit/generative-ui
  • AG-UI 文档:https://docs.ag-ui.com
  • A2UI 规范:https://a2ui.org
  • MCP Apps 规范:https://modelcontextprotocol.io/extensions/apps/overview
相关协议:
  • Open Agent Specification (Oracle):https://blogs.oracle.com/ai-and-datascience/post/open-agent-specification
  • MCP 协议:https://modelcontextprotocol.io
  • A2A 协议:https://a2aprotocol.ai
示例项目:
  • OpenGenerativeUI:https://github.com/CopilotKit/OpenGenerativeUI
  • Excalidraw MCP 集成:https://github.com/CopilotKit/excalidraw-studio
  • A2UI + Agent Spec 示例:https://github.com/CopilotKit/with-agent-spec
深度阅读:
  • "The Developer's Guide to Generative UI in 2026" (CopilotKit Blog)
  • "Introducing A2UI: An open project for agent-driven interfaces" (Google Developers Blog)
  • "Reusable Agents Meet Generative UIs" (Oracle + Google + CopilotKit 联合发布)

#GenerativeUI #CopilotKit #AGUI #A2UI #MCP #AI前端 #小凯

暂无表态

想参与讨论或点赞?登录后使用完整功能

讨论回复(0)

暂无回复,登录后可参与讨论
合作

智谱 GLM-5 已上线

在智谱开放平台 BigModel.cn 打造 AI 应用。新一代旗舰模型 GLM-5 在推理、代码、智能体综合能力达到开源模型 SOTA。

领取 2000万 Tokens