大模型结构化输出:为什么自然语言不稳定,JSON Schema怎么约束
结构化输出是大模型工程化的第一道门槛,内容准不算赢,格式稳才能被程序真正用起来
真实的场景
假设你做了一个AI应用,功能是:用户输入一段商品描述,模型帮你提取出"商品名称、价格、类别"三个字段,然后写入数据库
你测试了几次,效果很好,模型总是输出这样的内容:
商品价格:无线蓝牙耳机
价格:299元
类别:电子产品
结果过两天之后,模型输出变成了这些:
这款商品是无线蓝牙耳机,售价299元,属于电子产品类别
{"name":"无线蓝牙耳机","price":"$299"...}
这个不是bug,这是大模型输出的本质特征:他是概率生成的,每次输出的格式可能不一样
自然语言输出为什么不稳定?
大模型输出的每一个token,本质上都是在做一次概率采样
模型不是在"执行格式规则",他是在"预测什么词接下来最可能出现"。即便你在Prompt里面写了"请输出JSON格式",模型也只是在学习"什么样的输出符合JSON这个描述",而不是真的在运行一个格式化函数
问题
格式漂移:同一个Prompt,不同调用之间,模型可能输出冒号格式,JSON格式,Markdown列表格式,甚至是自然语言段落。
字段缺失或者增多:你让模型提取5个字段,它可能只返回3个,或者额外加了你没要的字段,还附上了一段"总结"
值的形式不一致:你要"价格",它可能返回299、299元、约299元
混入解释性文字:模型喜欢在给出结构化内容之前或者之后,加上"好的,以下是提取结果"这类内容
什么是结构化输出
结构化输出,就是让模型按照你预先定义好的格式和字段生成内容,而不是自由发挥
最常见的形式就是让模型返回JSON,并且这个JSON的结构是固定的,那些字段必须有,每个字段是什么类型,那些是可选的,全部提前定义好
目前实现结构化输出主要有三种方式,难度和可靠性递增:
方式一:Prompt约束
在Prompt里面写"请只输出JSON,不要有任何其他文字",然后自己去解析输出,这个方式对于简单场景勉强够用,但是对于格式敏感的业务,失败率相当高
方式二:JSON Schema + 输出验证
给模型提供一个JSON Schema(一种用于描述、验证和文档化JSON数据结构的标准化规范),告诉它输出的结构应该是什么样的,字段名是什么,类型是什么。收到输出后,用Schema验证一遍,如果不符合就重试。这个方式可靠性明显提升,但需要处理重试逻辑
方式三:模型原生结构化输出(最可靠)
在API层面强制模型按照你给的schema输出,模型内部会做约束解码,保证输出的JSON结构一定合法
结构化输出适合那些业务场景?
不是所有的业务都需要结构化输出,判断是否合适的标准很简单:你的下游逻辑,是否依赖模型输出的某个具体字段
适合做结构化输出的典型场景:
信息提取类任务,比如从合同文本里面提取甲方、乙方、金额、签署日期,写入CRM系统。输出必须是固定字段,不能是一段话
内容生成后的元数据附加,比如生成一篇文章的同时,要求模型一并输出文章的标题、摘要、关键词列表、预计阅读时间,这些字段需要分别存储和使用
不太适合的场景:纯粹的对话、内容创作等输出本身就是给人看的,不需要程序进一步处理