结构化输出与 JSON Schema:把 LLM 接进后端接口的正确姿势
Words: 786Read Time: 2 minLast edited: 2026-8-4
最近在做一个功能:从用户粘贴的网页正文里抽取标题、标签和摘要,存进博客数据库。调大模型做抽取不难,难的是接口的返回值要被代码消费——必须能稳定反序列化成强类型,一次都不能崩。
早期做法:靠 prompt 求 JSON
最开始我的做法是祖传 prompt:
请严格按照以下 JSON 格式返回,不要输出任何其他内容……
然后 C# 里
JsonSerializer.Deserialize<T>(content)。跑十次能成九次,剩下一次可能是:外面包了层 markdown 代码块标记、JSON 前面多了句「好的,以下是结果」、或者字段名给你换成中文。线上接口可不能接受 90% 的成功率,只能写一堆正则兜底,越写越丑。Structured Outputs:让 schema 成为硬约束
OpenAI 在 2024 年 8 月推出了 Structured Outputs:请求时把 JSON Schema 传给
response_format,模型输出被约束在 schema 内,格式层面保证合法。我这边用的是官方 OpenAI .NET SDK(2.x):到这里反序列化基本不会再炸了。注意点:strict 模式下 `required` 必须列出所有字段,可选字段要用
["string", "null"] 这样的类型并集表达,我第一次写就因为漏了 required 被直接拒绝。格式合法不等于内容正确
Schema 只能保证「是合法 JSON 且字段齐全」,保证不了「tag 不超过 5 个」「summary 不超过 200 字」这种业务规则。所以校验分两层:schema 层交给模型提供方,业务层自己写,失败就重试,重试时把错误原因带回去:
一些经验
- 模型选便宜的就够:
gpt-4o-mini做抽取绰绰有余,别把预算花在格式上
- Schema 里给每个字段写
description说清语义,抽取质量明显更好
- 重试不是万能的:prompt 本身有歧义时,重试三次也是错三次,先把指令写清楚
- 留好原始返回的日志,线上排查全靠它
从「求模型返回 JSON」到「用 schema 约束 JSON」,改动不过几十行代码,但接口的稳定性从「祈祷」变成了「可承诺」。这是我觉得今年把 LLM 接进后端最值得做的一件事。
Loading...