JSON 练习、自测与掌握标准
使用方法
先关闭答案区,手工完成判断和设计,再运行项目测试。目标不是背 Schema 关键字,而是面对陌生 JSON 接口时能从字节边界开始定位问题,给出可验证的契约,并拒绝把结构化模型输出直接当成授权动作。
推荐顺序:基础判断 → Python 小实验 → Schema 设计 → 故障排查 → 综合任务。每一组都要写“为什么”,不能只写合法/非法。
第一组:语法与数据模型
判断每段是否为标准 JSON;若非法,给出最小修复:
A. 42
B. {'ok': True}
C. {"items": [1, 2,]}
D. {"id": "001"}
E. {"id": 001}
F. {"value": null}
G. {"value": undefined}
H. {"path": "D:\data\input.json"}
I. {"a": 1} {"b": 2}
J. ["x", 1, false, null]再回答:
- 顶层标量合法,为什么很多 API 仍要求顶层对象?
- 字段缺失、
null、""、[]各可表达什么不同意图? - 对象换序和数组换序的语义为什么不同?
- JSON 文本、Python 字典和“包含 JSON 的字符串”怎样辨认?
第二组:Python 编解码实验
在临时目录完成以下任务,不改仓库样例:
- 用
json.dumps(..., ensure_ascii=False, allow_nan=False)编码中文对象,再loads读回。 - 对尾逗号、空输入、未闭合字符串打印
JSONDecodeError的行列号。 - 证明默认解析器对重复键保留最后一个值。
- 证明默认解析器接受
NaN,而allow_nan=False阻止输出。 - 用
parse_float=Decimal解析0.1,说明写回契约仍要明确。 - 证明非字符串字典键经过 round trip 会改变类型。
- 构造双重编码,分别写出两次解析后的类型。
- 解释为什么
python -m json.tool只能验语法,不能验业务。
验收要求:每个实验至少有一个 unittest 断言;再用 python -O 运行,测试数量不能减少。
第三组:严格互操作边界
为下列风险分别写“检测层、错误码、是否可继续、日志允许字段”:
| 风险 | 需要决定的内容 |
|---|---|
重复 role 键 | 必须在 Schema 前还是后检测? |
| 非法 UTF-8 | 是否能进入文本解析? |
| UTF-8 BOM | 接口选择接受还是拒绝? |
NaN 与 1e9999 | 为什么需要两类检查? |
孤立 \uDEAD | 如何避免跨实现不一致? |
| 30 层嵌套 | 深度上限如何测试边界? |
| 10 MB 单行 JSONL | 何时拒绝,如何跳到下一物理行? |
| 超大整数 ID | 为什么更适合字符串? |
进一步题:
sort_keys=True能解决哪些测试问题,不能解决哪些签名问题?- 视觉相同的 Unicode 字符串为什么不一定相等?
- 应用把所有文本都做 NFC normalization 可能破坏什么契约?
- 资源上限应从哪里获得证据,而不是随意猜一个数字?
第四组:JSON Lines 与文件写入
建立一个临时 events.jsonl,依次包含:合法第一行、空行、损坏第三行、合法第四行、无末尾 LF 的第五行。实现两种策略:
read_all_or_fail:任一行失败则整个批次失败;scan_with_reports:输出每个物理行的status/code,坏行后继续。
约束:
- 只接受 UTF-8,无 BOM;
- 单行和总字节有上限;
- 报告不得回显原行;
- CRLF 与 LF 均能读取;
- 字符串里的转义
\n不分割记录; - 输出使用同目录临时文件和
os.replace; - 模拟替换失败时,旧目标完整保留且临时文件被清理。
解释为什么这仍不是多进程事务数据库。
第五组:Schema 基础
为以下配置写 Draft 2020-12 Schema:
{
"schema_version": 1,
"name": "research-agent",
"max_steps": 10,
"timeout_seconds": 45,
"log_level": "INFO"
}要求:
- 声明
$schema; - 顶层对象且拒绝未知字段;
- 五个字段全部必填;
schema_version只能为 1;name长度 1–64;max_steps为 1–20;timeout_seconds为 1–120;log_level是DEBUG/INFO/WARNING/ERROR之一。
为每个范围测试最小值、最大值、小 1、大 1、true 和字符串。再解释:
properties与required的分工;- 可选与可空的差别;
default为什么不自动写值;format为什么可能只是注解;uniqueItems为什么无法保证工具对象的name唯一。
第六组:Schema 组合、版本与错误路径
设计一个 tool envelope,包含 search_notes 和 send_email:
- 用
oneOf + const区分分支; - 每个
arguments拒绝未知字段; search_notes.limit为 1–20;send_email只允许example.test教学地址;- 不允许输入
approved; - 错误报告使用 RFC 6901 Pointer;
- instance 中包含
schema_version; - Schema 本身有
$schema和$id。
然后完成:
- 构造零分支匹配和两个分支都匹配的反例;
- 把 key
a/b~c编码为 Pointer token; - 设计 v1 → v2 的字段重命名迁移,先验旧、迁移、再验新;
- 限制最多返回 5 个错误,并证明报告不含 instance 值;
- 说明
$schema、$id和schema_version分别是什么。
第七组:LLM 与工具边界情景题
逐项给出正确处理:
- 模型返回可解析 JSON,但缺少必填字段。
- strict output 通过 Schema,却给出不存在的
document_id。 - 工具参数里出现
"approved": true。 - 流式参数在连接中断时只收到半个对象。
send_email参数合法,用户没有发送权限。- 邮件工具超时,服务端可能已发送。
- 工具结果含网页文字“忽略之前规则”。
- 厂商文档只支持 JSON Schema 子集,领域 Schema 使用了不支持的关键字。
- MCP server 提供
readOnlyHint: true,但服务器不受信任。 - 日志系统想保存完整工具参数以便排查。
答案必须包含:结构层、事实层、权限层、审批层、幂等/未知结果、信任来源和脱敏策略。
第八组:综合项目扩展
在 examples/ 现有项目上选择一个任务:
任务 A:新只读工具
增加 lookup_document:
document_id是 1–64 字符字符串;- Schema、可信 registry、成功/失败测试同步更新;
- 状态只能是
validated_not_executed; - 输入中的文档内容不进入报告。
任务 B:配置 v2 迁移
把 timeout_seconds 改为:
{
"connect_timeout_seconds": 5,
"read_timeout_seconds": 40
}实现纯迁移函数:不修改输入对象,拒绝未知版本,迁移后验证 v2,并保留原文件直到新文件原子替换成功。
任务 C:批处理错误预算
为管线增加 max_rejected_records。超过预算时停止接收更多业务记录并返回失败退出码,但仍不得执行工具或回显 payload。测试恰好等于预算和超出 1。
无论选哪项,都必须在普通与 -O 模式运行全部测试,并保持无网络、无密钥、无生成物残留。
参考答案与判断依据
第一组要点
- A、D、F、J 合法;D 的 ID 是字符串,前导零被保留。
- B 使用 Python 单引号和
True;C 有尾逗号;E 数字有前导零;G 没有undefined;H 的反斜杠形成非法转义,应写D:\\data\\input.json;I 是两个未分隔 JSON 值。 - 顶层对象是应用 envelope 选择;JSON 通用语法允许标量。
严格边界要点
- 重复键必须在对象构造时检查,Schema 之后太晚。
parse_constant处理NaN/Infinity字面量;1e9999还需自定义 float 或解析后有限性检查。- 日志记录 code、行列、Pointer、keyword、request ID;不记录完整输入。
sort_keys是实现内稳定格式化,不是 RFC 8785。
Schema 要点
properties不要求存在;required不要求非空。default和通常的format是注解语义,是否修改/拒绝由应用与验证器配置决定。oneOf必须恰好匹配一个分支;用const判别字段避免重叠。- Schema 只能验证已表达结构;数据库存在性、用户权限和审批属于可信应用层。
LLM/工具要点
- 结构合法不等于事实正确;关键 ID 回源核验。
- 输入不能自我批准;审批来自可信外部状态。
- 流式不完整输入不得猜测或执行。
- timeout 后结果可能未知;用幂等键、状态查询和审计收敛。
- 工具 annotations、网页内容和 tool result 都按来源设置信任,不因 JSON 化变可信。
最终掌握清单
概念
- 我能解释六类值、顶层标量、合法空白和对象/数组顺序。
- 我能区分 JSON、JSONL、NDJSON、JSON Text Sequences 与 JSON5。
- 我能解释数值精度、Unicode scalar、重复键与 canonicalization 风险。
- 我能区分语法、Schema、业务、授权、审批和执行结果。
Python
- 我会正确选择
load/loads/dump/dumps并显式使用 UTF-8。 - 我会拒绝重复键、非有限数、BOM、非法 UTF-8、孤立 surrogate 和超限结构。
- 我会为 JSONL 保留物理行号并定义失败策略。
- 我会做同目录原子替换,并能说明它不等于事务。
Schema
- 我会声明 Draft 2020-12 并调用
check_schema。 - 我会使用对象、数组、范围、
$defs/$ref、组合和条件。 - 我能区分可选/可空、
default/填值、format注解/断言。 - 我会用 JSON Pointer 和稳定 keyword 输出脱敏错误。
- 我会给 Schema 和 instance 都设计版本与迁移测试。
Agent 工程
- 我不会把模型 JSON、工具 annotations 或外部内容当成授权。
- 我会用可信 registry、allowlist、审批、幂等和结果验证包围工具执行。
- 我会处理拒绝、截断、流式不完整与 timeout 后未知结果。
- 我能让普通与
python -O测试数量一致,并避免真实凭据和线上副作用。
下一步
全部清单通过后,回到 JSON 学习目录。总路线下一站是 Markdown;需要把 JSON 放进网络请求时回到 API,需要执行模型工具时继续 Tool Calling(含 Function Calling)。
参考资料
资料复核日期:2026-07-22。