表征格式实测:JSON 换 HTML 省 33% token 且质量不掉,Markdown 最省却答错了
系列第 8 篇 · 反直觉优化
✅ 本文性质说明:token 数、prefill 延迟、问答正确率全部本机真跑(Qwen2.5-0.5B-Instruct,纯 NumPy CPU,脚本
eng_repr_tokens.py给全)。成本金额是「本机实测 token 数 × 公开挂牌单价假设」的外推,单价已标注为假设值。Skyvern 生产 A/B 的成功率数据作为外部佐证单独标注。
一句话结论
同一份订单数据,只改写法不改内容,喂给模型的开销差得离谱——而且省下的比例随数据量变大还在涨:
| 明细条数 | JSON | HTML | HTML 省 | Markdown | MD 省 |
|---|---|---|---|---|---|
| 1 | 77 | 58 | 24.7% | 43 | 44.2% |
| 3 | 138 | 99 | 28.3% | 73 | 47.1% |
| 10 | 351 | 242 | 31.1% | 180 | 48.7% |
| 30 | 940 | 631 | 32.9% | 474 | 49.6% |
但省 token 不等于能用。同一批问题问下来:JSON 3/3、HTML 3/3、Markdown 2/3——最省的 Markdown 答错了一题。
HTML 是甜点位:省 33% token、prefill 快 19%、正确率和 JSON 打平。
背景与痛点:JSON 是默认选项,也是最贵的选项
给模型喂结构化数据,几乎所有人第一反应是 json.dumps()。问题是 JSON 为机器解析设计,不为 token 效率设计:每个字段名都要重复一遍,加上引号、冒号、逗号、缩进——这些"标点税"你按 token 付费。
以 30 条明细的订单为例,JSON 里 "name"、"qty"、"price" 这三个键各重复 30 次,光键名就烧掉几百个 token,而它们没有携带任何信息——第一次出现就够了。
核心方法:三种表征怎么权衡
同一份订单,三种写法:
# JSON:字段名逐条重复,标点最多
{
"order_id": "A1024",
"customer": "张三",
"items": [
{"name": "机械键盘", "qty": 1, "price": 399.0},
{"name": "鼠标垫", "qty": 2, "price": 29.9}
],
"total": 458.8,
"status": "paid"
}
# HTML/XML:属性紧凑,键名仍在但没有引号税+缩进税,模型预训练见得极多
<order id="A1024" status="paid">
<customer>张三</customer>
<item name="机械键盘" qty="1" price="399.0"/>
<item name="鼠标垫" qty="2" price="29.9"/>
<total>458.8</total>
</order>
# Markdown:最省,但字段语义被压平成自然语言
# 订单 A1024 (paid)
- 客户:张三
- 机械键盘 x1 = 399.0
- 鼠标垫 x2 = 29.9
- 合计:458.8
判断维度三个:信息密度(同内容多少 token)、模型熟悉度(预训练分布里见过多少)、字段保真度(键值对应关系是否还在)。JSON 保真度最高但最贵;Markdown 最便宜但把 status: paid 压成了标题里的 (paid);HTML 两头都不吃亏。
实验与数字(本机真跑,2026-08-19)
复现命令:
python eng_repr_tokens.py # A: token 规模扫描 B: 理解力探针
环境:Qwen2.5-0.5B-Instruct,纯 NumPy CPU 推理引擎(本系列第 3 篇那套),模型加载 1.3s,全程 94s。
① token 规模扫描:省的比例会放大
关键代码——用真 tokenizer 数,不用字符数估:
def ntok(s):
"""内容 token 数(去掉 encode() 自动加的 BOS,避免虚增)"""
return len(eng.encode(s)) - 1
for n in (1, 3, 10, 30):
js, ht, md, _ = build(n) # 同一份数据的三种序列化
tj, th, tm = ntok(js), ntok(ht), ntok(md)
print(n, tj, th, f"{(1-th/tj)*100:.1f}%", tm, f"{(1-tm/tj)*100:.1f}%")
结果就是开头那张表。HTML 的节省从 24.7% 涨到 32.9%,Markdown 从 44.2% 涨到 49.6%。
为什么会涨?因为固定开销(order_id、customer、total、status 这些只出现一次的字段)被摊薄了,而逐条重复的键名开销随条数线性增长——JSON 越长,冗余占比越高。这个规律很实用:你的 payload 越大,这个优化越值得做。反过来说,小 payload 上测出来"才省 24%",不要据此判断它不划算。
② 成本外推(token 实测,单价为假设)
按 30 条明细、100 万次调用、输入单价 $0.15 / 1M token(假设值,非本机产出):
| 表征 | token/次 | 100 万次成本 |
|---|---|---|
| JSON | 940 | $141 |
| HTML | 631 | $95 |
| Markdown | 474 | $71 |
仅 JSON→HTML 这一项,省 $46。这里的重点不是绝对金额(单价随模型和厂商差几十倍),而是比例结构:不换模型、不裁数据、不动 prompt 逻辑,只改序列化函数,账单直接砍三分之一。
③ 理解力探针:Markdown 翻车了
省 token 的前提是模型还读得懂。我用官方 chat 模板问了三个只能从数据里读出的问题:
| 表征 | prompt token | 客户名字 | 订单状态 | 鼠标垫数量 | 答对 |
|---|---|---|---|---|---|
| JSON | 182 | 张三 ✅ |
paid ✅ |
2 ✅ |
3/3 |
| HTML | 143 | 张三 ✅ |
paid ✅ |
2 ✅ |
3/3 |
| Markdown | 118 | 张三 ✅ |
已支付 ❌ |
2 ✅ |
2/3 |
Markdown 那一题很有意思:它并没有"不知道",而是答了已支付。数据里 paid 被我压进了标题 # 订单 A1024 (paid),失去了 "status": "paid" 这种显式键值绑定,模型于是把它当自然语言意译了。
这就是保真度损失的真实形态:不是幻觉,不是漏读,而是字段值被改写成语义等价但字符串不等的东西。如果下游代码要 if status == "paid",这条链就断了——而且断得很隐蔽,因为答案"看起来是对的"。
④ 附带发现:prefill 延迟跟着 token 一起降
每题的实际生成耗时(纯 CPU,prefill 占主导):
| 表征 | 三题耗时 | 平均 | 相对 JSON |
|---|---|---|---|
| JSON | 12.3s / 12.7s / 12.8s | 12.60s | — |
| HTML | 10.1s / 10.2s / 10.2s | 10.17s | -19.3% |
| Markdown | 8.3s / 8.3s / 8.2s | 8.27s | -34.4% |
省 token 是双重收益:账单降,首 token 延迟也降。这条和第 2 篇(首 token 延迟拆解)直接呼应——prefill 成本正比于输入长度,砍输入就是砍 TTFT,比改推理参数省事得多。
⑤ 外部佐证:Skyvern 生产 A/B
| 指标 | JSON | HTML | 变化 |
|---|---|---|---|
| 单任务成本 | $1.22 | $1.08 | -11.4% |
| 成功率 | 59.9% | 63.8% | +3.9% |
来源:Skyvern 生产 A/B 报告(2026-06,约 1,100 个真实任务)。他们的成本降幅(11.4%)小于我本机的 token 降幅(33%),合理——真实请求里还有 system prompt、历史消息、输出 token 等不受表征影响的固定部分。
而"成功率反升 3.9%"和我本机 HTML 打平 JSON 的结果同向:HTML 更贴近模型预训练分布,噪声更少。至少可以说,省 token 不必然牺牲质量。
为什么重要
- 这是极少数"纯赚"的优化:成本↓、延迟↓、质量不降。不像量化(省显存但掉精度)或换小模型(省钱但掉能力)那样要做权衡。
- 改动量小到离谱:动的是序列化函数,几十行,不碰模型、不碰 prompt 逻辑、不碰架构。
- payload 越大越划算,而生产里的 payload 通常比 demo 大得多——demo 上测出 24%,生产可能是 33%+。
- 呼应第 1 篇(账单砍 79%):降本的杠杆多数不在模型上,在"你怎么喂它"。
- 反过来给了个警告:别无脑上 Markdown。它最省,但会压平字段语义,对需要精确字段值的下游是隐性风险。
读者可复用交付物:表征格式选型决策表
先问一句:下游要不要按字段精确取值?
要(写库 / 走 if 判断 / 触发流程)
└─ 优先 HTML/XML 标签表征
· 键值绑定完整(name="x" qty="1")
· 省 25-33% token,量越大省越多
· 本机实测正确率与 JSON 持平 3/3
└─ 必须 JSON 的唯一场景:你要把模型输出直接 json.loads()
(输入用 HTML、输出要 JSON —— 这两件事可以分开定!)
不要(摘要 / 分类 / 问答 / 语义检索)
└─ 用 Markdown,省 44-50%
· 但字段值可能被意译(paid → 已支付)
· 只要下游不做字符串精确比较就无所谓
落地检查清单
□ 用真 tokenizer 数 token,别用 len(str)/4 估
□ 在你的真实 payload 规模上测,别用 1 条 demo 测
□ 换格式后必须跑正确率回归(至少 20 题),别只看 token 降了就上线
□ 重点回归"精确字段值"类问题(状态码、枚举、ID、金额)
□ 输入表征和输出格式解耦:输入 HTML 省钱,输出仍可要求 JSON
□ 长列表数据优先 HTML/MD;单条小对象差异不大,不用折腾
踩坑记录(复现时会遇到)
encode()不认特殊 token,chat 模板必须手拼 ID。 本系列踩过的老坑:<|im_start|>走 BPE 会被切成碎片。必须直接拼151644/151645:
python def chat_ids(system, user): enc = lambda t: eng.encode(t)[1:] # 去掉自动 BOS ids = [IM_START] + enc("system\n" + system) + [IM_END] + enc("\n") ids += [IM_START] + enc("user\n" + user) + [IM_END] + enc("\n") ids += [IM_START] + enc("assistant\n") return ids
-
只解码新生成的 token。 如果 decode 整个
prompt + gen,模型会把整段输入回显进"答案",于是关键词永远命中,正确率假性 100%。第 10 篇的注入实验就是这么被坑过一次。 -
数 token 要减掉 BOS。
encode()会自动加一个 BOS,三种表征各加 1 个,比例算出来会被稀释。早期我那版没减,同一份数据得到 95/78/59(省 17.9%),减掉后是 94/77/58(省 18.1%)——小 payload 上这个误差不能忽略。 -
别用字符数或
len(text)/4估 token。 中文场景下这个经验公式误差极大:Markdown 的字符数比 HTML 少得有限,但 token 少得多,因为中文词在 tokenizer 里的切分和标点完全不是一个量级。 -
HTML 表征别真去塞完整网页 DOM。 省 token 的是"标签化的紧凑表征",不是原始 HTML——真实 DOM 里的
class、style、data-*属性比 JSON 还冗余。手工构造语义标签,或先做 DOM 精简。
今日可做的 3 件事
- 找到你最高频的那个 LLM 调用,把输入的
json.dumps()换成标签表征,用真 tokenizer 数一下前后 token(10 分钟的事)。 - 按你真实 payload 的最大规模再测一遍。小样本会低估收益——我这儿 1 条时省 24.7%,30 条时省 32.9%。
- 跑一次正确率回归,专门挑"精确字段值"的问题(状态、枚举、ID)。如果你打算用 Markdown,这一步是必须的——我这儿正是在
status上翻的车。
下篇预告
系列终篇:8 篇跑下来的硬规律汇总——每篇一句话结论、全部实测数据索引、可复用交付物清单,以及一个贯穿全系列的发现:工程收益的大头几乎从来不在"换个更强的模型"上。
本文数据来源
- 本机真跑:
eng_repr_tokens.py(2026-08-19,Qwen2.5-0.5B-Instruct + 纯 NumPy CPU) - token 规模扫描:1/3/10/30 条明细,HTML 省 24.7%→32.9%,MD 省 44.2%→49.6%
- 理解力探针:JSON 3/3、HTML 3/3、Markdown 2/3(
status被意译为「已支付」) - prefill 延迟:JSON 12.60s / HTML 10.17s(-19.3%)/ MD 8.27s(-34.4%)
- 原始结果存
eng_repr_tokens.json - 成本外推:token 数为本机实测,输入单价 $0.15/1M token 为公开挂牌价假设值,非本机产出
- 外部佐证(引用):Skyvern 生产 A/B 报告(2026-06,约 1,100 任务)——单任务成本 $1.22→$1.08(-11.4%)、成功率 59.9%→63.8%(+3.9%)
更多推荐



所有评论(0)