LLM 结构化输出指南:JSON Schema 与可靠解析

大模型最擅长输出「一段话」,而生产系统最需要的是一份「结构」。从模型返回的文本里抠 JSON,是所有 AI 应用工程师都经历过的噩梦:多了一个逗号、中文引号、Markdown 代码块包裹、突然多了一句「好的,以下是你要的 JSON」……解析器一炸,整条链路就断了。早期调研里,不少团队的真实解析成功率只有 90%~95%——意味着每 20 次请求就有 1 次静默失败。

好消息是,2026 年的模型和 API 已经给了我们一整套「让模型直接输出合法结构」的手段。这篇文章按可靠程度从高到低,把 JSON Schema 约束、Function Calling、类型安全解析、容错重试和流式处理全部过一遍,最后给你一份「从 95% 到 99.9%」的账单。

一、先定契约:JSON Schema 是一切的基础

不管用哪种手段,第一步都是把输出格式写成 JSON Schema。它是你和模型之间的契约,也是校验、生成示例、类型生成的唯一事实来源:

{
  "type": "object",
  "properties": {
    "summary": {"type": "string", "description": "不超过 50 字的中文摘要"},
    "tags": {"type": "array", "items": {"type": "string"}, "maxItems": 5},
    "sentiment": {"enum": ["positive", "neutral", "negative"]},
    "score": {"type": "number", "minimum": 0, "maximum": 100}
  },
  "required": ["summary", "tags", "sentiment", "score"],
  "additionalProperties": false
}

写 Schema 的三个纪律:字段尽量少(超过 20 个字段,错误率明显上升);枚举给全(模型不知道你的隐含取值);每个字段写 description(约束长度、语言、格式,模型真的很吃这一套)。

二、第一手段:response_format 的 json_schema 模式

主流厂商的 OpenAI 兼容接口都支持 response_format,其中 json_schema 模式会在解码层约束输出——模型生成的 token 流被过滤器约束,根本产生不出不符合 Schema 的 JSON。这是目前可靠性最高的手段:

from openai import OpenAI

client = OpenAI(base_url="https://api.dr-ai.top/v1", api_key="sk-...")

resp = client.chat.completions.create(
    model="gpt-5-mini",
    response_format={
        "type": "json_schema",
        "json_schema": {
            "name": "review_summary",
            "strict": True,
            "schema": REVIEW_SCHEMA,
        },
    },
    messages=[{"role": "user", "content": "总结这条评论:……"}],
)
data = json.loads(resp.choices[0].message.content)

注意两点:strict 模式不支持可选字段和 $ref,Schema 要「扁平化」;JSON 模式不保证语义正确——结构合法了,字段值可能是错的,语义校验(枚举值合理性、范围)仍然要自己做。不同厂商对 json_schema 的实现有细微差异,用聚合网关时建议以兼容性最好的子集为准。

三、第二手段:Function Calling / 工具调用

如果你的应用本来就围绕「工具调用」设计(Agent、自动化流程),Function Calling 是天然的结构化出口:模型返回的不是自由文本,而是结构化的 function call(函数名 + 参数 JSON)。参数同样由 Schema 约束,而且和 Agent 的执行循环天然契合。相比手写 JSON 解析,它的优势是「意图」和「参数」分离:模型先决定调哪个函数,再填参数,每一步都可观测、可校验。

一个实用技巧:需要结构化输出但又不真想执行工具时,可以「声明一个叫 respond 的伪函数」,把输出结构定义在它的参数 Schema 里——很多团队用这招拿到了比 response_format 更稳定的结果(尤其在一些对 json_schema 支持不完整的模型上)。想深入了解 Agent 怎么组织工具调用,可看《2026 AI Agent 框架对比》

四、第三手段:Pydantic 与类型安全解析

无论模型端约束多强,解析端都必须有一层类型安全的收口。用 Pydantic 定义模型,把「JSON 到对象」的转换交给验证器:

from pydantic import BaseModel, Field
from typing import Literal

