TOON 与 JSON 对比:字节级效率模型
针对不同数据结构,对 TOON 与 JSON 的字节效率进行的数学分析。
本文档的范围
本页展示的是 TOON 与 JSON 之间基于理论、字符层面的对比。关于实际的基准测试和 token 计数,请参阅 性能基准。这是一份高级的、非规范性参考资料:它从数学角度解释了 TOON 的设计原理,但并不会改变 TOON 规范本身。
概述
标准 JSON 引入了结构性冗余,从而增加了 token 用量和推理成本。本页对 TOON 与 JSON 进行字节级形式化对比,以评估 TOON 是否通过消除结构冗余实现了可量化的效率提升。
在下文所述的假设条件下(紧凑 JSON、规范 TOON、ASCII 键与标点符号、浅到中等程度的嵌套,以及大多数不加引号的 TOON 字符串),对于本文分析的结构类型,除了"数组的数组"之外,TOON 的结构性开销都低于紧凑 JSON。
关键发现
- 表格化数组 是 TOON 的最佳使用场景,其效率提升随行数和字段数的增加而线性增长。
- 简单对象和基本类型数组 显示出稳定的字节数削减,节省量与字段数或元素数成正比。
- 嵌套对象 能从降低的开销中受益,但由于缩进成本,效率会随深度增加而下降;在足够深的嵌套下,紧凑 JSON 可能变得更小。
- 数组的数组 是本分析中唯一 TOON 效率低于 JSON 的结构,这是由于 TOON 显式的列表标记和内部数组头部所致。
方法论
我们为两种格式分别定义了递归的字节长度函数
其中
范围与假设
- 紧凑 JSON:假定 JSON 是紧凑的(字符串之外没有空格或换行符)。字节数按此紧凑形式计算。
- 规范 TOON:假定 TOON 遵循规范格式(缩进 = 2 空格,
:后恰好一个空格,数组/字段列表中逗号后无空格,无尾随空格)。 - 键与字符串:所有键均为"简单的" ASCII 标识符风格键,它们:
- 在 JSON 中必须加引号,并且
- 在 TOON 中可以不加引号(不含任何会强制要求加引号的字符)。 许多示例假定值为数字、布尔值、null,或是可以在 TOON 中不加引号、但在 JSON 中必须加引号的 TOON 安全字符串。
- 数字:仅在本分析中,假定两种格式使用相同的规范十进制表示。JSON 可以使用指数记法,但为了单独分析结构性差异,此处忽略这一点。
- ASCII/UTF-8:假定键和结构性 token 均为 ASCII,因此字节长度等于字符数(
)。非 ASCII 内容对两种格式的影响类似,不会改变结构性结论。 - 嵌套深度:针对扁平结构和单层嵌套给出了封闭形式的表达式。TOON 中每增加一层嵌套,每个嵌套行就会增加 2 字节的缩进。在足够深的嵌套下,紧凑 JSON 的大括号可能比 TOON 的缩进更有优势(参见 何时不使用 TOON)。
- 字节数 vs token 数:现代 LLM 分词器基于 UTF-8 字节运作,因此字节长度是 token 数的一个良好上界和一阶近似,尽管这种映射关系并非严格线性。
可以将其理解为一个简化的结构模型:我们剥离了现实世界中的各种噪声,只问一个问题——"如果只计算结构性字符,JSON 和 TOON 相比如何?"
形式化记号
数据模型
设
设
设
其中:
是一个键(字符串) 可以是一个基本类型值 、一个对象 ,或一个数组
因此:
字符串长度
设
整数长度
设
JSON 大小函数
对于一个具有
其中
JSON 中的基本类型值
当
| 类型 | 公式 |
|---|---|
| 字符串 | |
| 数字 | |
| 布尔值 | |
| Null |
JSON 中的数组
当
TOON 大小函数
对于一个具有
其中
TOON 中的基本类型值
当
| 类型 | 公式 |
|---|---|
| 字符串(普通) | |
| 字符串(看起来像数字/布尔值) | |
| 数字 | |
| 布尔值 | |
| Null |
TOON 中的简单数组
此处 key[N]: ... 的长度,而不仅仅是数组值本身。
当
TOON 中的表格化数组
当
说明:项
按结构类型的效率分析
以下每个小节都关注一种特定的结构类型,给出对应的公式,并展示一个小示例。直观来说,TOON 在以下情况下往往占优:
- 避免重复键名(表格化数组),
- 避免为键和大多数值加引号,
- 以及用缩进代替大括号,
而在需要为每个元素支付固定开销(数组的数组)或深度缩进(高度嵌套的配置)时往往落于下风。
简单对象
带有基本类型字符串值的扁平对象是最容易取胜的场景:JSON 要为大括号、带引号的键和字符串付出代价,而 TOON 在根级别去掉了大括号,省略了简单键的引号,并且每个字段一行。
对于仅含字符串基本类型值的对象:
如果所有值都是在 TOON 中可以不加引号的字符串,可简化为:
示例: 对于 1,000,000 个对象,TOON 节省 3,000,002 字节 ≈ 2.86 MB。
实证验证
{ "id": 1, "name": "Ada" }id: 1
name: Ada嵌套对象
添加一个包装对象(多一层嵌套)会为 JSON 引入额外的大括号,并为 TOON 引入额外的缩进和换行符。对于带有基本类型值的单层嵌套,TOON 仍然占优,但净优势会更小。
对于带有基本类型值的单层嵌套:
示例: 对于 1,000,000 个嵌套对象(深度为 1),TOON 节省 1,000,005 字节 ≈ 0.95 MB。
注意事项
该公式仅适用于单层嵌套。TOON 中每多一层嵌套,每个嵌套行就会增加 2 个空格的缩进;在足够深的嵌套下,紧凑 JSON 可能变得更小,尤其是当表格化的可能性消失时(参见 何时不使用 TOON 以及 性能基准 中的"深度嵌套配置"数据集)。
实证验证
{ "user": { "id": 1, "name": "Ada" } }user:
id: 1
name: Ada基本类型数组
对于字符串基本类型数组,JSON 写作 ["foo","bar","baz"],为每个字符串加引号,并使用 [] 表示数组。TOON 写作 key[N]: foo,bar,baz,只为长度标记付出一次代价,而省略了大部分引号。
对于由
如果字符串值在 TOON 中可以不加引号,可简化为:
示例: 对于 1,000,000 个元素,TOON 节省 1,999,996 字节 ≈ 1.91 MB。
实证验证
{ "tags": ["foo", "bar", "baz"] }tags[3]: foo,bar,baz根数组
在根级别,JSON 写作 ["x","y","z"];TOON 写作 [3]: x,y,z。这里没有对象键的开销,因此优势主要来自不为 TOON 安全字符串加引号,以及用 [N]: 代替 []。
对于由
示例: 对于 1,000,000 个元素,TOON 节省 1,999,991 字节 ≈ 1.91 MB。
实证验证
["x", "y", "z"][3]: x,y,z表格化数组
结构一致的对象数组是 TOON 的最佳应用场景。JSON 为每一行重复每个键,而 TOON 只声明一次长度和列名(key[N]{id,qty,...}:),然后以裸值的形式流式呈现各行。
对于具有
示例: 对于 1,000,000 行、2 个字段、字段名长度为 3 个字符的情况,TOON 节省 11,999,987 字节 ≈ 11.44 MB。
正是在这里,TOON 的设计(只声明一次字段,流式呈现各行)带来了最强的收益:节省量随行数和字段数二者线性增长。
实证验证
{ "items": [{ "id": 1, "qty": 5 }, { "id": 2, "qty": 3 }] }items[2]{id,qty}:
1,5
2,3数组的数组
基本类型数组组成的数组,是 TOON 在结构上落于下风的场景:每个内部数组都变成了一个带有自身头部的列表项,因此 TOON 要为每个内部数组支付固定开销("- " 加上 "[m]: "),而 JSON 只需使用逗号。
实践提示
对于基本类型数组组成的数组,该模型预测 JSON 的字节效率比 TOON 更高,因为 TOON 每个内部数组要多付出约 6 字节("- " 占 2 字节,"[m]: " 占 4 字节),再加上长度标记。
对于具有
对于字符串基本类型且
示例: 对于 1,000,000 个数组、
实证验证
{ "pairs": [[1, 2], [3, 4]] }pairs[2]:
- [2]: 1,2
- [2]: 3,4看起来像字面量的字符串
看起来像数字或布尔值的字符串(例如 "123"、"true")在 JSON 和 TOON 中都必须加引号,这会略微削弱 TOON 的优势,因为它不再能在这些值上节省引号。
对于包含此类字符串的对象:
示例: 对于 1,000,000 个对象,TOON 节省 2,000,002 字节 ≈ 1.91 MB。
实证验证
{ "version": "123", "enabled": "true" }version: "123"
enabled: "true"空结构
即使是极小的规模,空容器也能揭示出结构性差异。
空对象:
JSON 需要 {}(2 字节),而 TOON 中完全为空的根对象则表示为一个空文档(0 字节)。
空数组(字段):
对于名为 key 的字段,JSON 以紧凑形式使用 {"key":[]},而 TOON 使用:
key: []在该模型下,这为 TOON 带来了恒定的 3 字节优势。出于向后兼容考虑,旧式的 key[0]: 形式仍可解码。
总结表
下表汇总了各公式以及在建模假设下哪一方占优。
| 结构 | 效率公式 | TOON 是否占优? |
|---|---|---|
| 简单对象 | ✅ 是 | |
| 嵌套对象(1 层) | ✅ 是(随深度增加而收窄) | |
| 基本类型数组 | ✅ 是 | |
| 根数组 | ✅ 是 | |
| 表格化数组 | ✅ 最佳场景 | |
| 数组的数组 | ❌ JSON 在此更优 | |
| 字符串字面量 | ✅ 是(优势较小) | |
| 空结构 | ✅ 是 |
简而言之:
- 对于扁平对象,TOON 的收益与字段数量成线性关系。
- 对于数组,收益随元素数量线性增长;对于表格化数组,收益随行数和字段数双线性增长。
- 数组的数组是 JSON 更小的主要结构性场景。
- 深度嵌套和大量引号会在实际数据中削弱甚至逆转这些优势。
结论
这个简化的理论模型支持了 TOON 的设计目标:从结构上看,在许多常见模式下,它通过以下方式降低了相对于紧凑 JSON 的开销:
- 避免在表格化数组中重复键名,
- 省略许多键和值的引号,
- 以及在较浅的深度下用缩进代替大括号。
对于本文所考察的结构类型,在所述假设条件下,除了数组的数组之外,TOON 的结构性开销都低于紧凑 JSON。由于 UTF-8 字节长度是 token 数的一个合理的一阶近似,这些结构性节省通常会转化为这些模式下更低的 token 数量。
与此同时,这是一个刻意简化的模型。在真实数据集中,其他因素——更深或不规则的嵌套、大量加引号的字符串、JSON 中的指数记法,以及分词器的特殊行为——可能会削弱甚至逆转这些收益。我们的 性能基准 和 何时不使用 TOON 表明,对于深度嵌套或表格化程度较低的数据,紧凑 JSON 可能更高效。请将本页作为理解 TOON 为何 如此表现的直觉参考,而不是普遍适用的保证。
相关资源
参考文献
本分析基于以下内容:
- 原始研究:TOON vs. JSON: A Mathematical Evaluation of Byte Efficiency in Structured Data
- TOON 规范:toon-format/spec
- JSON 规范:RFC 8259、ECMA-404
本页由 Mateo Lafalce(@mateolafalce)贡献。
对该形式化分析有疑问,或发现了错误?欢迎在 GitHub 上提出 issue,或为本分析贡献改进内容。