实测十个网页发现 HTML 转 Markdown 的 token 压缩率从 1.4x 到 734x 不等,远非「约 5 倍」的常见说法,且最大压缩页面的代价是价格、参数等关键信息丢失。
TL/DR: 将 HTML 剥离为纯文本 markdown 被广泛描述为减少约 80% 的 token,即约 5 倍的压缩。在我所测量的十个页面中,压缩比从 1.4 倍到 734 倍不等。压缩比最大的并非紧密度高的页面,而是那些丢失了价格、规格和对比值的页面。对最佳段落进行排名后发送(而非发送整页)并不能解决这个问题。
当 AI Agent 读取一个网页时,它会读取全部内容。每个词都有成本。Token 是模型计费的单位,一个 Token 约等于四分之三个单词。
现代网页大部分并非文字。它是标记、脚本、样式和隐藏数据——这些是浏览器用来渲染你看到的页面的。把所有这些发送给模型,你就要为所有这些付费。
标准解决方案是将页面剥离为简单格式——仅保留文本,称为 markdown。几乎所有做这件事的工具都报告了类似的结果。Cloudflare 引用了一篇从 16,180 token 压缩到 3,150 的博文,减少了 80%。Apify actor 广告宣称 60% 到 77%。开源工具报告约 80%。这些数字足够集中,以至于"约 5 倍"已经成为工作假设。
我想测试另一个方向:不发送完整清洗后的页面,而是根据所提问题对各段落进行排名,只发送最好的几个?这在当前用法中有一个名字,叫 context engineering,核心理念是更少但更好的内容胜过更多。
我想知道它是否能以足够大的优势胜过 5 倍,从而值得去做。答案是并不能。但原因出乎意料,而且它比我正在测试的功能本身更重要。
我选择页面注重多样性而非便利性:文档页面、SaaS 定价页面、新闻文章、产品汇总、维基百科文章、GitHub README、产品页、食谱、Paul Graham 的散文(几乎无冗余的手写 HTML),以及我自己的网站。
对每个页面,我先写一个问题,在运行任何代码之前,以外部人的角度来措辞。如果一个页面有个标题叫"兼容性",我的问题就是"我能在 Cursor 内部运行它吗",而不是"兼容性是什么"。复用页面自身的措辞会让结果看起来比实际更好。
我还记录了正确答案及其所在的段落——在我自己完整阅读每个页面之后,在任何代码运行之前。这就是答案密钥。
转换步骤我用了 trafilatura,一个广泛使用的开源提取器。需要明确的是:我在那些页面上测量了这个工具。我没有测试 Cloudflare 的转换器或任何供应商的工具,本文的任何内容都不应被解读为对某一工具的测量。
中位数是 62 倍。范围从 1.4 倍到 734 倍,跨度超过 500 比 1。
常见的 4 倍到 5 倍数字在这个列表中无处可寻。最接近的是 Python 文档的 4.3 倍,它最接近是因为它是集合中最老式的页面:纯 HTML,框架代码非常少。
最底部的散文解释了这个规律。Paul Graham 手写他的 HTML,所以几乎没有什么可剥离的,转换几乎没有帮助。顶部的页面是现代 JavaScript 应用程序,大部分下载内容是隐藏数据。剥离后数字看起来就很惊人了。
已发表的数字都不完全错误。它们是对所选页面的测量,而那些页面大多是来自干净发布系统的干净文章页面。这个数字只是不能泛化,却被当作普遍适用来引用。
再看 Sentry 那行。542,996 token 降到 740。
Sentry 的定价页面有一个套餐对比图。转换后,该图表存活为约三十个裸露的行标签。"SSO: SAML2" 等等。没有值。显示哪个套餐包含哪个功能的勾选标记是绘制成图片的,而图片不是文本,所以消失了。企业版根本没有出现。
740 token 不是压缩后的定价页面。它是一个去掉了定价信息的定价页面。
ThermoWorks 产品页失败得更安静。580 倍的压缩,产品价格没有出现在输出中,因为该网站在页面加载后用 JavaScript 填充它。没有任何崩溃。工具正常运行,产生了关于厨房温度计的干净可读文本——价格未知。
我自己的网站:10.3 倍,整个定价表缺失。我写了那个页面。我毫不知情。
Tom's Guide 的产品汇总才是真正引起我注意的。每个"规格"和"购买理由"模块都转换为空的标题。所以当我问如果我想以后更换部件该选哪台笔记本电脑时,排名最高的段落返回了一个自信的推荐,但没有包含一个数字。我的测试脚本给它打了通过,因为正确的产品名称在那里了。这是正确答案,但所有证据都被移除了。
失败的不是我预期的那个
开始之前,我预期的是一个不同的问题:数字保留,警告标签丢弃。我的网站在大美元数字旁边显示了总 token 节省量,旁边就是解释 token 是计数而美元是估算的文字。我假设转换会保留这个令人印象深刻的数字而丢弃免责条款。
并没有。免责条款在该数字后 116 个字符处,所以无论我怎么切分页面,它们都一起被发送。我尝试了从 1,500 字符到 300 字符的不同块大小,无法将它们分开。这是特定块编写方式的幸运,而不是方法安全的证据。
真正的失败是另一个方向:数字被丢弃,而 prose 留下来了!
这更难捕捉。截断的输出看起来就是截断的。这个看起来是完整的。你得到的是流畅、自信、井井有条的文本,数量信息悄然缺失,没有任何地方发出损失的信号。读取它的 Agent 无法判断它正在从一个没有证据的摘要中作答。
这是我真正想要测试的功能。对段落根据问题排名,只返回前几个,跳过其余部分。
相对于原始 HTML,数字看起来很惊人,高达 1,440 倍。但任何真实产品都会先转换页面,所以公平的问题是:排名在转换之上增加了什么。下方,"k"是你发回的段落数,"recall"是正确答案实际出现在其中的频率。
要么便宜且错误,要么正确且几乎不便宜。发送三个段落没有发现任何发送一个段落没有发现的东西。每一次准确率提升都出现在第四和第五排名,而这正是节省消失的地方。没有任何设置能同时兼顾两者。
有两个页面效果变差了。在新闻文章和产品页上,发送前五个段落比发送整个转换后的页面花费更多。短页面分成少数块,这些块又重叠,所以你把一些文本发送了两次。
最有用的一行是我自己的网站,因为这是我唯一有手写版本可以对比的页面。我手写的 markdown:1,464 token,回答了所有三个测试问题。五个段落的排名检索:1,468 到 1,702 token,只回答了两个。人类手写的完整页面在我尝试的每种自动化方法上都同时在成本和准确率上胜出。样本量小,而且页面和摘要都是我写的,所以请酌情权衡。
一次失误是结构性的,无法修复。我问维基百科的 transformer 文章:"如果它同时读取所有词,它怎么知道哪个先出现。"正确段落的标题是"位置编码"。它在 43 个段落中排名第 12。我问题中的词拉向另一个关于分词的段落,而小型排名模型没有办法将这种措辞与那个术语联系起来。要捕捉它意味着要发送十二个段落,约占页面的三分之一。
没有保真度检查的压缩比只是半个测量。很多工具发布缩减数字。据我所查,没有一个发布价格、规格或表格值的存活比例。这是两个不同的问题,而且只有一个在被问及。
在你真正关心的页面上测试。这里的跨度超过 500 比 1。单一的 headline 倍数在混合页面类型中意义非常有限,包括我自己的。
如果你的内容在商业上重要,检查它是否存活下来。在你自己的产品或定价页面上运行提取器,在输出中搜索你的价格。这大约需要五分钟。我原本期望确认某些事情,结果在我自己写的页面中发现了一个漏洞。
如果你是为 Agent 发布内容,手写版本仍然难以击败。在我能够进行比较的唯一页面上,它在我尝试的每种自动化方法上都同时在两个指标上胜出。
还有一件事值得记录。我的十次页面抓取中有八次被拒绝,其中一次返回了正常的 HTTP 200,但同时返回了 1.09 MB 的完全不同页面。如果你在构建任何从客户端抓取页面的东西,这是一个需要尽早发现的数字……
所有页面、代码、答案密钥和原始下载都已保存,所以这些数字是对存储字节的测试,而非对一个不断变化的网络的测试。披露:我在构建 token 效率工具。这就是我去找 5 倍基准线的原因,也是我对它并不存在感到恼火的原因。
J. Gravelle jCodeMunch.com