W
AI-Wiki
CONCEPT

SpecStream

定义

SpecStream 是 json-render 内置的流式 JSON Spec 编译与处理能力,用于接收 LLM 的分块输出,并把这些片段增量解析为可被渲染器使用的界面描述。

json-render 的设计中,AI 不直接写 JSX、Vue 组件或任意前端代码,而是在开发者预先定义的 组件目录(Catalog) 与 schema 护栏内生成结构化 JSON Spec。SpecStream 负责处理“模型还没有完整输出整个 JSON Spec,但已经陆续吐出若干块内容”的场景,使系统可以边接收、边解析、边尝试渲染。

一句话说,SpecStream 让 生成式 UI 从“等模型完整想完再一次性出界面”,变成“模型每生成一段合法结构,界面就可以渐进出现”。

在本文档中的语境

SpecStream 出现在介绍 json-render 核心功能的“流式渲染:SpecStream 边生成边画”部分。原文把它描述为 json-render 的内置能力:模型每吐出一块 JSON,界面就渐进渲染一块,体验类似 ChatGPT 的打字机式输出。

这里的“打字机式输出”不是指简单地把文字一字一字显示出来,而是指 AI 输出的对象变成了可渲染的界面结构。也就是说,流式传来的不是普通 Markdown 或纯文本,而是 JSON Spec 的片段;这些片段经过增量编译后,会被 Renderer 用来生成真实 UI。

它解决的问题

直接让模型完整生成界面描述再渲染,主要会遇到两个问题:

  • 体验卡顿:如果必须等 LLM 完整生成整个界面 JSON、系统完整解析、再交给渲染器,用户只能长时间看空白或 loading。界面越复杂、模型输出越长,等待感越明显。
  • 结构不可预测导致难以安全流式渲染:如果不加约束地让模型直接输出 UI 代码、JSX 或任意结构,系统无法可靠判断当前片段是否安全、是否能渲染、是否会幻觉出不存在的组件,甚至可能引入 XSS 等风险。
  • 生成式 UI 既要灵活又要确定:模型擅长“涌现”和自由组合,但界面工程要求组件、属性、动作和数据绑定都可预测。SpecStream 的价值就在于把流式体验和 schema 约束结合起来。

因此,SpecStream 并不是单纯为了“更快显示文字”,而是为了让 AI 生成的界面可以在受控结构中渐进出现,降低等待感,同时避免把不可预测的模型输出直接交给前端执行。

关键 API

原文明确提到的流式编译 API 是:

createSpecStreamCompiler().push(chunk)

其中:

  • createSpecStreamCompiler() 用于创建 SpecStream 编译器;
  • push(chunk) 用于把模型流式输出的一块 JSON 文本片段推入编译器;
  • 编译器会在每次收到 chunk 后尝试增量解析;
  • 当已有内容形成合法、可理解的 Spec 结构时,Renderer 就可以根据当前可用的部分渐进渲染界面。

这个 API 的重点是“逐块解析模型输出”,而不是等待 LLM 结束后再把完整 JSON 一次性 JSON.parse

工作方式

SpecStream 的典型工作流程可以分为五步:

  1. 开发者先用 组件目录(Catalog) 定义 AI 能使用哪些组件、能绑定哪些数据、能触发哪些动作,并用 schema 描述合法 JSON Spec 的结构。
  2. 系统通过 catalog 生成提示词,要求模型只在该目录和 schema 允许的范围内输出 JSON Spec。
  3. LLM 开始流式输出 JSON。输出不是一次性完成,而是分成多个 chunk 陆续返回。
  4. 每当模型吐出一块 JSON,调用 createSpecStreamCompiler().push(chunk) 把该片段送入 SpecStream 编译器。
  5. 编译器尝试增量解析当前累计内容;当某些部分已经形成合法 spec,Renderer 就可以据此渐进渲染界面。

在这个过程中,界面可以逐步从无到有:例如先出现外层布局,再出现卡片、指标、按钮等组件,最后补齐数据绑定、条件显示或交互动作。用户看到的是一个逐渐成形的 UI,而不是长时间等待后突然出现完整界面。

与 Catalog 和 schema 的关系

SpecStream 不是绕过 组件目录(Catalog) 或 schema 校验的捷径。相反,它是在流式过程中继续服从 json-render 护栏设计的一部分。

json-render 的整体架构中,开发者会把 AI 可用的组件、动作、数据绑定能力登记到 Catalog,并用基于 zod 的 schema 定义 JSON Spec 的合法结构。模型只能在这个白名单内生成结构化描述,Renderer 再把 JSON Spec 映射到真实组件。

SpecStream 的边界是:

  • 它允许 LLM 分块输出 JSON Spec;
  • 它允许系统对这些分块做增量解析;
  • 它允许 Renderer 基于已经形成的合法部分渐进渲染;
  • 但它不允许最终结果偏离开发者定义的 schema;
  • 它也不意味着模型可以生成任意 UI 代码或调用未登记组件。

原文在功能表中把 SpecStream 的一致性描述为“输出永远严格匹配你定义的 schema”。这说明流式渲染能力与 schema 约束是绑定的:流式只是改变输出和渲染的时机,不改变安全边界。

与普通文本流式输出的区别

SpecStream 的体验可以类比 ChatGPT 打字机式输出,但两者处理对象不同:

对比项ChatGPT 文本流式输出SpecStream
输出对象普通文本、Markdown 或代码文本JSON Spec 的分块片段
用户看到的结果文本逐字或逐段出现UI 结构逐步成形
解析目标文本展示为主增量编译为可渲染界面描述
约束方式通常依赖提示词和后处理仍要求匹配 Catalog/schema
风险控制文本显示风险较低,但代码执行需额外防护通过组件白名单和 schema 限制可渲染内容

因此,SpecStream 更接近“结构化界面的流式编译器”,而不是普通的 token 流展示组件。

细节与边界

  • SpecStream 面向的是 AI 输出的 JSON Spec,不是让 AI 直接输出并执行 JSX、HTML 或脚本。
  • 它解决的是生成式 UI 的流式体验问题:避免用户等待模型完整输出界面描述后才能看到结果。
  • 它仍然依赖 json-render 的 Renderer 将 JSON Spec 转换为真实 UI;SpecStream 本身不是组件库,也不是最终渲染器。
  • 它与开发者定义的 Catalog/schema 配套使用;没有受控组件目录和结构约束,流式解析就难以保证安全和可预测。
  • 它适用于任意支持流式输出的 LLM 接入路径。原文说明开发者可以调用 catalog.prompt() 生成系统提示词,把任意 LLM 的流式输出喂给 SpecStream,并不需要绑定 Vercel 自家服务。
  • 它的“渐进渲染”并不等于每个 chunk 都一定立刻变成可见 UI;只有当片段已经形成合法、可理解的 spec 部分时,Renderer 才能据此更新界面。

在 json-render 架构中的位置

SpecStream 位于“AI 生成 JSON Spec”和“Renderer 渲染 UI”之间,是连接模型流式输出与受控界面渲染的中间层。

整体链路可以表示为:

用户 Prompt → AI + Catalog → 流式 JSON chunk → SpecStream 编译器 → 合法 JSON Spec → Renderer → 真实 UI

其中 Catalog 决定 AI 能生成什么,SpecStream 决定这些生成内容如何被流式接收和增量编译,Renderer 决定如何把合法 spec 映射到 React、Vue、Svelte、React Native、Ink 等具体运行环境中的真实组件。

相关条目