文档
CodeRabbit
Cloudflare
AG Grid
Netlify
Neon
WorkOS
Clerk
Convex
Electric
PowerSync
Sentry
Railway
Prisma
Strapi
Unkey
CodeRabbit
Cloudflare
AG Grid
Netlify
Neon
WorkOS
Clerk
Convex
Electric
PowerSync
Sentry
Railway
Prisma
Strapi
Unkey
类引用
函数引用
接口引用
类型别名引用
变量引用
指南

结构化输出

结构化输出允许您约束 AI 模型响应以匹配特定的 JSON 模式,从而确保一致且类型安全的数据提取。TanStack AI 使用 标准 JSON Schema 规范,允许您使用任何兼容的模式库。

概述

当您向 chat() 函数提供 outputSchema 时,TanStack AI 会

  1. 将您的模式转换为 JSON Schema 格式
  2. 将其发送到提供商的本机结构化输出 API
  3. 根据您的模式验证响应
  4. 返回完全类型化的结果

这对于

  • 从非结构化文本中提取结构化数据
  • 使用 AI 生成的内容构建表单或向导
  • 创建返回可预测 JSON 形状的 API
  • 确保 AI 响应与您的应用程序之间的类型安全

模式库

TanStack AI 使用 标准 JSON Schema,这意味着您可以使用任何实现该规范的模式库

  • Zod (v4.2+)
  • ArkType
  • Valibot (通过 @valibot/to-json-schema)
  • 纯 JSON Schema 对象

注意: 请参阅您的模式库的文档,了解有关定义模式和使用诸如 .describe() 之类功能的详细信息。TanStack AI 会自动将您的模式转换为 JSON Schema 格式。

基本用法

以下是如何使用 Zod 模式使用结构化输出

typescript
import { chat } from "@tanstack/ai";
import { openaiText } from "@tanstack/ai-openai";
import { z } from "zod";

// Define your schema
const PersonSchema = z.object({
  name: z.string().describe("The person's full name"),
  age: z.number().describe("The person's age in years"),
  email: z.string().email().describe("The person's email address"),
});

// Use it with chat()
const person = await chat({
  adapter: openaiText("gpt-5.2"),
  messages: [
    {
      role: "user",
      content: "Extract the person info: John Doe is 30 years old, email john@example.com",
    },
  ],
  outputSchema: PersonSchema,
});

// person is fully typed as { name: string, age: number, email: string }
console.log(person.name); // "John Doe"
console.log(person.age); // 30
console.log(person.email); // "john@example.com"

类型推断

chat() 的返回类型会根据 outputSchema 属性而变化

配置返回类型
没有 outputSchemaAsyncIterable<StreamChunk>
outputSchemaPromise<InferSchemaType<TSchema>>

当您提供 outputSchema 时,TanStack AI 会自动从您的模式中推断 TypeScript 类型

typescript
import { z } from "zod";

// Define a complex schema
const RecipeSchema = z.object({
  name: z.string(),
  prepTime: z.string(),
  servings: z.number(),
  ingredients: z.array(
    z.object({
      item: z.string(),
      amount: z.string(),
    })
  ),
  instructions: z.array(z.string()),
});

// TypeScript knows the exact return type
const recipe = await chat({
  adapter: openaiText("gpt-5.2"),
  messages: [{ role: "user", content: "Give me a recipe for scrambled eggs" }],
  outputSchema: RecipeSchema,
});

// Full type safety - TypeScript knows all these properties exist
recipe.name; // string
recipe.prepTime; // string
recipe.servings; // number
recipe.ingredients[0].item; // string
recipe.instructions.map((step) => step.toUpperCase()); // string[]

使用字段描述

模式字段描述有助于 AI 理解要提取的数据。大多数模式库都支持 .describe() 方法

typescript
const ProductSchema = z.object({
  name: z.string().describe("The product name"),
  price: z.number().describe("Price in USD"),
  inStock: z.boolean().describe("Whether the product is currently available"),
  categories: z
    .array(z.string())
    .describe("Product categories like 'electronics', 'clothing', etc."),
});

这些描述包含在发送到提供商的 JSON Schema 中,为 AI 提供有关每个字段的上下文。

复杂的嵌套模式

您可以定义深度嵌套的结构

