SuperAPI AI 工具集

tanstack-ai-core-structured-outputs

编程与开发

查看项目

更新于 10-16 09:23

技能介绍

用途

本技能用于让大语言模型返回符合预定义 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 同时流式,会回退到非流式路径。
  • 具体价格、平台支持范围等未在资料中提供。