class ReviewSummary(BaseModel):
    summary: str = Field(..., max_length=50, description="中文摘要")
    tags: list[str] = Field(..., max_length=5)
    sentiment: Literal["positive", "neutral", "negative"]
    score: float = Field(..., ge=0, le=100)

data = ReviewSummary.model_validate_json(raw_content)

Pydantic 的价值不止类型检查:字段名映射(模型爱用 camelCase,你爱用 snake_case)、默认值兜底、嵌套模型、错误信息定位——全都免费拿到。解析失败时,ValidationError 会精确告诉你哪个字段不对,这是后面容错重试的输入。

五、容错:解析失败不是终点

再强的约束也有漏网之鱼。生产级的解析管线必须内置三级容错:

  1. 清洗:去掉 Markdown 代码块围栏(```json ... ```)、裁剪首尾空白、修复常见非法字符(中文引号、尾逗号)。这一步能救回一半以上的「解析失败」。
  2. 修复重试:把「原始输出 + 报错信息」塞回模型,要求「只输出修正后的 JSON」。实测修复一轮的成功率在 90% 以上,最多重试两轮,再多成本不划算。
  3. 降级:重试仍失败就返回结构化错误(error 对象 + 原始文本),让上层走人工/兜底路径,绝不抛裸异常。
@retry(stop=stop_after_attempt(2), reraise=True)
def parse_with_repair(raw: str) -> dict:
    try:
        return ReviewSummary.model_validate_json(clean(raw)).model_dump()
    except ValidationError as e:
        repair = client.chat.completions.create(
            model="gpt-5-mini",
            messages=[
                {"role": "user", "content": raw},
                {"role": "assistant", "content": "修正以下 JSON 使其合法:" + str(e.errors())},
            ])
        return ReviewSummary.model_validate_json(repair.choices[0].message.content).model_dump()

六、流式与结构化:先流后析

流式(stream=true)场景下没有「完整响应」可解析,常见做法是先让模型输出「结构摘要 + 正文」两部分:开头一小段固定格式的 JSON 元数据(标题、要点),随后是流式正文。客户端按「首次出现分隔符」切换解析模式。更稳妥的变体是让模型先输出一个紧凑的 JSON 大纲再展开——代价是多一次调用,收益是首屏体验和结构完整性兼得。流式相关的更多细节见《LLM API 延迟优化》

七、实测:从 95% 到 99.9% 的账单

手段解析成功率额外成本 / 延迟
裸提示词「请返回 JSON」~90%
+ JSON Schema 提示 + 清洗~95%几乎为零
+ response_format json_schema(严格模式)~99%零(同 token 数)
+ Pydantic 校验 + 修复重试~99.9%重试轮次 × 输入 token(少量)

看到没有:最便宜、最有效的一刀是「声明式约束」,不是重试。重试是最后一道保险,不是主力。按这个顺序叠加,绝大多数应用能把解析失败率压到千分之一以下。

八、常见坑

结构化输出做扎实了,你的 AI 应用才配叫「系统」,而不是「聊天框」。需要多模型对比不同厂商的结构化输出表现?注册 DrAI,一个 API Key 切换 40+ 模型,同一份 Schema 直接跑对比。

🚀 一个 Key 测试所有模型的结构化输出

注册 DrAI,OpenAI 兼容接口,GPT-5、Claude 4、DeepSeek R1、Qwen、GLM 等 40+ 模型随意切换,Pro 套餐仅 $9.99/月。

免费注册 →   查看定价

📚 延伸阅读

AI API 测试技巧:从单元测试到压测Mock 单元测试、Schema 契约校验、集成回归、黄金样本集与 Locust 压测的分层测试方案。 AI 代码生成最佳实践安全高效地用 AI 写代码:提问技巧、代码审查、护栏与团队规范。 10 分钟接入 AI 聊天零基础给应用加上对话能力:API Key、base_url、Python 与 curl 示例、常见报错排查。
🌐 中文