这个问题其实本质是在问,怎么让大模型规规矩矩地吐出我们想要的JSON,而且每次都能稳定输出。我理解它的核心挑战是,大模型本质上是概率生成,但JSON是个严格的格式,所以需要从解码、提示、后处理、甚至模型选型几个层面合力解决。
先说解码层,这是最硬核的手段。现在像OpenAI的JSON Mode,或者开源的Outlines、Guidance这类库,都是在token级别做约束,比如生成的时候只允许合法的JSON token通过,括号引号逗号这些语法错误直接就过滤掉了。你可以把它想象成给模型戴了个脚镣,只能在JSON的文法范围内跳舞。要区分JSON mode主要管语法与strict schema管支持的结构规则;是否完成、拒绝或截断需另判,延迟开销依实现和schema实测。
支持这些规则的strict schema可约束必填字段、类型与枚举;它不能证明金额、身份、引用等业务事实正确。所以第二层就是提示工程。我会在prompt里把Schema写清楚,比如字段名、类型、枚举值、必填还是可选,再给两三个完整的输入输出示例。这里有个技巧,我会让模型输出先以{开头,并且在最后加一句“只返回JSON,不要任何解释”,这样能减少很多噪声。不过提示工程是软约束,模型可能不听话,所以不能完全依赖。
第三层是后处理兜底。实际线上跑的时候,模型偶尔还是会输出截断或者带markdown的JSON。我会用正则或者栈匹配把JSON块提取出来,然后走Pydantic校验。如果语法不对,可尝试格式修复后重新严格校验;字段缺失时只允许协议明确的默认值,关键业务字段不能猜补,应有界重试或返回失败/复核。重试的时候我会把上一次的错误信息塞回prompt,让模型自己修正,效果往往不错。这里有个坑:重试次数不能太多,否则延迟和成本受不了,我一般设两到三次。
再说模型选型。不能仅凭Code系列名称就断言比通用模型更强,应在目标schema和业务题集上比较合法完成率、任务准确率、延迟与成本,再选所需的strict接口或本地文法能力。另外,如果业务场景很固定,也可以用[[SFT]]微调,构造一批带Schema的JSON数据让模型专门学。
真正落地的时候,我不会只用一种方法,而是分层组合:解码层保语法,提示工程降低歧义,后处理做容错,模型选型提上限。举个例子,比如做一个客服退款接口,需要模型输出{reason, amount, decision}这样的JSON。我会先用Grammar-based Decoding确保括号引号没错,然后在prompt里给一个“退款原因只能是枚举值”的Schema,最后再加一层业务规则校验,比如金额不能为负。如果校验失败,就带错误信息重试一次。
不过这里有个容易被忽略的前提:约束解码和提示工程的效果很大程度上取决于Schema设计得好不好。如果Schema本身字段定义模糊,或者枚举值范围没想清楚,模型再厉害也容易出错。所以我上线前一定会花时间打磨Schema的颗粒度和边界条件,比如哪些字段可以容忍默认值,哪些必须严格匹配。
所以整体上,我更倾向于把这件事看成系统工程,不是靠某一种技术通吃。我会优先保证解码层的语法正确性,然后通过提示和后处理补语义,最后用业务校验兜底。这样即使模型偶尔抽风,系统也不会崩。