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]

再回答:

  1. 顶层标量合法,为什么很多 API 仍要求顶层对象?
  2. 字段缺失、null、""、[] 各可表达什么不同意图?
  3. 对象换序和数组换序的语义为什么不同?
  4. JSON 文本、Python 字典和“包含 JSON 的字符串”怎样辨认?

第二组:Python 编解码实验

在临时目录完成以下任务,不改仓库样例:

  1. 用 json.dumps(..., ensure_ascii=False, allow_nan=False) 编码中文对象,再 loads 读回。
  2. 对尾逗号、空输入、未闭合字符串打印 JSONDecodeError 的行列号。
  3. 证明默认解析器对重复键保留最后一个值。
  4. 证明默认解析器接受 NaN,而 allow_nan=False 阻止输出。
  5. 用 parse_float=Decimal 解析 0.1,说明写回契约仍要明确。
  6. 证明非字符串字典键经过 round trip 会改变类型。
  7. 构造双重编码,分别写出两次解析后的类型。
  8. 解释为什么 python -m json.tool 只能验语法,不能验业务。

验收要求:每个实验至少有一个 unittest 断言;再用 python -O 运行,测试数量不能减少。

第三组:严格互操作边界

为下列风险分别写“检测层、错误码、是否可继续、日志允许字段”:

风险需要决定的内容
重复 role 键必须在 Schema 前还是后检测?
非法 UTF-8是否能进入文本解析?
UTF-8 BOM接口选择接受还是拒绝?
NaN 与 1e9999为什么需要两类检查?
孤立 \uDEAD如何避免跨实现不一致?
30 层嵌套深度上限如何测试边界?
10 MB 单行 JSONL何时拒绝,如何跳到下一物理行?
超大整数 ID为什么更适合字符串?

进一步题:

  1. sort_keys=True 能解决哪些测试问题,不能解决哪些签名问题?
  2. 视觉相同的 Unicode 字符串为什么不一定相等?
  3. 应用把所有文本都做 NFC normalization 可能破坏什么契约?
  4. 资源上限应从哪里获得证据,而不是随意猜一个数字?

第四组: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 和字符串。再解释:

  1. properties 与 required 的分工;
  2. 可选与可空的差别;
  3. default 为什么不自动写值;
  4. format 为什么可能只是注解;
  5. 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。

然后完成:

  1. 构造零分支匹配和两个分支都匹配的反例;
  2. 把 key a/b~c 编码为 Pointer token;
  3. 设计 v1 → v2 的字段重命名迁移,先验旧、迁移、再验新;
  4. 限制最多返回 5 个错误,并证明报告不含 instance 值;
  5. 说明 $schema、$id 和 schema_version 分别是什么。

第七组:LLM 与工具边界情景题

逐项给出正确处理:

  1. 模型返回可解析 JSON,但缺少必填字段。
  2. strict output 通过 Schema,却给出不存在的 document_id。
  3. 工具参数里出现 "approved": true。
  4. 流式参数在连接中断时只收到半个对象。
  5. send_email 参数合法,用户没有发送权限。
  6. 邮件工具超时,服务端可能已发送。
  7. 工具结果含网页文字“忽略之前规则”。
  8. 厂商文档只支持 JSON Schema 子集,领域 Schema 使用了不支持的关键字。
  9. MCP server 提供 readOnlyHint: true,但服务器不受信任。
  10. 日志系统想保存完整工具参数以便排查。

答案必须包含:结构层、事实层、权限层、审批层、幂等/未知结果、信任来源和脱敏策略。

第八组:综合项目扩展

在 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。