让模型稳定输出 JSON 的几个层次
层次一:提示里写清 schema
给出字段名、类型、是否可空,最好带一个完整示例:
只输出一个 JSON 对象,不要 Markdown 代码围栏,不要任何解释文字。
结构:
{"title": string, "tags": string[], "score": number}
这一层能解决大部分场景,但不保证。总会有一小部分输出带前后缀或多余换行。
层次二:解析时容错
不要假设输出永远干净。常见处理:
- 去掉
```json和```围栏 - 取第一个
{到最后一个}之间的子串 - 解析失败就重试一次,并在重试时把错误信息一起喂回去
try {
return JSON.parse(raw);
} catch {
const m = raw.match(/\{[\s\S]*\}/);
if (m) return JSON.parse(m[0]);
throw new Error("unparseable");
}
"解析失败重试"这个动作能覆盖掉一大半偶发问题,成本极低。
层次三:用结构化解码约束
要真正稳定,靠提示是不够的,得在生成时限制候选 token:
- 支持 function calling / tool use 的接口,把参数定义交给 API
- 支持 JSON Schema 约束(结构化输出)的接口
- 本地推理可以用语法约束解码(grammar-constrained decoding),直接把输出空间限制成合法 JSON
这一层是数学上保证输出符合 schema,不依赖模型听话。
怎么选
| 场景 | 层次 |
|---|---|
| 内部脚本、偶尔跑一次 | 一 + 二 |
| 线上服务、结果直接入库 | 二 + 三 |
| 输出要进强类型系统 | 必须三 |
一个提醒
即使 schema 完全合法,语义也可能错 —— 字段都在、类型都对,但值是编的。格式校验和事实校验是两件事,别把前者当成后者的保证。
本文为个人学习记录,可能存在错误或已过时,仅供参考。
← 返回笔记列表