AI 结构化输出指南:JSON Mode、Function Calling 与 Pydantic 实战
在将大语言模型(LLM)集成到实际应用中时,最大的挑战之一是不确定性。LLM 喜欢“聊天”,但程序需要的是“数据”。
如果你的 AI 应用经常因为 AI 返回了 Here is your JSON: 前缀而导致解析失败,或者字段类型不匹配,那么这篇文章就是为你准备的。我们将深入探讨几种强制 LLM 输出结构化数据(Structured Output)的方法。
为什么需要结构化输出?
LLM 默认输出的是文本字符串。但在 RAG(检索增强生成)、Agent 或数据处理场景中,我们需要 JSON、YAML 或 XML 等格式,以便:
- 对接 API:将输出直接传给后端接口。
- 数据存储:存入数据库。
- 前端渲染:直接渲染为 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" } 参数。
使用条件:
- API 请求中设置
response_format。 - 必须在 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);
常见坑与最佳实践
- Retry 机制: 即使有 JSON Mode,偶尔也会出错。建议在
try-catch解析失败时,自动将错误信息喂回给 AI 让其“修复”。 - 枚举值约束: 在 Schema 中使用
enum限制字段值(如情感分类只能是positive,negative)。 - 注释即文档: 在 Pydantic/Zod 中添加
.describe("xxx"),这些描述会被传给 AI,帮助它理解字段含义。
总结
- 简单任务 + 通用模型 -> Prompt Engineering
- 需要 JSON 格式但不定字段 -> JSON Mode
- 需要严格字段与类型 -> Function Calling / Zod / Pydantic
结构化输出是构建可靠 AI Agent 的基石。掌握了这一点,你就从“和 AI 聊天”进阶到了“用 AI 编程”。


