返回博客

Next.js + Vercel AI SDK 实现稳定的结构化输出

2025-12-24
AI
4 分钟

在 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,开发体验极佳。

留言