上周把「让模型总结一下这份日志」当成万能钥匙,结果三天后才发现:真正省时间的不是总结能力,而是结构化输出到底做没做实。
一、第一版:把要求写进 Prompt
提示词写得像法律文书:请输出 JSON,不要任何额外文字。
模型偏要在外面套一层代码块,末尾再补一句「希望对你有帮助」。解析函数第一天就见了红。
二、第二版:换成接口层的结构化输出
国内外几家大模型厂商都把 schema 做进了 tool_calls 与 response_format,字段类型、必填、枚举一并声明,解释性废话立刻消失。
代价也很实在:单次调用更贵更慢;字段一改名字,所有消费方跟着抖。所以大厂内部一般把它当协议来管,有版本、有兼容期,而不是随手加个字段。
三、第三版:模型出初稿,代码做守卫
最后落在一个很土的方案上:
- 模型只负责给候选根因和证据行号,别的一概不管;
- 代码层做宽松解析,兜住绝大多数正常返回;
- 解析失败只重试一次,第二次直接用兜底文案。
js
const parse = (s) => {
try { return JSON.parse(s) } catch (e) { return loose(s) }
}
土,但上线以后「解析失败」的告警少了一大半。
四、一点思考
结构化输出这件事,模型侧解决的是格式,工程侧解决的是语义。前者能买,后者只能自己写。
真正难缠的从来不是 JSON 少了个括号,而是模型言之凿凿地给出一个错字段:名字对、类型对、值对不上。schema 校验对此毫无办法,能救的只有业务不变量。
把 prompt 当接口来评审,把校验当灰度来做,大概是这一年大模型落地里最朴素也最管用的一条经验。