提示工程

怎么让模型稳定输出 JSON 等结构化结果?

91学AI·2026/7/26·11 阅读

考察点

这是大模型应用落地必考题,因为几乎所有工程系统都要程序解析模型输出。面试官想看你是否清楚各种手段的可靠性等级——尤其是否知道 prompt 约束和受限解码的本质区别(一个是「求模型」,一个是「改采样」),以及线上系统怎么做兜底。追问会往 function calling 原理、非法输出的重试策略走。

参考答案

手段的谱系:从软约束到硬约束

按可靠性从低到高,常用手段有这么几层:

1. Prompt 里描述格式。 最基础的做法:文字说明 schema,给一两个输出示例,要求「只输出 JSON,不要其他内容」。能覆盖大部分情况,但模型仍可能犯病:多加一句「好的,以下是结果」、字段名大小写漂移、输出截断导致 JSON 不闭合。只适合配合校验重试使用,不能单独依赖。

2. JSON mode。 各家 API 提供的模式(OpenAI 的 response_format={"type": "json_object"}),保证输出是合法 JSON,但不保证符合你的 schema——字段可能缺、类型可能错。注意它通常要求 prompt 里明确出现 JSON 字样,且只解决语法合法性。

3. Function Calling / Tool Use。 把目标结构定义成工具参数 schema 传给 API,模型输出结构化的 tool call。可靠性显著高于纯 prompt,因为模型在后训练阶段专门做过这类对齐。但这依然属于「模型自觉」层面,极端 case 下仍可能产出不符合 schema 的参数。

4. 受限解码(Constrained Decoding)。 真正的硬约束:解码每一步都用 schema(编译成有限状态机或 CFG)过滤词表,非法 token 概率直接置零,模型在数学上不可能输出非法结构。代表工具:Outlines、lm-format-enforcer、xgrammar(SGLang/vLLM 集成)。OpenAI 的 Structured Outputs(response_format 传 JSON Schema)底层也是这个思路,官方声称 schema 合规率接近 100%。自建推理服务(vLLM)可以直接开 guided_json 参数。

选型建议

场景推荐方案
调闭源 APIStructured Outputs 优先,不支持就 function calling
自建 vLLM/SGLangguided_json / xgrammar 受限解码
结构简单、成本敏感prompt 约束 + 校验重试
嵌套深、schema 复杂必须受限解码,别指望 prompt

工程兜底:校验 + 重试的正确姿势

即使用了硬约束,语义正确性仍要兜(字段合法但内容错)。标准做法:

  1. 拿到输出先 parse,parse 失败说明结构坏了。
  2. 用 pydantic 定义 schema 做校验,类型、枚举、必填字段一次查完。
  3. 失败时重试,关键是把错误信息喂回去:「你上次输出的 age 字段是字符串,应为整数,请修正后重新输出」。模型读到具体报错后修正率很高,通常一两轮内收敛。这比无脑重跑有效得多。
  4. 重试设上限(2-3 次),超限降级:转人工、返回兜底结果、或换更强模型重试。别让重试循环打爆延迟和成本。

几个实战细节

Schema 尽量扁平。嵌套三层以上、字段超过二三十个,模型的语义准确率会明显掉——结构合法但值填错的情况增多,这时候该考虑拆成多次调用分步填充。字段命名要语义清晰(user_agea1 好),模型是按语义填值的。枚举值在 schema 里用 enum 限定死,不要让模型自由发挥分类标签。流式输出场景下做增量 parse 有坑(半截 JSON 不合法),要么等完整输出再 parse,要么用支持增量解析的库。

最后一点:结构化输出场景的评测要把「schema 合规率」和「字段准确率」分开统计,前者看解码层,后者才是模型能力,混在一起你定位不了问题。

可能的追问

  • Function calling 底层是怎么实现的? 主流做法是后训练时加入大量工具调用格式的对齐数据,让模型学会在特定 token 序列下输出结构化参数;推理时 API 侧解析这段结构化文本。部分厂商还叠加了受限解码保证参数符合 schema。
  • 受限解码有代价吗? 有。每步解码要做状态机转移计算,schema 复杂时吞吐有可见损耗(xgrammar 这类新实现已经把开销压得很低);另外约束过死会轻微影响内容质量,比如强制极短字段可能让模型没空间表达。
  • 模型输出 JSON 老是截断怎么办? 先查 max_tokens 是否给足,长 schema 输出很容易超;其次减少不必要字段;还不行就把一个大 JSON 拆成多次小输出。截断本质是长度规划问题,不是格式问题。

评论 (0)

暂无评论,快来抢沙发吧!

91学AI

© 2026 91学AI · 按岗位学 AI 与大数据. All rights reserved.