JSON 与 JSON Schema
Tool Calling 的通用语言,以及如何用 Schema 约束数据结构。
一句话理解:JSON 是系统之间交换数据的通用格式,JSON Schema 是描述“这份 JSON 应该长什么样”的规则;模型通过 Schema 理解工具需要什么参数,程序通过 Schema 检查模型填得对不对。
在 Agent 系统里,JSON 无处不在:API 返回的是 JSON,模型调用工具时输出的是 JSON,工具定义本身也是 JSON,结构化输出要求的还是 JSON。而 JSON Schema 是让这一切“可靠”的关键——它把“请填一个日期”这种模糊的要求,变成程序可以检查的精确规则。
产品经理不需要手写复杂的 Schema,但需要能读懂它,因为 工具定义里的 Schema 就是模型理解工具的唯一说明书,写得好不好直接决定 Agent 会不会用错工具。
JSON:六种值就够了
JSON(JavaScript Object Notation)是一种纯文本数据格式,只有六种值类型:
| 类型 | 写法 | 例子 |
|---|---|---|
| 字符串 string | 双引号包裹 | "SF1234" |
| 数字 number | 直接写 | 18.5、42 |
| 布尔 boolean | true / false |
true |
| 空值 null | null |
null |
| 对象 object | 花括号,键值对 | {"city": "杭州"} |
| 数组 array | 方括号,有序列表 | ["饮料", "零食"] |
对象和数组可以任意嵌套。一个销售分析工具返回的结果可能是这样:
{
"region": "华东",
"period": { "start": "2026-09-07", "end": "2026-09-13" },
"total_sales": 1284500.0,
"change_rate": -0.18,
"is_anomaly": true,
"top_declines": [
{ "category": "饮料", "change_rate": -0.62 },
{ "category": "日化", "change_rate": -0.05 }
],
"note": null
}
把这份 JSON 展开成一棵树,层级就一目了然:
读 JSON 的几个小技巧:
- 先看最外层是对象还是数组,再逐层展开。
- 键名通常能说明含义,
change_rate为负数表示下降。 - 注意单位和格式:
-0.18是 -18% 还是 -0.18%?日期是哪个时区?这些 JSON 本身不会告诉你,要看文档或 Schema 描述。
常见的语法错误:键名没加双引号、字符串用了单引号、最后一个元素后面多了逗号、出现注释。模型偶尔也会犯这些错误,这就是为什么要用程序校验。
JSON Schema:给 JSON 写规则
JSON Schema 本身也是一份 JSON,用来描述另一份 JSON 应该满足的结构。当前版本是 2020-12。看一个“查询销售数据”工具的参数 Schema:
{
"type": "object",
"properties": {
"region": {
"type": "string",
"description": "销售大区名称",
"enum": ["华东", "华南", "华北", "西南"]
},
"start_date": {
"type": "string",
"description": "开始日期,格式 YYYY-MM-DD,包含当天",
"pattern": "^\\d{4}-\\d{2}-\\d{2}$"
},
"end_date": {
"type": "string",
"description": "结束日期,格式 YYYY-MM-DD,包含当天"
},
"group_by": {
"type": "string",
"description": "拆分维度;不需要拆分时不要传",
"enum": ["category", "channel", "sku"]
},
"limit": {
"type": "integer",
"description": "最多返回的分组数",
"minimum": 1,
"maximum": 50,
"default": 10
}
},
"required": ["region", "start_date", "end_date"],
"additionalProperties": false
}
常用关键字一览:
| 关键字 | 作用 | 本例中的用法 |
|---|---|---|
type |
值的类型 | object、string、integer |
properties |
对象有哪些字段 | region、start_date 等 |
required |
哪些字段必填 | 大区和起止日期必填 |
description |
给人和模型看的说明 | 说明日期格式与是否包含当天 |
enum |
只能取列出的值 | 大区只能是四个之一 |
minimum / maximum |
数字范围 | limit 在 1–50 之间 |
pattern |
字符串需匹配的正则 | 日期格式 |
items |
数组中每个元素的规则 | 用于数组类型字段 |
additionalProperties |
是否允许未定义的字段 | false 表示不允许多余字段 |
default |
默认值说明 | limit 默认 10 |
还有一个 format 关键字(如 "format": "date"),但在 2020-12 版本中它默认只是注释性的说明,是否真正校验取决于所用的校验库,所以关键格式最好配合 pattern 或程序检查。
Schema 在 Agent 中的三个用途
Schema 在一次工具调用里会出现三次:
用途 1:工具定义。 以 Anthropic 的 Messages API 为例,一个工具由 name、description 和 input_schema 三部分组成,其中 input_schema 就是一份 JSON Schema。其他厂商的字段名略有差异,但结构大同小异:
{
"name": "query_sales",
"description": "按大区和日期范围查询销售额,可按品类、渠道或 SKU 拆分。用于分析销售变化原因。只读。",
"input_schema": {
"type": "object",
"properties": {
"region": { "type": "string", "enum": ["华东", "华南", "华北", "西南"] },
"start_date": { "type": "string", "description": "YYYY-MM-DD" },
"end_date": { "type": "string", "description": "YYYY-MM-DD" }
},
"required": ["region", "start_date", "end_date"]
}
}
模型调用时,会输出一个工具调用块,其中的 input 就是按 Schema 填写的参数。工具定义的写法见工具定义三要素。
用途 2:校验。 模型填写参数是概率性的,可能漏字段、填错类型、编造枚举之外的值。程序应该在执行前校验:
from jsonschema import validate, ValidationError
schema = {
"type": "object",
"properties": {
"region": {"type": "string", "enum": ["华东", "华南", "华北", "西南"]},
"limit": {"type": "integer", "minimum": 1, "maximum": 50},
},
"required": ["region"],
"additionalProperties": False,
}
model_output = {"region": "华中", "limit": 100}
try:
validate(instance=model_output, schema=schema)
except ValidationError as e:
# 把可读的错误信息返回给模型,让它修正,而不是直接调用 API
print("参数不合法:", e.message)
运行后会输出类似 参数不合法: '华中' is not one of ['华东', '华南', '华北', '西南'] 的错误(需要先 pip install jsonschema)。部分模型厂商也提供“严格模式”,在生成阶段就保证输出符合 Schema,例如 Anthropic 的工具定义支持 strict: true,但程序侧的业务校验(例如结束日期不能早于开始日期)仍然需要。
用途 3:结构化输出。 让 Agent 的最终结论按约定字段输出,下游系统才能直接使用,详见结构化输出与输出契约。
好的 Schema 与差的 Schema
同一个“订单查询”工具,对比两种写法:
| 写法 | 差的 Schema | 好的 Schema |
|---|---|---|
| 字段名 | id |
order_no |
| 类型 | 所有字段都是 string |
数量用 integer,开关用 boolean |
| 取值范围 | status 可以是任意字符串 |
status 用 enum 列出合法值 |
| 描述 | 没有 description |
说明格式、单位、示例、什么时候不需要传 |
| 必填 | 全部可选 | 只有真正必需的字段放进 required |
| 多余字段 | 允许任意字段 | additionalProperties: false |
记住一个原则:模型看不到你的代码和数据库,只能看到 Schema 和描述。 你会对新同事口头解释的每一个细节——“订单号是字母 A 开头”“日期是北京时间”“金额单位是分”——都应该写进描述。
常见误区
- “Schema 是给程序看的,描述写不写无所谓。” 恰恰相反,
description是模型选择工具、填写参数最主要的依据。 - “用了严格模式就不需要校验了。” 结构正确不等于业务正确。格式完全合法的
{"refund_amount": 99999}仍然需要程序检查是否超过订单金额。 - “字段越多越灵活。” 可选字段过多会让模型困惑、填入不必要的值。只暴露任务真正需要的参数。
产品经理检查清单
评审工具定义或结构化输出方案时:
- 每个字段的名称是否一眼能看懂?有没有
id、type、data这类含糊的名字? - 有固定取值的字段是否用了
enum? - 单位、时区、格式是否写进了描述?
- 必填字段是否是真正必须的最小集合?
- 模型输出参数后,程序做了哪些校验?校验失败时模型能看到什么错误信息?
- 业务规则(金额上限、状态流转)是否由程序检查,而不只依赖 Schema?
练习
用 30–45 分钟完成:
- 为订单售后诊断 Agent 的工具
get_order_events写一份参数 Schema,要求:订单号必填且以字母 A 开头;可选的事件类型只能是“已创建、已支付、已确认、已完成、已取消”之一;可选的最多返回条数在 1–100 之间。 - 为每个字段写一句面向模型的
description。 - 写出 3 个“不合法”的参数示例,并说明它们分别违反了哪条规则。
- 进阶:安装
jsonschema,用上面的 Python 代码验证你的 3 个反例确实会报错。
延伸阅读
- JSON Schema 官方:Specification,规范各版本与当前版本说明。
- Anthropic:Tool use with Claude,工具定义中
input_schema的完整示例。
下一步
工具要调用真实系统,首先得证明“你是谁、能做什么”。下一课「认证、授权与 OAuth」讲清 Agent 如何安全地拿到访问权限。