JSON Schema 不是格式化:给大模型立“输出契约”的一次复盘
我一直觉得“让模型按格式输出”是一件很小的事。
直到我们把一个看似简单的需求(把用户需求解析成结构化任务)接进前端流程:按钮点下去要立刻渲染卡片、再驱动后续工具调用。
那一周我们见识了人类语言的任性,也见识了模型的任性:
- 同一个字段名,有时叫
title,有时叫task_title - 需要数组,它给你一段自然语言列表
- 少一个逗号,前端就白屏
最后我们发现:这不是“格式化”问题,这是“契约”问题。
1. 为什么今年这件事突然变重要
今年大家都在谈 Agent、工具、编排。只要你开始做编排,就一定会遇到一个现实:
你真正依赖的不是模型的文字,而是模型输出里的结构。
结构才是系统之间的通用语言。
前端要渲染卡片、后端要触发任务、数据库要落字段、风控要审计——这些都不想读一段散文。
2. 我们踩的坑:把“解析”交给了运气
最开始我们走的是常见路线:
- Prompt 里强调“请输出 JSON”
- 后端用
json.loads()解析 - 失败就让模型重试一次
它在 Demo 阶段非常顺。
但一旦接入真实用户,问题就像潮水:
- 用户会粘贴半段表格
- 用户会夹带一段代码
- 用户会用“顺便”提出第二个需求
模型当然也会“顺便”输出多一些解释。
那一刻我才意识到:
不要把生产系统建立在“模型今天心情好”的概率上。
3. 解决方案:把输出当作 API 来设计
我们后来把模型输出当作一个 API Response 来设计:
- 有 schema(字段、类型、枚举、默认值)
- 有错误语义(缺字段算什么错)
- 有版本(schema v1/v2)
- 有兼容策略(新增字段不破坏旧客户端)
下面是一个简化的 Schema(示例):
1 | { |
在 Prompt 里我们不再说“输出 JSON”,而是说:
- 你在实现一个响应体
- 必须完全符合 schema
- 不允许额外文字
- 如果信息不足,填
null并把need_clarification=true
4. 后端实现:验证永远比相信更便宜
我们在服务端做了三件事:
- 严格校验:不合 schema 就判失败
- 自动修复:仅做“安全的修复”(比如去掉 Markdown 代码块包裹)
- 可观测:记录失败原因,回灌到评测集
伪代码(Python):
1 | import json |
为什么不做“自动修一切”?
因为修复本质上是在帮模型做隐式决策,越修越会引入不可控分支。
我们宁愿失败得更明确一点,然后把失败样本加入回归。
5. 前端侧的经验:不要让 UI 等模型“写完作文”
当你把结构化输出做稳后,前端体验会明显变好:
- 先渲染骨架(intent、tasks 数量)
- 再填充细节
- 如果
need_clarification=true,直接渲染澄清卡片
用户会感觉它在“做事”,而不是“思考”。
6. 什么时候不该用 Schema
我不是 Schema 传教士。下面这些场景我会放弃强结构:
- 纯创作(文案、故事、风格化写作)
- 极强开放的问题(讨论、脑暴)
- 输出只给人看、不进系统
只要输出要进入系统,就尽量立契约。
结语
今年 AI 应用最大的变化之一,是我们越来越少把模型当作“聊天对象”,越来越多把它当作“系统组件”。
组件之间靠契约协作。
当你开始用 Schema 思维设计输出,你会发现很多问题突然变简单:
- 失败可解释
- 兼容可演进
- 体验可优化
它不浪漫,但很工程。
- Title: JSON Schema 不是格式化:给大模型立“输出契约”的一次复盘
- Author: zhichao
- Created at : 2025-04-19 20:40:00
- Updated at : 2025-12-22 17:15:29
- Link: https://chozzc.me/2025/04/19/2025-04-tech-structured-output-contract/
- License: This work is licensed under CC BY-NC-SA 4.0.
Comments