结构化输出真正改变了什么:从解析 JSON 到约束接口
结构化输出的价值不只是少写一次 JSON.parse,而是把模型结果变成可以验证、观测和演进的工程接口。
发布于 更新于
模型返回一段看起来像 JSON 的文本,并不等于系统获得了一个可靠对象。早期原型里,我们常在提示词末尾加一句“只输出 JSON”,然后删除 Markdown 围栏、尝试修复尾逗号,再把结果交给 JSON.parse。演示通常能跑通,但一旦输入变长、字段增多或模型拒答,修复逻辑就会迅速变成新的不确定性来源。
变化不在语法,而在接口
结构化输出把约束提前到生成阶段:调用方声明允许的字段、类型和枚举,模型在约束范围内组织结果。它并没有让内容天然正确,却把一类“格式能否被程序消费”的问题从提示词习惯变成了接口契约。
这一区分很重要。可靠性至少有三层:
- 语法可靠:结果能够被解析;
- 结构可靠:字段和类型符合约定;
- 语义可靠:字段里的判断与事实确实正确。
结构化输出主要解决前两层,第三层仍需要证据、规则或人工复核。把三层混为一谈,会让团队高估系统已经获得的保证。
一个最小的消费边界
下面的例子故意保留运行时校验。即使上游承诺遵循 schema,服务边界仍应验证数据,避免版本漂移或错误配置悄悄进入核心逻辑。
type Triage = {
priority: 'low' | 'normal' | 'high';
summary: string;
needsHuman: boolean;
};
export function acceptTriage(value: unknown): Triage {
if (!value || typeof value !== 'object') {
throw new Error('triage must be an object');
}
const item = value as Record<string, unknown>;
const priorities = new Set(['low', 'normal', 'high']);
if (!priorities.has(String(item.priority)) || typeof item.summary !== 'string') {
throw new Error('triage contract mismatch');
}
return item as Triage;
}
适合先落地的场景
我会优先把它放在分类、抽取、路由和工具参数生成这类任务中,因为输出空间相对清楚,失败也容易被检测。对于开放式写作或需要大量引用的研究任务,schema 只能整理结果的外形,不能替代来源核验。
上线前还应记录 schema 版本、验证失败次数、拒答分支和人工改写比例。只有这些信号被观测,团队才能判断变化究竟减少了多少胶水代码,又把多少失败转移到了语义层。
(示例内容,用于站点骨架验证)
原始来源:https://platform.openai.com/docs/guides/structured-outputs(在新窗口打开)