Wink Pings

Vercel 让 AI 在 Slack 里画表格,边生成边渲染

Slack、Teams、Discord 里的 Agent 回答不再只有文字。Vercel Labs 的 json-render/chat 让模型直接吐出原生卡片,一条组件目录能在十几个平台上渲染。好看是真的,让人担心的地方也在这。

Vercel Labs 发布了一个新包,@json-render/chat。目标很直接:让 AI Agent 在 Slack、Teams、Discord 里回复的不再是一段文字,而是原生卡片,表格、字段、图表、按钮都装在里面。模型写到哪,界面渲染到哪。

原帖:https://x.com/ctatedev/status/2118853661040295997

以前的流程是模型输出 markdown 或者裸 JSON,前端再自己解析,出错是常态。json-render 把流程切成三步固定动作。

一、定义 catalog

用 zod 写清楚有哪些组件、每个组件接受什么 props、有哪些动作可以触发。

import { defineCatalog } from "@json-render/core";
import { schema } from "@json-render/react/schema";
import { z } from "zod";

const catalog = defineCatalog(schema, {
  components: {
    Card: {
      props: z.object({ title: z.string() }),
      description: "A card container",
    },
    Metric: {
      props: z.object({
        label: z.string(),
        value: z.string(),
        format: z.enum(["currency", "percent", "number"]).nullable(),
      }),
      description: "Display a metric value",
    },
    Button: {
      props: z.object({ label: z.string(), action: z.string() }),
      description: "Clickable button",
    },
  },
  actions: {
    export_report: { description: "Export dashboard to PDF" },
    refresh_data: { description: "Refresh all metrics" },
  },
});

二、让模型按 catalog 说话

catalog.prompt() 直接生成系统提示词,里面带着组件描述、prop schema、动作清单。模型只能在这份白名单里组合,生成的 JSON 结构受 schema 约束。

三、渲染 spec

产物是一份 JSON spec:一个 root 键,加一个 elements map。

const spec = {
  root: "card-1",
  elements: {
    "card-1": { type: "Card", props: { title: "Hello" }, children: ["button-1"] },
    "button-1": { type: "Button", props: { label: "Click me" }, children: [] },
  },
};

<Renderer spec={spec} registry={registry} />

安全边界落在这一步:AI 造不出目录之外的组件,输出也不容易跑偏。

跨平台是它比较实在的部分。同一份 catalog,React、Vue、Svelte、Solid、React Native、Next.js、TanStack Start、Remotion 视频、React PDF、React Email、Ink 终端、react-three-fiber 的 3D 场景都能渲染。聊天场景用 @json-render/chat,自带标准组件定义和 streamCard:

chat.onNewMention(async (thread, message) => {
  const result = streamText({
    model: "anthropic/claude-haiku-4.5",
    system: catalog.prompt(),
    prompt: message.text,
  });
  await streamCard(thread, result.textStream);
});

流式输出靠 SpecStream。createSpecStreamCompiler 接收模型吐出的 chunk,返回当前结果和新补丁,UI 跟着更新。

还带了 36 个预制的 shadcn/ui 组件,MCP 集成(Claude、ChatGPT、Cursor、VS Code),一个 devtools 面板,Ctrl/Cmd + Shift + J 呼出,生产环境会被 tree-shake 掉。仓库在这里:https://github.com/vercel-labs/json-render

好看之外的事

Vercel 团队的 Kyle Ledbetter 在回复里说 that's cool as hell。另一条回复更值得看。Lane Henslee 写的是:幻觉出来的收入数字,配上原生表格和图表,看起来会官方得多。

这句话说到点上。纯文本里一个明显离谱的数字,读者会停一下。放进一张排版规整、字段齐全的卡片里,那点犹豫就没了。生成式 UI 让输出更可信,同时也让错误的伪装成本更低。

有人在回复里问,为什么不用现成的 OpenUI,要再造一个标准。这个问题 README 里没有回答。

还有人问,卡片还在流式输出的时候,用户能不能点按钮,动作是等渲染结束还是立刻触发。这类交互边界在文档里写得不多。

Vercel Labs 一贯的做法是快速放出小实验包,demo 好看,能跑,然后看社区接不接。这个包大概也一样。要不要用,取决于你能不能接受一个前提:把 UI 生成权交给模型,同时相信自己的 catalog 边界足够严。边界一松,模型造出来的界面,比它说出来的话更容易骗到人。

发布时间: 2026-11-08 03:35