AI 结构化输出指南:JSON Mode、Function Calling 与 Pydantic 实战

HTMLPAGE 团队
10 分钟阅读

深入解析如何让 LLM 稳定输出 JSON 数据,掌握 Schema 定义与校验技巧。

#JSON Output #OpenAI API #Structured Data

AI 结构化输出指南:JSON Mode、Function Calling 与 Pydantic 实战

在将大语言模型(LLM)集成到实际应用中时,最大的挑战之一是不确定性。LLM 喜欢“聊天”,但程序需要的是“数据”。

如果你的 AI 应用经常因为 AI 返回了 Here is your JSON: 前缀而导致解析失败,或者字段类型不匹配,那么这篇文章就是为你准备的。我们将深入探讨几种强制 LLM 输出结构化数据(Structured Output)的方法。

为什么需要结构化输出?

LLM 默认输出的是文本字符串。但在 RAG(检索增强生成)、Agent 或数据处理场景中,我们需要 JSON、YAML 或 XML 等格式,以便:

  1. 对接 API:将输出直接传给后端接口。
  2. 数据存储:存入数据库。
  3. 前端渲染:直接渲染为 UI 组件。

方法一:Prompt Engineering(基础版)

最简单的方法是在提示词中明确要求 JSON 格式,并给出一个“样本”。

Prompt 示例:

请分析以下用户评论的情感,并提取关键词。
即使评论是负面的,也请保持客观。

输出格式务必为严格的 JSON,不要包含 Markdown 代码块标记(```json)。

JSON 示例:
{
  "sentiment": "positive",
  "score": 0.9,
  "keywords": ["fast", "reliable"]
}

用户评论:这个产品太慢了,我很失望。

优点: 所有模型都通用。 缺点: 不稳定,模型可能会加废话,或者 JSON 格式错误(比如末尾多逗号)。

方法二:JSON Mode (OpenAI / DeepSeek)

现代模型(如 GPT-4o, DeepSeek-V3)通常支持 response_format: { type: "json_object" } 参数。

使用条件:

  1. API 请求中设置 response_format
  2. 必须在 System Prompt 中包含 "JSON" 字眼。

代码示例 (Node.js/OpenAI):

const completion = await openai.chat.completions.create({
  model: "gpt-4o",
  messages: [
    { role: "system", content: "You are a helpful assistant designed to output JSON." },
    { role: "user", content: "List 3 colors." }
  ],
  response_format: { type: "json_object" },
});

优点: 保证输出不仅是 JSON,而且语法有效。 缺点: 不校验 Schema(字段名可能乱写)。

方法三:Function Calling / Tool Use (进阶版)

Function Calling 最初是为了让 AI 调用外部函数,但它也是获取结构化输出的最强手段,因为它允许你定义严格的 Schema。

原理: 你假装有一个函数 save_data(data: MySchema),让 AI 去“调用”它,AI 生成的参数就是你想要的结构化数据。

Schema 定义 (JSON Schema):

{
  "name": "extract_info",
  "parameters": {
    "type": "object",
    "properties": {
      "username": { "type": "string" },
      "age": { "type": "integer" },
      "interests": { 
        "type": "array",
        "items": { "type": "string" }
      }
    },
    "required": ["username", "age"]
  }
}

优点: 强类型约束,支持嵌套结构。

方法四:Zod / Pydantic (工程化封装)

在实际开发中,手写 JSON Schema 很痛苦。我们可以使用 Zod (TypeScript) 或 Pydantic (Python) 来定义数据结构,配合 LangChain 或 Vercel AI SDK 自动转换。

TypeScript (Vercel AI SDK):

import { z } from 'zod';
import { generateObject } from 'ai';

const schema = z.object({
  recipe: z.object({
    name: z.string(),
    ingredients: z.array(z.object({
      name: z.string(),
      amount: z.string()
    })),
    steps: z.array(z.string())
  })
});

const { object } = await generateObject({
  model: openai('gpt-4o'),
  schema: schema,
  prompt: 'Generate a lasagna recipe.',
});

// object is fully typed here!
console.log(object.recipe.name); 

常见坑与最佳实践

  1. Retry 机制: 即使有 JSON Mode,偶尔也会出错。建议在 try-catch 解析失败时,自动将错误信息喂回给 AI 让其“修复”。
  2. 枚举值约束: 在 Schema 中使用 enum 限制字段值(如情感分类只能是 positive, negative)。
  3. 注释即文档: 在 Pydantic/Zod 中添加 .describe("xxx"),这些描述会被传给 AI,帮助它理解字段含义。

总结

  • 简单任务 + 通用模型 -> Prompt Engineering
  • 需要 JSON 格式但不定字段 -> JSON Mode
  • 需要严格字段与类型 -> Function Calling / Zod / Pydantic

结构化输出是构建可靠 AI Agent 的基石。掌握了这一点,你就从“和 AI 聊天”进阶到了“用 AI 编程”。