这道题其实是在问,当大模型输出不可控时,你怎么在保证格式合规的同时,不把业务的灵活性和成功率丢掉。我一般会从三层防护来设计,从预防到硬约束再到兜底,每一层解决不同的问题。
先说第一层,Prompt工程。这层是预防性的,成本最低。我会在Prompt里给两三个格式样例,明确说必须严格遵循某个JSON格式,甚至让它扮演一个严格的JSON生成器角色。但这层只能提高概率,不能保证100%听话,所以不能只靠它。
第二层是结构化输出,这才是真正的硬约束。能用模型原生能力就用,例如具体模型/API支持并启用的strict工具schema。普通Function Calling不一律strict,JSON mode只约束JSON语法,不保证某个schema的必填项、类型和枚举。拒绝、截断和未调用工具需单独处理。如果模型本身不支持,或者场景更复杂,我会用Guidance这类约束解码库,在生成过程中实时卡住非法token。说白了,这层是从模型内部把输出框死,比Prompt可靠得多。
第三层是后处理校验,做兜底。不管前面两层多强,总会有意外,比如模型输出了合法JSON但业务逻辑不对。我会写一个validate函数,先用json.loads解析,再用jsonschema校验结构,最后跑业务规则。如果发生预期解析/校验失败,可在次数与时限内带错误反馈重试,或返回明确失败/降级状态;退款等写操作还要有权限与幂等控制。
这三层怎么选,得看场景。我举个例子,客服退款场景,模型需要调用API修改订单状态,这时候输出格式必须绝对正确,一个字段都不能错。我会用Function Calling加严格校验,失败就重试,不接受脏数据。但如果是创意写作,比如给用户生成一段文案,格式要求就宽松很多,用Prompt引导加一个简单的后处理就够了,太严格反而扼杀创造性。真正落地时,常常是X加Y一起上,没有银弹。
这里有个坑:后处理校验不能太死板。比如流式输出场景,模型在生成过程中可能先输出一个不完整的JSON片段,你不能等它全吐完了再校验,那延迟就太大了。我会用增量解析加状态机,实时发现格式错误,提前截断或者修正。
还有一个点值得注意:Function Calling虽然好,但它的schema设计其实有讲究,嵌套太深或者可选字段太多,模型反而容易出错。所以我会把schema尽量扁平化,只留必填字段,复杂逻辑放到后处理里做。
总的来说,我更倾向于把输出过滤看成一种风险控制,而不是追求完美的格式。前提是你要清楚业务对格式的容忍度有多高,如果容忍度低,就多上几层约束;如果容忍度高,就放宽一点,把成功率拉上去。上线后我会特别关注重试率和降级比例,如果某个场景频繁触发降级,要区分schema不支持、截断、输入不适配、服务异常与模型误判,再调整对应环节,不能直接归因于约束太严。