Generative UI

模型输出结构化工具调用,UI 层做组件映射:天气卡片、股价走势图、待办清单直接渲染成真实 React 组件,与文本气泡混排在同一条消息流

工具调用渲染演练(可运行)

GET /api/ai/generative-ui 模拟模型的工具决策;同一条消息流里文本气泡与组件卡片混排

输入问题或点下方示例,观察工具调用结果如何渲染成组件而不是 JSON

Generative UI 的关键

分工:模型负责「调哪个工具、参数是什么」,UI 层负责「渲染成什么」

  • 模型输出结构化工具调用,不是排版指令:返回 `{ tool, payload }` 契约,组件映射表(GenUiPlayground 里的 ToolRenderer) 把 tool 名翻译成真实组件 —— 渲染产物由前端工程师掌控,不依赖模型的排版能力
  • 组件是「活的」:渲染成 React 组件意味着可以继续交互 (刷新行情、勾选待办、展开详情),而文本/图片快照是死的
  • 与 react-playground 的 Agent 实战专题互补: 那边讲状态链路(SSE → Runtime Store → useSyncExternalStore), 这边讲渲染产物(工具调用 → 组件映射);两边拼起来才是完整的 Agent 前端

生产里不手写这个:AI SDK 的 Generative UI 原语

本页的「工具调用 → 组件映射」正是 AI SDK tool rendering 的官方模式(ai@7)

// 工具定义(示意,ai@7;可运行的协议对照见 /ai-native/ai-sdk 专题):
import { tool, type InferUITools } from "ai";

const tools = {
    getWeather: tool({
        inputSchema: z.object({ city: z.string() }),
        execute: async ({ city }) => fetchWeather(city),
    }),
};
type MyTools = InferUITools<typeof tools>;

// Client 侧(示意):useChat<UIMessage<unknown, never, MyTools>> 之后,
// message.parts 里出现 type === "tool-getWeather" 的类型化部分,
// 按其 state(input/output)映射 <WeatherCard /> 渲染 ——
// 等价于本页 ToolRenderer 那张手写映射表,但协议与类型由 SDK 维护,
// 且工具调用随流逐步到达

手写仍合理的场景:教学(看清「契约 + 映射表」这一层没有任何魔法)、 组件渲染要接自研协议或现有数据通道、零依赖场景。 生产里用 SDK 可以少维护一套工具调用的流式协议与状态机; 对照本站的 SDK 落地版见手写 SSE vs Vercel AI SDK专题。

什么时候别用 Generative UI

组件映射表是要长期维护的:每加一个工具,就多一个组件 + 一份契约

  • 结果天然是文本的场景:问答、总结、翻译、写作 — 硬把段落文字塞进卡片是过度设计,流式文本就是最优形态
  • 长尾、低频的工具:组件映射表的维护成本随工具数线性增长; 偶尔用一次的工具,渲染成结构化文本/表格比写专用组件划算
  • payload 形状不稳定的探索期:工具契约还在频繁变动时, 先用通用 JSON 视图顶住,契约稳定后再投资专用组件