在 AI 应用开发的早期(也就是一两年前),我们让 AI 生成 JSON 数据通常是场噩梦。
我们不得不在 Prompt 里写上 "Please reply with valid JSON only, no markdown code blocks",然后战战兢兢地拿到结果,用 JSON.parse() 去解析。一旦 AI 多说了一句废话,或者少写了一个括号,整个应用就会崩掉。
但在 2025 年的今天,使用 Next.js + Vercel AI SDK,我们终于有了优雅的解决方案:Structured Outputs(结构化输出)。
今天记录一下如何利用 zod 和 generateObject 让 AI 乖乖按格式干活。
为什么我们需要结构化输出?
当我们想把 AI 集成到实际业务流中(比如自动生成 SEO 标题、提取简历信息、生成图表数据)时,我们需要的是机器可读的数据,而不是一段聊天记录。
以前的流程:
<u>Prompt -> AI 返回字符串 -> 正则提取/清洗 -> JSON.parse -> 祈祷不报错 -> 使用</u>
现在的流程:
<u>Schema 定义 -> AI 返回类型安全的对象 -> 直接使用</u>
核心实现:Schema 即 Prompt
在 Vercel AI SDK 中,核心魔法在于 generateObject 方法配合 zod schema
1. 定义“蓝图” (The Blueprint)
z.object 不仅仅是用来做数据验证的,它的 .describe() 方法其实是写给 AI 看的“微型提示词”。
import { z } from 'zod';
// 定义我们想要的数据结构
const SeoSchema = z.object({
// 字段定义 + 提示词指令
seoTitle: z.string().describe(
'SEO 优化的文章标题。要求:长度 25-50 字符,核心关键词靠前,采用"主标题 + 价值"格式。'
),
slug: z.string().describe(
'URL 路径。要求:纯小写英文单词,用连字符连接,严禁使用拼音,去除无意义介词。'
),
tags: z.array(z.string()).describe(
'3-5 个相关的技术标签'
)
});
2. 执行生成 (The Execution)
在 Next.js 的 Server Action 或 Route Handler 中调用:
import { generateObject } from 'ai';
import { deepseek } from '@ai-sdk/deepseek'; // 或 openai
export async function POST(req: Request) {
const { content } = await req.json();
const result = await generateObject({
model: deepseek('deepseek-chat'),
schema: SeoSchema, // <--- 把蓝图传给 AI
prompt: `请分析以下内容并生成 SEO 信息:\n${content}`,
temperature: 0.3,
});
// 重点:这里不需要 JSON.parse()
// result.object 已经是完全类型安全的 TypeScript 对象了!
return Response.json(result.object);
}
深入理解:Schema 的双重作用
这段代码之所以优雅,是因为 z.object 承担了两个角色:
1、给 AI 看 (Prompting): SDK 会自动把 schema 转换成 JSON Schema 格式发给大模型。模型看到 describe 里的 "严禁使用拼音",就会严格执行。这比在长文本 Prompt 里写规则效果好得多。
2、给代码看 (Typing): result.object 会自动获得 TypeScript 类型推导。在写前端代码时,编辑器会自动提示 .seoTitle 和 .slug,开发体验极佳。