TOON for LLMs:基准性能分析
I’m happy to translate the article for you, but I’ll need the full text of the post (the content you’d like translated). Could you please paste the article’s body here? Once I have the text, I’ll provide a Simplified‑Chinese translation while preserving the original formatting, markdown, and any code blocks.
每次使用 JSON 的 API 调用都比你想象的更耗费
我使用 Gemini 2.5 Flash 进行真实场景的抽取实验,结果令人震惊:JSON 的输出 token 数始终比 TOON 格式多 30–40 %。在一次测试中,JSON 消耗了 471 个输出 token,而 TOON 只用了 227——降低了 51 %。
但有趣的地方在于: TOON 最初的失败率高达 70 %。
经过优化后,我实现了 100 % 的解析成功率,并发现了一个违背直觉的事实——TOON 实际上 整体上为你省钱,因为在需要可靠解析时它使用的提示 token 更少。当我使用 Pydantic 模型测试结构化输出时,JSON 需要 389 个输出 token,而 TOON 的编码方式更为简洁。
隐藏的金矿? 工具/函数调用
这正是 TOON 紧凑格式发挥最大优势的地方,在响应会成为下一个提示的代理工作流中,大幅削减 token 成本。
这并非理论推测。下面展示了实际的提示、解析错误、token 计数以及将 TOON 从 70 % 失败率提升到可投入生产的代码。TOON 是否优于 JSON 取决于你的使用场景——而我拥有的数据可以准确证明何时适用。
让我们拆解这些数字
实验 #1 – 初始 TOON 失败(成功率 70 %)
我从一个直接的测试开始:使用 TOON 而不是 JSON 提取结构化的职位描述数据。
设置
我的提示很简单——让 Gemini 2.5 Flash 提取 角色、技能、经验、地点和职责。对于输出格式,我使用了看似合乎逻辑的方式:展示 TOON 的编码结构,使用实际的输出格式(本质上是直接替换的方法)。
提示
Extract Role, Primary Skills, Secondary Skills,
Minimum Experience, Maximum Experience,
Location, Employment Type, Summary, and Responsibilities
Job Description:
Output in TOON format:
Role: ""
"Primary Skills"[2]: Python,JavaScript
"Secondary Skills"[2]: Responsibility,Communication
"Minimum Experience": ""
"Maximum Experience": ""
Location: ""
"Employment Type": ""
Summary: ""
Responsibilities[2]: Task A,Task B
我的预期: 通过展示带有空字符串和通用占位符的编码格式,模型会理解结构。
现实检查 – 70 % 失败率
错误信息很直观:
Error parsing TOON format for JD#2: Expected 10 values, but got 16Error parsing TOON format for JD#5: Missing colon after key
模型对数组感到困惑。有时它会输出 Skills: Python, JavaScript, React 作为平铺字符串;有时它尝试使用方括号,但语法却弄错了。
假设: 只展示空示例是问题所在。模型需要看到真实的数据模式,尤其是数组的写法。
Token 使用情况(失败尝试,成功率 70 %)
| Tokens | |
|---|---|
| Prompt | 729 |
| Output | 227 |
| Success Rate | ~30 % 最初,加入两个带填充值的真实示例后提升至 70 % |
JSON Token 使用情况(相同测试)
| Tokens | |
|---|---|
| Prompt | 723 |
| Output | 471 |
关键洞察
TOON 的紧凑语法非常不宽容。JSON 的冗余({"key":"value"})帮助模型自我纠正。TOON 的 Key: value 格式没有这种安全网,因此模型需要具体示例,而不是抽象模板。
但 70 % 的成功率仍不足以投入生产。是时候彻底解决这个问题了。
实验 #2 – 实现 100 % 解析成功(以及 Token 的权衡)
我需要解决 70 % 的成功率问题。解决方案是什么?停止使用极简的示例。
修订后的提示
Extract Role, Primary Skills, Secondary Skills,
Minimum Experience, Maximum Experience,
Location, Employment Type, Summary, and Responsibilities
Job Description:
Output in TOON format. Example structure:
Role: "Senior Data Scientist"
Primary_Skills:
[1]: "Machine Learning"
[2]: "Statistical Analysis"
Secondary_Skills:
[0]: "Big Data"
[1]: "Cloud Platforms"
Minimum_Experience: "5 years"
Maximum_Experience: "10 years"
Location: "New York, NY or Remote"
Employment_Type: "Full-time"
Summary: "Lead data science initiatives"
Responsibilities:
[0]: "Design ML models"
[1]: "Analyze datasets"
Now provide the extraction in TOON format. Keep the format exactly as shown above.
结果: 100 % 解析成功。再也没有出现错误的数组,也没有缺失冒号的情况。
代价: 提示变得更重。
Token 对比 – TOON 与 JSON(相同的 10 条职位描述)
| 方法 | Prompt Tokens | Output Tokens | Total Tokens | Success Rate |
|---|---|---|---|---|
| JSON | 723 | 471 | 1 194 | 100 % |
| TOON – 初始(70 % 成功) | 729 | 227 ✅ | 956 | 70 % ❌ |
| TOON – 优化后(100 % 成功) | 802 ❌ (+11 % vs JSON) | 455 ✅ (比 JSON 减少 3.4 %) | 1 257 | 100 % ✅ |
不舒服的真相
对于基本的提取任务,优化后的 TOON 成本比 JSON 更高。
- 输出略微更紧凑(455 与 471 个 token)。
- 为了实现 100 % 可靠性所需的冗长提示会抹去任何节省。
- 实际上,你每次请求要多付 约 5 %。
为什么继续测试 TOON?
因为基准比较具有误导性。实际的 LLM 应用并不仅仅提取一次数据——它们会使用结构化输出来:
- Pydantic 模型验证(原生 SDK 支持)
- 工具/函数调用(输出成为输入)
- 多轮代理工作流
在这些场景中,紧凑输出格式带来的 token 节省可能 相当显著,尤其是当相同的结构化数据被反复传递时。
要点
- JSON 容错性好,且只需最少提示即可正确生成,但会消耗更多输出 token。
- TOON 能显著减少输出 token,但你必须在提示中投入更多内容(真实示例、明确的数组语法)以实现可靠的解析。
- 当结构化数据被 重复使用(例如工具调用、代理循环)时,TOON 紧凑格式带来的 token 节省可以抵消额外的提示成本。
欢迎深入查看我使用的代码片段和 token 计数脚本;它们已包含在下面链接的仓库中。祝你 token 优化愉快!
实验 #3:Pydantic 模型 — SDK 完成繁重工作
这里的情况变得有趣起来。现代 LLM SDK 对使用 Pydantic 模型的结构化输出提供了一流的支持。你不需要进行提示工程,只需定义一个模式,让 SDK 自动处理格式化。
关键区别: 你不必在提示中解释输出格式——SDK 会自动从你的 Pydantic 模型中提取它。
环境搭建:Google 的 GenAI SDK
我使用相同的职位提取任务,但这次使用了 Pydantic 模型:
response = client.models.generate_content(
model="gemini-2.5-flash",
contents=prompt,
config={
"response_mime_type": "application/json",
"response_schema": JobModel,
},
)
注意缺少的内容: 没有输出格式指令、没有示例、没有 “以 JSON 输出并使用这些精确键”。
SDK 在幕后注入了模式。
Become a member – The SDK injects the schema behind the scenes.
令牌比较:Pydantic JSON vs. 手动 TOON
| 指标 | Pydantic + JSON(SDK 管理) | 手动 TOON(实验 #2) |
|---|---|---|
| 提示令牌 | 647 ✅(比优化后的 TOON 少 19.3%) | 802 ❌ |
| 输出令牌 | 389 ✅(比优化后的 TOON 少 14.5%) | 455 ❌ |
| 成功率 | 100 % ✅ | 100 % ✅ |
| 解析方式 | 原生(SDK 返回已类型化的 Python 对象) | 自定义(需要自行编写解析器) |
残酷的结论
对于拥有强大 SDK 支持的结构化提取,Pydantic 表现出色。原生的 Pydantic 集成带来:
- ✅ 更简洁的提示(约减少 155 条提示令牌)
- ✅ 更小的输出(约减少 66 条输出令牌)
- ✅ 无需自定义解析逻辑
- ✅ 内置类型校验
- ✅ 直接返回已解析的对象,随时可用
- ✅ 开发者体验大幅提升
正因为如此,我将越来越多地依赖 Pydantic 和原生解析支持来进行结构化提取。相较于手动处理解析和校验,它更可靠、更易维护。
注意: 有一种情况会让 JSON 的冗长成为真正的负担:在代理工作流中的工具调用。这时 TOON 才最终显示出它的价值。
Source: …
实验 #4:工具调用 — TOON 最终获胜之处
在具备代理能力的工作流中,LLM 不仅仅一次性提取数据——它会调用工具,接收结果,并利用这些结果进一步推理。工具的响应会成为下一个提示的一部分。如果该响应被冗余的 JSON 语法所膨胀,你实际上是为同一信息付了两次费用:一次作为输出,一次作为输入。
洞察: 工具结果本质上是纯粹的 token 浪费。模型不需要 {"key": "value"} 这种仪式感——它只需要数据,并且要高效编码。
设置:带函数调用的天气代理
我构建了一个简单的代理,它调用 get_current_weather 函数。用户询问天气,模型调用工具,函数返回数据,模型再合成回复。
版本 A:JSON 工具响应
data = {
"location": location,
"current": {
"temperature": "72 F",
"condition": "sunny",
},
"forecast": forecast,
}
return json.dumps(data) # Returns JSON string
版本 B:TOON 工具响应
data = {
"location": location,
"current": {
"temperature": "72 F",
"condition": "sunny",
},
"forecast": forecast,
}
return encode(data) # Returns TOON‑encoded string
主代码
response = client.models.generate_content(
model="gemini-2.5-flash",
contents="What is the weather like in New York? Share next 15 days forecast as well.",
config=types.GenerateContentConfig(
tools=[get_current_weather],
),
)
结果 Token 使用情况
- 初始提示 token: 152(用户消息 + 工具定义)
- 工具响应 token(作为输入): 480 ✅(降低 24 %)
- 模型最终输出: 384(略长,但仍在合理范围)
- 总 token: 1,016 ✅(整体降低 11.5 %)
为什么 TOON 在代理工作流中占优势
单次工具调用
| 方法 | 工具结果所需 token |
|---|---|
| JSON | 632 |
| TOON | 480 |
| 节省 | 152 token(24 %) |
多轮代理(5 次工具调用)
- JSON:632 × 5 = 3,160 token
- TOON:480 × 5 = 2,400 token
节省量: 760 token(24 %)
复利效应
- 工具结果是纯粹的输入 token — 每次都要为它们付费。
- 冗余会成倍放大 — JSON 的
{}、:、,语法会为嵌套数据额外增加 20‑30 % 的开销。 - 无解析惩罚 — 模型同样轻松消费 TOON(在后续测试中已验证)。
- 随代理复杂度线性扩展 — 工具越多,节省越多。
底线
在测试了四种不同情景后,数据告诉我们:
-
TOON 在单次抽取时表现不佳。 无论是手动提示还是使用 Pydantic 模型,带有 SDK 支持的 JSON 更简洁、更便宜且更可靠。原生模式集成带来的 17.6 % 令牌节省始终胜过 TOON 的手动方式。
-
TOON 在对代理有意义的场景中占优势:工具调用工作流。 当 LLM 的输出成为下一个提示——即数据在模型与函数之间反复循环时,TOON 每次工具调用约 24 % 的减少会从好奇心转变为实际的成本节约优势。
简而言之:对直接的结构化抽取使用 Pydantic/JSON,而在任何需要模型反复消费自身工具输出的代理式、工具调用管道中切换到 TOON。
# king 20 tool calls saves 3,040 tokens per session
**The decision matrix is simple:**
- **Building a chatbot that extracts structured data?**
Use **JSON + Pydantic**.
- **Building an agent that calls tools 10+ times per session?**
Test **TOON**.
- **Building anything else?**
Profile first, optimize later.
亲自尝试
我已开源所有实验、提示词和 token 测量:
View complete code and results on GitHub Gist
该仓库包括:
- ✅ 包含所有四个实验设置及实际提示词
- ✅ 每个测试案例的 token 使用日志
- ✅ 并排比较脚本
- ✅ 我用于测试的职位描述
TOON 不是魔法——它是数学。 只有在 token 效率真正重要时,这套数学才有效。对于大多数应用来说,JSON 生态系统的优势超过了节省的 token,但对于 token 消耗巨大的智能体工作流,TOON 可能恰好能抵消其成本。