考察点
这是阿里系面试题库里出现过原题的高频题(「如何设计一个 Prompt,确保模型输出严格的 JSON 格式」)。面试官想看的分层很清楚:只会答「在 Prompt 里要求输出 JSON」的是初级;能讲出约束解码原理、解析失败兜底策略的才是做过生产的。追问方向:模型还是输出非法 JSON 怎么办、Function Calling 和 JSON mode 什么区别。
参考答案
第一档:Prompt 层约束
基础但必要。三件事:给出完整 JSON Schema 或字段清单;给一个输入输出示例(few-shot 对格式对齐效果极好);加负面指令——「不要输出 JSON 以外的任何文字,不要用 markdown 代码块包裹」。其中第三条很重要,模型特别爱在 JSON 外面套 ```json 栅栏或者加一句「以下是结果」。
Prompt 层能到 95% 以上的合规率,但剩下的几个百分点对程序集成是致命的——json.loads 一次失败就是一次线上异常。所以它只是起点。
第二档:API 层能力
- JSON mode:OpenAI、通义千问等主流 API 都提供
response_format={"type": "json_object"},服务端保证输出是合法 JSON(保证语法合法,不保证字段符合你的 Schema)。 - Function Calling / Tool Use:把目标结构定义成工具的
parametersSchema,模型输出结构化参数。这本质是让模型走训练时专门强化过的结构化通道,合规率比裸 Prompt 高得多,还能拿到字段级的类型保证。 - 约束解码(Constrained Decoding):最强的一档。vLLM 的 guided decoding、Outlines、lm-format-enforcer 这类方案,把 JSON Schema 编译成状态机,解码时每个 token 位置只允许符合 Schema 的词表子集——从机制上 100% 合法,不可能输出非法 JSON。代价是可选 token 被剪枝,对生成质量有轻微影响,且需要自建推理服务才能用。
第三档:解析端兜底
不管前面用了哪档,消费端都假设输出可能坏,这是工程师的基本素养:
- 预处理:截取第一个
{到最后一个}之间的内容,剥掉代码块栅栏。 - Schema 校验:用 Pydantic(Python)或 zod(TS)做字段级校验,类型错误、缺字段、枚举越界都能拦下来,比裸
json.loads能发现问题。 - 修复重试:校验失败时,把报错信息和原始输出一起回喂给模型让它修——「你上次输出缺了字段 reason,请只输出修正后的完整 JSON」。一次重试能救回绝大部分失败 case,重试两次还失败就走降级(人工队列或默认值)。
- 监控:格式失败率是个重要指标,Prompt 或模型版本变更后要盯它的回归。
设计层面的两个建议
Schema 尽量扁平。 嵌套三层以上的 JSON 出错率明显上升,能拍平就拍平;字段名用含义明确的英文,别用 a、b、c。
枚举值先在 Prompt 里穷举。 分类字段把可选值全部列出来并说明含义,否则模型会自造标签。我们踩过的坑:要求输出「投诉/咨询/建议」三选一,模型输出「complaint」,格式合法但下游路由直接崩。
可能的追问
- Function Calling 和 JSON mode 有什么区别? JSON mode 只保证合法 JSON;Function Calling 有 Schema 约束、字段级类型保证,且模型在训练时对工具调用格式专门强化过,合规率更高。需要严格结构优先 Function Calling。
- 约束解码会影响模型智力吗? 会有一点点——剪枝限制了模型的表达路径,复杂推理任务里可能感觉输出变「僵」。常见做法是推理内容自由生成,只在最终答案字段上约束。
- 流式输出场景怎么解析 JSON? 用增量 JSON 解析器(partial json parser)逐段拼装,或者改协议——SSE 按字段事件推送。别等流结束再解析,失去流式的意义了。