用途
本技能用于让大语言模型返回符合预定义 JSON Schema 的结构化数据,而不是自由文本。通过在 chat() 或 useChat() 上提供 outputSchema,模型输出会被校验并推断为对应的 TypeScript 类型,无需手动类型断言。
依赖说明:本技能建立在 ai-core 之上,需先阅读 ai-core 了解关键规则;useChat 相关模式建立在 ai-core/chat-experience 之上,需先了解基础 hook 接口。
主要能力
- 支持 Zod、ArkType、Valibot 等 schema 库。
- 当提供
outputSchema时,chat()返回Promise<InferSchemaType<TSchema>>而非AsyncIterable<StreamChunk>,结果完全类型化。 - 添加
stream: true后返回StructuredOutputStream<InferSchemaType<TSchema>>,提供增量 JSON 片段以及最终校验后的对象。 - 支持嵌套 schema、可选字段、数组等复杂结构。
- 客户端
useChat({ outputSchema })提供partial(流式填充的 DeepPartial 对象)与final(校验后的完整对象)。 - 多轮对话中,每个助手回合都会生成独立的
StructuredOutputPart,历史记录可保留并渲染。
使用方式
基础结构化输出
import { chat } from '@tanstack/ai'
import { openaiText } from '@tanstack/ai-openai'
import { z } from 'zod'
const PersonSchema = z.object({
name: z.string().meta({ description: "The person's full name" }),
age: z.number().meta({ description: "The person's age in years" }),
email: z.string().email().meta({ description: 'Email address' }),
})
const person = await chat({
adapter: openaiText('gpt-5.2'),
messages: [{ role: 'user', content: 'Extract: John Doe is 30, john@example.com' }],
outputSchema: PersonSchema,
})
console.log(person.name) // "John Doe"
console.log(person.age) // 30
流式迭代
传入 stream: true 后,可异步迭代标准流式 chunk,并在终止事件中获取校验后的对象:
const stream = chat({
adapter: openaiText('gpt-5.2'),
messages: [{ role: 'user', content: 'Extract: John Doe is 30, john@example.com' }],
outputSchema: PersonSchema,
stream: true,
})
for await (const chunk of stream) {
if (chunk.type === 'CUSTOM' && chunk.name === 'structured-output.complete') {
chunk.value.object.name // string
chunk.value.object.age // number
}
}
终止事件为 { type: 'CUSTOM', name: 'structured-output.complete', value: { object: T, raw: string, reasoning?: string } }。
客户端渐进式 UI
服务端通过 SSE 返回流,客户端使用 useChat 并传入 outputSchema:
const { sendMessage, isLoading, partial, final } = useChat({
connection: fetchServerSentEvents('/api/extract-person'),
outputSchema: PersonSchema,
})
partial 为 DeepPartial<z.infer<typeof PersonSchema>>,随流式内容逐字段填充;final 在终止事件到达时填充为完整校验对象。注意 outputSchema 在客户端仅用于类型推断,实际校验在服务端进行。
多轮结构化对话
每个助手回合在 messages[i].parts 上携带自己的 StructuredOutputPart,历史回合保持可渲染。partial 与 final 派生自最新助手消息的 part,而非粘性状态。
适配器覆盖
@tanstack/ai-openai(Responses + Chat Completions):原生组合模式,schema 与 tools 一同接入常规 chatStream 调用。@tanstack/ai-anthropic(仅 Claude 4.5+):原生组合模式,output_config.format与 tools 在单次 beta Messages 调用中。旧版 Claude 回退。@tanstack/ai-gemini(仅 Gemini 3.x):原生组合模式,responseSchema与 tools 在单次 generateContentStream 中。Gemini 2.x 回退。@tanstack/ai-grok(仅 Grok 4 系列):原生组合模式,response_format: json_schema与 tools。Grok 2/3 回退。@tanstack/ai-openrouter:原生单请求流(旧版 structuredOutputStream 路径)。@tanstack/ai-groq:仅旧版 structuredOutputStream(不支持 tools,Groq API 拒绝 schema + tools + stream)。- 其他适配器(ollama、旧版 Claude、Gemini 2.x、Grok 2/3):回退为非流式 structuredOutput,发出单个
structured-output.complete事件。
原生组合模式与回退由适配器的可选方法 supportsCombinedToolsAndSchema(modelOptions) 标识。消费者代码在各提供商间保持一致,始终从 structured-output.complete 读取最终对象。
适用场景
- 脚本、服务端端点、CLI 中一次性输入提示、输出类型化对象。
- 需要逐字段填充的渐进式表单或实时卡片 UI。
- Node 或测试中直接迭代流。
- 用户跨多轮迭代结构化对象(如食谱构建器、工单细化)。
- 结合 tools 先收集信息再返回类型化对象。
限制与注意事项
- 客户端
outputSchema仅用于类型推断,校验在服务端执行。 - 使用
outputSchema时,不应再过滤 TextPart 来隐藏 JSON;结构化 JSON 增量已路由到专用的StructuredOutputPart。 partial与final派生自最新助手消息,不是跨回合的粘性状态;渲染历史需直接遍历messages。- 部分适配器不支持 schema 与 tools 同时流式,会回退到非流式路径。
- 具体价格、平台支持范围等未在资料中提供。