typescript
const CompanySchema = z.object({
  name: z.string(),
  founded: z.number().describe("Year the company was founded"),
  headquarters: z.object({
    city: z.string(),
    country: z.string(),
    address: z.string().optional(),
  }),
  employees: z.array(
    z.object({
      name: z.string(),
      role: z.string(),
      department: z.string(),
    })
  ),
  financials: z
    .object({
      revenue: z.number().describe("Annual revenue in millions USD"),
      profitable: z.boolean(),
    })
    .optional(),
});

const company = await chat({
  adapter: anthropicText("claude-sonnet-4-5"),
  messages: [
    {
      role: "user",
      content: "Extract company info from this article: ...",
    },
  ],
  outputSchema: CompanySchema,
});

// Access nested properties with full type safety
console.log(company.headquarters.city);
console.log(company.employees[0].role);

与工具结合

结构化输出与代理工具循环无缝协作。当同时提供 outputSchematools 时,TanStack AI 将

  1. 执行完整的代理循环(根据需要运行工具)
  2. 完成之后,生成最终的结构化输出
  3. 返回经过验证的类型化结果
typescript
import { chat, toolDefinition } from "@tanstack/ai";
import { z } from "zod";

const getProductPrice = toolDefinition({
  name: "get_product_price",
  description: "Get the current price of a product",
  inputSchema: z.object({
    productId: z.string(),
  }),
}).server(async ({ input }) => {
  // Fetch price from database
  return { price: 29.99, currency: "USD" };
});

const RecommendationSchema = z.object({
  productName: z.string(),
  currentPrice: z.number(),
  reason: z.string(),
});

const recommendation = await chat({
  adapter: openaiText("gpt-5.2"),
  messages: [
    {
      role: "user",
      content: "Recommend a product for a developer",
    },
  ],
  tools: [getProductPrice],
  outputSchema: RecommendationSchema,
});

// The AI will call the tool to get prices, then return structured output
console.log(recommendation.productName);
console.log(recommendation.currentPrice);
console.log(recommendation.reason);

使用纯 JSON Schema

如果您不想使用模式库,可以传递纯 JSON Schema 对象

typescript
import type { JSONSchema } from "@tanstack/ai";

const schema: JSONSchema = {
  type: "object",
  properties: {
    name: { type: "string", description: "The person's name" },
    age: { type: "number", description: "The person's age" },
  },
  required: ["name", "age"],
};

const result = await chat({
  adapter: openaiText("gpt-5.2"),
  messages: [{ role: "user", content: "Extract: John is 25 years old" }],
  outputSchema: schema,
});

// Note: With plain JSON Schema, TypeScript infers `unknown` type
// You'll need to cast or validate the result yourself
const person = result as { name: string; age: number };

注意: 使用纯 JSON Schema 时,TypeScript 无法推断返回类型。结果将被类型化为 unknown。为了获得完整的类型安全,请使用 Zod 等模式库。

提供商支持

结构化输出通过其本机 API 受所有主要提供商的支持

提供者实现
OpenAI使用 response_formatjson_schema
Anthropic使用基于工具的提取
Google Gemini使用 responseSchema
Ollama使用带有模式的 JSON 模式

TanStack AI 会自动处理提供商特定的实现细节,因此您可以在不同的提供商中使用相同的代码。

最佳实践

  1. 使用描述性的字段名称和描述 - 这有助于 AI 理解要提取的数据

  2. 保持模式聚焦 - 仅提取您需要的数据;更简单的模式会产生更可靠的结果

  3. 适当使用可选字段 - 当数据可能不存在于源中时,将字段标记为可选

  4. 验证边缘情况 - 使用各种输入进行测试,以确保模式正确处理边缘情况

  5. 对受限值使用枚举 - 当字段具有有限的有效值集时,使用枚举

    typescript
    const schema = z.object({
      status: z.enum(["pending", "approved", "rejected"]),
      priority: z.enum(["low", "medium", "high"]),
    });
    

错误处理

如果 AI 响应与您的模式不匹配,TanStack AI 将抛出验证错误

typescript
try {
  const result = await chat({
    adapter: openaiText("gpt-5.2"),
    messages: [{ role: "user", content: "..." }],
    outputSchema: MySchema,
  });
} catch (error) {
  if (error instanceof Error) {
    console.error("Structured output failed:", error.message);
  }
}

该错误将包括有关哪些字段验证失败的详细信息,帮助您调试模式不匹配。