TOON 与 JSON 对比:字节级效率模型
本文从数学角度分析不同数据结构下 TOON 相对于 JSON 的字节效率。
本文档的范围
本页从理论角度比较 TOON 与 JSON 的字符级开销。如需查看实际基准测试和 token 计数,请参阅 性能基准。本文属于进阶参考资料,不具有规范效力。它从数学角度解释 TOON 的设计思路,但不改变 TOON 规范本身。
概述
标准 JSON 会引入额外的结构性字符。这会增加 token 用量和推理成本。本页从字节级对 TOON 与 JSON 进行形式化比较,评估 TOON 能否通过减少结构性冗余获得可量化的效率提升。
本文的比较基于几个前提:JSON 采用紧凑形式,TOON 采用规范格式。键和标点均为 ASCII。嵌套深度较浅或中等。大多数字符串无需加引号。在这些前提下,除“数组的数组”外,TOON 在本文分析的各类数据结构中,结构性开销都低于紧凑 JSON。
关键发现
- 表格化数组 是 TOON 最适合的场景。行数和字段数越多,效率提升越明显,并且呈线性增长。
- 简单对象和基本类型数组 通常能稳定减少字节数,节省量与字段数或元素数成正比。
- 嵌套对象 可受益于较低的结构性开销。但缩进也会带来额外成本。嵌套越深,TOON 的优势越小。嵌套足够深时,紧凑 JSON 反而可能比 TOON 更省字节。
- 数组的数组 是本分析中唯一 TOON 效率低于 JSON 的结构。原因是 TOON 需要显式的列表标记和内部数组首部。
方法论
我们分别为 JSON 和 TOON 定义递归的字节长度函数:
其中
范围与假设
紧凑 JSON:假定 JSON 是紧凑的(字符串之外没有空格或换行符)。字节数按此紧凑形式计算。
规范 TOON:假定 TOON 遵循规范格式。缩进为 2 个空格,
:后恰好一个空格,数组和字段列表中逗号后无空格,也没有行尾空格。键与字符串:所有键都是“简单”的 ASCII 标识符风格键。也就是说,它们:
- 在 JSON 中必须加引号,并且
- 在 TOON 中可以不加引号(不含任何会强制要求加引号的字符)。
许多示例假定值为数字、布尔值、null,或符合 TOON 非引号字符串规则、但在 JSON 中必须加引号的字符串。
数字:仅在本分析中,假定两种格式使用相同的规范十进制表示。JSON 可以使用指数记法。但为单独分析结构性差异,本文忽略这一点。
ASCII/UTF-8:假定键和结构性 token 均为 ASCII。因此,字节长度等于字符数(
)。非 ASCII 内容对两种格式的影响类似,不会改变结构性结论。 嵌套深度:本文针对扁平结构和单层嵌套给出闭式表达式。TOON 中每增加一层嵌套,每个嵌套行就会增加 2 字节缩进。嵌套足够深时,紧凑 JSON 的大括号可能比 TOON 的缩进更省字节(参见 何时不使用 TOON)。
字节数 vs token 数:现代大语言模型分词器基于 UTF-8 字节工作。因此,字节长度可以作为 token 数的上界和一阶近似。不过,二者并不是严格线性映射。
可以把它理解为一个简化的结构模型。它先剥离真实数据中的各种干扰因素,只关注一个问题:“如果只计算结构性字符,JSON 和 TOON 相比如何?”
形式化记号
数据模型
设
设
设
其中:
是键(字符串) 可以是基本类型值 、对象 ,或数组
因此:
字符串长度
设
整数长度
设
JSON 字节长度函数
对于具有
其中
JSON 基本类型值
当
| 类型 | 公式 |
|---|---|
| 字符串 | |
| 数字 | |
| 布尔值 | |
| Null |
JSON 数组
当
TOON 字节长度函数
对于具有
其中
TOON 基本类型值
当
| 类型 | 公式 |
|---|---|
| 字符串(普通) | |
| 字符串(看起来像数字/布尔值) | |
| 数字 | |
| 布尔值 | |
| Null |
TOON 简单数组
此处 key[N]: ... 的长度,而不只是数组值本身。
当
TOON 表格化数组
当
说明:项
按结构类型的效率分析
以下各小节分别分析一类特定的数据结构。每一节都会给出相应公式,并附简短示例。直观来看,在以下情况下 TOON 通常更省字节:
- 避免重复键名(表格化数组),
- 避免为键和大多数值加引号,
- 以及用缩进代替大括号,
但在另一些情况下,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 更省字节。数据无法整理为表格化结构时,这一点尤其明显(参见 何时不使用 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 的设计目标。从结构层面看,在许多常见数据模式中,TOON 可以通过以下方式降低相对于紧凑 JSON 的开销:
- 避免在表格化数组中重复键名,
- 省略许多键和值的引号,
- 并在嵌套较浅时用缩进代替大括号。
对于本文考察的结构类型,在上述假设下,除数组的数组外,TOON 的结构性开销都低于紧凑 JSON。UTF-8 字节长度可以作为 token 数的合理一阶近似。因此,这些结构性节省通常会转化为相应模式下更低的 token 数。
同时,这个模型有意做了简化。真实数据集还会受到其他因素影响,例如更深或不规则的嵌套、大量需要加引号的字符串、JSON 中的指数记法,以及分词器的特殊行为。这些因素都可能削弱甚至逆转 TOON 的收益。
基准测试 和 何时不使用 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,或为本分析贡献改进内容。