JSON Schema 校验:强制大模型生成合规的结构化数据
FreeGuideOnline
最新
2026-06-29
json { "type": "object", "properties": { "name": { "type": "string" }, "age": { "type": "integer", "minimum": 0 } }, "required": ["name"] }
这份 Schema 表示:数据必须是一个对象,有一个字符串类型的 `name` 属性(必填),和一个可选的整数类型 `age` 属性,且 `age` 不能小于 0。
## JSON Schema 基础语法
### 核心关键字
- `type`:指定数据类型,常用值有 `"string"`、`"number"`、`"integer"`、`"object"`、`"array"`、`"boolean"`、`"null"`。
- `properties`:定义对象的属性及其对应的子 Schema。
- `required`:字符串数组,列出必须出现的属性名。
- `additionalProperties`:是否允许对象中出现 `properties` 未定义的属性,默认 `true`。设置为 `false` 可严格限制结构。
### 数字与字符串约束
- 数字约束:
- `minimum` / `maximum`:最小值 / 最大值。
- `multipleOf`:必须是该值的倍数。
- 字符串约束:
- `minLength` / `maxLength`:最小 / 最大长度。
- `pattern`:正则表达式字符串,用于格式匹配。
- `enum`:枚举值数组,数据必须为其中之一。
示例:一个包含约束的用户邮箱 Schema。
```json
{
"type": "object",
"properties": {
"username": { "type": "string", "minLength": 3, "maxLength": 20 },
"email": { "type": "string", "pattern": "^[^@\\s]+@[^@\\s]+\\.[^@\\s]+$" }
},
"required": ["username", "email"],
"additionalProperties": false
}
数组约束
items:适用于数组中每个元素的 Schema。如果数组元素类型统一,直接传入一个 Schema;若需要元组模式,可传入数组。minItems/maxItems:数组长度约束。uniqueItems:布尔值,是否要求数组元素唯一。
示例:
{
"type": "array",
"items": {
"type": "object",
"properties": {
"id": { "type": "integer" },
"name": { "type": "string" }
},
"required": ["id", "name"]
},
"minItems": 1,
"maxItems": 10,
"uniqueItems": true
}
组合条件
可以使用逻辑关键字组合多个 Schema:
allOf:必须同时满足所有子 Schema。anyOf:满足其中任意一个即可。oneOf:必须满足恰好一个子 Schema。not:不能匹配指定的 Schema。
例如,一个商品可以是电子书或实体书,用 oneOf 区分:
{
"type": "object",
"properties": {
"title": { "type": "string" },
"type": { "enum": ["ebook", "physical"] }
},
"oneOf": [
{
"properties": {
"type": { "const": "ebook" },
"file_size_mb": { "type": "number" }
},
"required": ["file_size_mb"]
},
{
"properties": {
"type": { "const": "physical" },
"weight_kg": { "type": "number" }
},
"required": ["weight_kg"]
}
]
}
如何编写有效的 JSON Schema
从需求出发,明确结构
- 写出你希望的数据范例。
- 标记每个字段的类型、约束、是否必填。
- 逐步添加验证规则(长度、范围、枚举、正则等)。
- 考虑边缘情况:空数组?缺失字段?多余字段?
使用工具进行实时校验
- 在线验证器:JSON Schema Validator 等。
- 代码库:多数编程语言都有 JSON Schema 校验库(如 Python 的
jsonschema,Node 的ajv)。建议编写单元测试确保 Schema 自身正确。
遵守最佳实践
- 保持 Schema 可读,合理使用
$defs/definitions重用结构。 - 为每个 Schema 添加
title、description注解,便于生成文档。 - 使用
additionalProperties: false防止未声明的字段混入,尤其在与大模型集成时。
JSON Schema 与大模型结构化输出
为什么大模型需要 JSON Schema
大语言模型本质上是文本生成器,默认情况下输出自由文本。但在实际应用中,我们往往需要解析其输出,用于下游程序。通过 JSON Schema,可以:
- 强制输出符合约定的 JSON 结构,避免解析失败。
- 减少幻觉,因为模型被约束在特定字段和类型内。
- 实现可靠的函数调用(Function Calling)和工作流自动化。
主流大模型 API(如 OpenAI、Anthropic)都提供了结构化输出模式,允许开发者传入 JSON Schema,模型保证生成的 JSON 完全符合 Schema。
实践:使用 OpenAI 的结构化输出
以 OpenAI GPT‑4o 为例,response_format 参数允许定义 json_schema。
步骤:
- 设计 JSON Schema 描述想要的输出。
- 在 API 请求中设置
response_format。 - 直接从返回的 Parsed JSON 中读取数据。
示例:提取结构化地址信息
Schema 定义:
{
"type": "object",
"properties": {
"country": { "type": "string", "description": "国家" },
"province": { "type": "string", "description": "省份" },
"city": { "type": "string" },
"street": { "type": "string" },
"postal_code": { "type": "string", "pattern": "^[0-9]{6}$" }
},
"required": ["country", "province", "city", "street"],
"additionalProperties": false
}
API 调用(Python 风格示例):
from openai import OpenAI
client = OpenAI()
completion = client.chat.completions.create(
model="gpt-4o",
messages=[
{"role": "user", "content": "请解析地址:北京市海淀区中关村大街1号,100080"}
],
response_format={
"type": "json_schema",
"json_schema": {
"name": "address_schema",
"schema": {
"type": "object",
"properties": {
"country": {"type": "string"},
"province": {"type": "string"},
"city": {"type": "string"},
"street": {"type": "string"},
"postal_code": {"type": "string", "pattern": "^[0-9]{6}$"}
},
"required": ["country", "province", "city", "street"],
"additionalProperties": false
}
}
}
)
parsed = json.loads(completion.choices[0].message.content)
print(parsed)
得到的 parsed 一定是合法的 JSON 并且结构严格匹配 Schema,可以直接用于程序后续逻辑。
处理复杂结构与函数调用
在函数调用场景中,JSON Schema 被用来描述函数参数的形状。模型会根据用户输入,选择调用某个函数并生成符合 Schema 的 JSON 参数。
例如定义一个查天气的函数:
{
"name": "get_weather",
"description": "获取指定城市当前天气",
"parameters": {
"type": "object",
"properties": {
"city": { "type": "string", "description": "城市名称,如 'Beijing'" },
"units": { "type": "string", "enum": ["celsius", "fahrenheit"] }
},
"required": ["city"],
"additionalProperties": false
}
}