在开发 AI 应用时,单纯的文本生成往往不够用。不管是开发自动化发布工具、智能体(Agent)还是内容生成流水线,我们通常需要让大模型输出严格的结构化数据(比如 JSON)。这样才能确保系统能够稳定地解析信息并与下游业务逻辑(如数据库操作或 API 调用)对接。
Vercel AI SDK 在最新的 v6 版本中,对结构化数据生成进行了重磅升级,将其无缝集成到了 generateText 和 streamText 工作流中。本文将带你深入了解如何使用 Vercel AI SDK 生成结构化数据,并结合智谱 AI 最新模型 (GLM-4-Plus) 提供开箱即用的实战代码。
🌟 核心概念更新:告别 Legacy API
如果你以前用过 AI SDK,可能对 generateObject 和 streamObject 很熟悉。注意,这两个方法现在已经被标记为 Legacy(弃用) 。
在最新的标准中,AI SDK 统一了文本和结构化生成的入口。你现在只需要在 generateText 或 streamText 中配置 output 属性即可。这样做的好处是:结构化输出现在可以和工具调用(Tool Calling)在同一个请求中结合使用了!
🛠️ 准备工作:接入智谱 AI
AI SDK 原生支持通过 OpenAI 兼容接口接入第三方大模型。由于我们要使用智谱最新的 GLM-5,只需利用 @ai-sdk/openai 并修改 BaseURL 即可完成配置。
Bash
npm install ai @ai-sdk/openai zod
创建一个智谱 provider 实例:
TypeScript
// zhipu-provider.ts
import { createOpenAI } from '@ai-sdk/openai';
// 配置智谱 AI (兼容 OpenAI API 格式)
export const zhipu = createOpenAI({
baseURL: 'https://open.bigmodel.cn/api/paas/v4/',
apiKey: process.env.ZHIPU_API_KEY, // 填入你的智谱 API Key
});
// 选用智谱最新旗舰模型
export const model = zhipu('glm-5');
📦 1. 生成单体结构化对象:Output.object()
使用 Output.object({ schema }) 可以基于 Zod 定义的数据验证格式,强制模型输出符合要求的数据。这在做社交媒体自动生成工具时非常实用。
实战场景: 自动生成一篇带有标题、标签和正文的社交平台(如小红书/抖音)爆款文案。
TypeScript
import { generateText, Output } from 'ai';
import { z } from 'zod';
import { model } from './zhipu-provider';
async function generateSocialPost() {
const { output } = await generateText({
model,
// 定义严格的输出 Schema
output: Output.object({
schema: z.object({
post: z.object({
title: z.string().describe('吸引眼球的爆款标题,带有适当的 Emoji'),
content: z.array(z.string()).describe('正文分段落,每句话需要有网感'),
tags: z.array(z.string()).describe('相关话题标签,如 #AI #效率工具'),
}),
}),
}),
prompt: '请帮我写一篇介绍 "Vercel AI SDK 新特性" 的社交媒体种草笔记。',
});
console.log(output.post.title);
console.log(output.post.tags.join(' '));
// 这里的 output 已经被 Zod 严格校验过,具备完整的 TypeScript 类型提示!
}
generateSocialPost();
💡 技巧:利用 .describe() 为字段添加描述,可以大幅提升模型生成格式的准确率。
📚 2. 生成结构化数组:Output.array()
当你期望模型返回一个列表(例如批量生成选题、提取多个实体)时,Output.array({ element }) 是最佳选择。
TypeScript
import { generateText, Output } from 'ai';
import { z } from 'zod';
import { model } from './zhipu-provider';
async function generateTopics() {
const { output } = await generateText({
model,
output: Output.array({
// 只需要定义数组内部单个元素的 Schema
element: z.object({
topic: z.string(),
difficulty: z.enum(['初级', '中级', '高级']),
estimatedWordCount: z.number(),
}),
}),
prompt: '请列出 3 个关于 AI Agent 开发的教程选题。',
});
// 返回结果直接是一个类型安全的数组
console.dir(output, { depth: null });
}
⚡ 3. 流式输出结构化数据:streamText
在交互式应用中,等待大模型生成完整的 JSON 可能需要几秒钟甚至更久。通过 streamText,我们可以流式地获取并渲染结构化数据!
场景 A:流式解析部分对象 (partialOutputStream)
当使用 Output.object 时,你可以获取正在逐步构建的 JSON 对象。
TypeScript
import { streamText, Output } from 'ai';
import { z } from 'zod';
import { model } from './zhipu-provider';
async function streamSocialPost() {
const { partialOutputStream } = streamText({
model,
output: Output.object({
schema: z.object({
title: z.string(),
paragraphs: z.array(z.string()),
}),
}),
prompt: '写一段关于"为什么需要本地部署 LLM"的短文。',
});
// 使用异步迭代器实时读取增量生成的对象
for await (const partialObject of partialOutputStream) {
console.clear();
console.log('正在生成...', partialObject);
}
}
场景 B:流式解析数组元素 (elementStream)
当使用 Output.array 时,你可以通过 elementStream 在每一个数组元素生成完毕并校验通过后立即拿到它,这非常适合流式渲染卡片列表。
TypeScript
const { elementStream } = streamText({
model,
output: Output.array({
element: z.object({ name: z.string(), description: z.string() })
}),
prompt: '生成 5 个开源大模型的名称和简介。'
});
for await (const modelInfo of elementStream) {
// 每当一个完整的 modelInfo 生成完,就会触发一次
console.log('✅ 生成完毕:', modelInfo.name);
}
🎯 4. 更多 Output 策略
除了对象和数组,SDK 还提供了灵活的内置方案:
-
Output.choice({ options }):用于分类或意图识别。强制模型从你给定的字符串数组中选一个。TypeScript
output: Output.choice({ options: ['技术向', '情感向', '干货向'] }) -
Output.json():当你不需要严格的 Schema 校验,只希望模型返回合法的任意 JSON 结构时使用。 -
Output.text():纯文本输出(这也是默认行为)。
🛡️ 异常处理:拦截非法输出
虽然加上了 Schema 限制,但大模型偶尔还是会“翻车”(比如输出无法解析的 JSON)。AI SDK 提供了专门的 NoObjectGeneratedError 用于捕获这类异常。
TypeScript
import { generateText, Output, NoObjectGeneratedError } from 'ai';
try {
await generateText({
model,
output: Output.object({ schema: yourSchema }),
prompt: '...',
});
} catch (error) {
if (NoObjectGeneratedError.isInstance(error)) {
console.error('模型未能生成有效对象!');
console.error('原始文本:', error.text); // 模型实际输出的文本
console.error('失败原因:', error.cause); // 比如 JSON 解析错误
}
}
(对于 streamText,可以在配置中传入 onError({ error }) 回调来处理流中的异常,从而防止应用崩溃。)
总结
Vercel AI SDK v6 通过将 Output 深度整合进 generateText / streamText,极大降低了我们处理大模型结构化数据的门槛。结合 Zod 的类型推导与智谱等优秀大模型的泛化能力,开发者可以非常丝滑地构建基于 AI 的自动化流程和多端智能应用。
如果你觉得这篇教程有帮助,别忘了点赞收藏!快把这套方案应用到你的下一个 AI 项目中吧!🚀