结构化输出的隐性代价:JSON 模式质量税
大多数团队采用结构化输出,是因为厌倦了用脆弱的正则表达式从模型响应中抽取数据。这个动机合情合理。但他们没料到的是,几个月后当他们真正度量任务准确率时,会发现那次"可靠性提升"同时让推理密集型任务的内容质量下降了 10 到 15 个百分点。语法问题解决了,语义问题却悄然而生。
本文的目的是精确理解这一权衡——约束解码的实际代价是什么、什么时候值得支付这笔税,以及如何在上线前构建评测来判断它是否正在拖累你的系统。
大多数团队采用结构化输出,是因为厌倦了用脆弱的正则表达式从模型响应中抽取数据。这个动机合情合理。但他们没料到的是,几个月后当他们真正度量任务准确率时,会发现那次"可靠性提升"同时让推理密集型任务的内容质量下降了 10 到 15 个百分点。语法问题解决了,语义问题却悄然而生。
本文的目的是精确理解这一权衡——约束解码的实际代价是什么、什么时候值得支付这笔税,以及如何在上线前构建评测来判断它是否正在拖累你的系统。
有数据时,微调模型很容易。残酷之处在于产品诞生之前的那个时刻:你需要个性化来吸引用户,但又需要用户才能积累个性化数据。大多数团队要么完全跳过微调("以后再加"),要么花数周手工收集标注样本。两种方式都行不通。前者产出一个用户一眼就能看穿的通用模型,后者慢到等你有了数据,任务早已演变。
合成种子数据能解决这个问题——但前提是你必须清楚它在哪里会失效。
大多数工程团队在第一次收到账单暴涨时都会发现同一件事:他们的系统提示词已经悄悄增长到4,000个token的精心指令,而模型也悄悄开始忽略其中一半。解决方法很少是添加更多指令,几乎总是删除它们。
追求面面俱到的本能是可以理解的。更多约束感觉像是更多控制。但随着系统提示词膨胀,存在一种可量化的质量下降——而且它与成本的复合方式在造成损害之前并不明显。研究一致发现,在大约3,000个输入token处准确率开始下降,远在达到任何名义上的上下文限制之前。模型不会拒绝遵守;它只是开始以难以查明的方式表现不佳。
本文的目的是使这种退化变得可见,理解其发生原因,并建立一套不需要寄希望于"不会出问题"的精简规范。
你的企业刚刚部署了一个 RAG 系统。你索引了每个 Confluence 页面、每份运行手册(runbook)、每篇架构文档。六个月后,一位高级工程师离职了——就是那个知道为什么支付服务会有那种不寻常的重试模式、为什么你们从不把缓存扩容超过 80%,以及周五绝对不要给哪家供应商打电话的人。这些知识从未被记录下来。你的 RAG 系统根本不知道它的存在。
这就是隐性知识(tacit knowledge)问题。这也是为什么大多数企业 AI 系统表现不佳的原因——不是因为检索质量或幻觉,而是因为它们所需的知识从一开始就没被捕获。60% 的员工表示,很难甚至几乎不可能从同事那里获取关键信息。90% 的组织表示,员工离职会导致严重的知识流失。你的 RAG 能索引的文档只是冰山一角。
每当一个新的 LLM 功能上线,总会有人问:"我们该用多少 temperature?"答案几乎千篇一律:"不知道,留着 0.7 吧。"然后对话结束,没有人再碰这个值。
这是一个用默认值做出的产品决策。Temperature 不只是控制模型听起来有多"随机"——它决定了用户是否信任输出、是否会重新运行查询、是否感到被帮助或被淹没。把它调好比大多数团队意识到的更重要;调错了也很难诊断,因为失败的表现看起来像是模型行为差,而不是配置差。
Text-to-SQL 演示看起来出奇地简单:把 schema 粘贴到提示词里,向 GPT-4 提个问题,拿到一条整洁的 SELECT 语句,然后 Slack 里就开始涌现"要不要把这个集成进数据平台?"的消息。等到你真正打算上线时,麻烦来了。基准测试显示 85% 的准确率,但内部数据团队反映大约一半的答案是错的,而安全团队则在追问:生成的查询在执行前有没有经过审查?没人能给出一个像样的答案。
这正是 text-to-SQL 作为研究问题与作为工程问题之间的鸿沟。研究问题关注的是让模型生成语法正确的 SQL;工程问题面对的是 schema 歧义、访问控制、查询验证,以及你的企业数据库根本不像 Spider 或 BIRD 数据集这一现实。
你的ASR系统返回了"the patient takes metaformin twice daily"。正确的词应该是metformin。转录看起来很干净——没有[INAUDIBLE]标记,没有错误标志。那个词的置信度是0.73。你的管道丢弃了这个数字,将干净的文本传给了LLM。LLM将其视为真实情况,围绕一种不存在的药物进行推理。
这就是转录层的谎言:一种隐性假设,认为中间文本表示——无论是由语音识别、OCR还是解析文档的视觉模型产生的——都足够可靠,可以不加保留地向下游传递。事实并非如此。但几乎每个生产管道都将其视为可信来源。
当确定性系统崩溃时,你会找到 bug。堆栈跟踪指向某一行代码。代码差异(diff)显示了更改。回顾起来,修复方案显而易见。但 AI 系统并非如此。
当一个由大语言模型(LLM)驱动的功能开始输出更差的结果时,你寻找的不是 bug。你面对的是一个发生偏移的概率分布,它存在于一系列组件构成的堆栈中,而每个组件都引入了各自的方差。是模型的问题吗?是供应商在某个周二进行的无声更新?是架构变更后未刷新的检索索引?是某人为了修复另一个问题而修改的系统提示词(system prompt)?还是三个冲刺(sprint)前就停止捕获回归的评估系统(eval)?
复盘会议变成了责任拍卖会。每个人都出价“模型变了”,因为这是一个无法证伪且无需成本的借口。