
一份工具返回的订单列表,三百行,每行七个字段,缩进写成 JSON 是 55922 个字符。同一份数据换成制表符分隔,18767 个字符,少了百分之六十六。两份装法的值是同一批,一行没少,一列没丢,差别全在「同一件事说了多少遍」上。
做这个账的起因很朴素:工具结果最后都要进上下文,而上下文是有上限的。裁掉一半内容会让下游判断出错,那就先问一个更便宜的问题,同样的内容有没有更短的装法。
先看六种装法的字符数。数据是本机按固定规则生成的三百行订单记录,数出来的都是 len(str),没有估算。
== 同一份 300 行工具返回值,六种装法的字符数 ==
1 缩进 JSON(indent=2) 55922 字符 占缩进 JSON 的 100.0% 行数 2702
2 紧凑 JSON 41521 字符 占缩进 JSON 的 74.2% 行数 1
3 紧凑 JSON + 去掉空值 38521 字符 占缩进 JSON 的 68.9% 行数 1
4 只留五个核心字段 33721 字符 占缩进 JSON 的 60.3% 行数 1
5 制表符分隔(TSV) 18767 字符 占缩进 JSON 的 33.6% 行数 301
6 Markdown 表格 23613 字符 占缩进 JSON 的 42.2% 行数 302
== 字段名重复占了多少 ==
七个字段名连引号带上冒号,在紧凑 JSON 里出现 2100 次,共 18600 字符
紧凑 JSON 总长 41521 字符,字段名占 44.8%
同样的七个字段名,在 TSV 里只写一次(表头),共 54 字符
TSV 比紧凑 JSON 少 22754 字符(54.8%)
== 换成「只留字段名一次」的另一种 JSON 写法 ==
列名 + 二维数组 23004 字符 占缩进 JSON 的 41.1%
== 有没有一行是省不掉的:三类字符的占比(以紧凑 JSON 为准) ==
数字 10800 个字符(26.0%)
引号 7800 个字符(18.8%)
其余 22921 个字符(55.2%)
== 校验:六种装法里,核心字段的值有没有丢 ==
1 缩进 JSON(indent=2) 核心字段值命中 1500/1500
2 紧凑 JSON 核心字段值命中 1500/1500
3 紧凑 JSON + 去掉空值 核心字段值命中 1500/1500
4 只留五个核心字段 核心字段值命中 1500/1500
5 制表符分隔(TSV) 核心字段值命中 1500/1500
6 Markdown 表格 核心字段值命中 1500/1500
== 缩进 JSON 里,白空格占多少 ==
空格 11700 字符(20.9%),换行 2701 个
== 结束 ==
缩进 JSON 里的空白占了很大一块,其中空格一万一千七百个,绝大部分用在每行的缩进上。紧凑 JSON 去掉的是排版,从 55922 掉到 41521,降幅 25.8%,而数据一个字节没变。去掉值为空的字段再降到 38521。只留五个核心字段是 33721,这时开始有信息取舍了。前两种只是排版差异,后两种开始舍得掉东西,去掉空值和只保留核心字段都属于这一类,值虽然还在核对的范围内,字段本身已经不在返回值里了。
制表符分隔 18767,Markdown 表格 23613。表格比 TSV 多出来的部分是每行两侧的竖线和表头分隔行。
省下来的到底是什么:
== 字段名重复占了多少 ==
七个字段名连引号带上冒号,在紧凑 JSON 里出现 2100 次,共 18600 字符
紧凑 JSON 总长 41521 字符,字段名占 44.8%
同样的七个字段名,在 TSV 里只写一次(表头),共 54 字符
TSV 比紧凑 JSON 少 22754 字符(54.8%)
== 换成「只留字段名一次」的另一种 JSON 写法 ==
列名 + 二维数组 23004 字符 占缩进 JSON 的 41.1%
== 有没有一行是省不掉的:三类字符的占比(以紧凑 JSON 为准) ==
数字 10800 个字符(26.0%)
引号 7800 个字符(18.8%)
其余 22921 个字符(55.2%)
== 校验:六种装法里,核心字段的值有没有丢 ==
1 缩进 JSON(indent=2) 核心字段值命中 1500/1500
2 紧凑 JSON 核心字段值命中 1500/1500
3 紧凑 JSON + 去掉空值 核心字段值命中 1500/1500
4 只留五个核心字段 核心字段值命中 1500/1500
5 制表符分隔(TSV) 核心字段值命中 1500/1500
6 Markdown 表格 核心字段值命中 1500/1500
== 缩进 JSON 里,白空格占多少 ==
空格 11700 字符(20.9%),换行 2701 个
== 结束 ==
七个字段名在每个对象里都写一遍,三百行就是两千一百次,连引号带上冒号一共 18600 个字符,占紧凑 JSON 的 44.8%。换成表格形态,这七个名字只在表头出现一次,一共 54 个字符。这就是从 41521 到 18767 那段差距的主要来源,不是「压缩」,是没说第二遍。
另一部分在空白里:
== 缩进 JSON 里,白空格占多少 ==
空格 11700 字符(20.9%),换行 2701 个
== 结束 ==
空格 11700 个字符,换行 2701 个,加起来接近缩进 JSON 的三成。这些字符对机器没有信息量,缩进 JSON 唯一的优势是人能直接看,而工具返回的值通常是给下游读的,不是给人读的。
还有第三种装法值得放一起看,列名加二维数组,字段名也只写一次,但保留了 JSON 的类型和嵌套:
== 换成「只留字段名一次」的另一种 JSON 写法 ==
列名 + 二维数组 23004 字符 占缩进 JSON 的 41.1%
== 有没有一行是省不掉的:三类字符的占比(以紧凑 JSON 为准) ==
数字 10800 个字符(26.0%)
引号 7800 个字符(18.8%)
其余 22921 个字符(55.2%)
== 校验:六种装法里,核心字段的值有没有丢 ==
1 缩进 JSON(indent=2) 核心字段值命中 1500/1500
2 紧凑 JSON 核心字段值命中 1500/1500
3 紧凑 JSON + 去掉空值 核心字段值命中 1500/1500
4 只留五个核心字段 核心字段值命中 1500/1500
5 制表符分隔(TSV) 核心字段值命中 1500/1500
6 Markdown 表格 核心字段值命中 1500/1500
== 缩进 JSON 里,白空格占多少 ==
空格 11700 字符(20.9%),换行 2701 个
== 结束 ==
23004 个字符,比 Markdown 表格还少一点,比 TSV 多两成。多出来的部分是引号和括号这类符号,换回来的是每个值的类型不会被猜:数字还是数字,null 还是 null,含分隔符的字符串不会被切错。
最后核一遍有没有为了省字符把值弄丢。
== 校验:六种装法里,核心字段的值有没有丢 ==
1 缩进 JSON(indent=2) 核心字段值命中 1500/1500
2 紧凑 JSON 核心字段值命中 1500/1500
3 紧凑 JSON + 去掉空值 核心字段值命中 1500/1500
4 只留五个核心字段 核心字段值命中 1500/1500
5 制表符分隔(TSV) 核心字段值命中 1500/1500
6 Markdown 表格 核心字段值命中 1500/1500
== 缩进 JSON 里,白空格占多少 ==
空格 11700 字符(20.9%),换行 2701 个
== 结束 ==
六种装法的核心字段值都命中 1500 个,没有哪种是靠在数据上打折换来的长度。这一步不能省:任何一次装法变化都可能在类型和空值这类细节上出问题,长度省了,值错了,下游的错误会藏得很深。
把数字连起来看,结论有两条。第一条是排版差异比想象中贵,同一个数据结构,只把缩进和换行去掉就少了四分之一字符,这一步没有任何风险,应该默认做。第二条是表格形态的节省来自结构本身,只要结果是「同类记录很多条」,把字段名提到表头就省掉四成以上。
这里的判断有一处没实测:模型读 TSV 和读缩进 JSON 的准确率差别,本机没有可供调用的模型接口,行为这一层不做结论。能说的只有字符账和值有没有丢,模型侧的表现留给有条件的人去测。
所以我给的取舍是按结果形态分。列表型的返回值走「列名加二维数组」,字段名只写一次,类型不丢;单个对象或者嵌套深的返回值保持紧凑 JSON,硬压成表格会引入转义歧义。剩下的那些省字符的手法,比如去掉空字段,能做但要留意一件事:缺字段和值为空在下游往往是两种不同的判断,省之前先确认调用方分得清。