第三章:Structured Outputs:稳定 JSON 输出
——让 AI 输出程序能读懂的结果
在网页聊天里,AI 输出一段自然语言通常没问题。
但在程序里,这远远不够。
程序更喜欢确定的结构。
比如:
{
"name": "王女士",
"company": "云舟教育",
"need": "企业内部 AI 培训",
"budget_level": "中",
"urgency": "较急",
"next_action": "安排需求访谈"
}
这就是结构化输出。
你可以先这样理解:
自然语言适合人看。
结构化输出适合程序继续处理。
Structured Outputs 的目标,就是让模型尽量按照你定义的字段和结构输出。
固定输出格式不只是为了好看,而是为了让后续流程能继续自动处理。【主体课:第四章 固定输出格式】
一、为什么需要 JSON?
如果你让模型输出:
这个客户看起来比较着急,预算中等,可以尽快安排销售跟进。
人能看懂。
但程序很难稳定处理。
程序会问:
客户名在哪里?
预算等级是什么?
紧急程度字段叫什么?
下一步动作怎么提取?
如果模型输出 JSON,程序就可以直接读取字段:
budget_level
urgency
next_action
这就是结构化输出的价值。
二、先从普通 JSON Prompt 开始
在 AI Studio 里,你可以先用提示词要求 JSON:
请把下面客户线索整理成 JSON。
要求:
1. 只输出 JSON
2. 不要输出解释
3. 字段包括 name、company、need、budget_level、urgency、next_action
4. 如果信息缺失,字段值写 null
输入:
王女士,来自云舟教育,希望做企业内部 AI 培训,预算 10 万左右,希望下个月启动。
这已经比自然语言稳定很多。
但它仍然只是“提示词约束”。
模型有时可能会输出:
下面是 JSON:
或者加上 Markdown 代码块。
真正接程序时,最好使用 API 的结构化输出能力。
三、用 Schema 约束输出
在 API 中,可以通过 schema 定义你想要的结构。
你可以把 schema 理解成:
给模型的一张字段表。
比如销售线索分析结果:
{
"name": "string",
"company": "string",
"need": "string",
"budget_level": "low | medium | high | unknown",
"urgency": "low | medium | high | unknown",
"next_action": "string",
"questions": ["string"]
}
字段越清楚,程序越容易接。
四、Python 示例:结构化销售线索
示例:
from google import genai
from pydantic import BaseModel
from typing import List
class LeadAnalysis(BaseModel):
name: str | None
company: str | None
need: str
budget_level: str
urgency: str
next_action: str
questions: List[str]
client = genai.Client()
prompt = """
请分析下面销售线索。
规则:
- budget_level 只能是 low、medium、high、unknown
- urgency 只能是 low、medium、high、unknown
- 如果信息缺失,请写入 questions
输入:
王女士,来自云舟教育,希望做企业内部 AI 培训,预算 10 万左右,希望下个月启动。
"""
response = client.models.generate_content(
model="gemini-3.5-flash",
contents=prompt,
config={
"response_format": {
"text": {
"mime_type": "application/json",
"schema": LeadAnalysis.model_json_schema()
}
}
}
)
result = LeadAnalysis.model_validate_json(response.text)
print(result)
这段代码的重点不是语法细节。
重点是:
1. 先定义字段结构
2. 再让模型按结构输出
3. 最后用程序校验输出
五、Node.js 示例:结构化输出思路
Node.js 里也可以定义 JSON Schema。
示意:
import { GoogleGenAI } from "@google/genai";
const ai = new GoogleGenAI({});
const schema = {
type: "object",
properties: {
name: { type: "string", nullable: true },
company: { type: "string", nullable: true },
need: { type: "string" },
budget_level: {
type: "string",
enum: ["low", "medium", "high", "unknown"],
},
urgency: {
type: "string",
enum: ["low", "medium", "high", "unknown"],
},
next_action: { type: "string" },
questions: {
type: "array",
items: { type: "string" },
},
},
required: ["need", "budget_level", "urgency", "next_action", "questions"],
};
const response = await ai.models.generateContent({
model: "gemini-3.5-flash",
contents: `
请分析下面销售线索:
王女士,来自云舟教育,希望做企业内部 AI 培训,预算 10 万左右,希望下个月启动。
`,
config: {
responseFormat: {
text: {
mimeType: "application/json",
schema,
},
},
},
});
console.log(response.text);
不同 SDK 版本的参数写法可能会调整。
实际写项目时,以官方最新示例为准。
六、字段设计比代码更重要
结构化输出最容易犯的错误是:
只关心 JSON,忽略字段设计。
字段设计不好,输出再稳定也没用。
比如:
{
"result": "挺有意向,建议跟进"
}
这个 JSON 是合法的。
但没什么业务价值。
更好的结构是:
{
"intent_level": "high",
"budget_level": "medium",
"urgency": "medium",
"recommended_action": "schedule_call",
"reason": "客户有明确预算和启动时间",
"missing_info": ["具体参训人数", "培训形式"]
}
字段要服务后续流程。
如果后面要分配销售,就要有意向等级。
如果后面要进入 CRM,就要有客户字段。
如果后面要自动提醒,就要有跟进动作。
七、不要把所有东西塞进一个 JSON
新手会想一次性输出很多字段:
客户信息。
需求分析。
预算判断。
情绪分析。
风险预测。
合同建议。
跟进话术。
邮件草稿。
这样很容易变乱。
建议先分层:
第一层:基础信息
第二层:判断结果
第三层:下一步动作
第四层:可选说明
复杂任务可以拆成多个结构化输出。
不要让一个 JSON 承担所有业务。
八、结构化输出也要校验
即使使用 schema,也要在程序里校验。
比如:
1. 字段是否存在
2. 枚举值是否合法
3. 数字范围是否合理
4. 日期格式是否正确
5. 数组是否为空
6. 是否出现 null
不要以为模型输出了 JSON,就一定能直接进数据库。
AI 输出是候选结果。
程序校验是安全门。
练习 1:设计销售线索 JSON
字段至少包括:
name
company
need
budget_level
urgency
next_action
questions
测试 5 条输入。
练习 2:给字段加枚举值
把:
预算较高
预算一般
预算不清楚
改成:
low
medium
high
unknown
观察程序处理是否更简单。
练习 3:设计失败处理
如果输出 JSON 缺字段,你的程序应该:
1. 重试
2. 要求模型修复 JSON
3. 交给人工检查
4. 记录错误日志
写出你的处理策略。
1. 结构化输出是不是一定 100% 稳定?
不是。
它比普通 Prompt 稳定,但仍然要做程序校验和失败处理。
2. JSON 字段用中文还是英文?
建议用英文。
程序字段、数据库字段、API 字段通常用英文更方便。
显示给用户时再翻译成中文。
3. 能不能让模型直接输出数据库记录?
不建议直接写入数据库。
先输出结构化结果,程序校验后,再决定是否写入。
完成本章后,你应该确认:
1. 知道自然语言适合人看,JSON 适合程序处理。
2. 知道结构化输出可以提高程序接入稳定性。
3. 知道 schema 是字段结构约束。
4. 知道字段设计比“能不能输出 JSON”更重要。
5. 知道复杂任务不要塞进一个超大 JSON。
6. 知道结构化输出仍然需要程序校验。