大模型结构化输出怎么做才稳:从字段约束到后处理校验

大模型结构化输出怎么做才稳:从字段约束到后处理校验

只要把大模型接进程序里,迟早会遇到同一个问题:它偶尔会“多说一句”。你要求返回 JSON,它在外面裹一层“好的,以下是结果:”;你要求三个字段,它自作主张加了个备注。人在界面上看着无所谓,程序解析时就是一次失败。

这篇不谈怎么把提示词写得更漂亮,只谈工程上怎么把输出变稳。核心结论是:别指望单一环节解决,要靠三层叠加。

第一层:把约束写成“字段契约”,而不是自然语气

少写“请务必返回标准 JSON”,多写可以直接照抄的契约:

只输出一个 JSON 对象,不要任何前后文字、不要代码块围栏。对象必须且只能包含以下字段:
- title: string,不超过 30 字
- score: integer,范围 0–100
- reasons: string 数组,长度 2–4
字段缺失时填空值,不要新增字段。

关键在三点:给出字段清单与类型、给出取值范围、明确缺失时怎么办。最后一条最常被漏掉,而模型“自作主张补字段”多半就是因为没告诉它缺数据该如何表现。

第二层:给一个反例,比给三个正例有用

样例(few-shot)大家都用,但对结构化输出来说,一个典型错误样例的收益往往更高。把“带解释文字的返回”“字段名写成中文”“数组里混了对象”这类真实踩过的错摆出来,标注“以下均为不合格输出”。模型对边界的敏感度会明显提高。

做接口相关的批处理时,我习惯先去 BackendWiki 的接口与数据格式章节 把字段定义抄准,再写进契约里。字段命名这一层如果不严谨,后面三层都救不回来。

第三层:后处理校验,把“偶发失败”变成可控分支

再稳的提示词也不能当校验用。程序侧至少要做三件事:

  1. 剥离:去掉首尾可能存在的说明文字与代码块围栏,再尝试解析。
  2. 校验:按契约逐字段检查类型、必填、范围;不合格直接判为失败,不要让下游猜。
  3. 有限重试:失败时把具体错误回传给模型(例如“score 返回了字符串,需要 integer”),最多重试两次;仍失败则走人工或降级结果。

这里有个细节:重试时要把解析器的报错原文带上,而不是笼统说“格式不对,请重新输出”。带具体错误,一次重试的成功率会高很多。

关于“保不保险”的预期管理

三层叠加之后,通常能把格式失败率压到很低,但不是零。所以设计上要接受“会有失败”,把失败当成正常分支处理,而不是当成异常去祈祷不发生。这也是我把它叫“契约 + 校验”而不是“提示词技巧”的原因:一个属于工程,一个属于表达。

顺带一提,同样的思路也适用于给静态页面生成结构化数据。HTML 入门教程站讲的 sitemap 与结构化数据实践 其实是一回事:内容由模型生成,结构由校验保证,两者分开才稳。

小结

字段契约负责“说清楚要什么”,反例负责“划清边界”,后处理校验负责“不把希望寄托在模型自觉上”。三层都不复杂,但缺任何一层,线上都会在某个深夜给你一次惊喜。