Be Known通知设置

课程库 技术雷达 AI 工程 › 第 4

一粒米上的代码库 —— 上下文成本与「按像素计价」的套利

普通课40 分钟

本课导读

2026 年 7 月底,Reddit 上一个网友受够了满屏「把文本转成图片再 OCR 回来,无损省下 30-600% token」的教程帖,写了个段子讽刺:

最近我一直在这样用 Claude——把整个代码库重写到一粒米上,然后把米粒照片上传上去。100 万 token 的代码库每次查询要花 $10,但同样内容塞进一粒米的照片里只要几分钱。我不明白为什么还没人想到这个妙招!

评论区疯了:有人认真讨论半粒米能不能更省、糯米会不会防止 context 腐烂、Jasmine 米和泰国香米哪个效果更好。

离谱的是,几乎同一时间,真有人把这个段子做成了产品,还跑通了 SWE-bench。 这个工具叫 pxpipe,MIT 开源,README 里明明白白写着它能省 59-70% 的账单。

本课不做「这工具值不值得用」的评价(那是下一课的事),而是借它把一串你迟早会撞上的名词一次讲透:上下文为什么要钱、token 是怎么算出来的、图片的 token 又是怎么算的、什么叫本地代理、以及什么叫「盈亏线判断器」。预计 40 分钟。

地基:为什么「上下文」本身就是成本

要理解这个 hack,先得纠正一个几乎所有人都有的错觉:你以为跟 AI 的对话是「连续的」,其实每一轮都是从头讲一遍。

LLM 的 API 是无状态的(stateless)——服务器不记得你上一句说了什么。所以每一次请求,客户端(Claude Code、学径里的 AI 功能、任何 app)都必须把完整的上下文重新发一遍。一次典型的 Claude Code 请求,请求体里装着这些东西:

请求体的组成部分是什么体积特征
system prompt(系统提示词)告诉模型「你是谁、规矩是什么」的开场白固定的一大坨,每次都重发
tool 定义(工具文档)模型能调用哪些工具、参数长什么样的说明书固定的一大坨,每次都重发
对话历史你之前说的、模型之前答的只增不减,越聊越大
tool_result(工具结果)读文件读出来的内容、命令输出、日志体积冠军,一次读文件就上万字符
你这一句新消息真正的「新信息」通常最小的那块

看出问题了吗:你输入的那句话可能只有 20 个字,但这次请求实际发出去的可能是 8 万字符。 而 API 按输入的 token 数计费——所以真正花你钱的,几乎从来不是你打的字,是背景里那一大坨反复重发的上下文

说明

锚定你已知的东西:这和你调 Supabase 的感觉完全不同。supabase.from('lessons').select() 是无状态的,但每次只发一句 SQL;LLM 的无状态请求却要把「至今为止发生的一切」重新驮一遍。上下文窗口越大的模型,这个包袱越沉。 上一课讲的「token 成本随规模复利」,一大半就复利在这里。

token 与「字符密度」:同样一万字,价钱不一样

token(词元) 你在上一课见过了:模型把文本切成的小块,计费和上下文长度都按它算。但这一课要往下挖一层——一个 token 平均能装多少个字符,是会变的,而且变化幅度大到能决定一个工程决策。

模型切词用的是 tokenizer(分词器),主流做法叫 BPE(Byte Pair Encoding,字节对编码):把训练语料里高频出现的连续字节合并成一个 token。结论很直白:

  • 常见英文散文 → 词根、常用词早被合并成整块,一个 token 常能装 4 个字符以上;
  • 代码、JSON、日志、哈希 → 满是 {}_、缩进、随机字符串,这些组合在语料里不算高频,切得极碎,一个 token 可能只装 1-2 个字符。

pxpipe 的作者拿 391 条真实 Claude Code 流量测了一下:平均字符密度约 1.91 chars/token(每个 token 才装不到 2 个字符)。也就是说,写代码这个场景,是 token 效率最糟糕的场景之一。

亲手算一下这个「密度」是怎么回事:

TypeScript

跑出来大致是「英文散文 ≈ 3.6 > JSON 工具结果 ≈ 2.0 > 中文 ≈ 1.0」。同样长的一段文字,值多少钱能差三倍以上——这就是为什么要盯住 chars/token 这个单位:它把「一段内容值多少钱」变成了一个可比较的数。接下来的整个 hack,就是一次针对这个数的套利。

核心:vision token 按像素计,不按内容计

现在是本课的转折点。Claude 能看图(vision)。那么问题来了:一张图片消耗多少 token?

答案出乎意料地简单粗暴:按图片的像素尺寸算,跟图里塞了多少字完全无关。

Anthropic 的公式大致是「宽 × 高 ÷ 750」。一张 1928×1928 的 PNG,固定消耗约 4,761 个 vision token——不管这张图是一片纯白,还是密密麻麻印满了小字。

于是套利空间出现了:

同样的 92,000 个字符消耗 token密度
纯文本发送约 48,000 token约 1.9 chars/token
渲染成 1928×1928 PNG 发送约 4,761 token19+ chars/token

账面上约 10 倍的差价——这就是整个 hack 的全部秘密。

但注意别把这 10 倍当成你能省的钱:pxpipe 实测的端到端账单节省是 59-70%(约 2.5-3.3 倍),因为一次请求里只有一部分内容适合图片化,剩下的照样按文本计费。这个落差本身就值得记住——局部优化的倍数,永远不等于整体账单的倍数(这条在计算机领域有个正式名字叫阿姆达尔定律)。

请务必把这句话记牢:这不是压缩算法,这是计价模型的套利。 信息量一个比特都没减少(甚至因为要画成图,字节数还变多了),变便宜的原因纯粹是文本和图像走的是两套完全不同的计价规则,而其中一套恰好对「高密度内容」极其宽容。

注意

「套利」这个词是有分量的:套利机会依赖定价规则不变。哪天 Anthropic 把 vision 计价改成跟内容复杂度挂钩,或者调整像素系数,这个技巧当天失效。任何建立在别人定价规则缝隙上的优化,都自带保质期——这是评估这类技巧时第一条要问的。

谁来干这件事:本地代理(proxy)

原理清楚了,但还有个现实问题:Claude Code 是别人写的软件,你怎么让它在发请求前先把内容画成图?

答案是一个你其实已经很熟悉的东西:代理(proxy)

代理就是站在客户端和服务器中间、替双方转发请求的程序。因为消息必须经过它,它就有机会在转发前改写内容。pxpipe 干的就是这件事:

Claude Code ──► pxpipe(本机 127.0.0.1:47821)──► api.anthropic.com
                    │
                    └─ 拦下请求体,把最"重"的部分渲染成 PNG,
                       再把图片塞回请求里继续发出去

几个跟着一起扫盲的名词:

  • 127.0.0.1(也写作 localhost)——「本机」的固定地址。发往这个地址的数据根本不出网卡,所以「代理会不会偷看我的代码」这个担心,在本地代理这里是不成立的:它就跑在你自己电脑上。
  • 47821 ——端口号。一台机器上跑着很多服务,IP 定位到机器,端口定位到机器上的哪个程序。(你 npm run dev 时的 localhost:3000,3000 就是端口。)
  • ANTHROPIC_BASE_URL ——环境变量。绝大多数 SDK 都留了这么一个「改基址」的开关,允许你把请求发往别处而不是官方域名。整个劫持动作不需要改 Claude Code 一行代码,只要启动时把这个变量指向本地代理:
# 终端一:启动代理,它监听 127.0.0.1:47821
npx pxpipe-proxy

# 终端二:让 Claude Code 把请求发给代理,而不是官方 API
ANTHROPIC_BASE_URL=http://127.0.0.1:47821 claude
  • npx ——你在 Node 生态见过:不安装、直接下载并运行一个 npm 包。
  • kill switch(急停开关) ——pxpipe 提供 PXPIPE_MODELS=off 一键退回全文本。任何会改写你数据的中间件,都必须有一个能瞬间关掉、且关掉后行为回到原样的开关——这是中间件设计的基本礼貌,也是你评估这类工具的必查项。

说明

锚定你已知的东西:学径里的 proxy.ts 做的就是同一类事——请求经过它,它有机会检查和改写。区别只是位置:那个跑在服务端做门卫,pxpipe 跑在你自己电脑上做「省钱中间商」。「在链路中间插一层」是工程里复用度最高的一招:缓存、鉴权、限流、日志、压缩,全都长这个样子。

精妙之处:一个「盈亏线判断器」

如果 pxpipe 只是「把所有东西都画成图」,它会是个糟糕的工具。因为套利只在高密度内容上成立

回头看那张表:图片模式的有效密度大约是 19 chars/token。这就是盈亏线(break-even)

  • 一段内容的原始密度高于 19 chars/token → 转成图片反而更贵(图片是固定价,装不满就亏),保持文本;
  • 低于 19 chars/token(比如 Claude Code 那平均 1.91 的代码和 tool_result)→ 转图片大赚。

注意

这里有个作者没提、但你必须自己补上的坑:这条盈亏线是按拉丁字形标定的。 「1928×1928 装得下 92,000 字符」的前提是这些字符长得像 a{_——又窄又简单。中文汉字笔画多、字形宽,要保证模型看得清,同样一张图装不下 92,000 个汉字。所以别看上面演示里中文密度只有 1.0(账面上最该图片化),按字符数算的盈亏线不能直接套到中文上——真要用,得按「一张图能塞下多少个仍然认得出的汉字」重新标定。这也是上一课那个元技能的应用:别人的基准数据,先问它是在什么条件下测的。

所以 pxpipe 内置了一个判断器(heuristic,启发式规则):逐段算密度,只对划得来的部分动手,稀疏的散文和短消息自动跳过。而且它的分工是有讲究的:

内容处理理由
system prompt、工具文档转图片又大又固定,读过一次就够
久远的对话历史、旧 tool_result转图片体积大,且不需要逐字精确回忆
你的新消息、最近几轮对话保持文本模型正在依赖它做精确推理
模型的输出保持文本本来就要原样吐给你

这里有个值得你带走的工程观念,比这个工具本身更耐用:优化的价值不在于「能优化多少」,而在于「知道什么时候不该优化」。 一个无脑全量应用的优化,通常在某些输入上是负收益;带盈亏线判断的优化才是工程。而这条盈亏线不是拍脑袋定的——它是用 391 条真实流量数据校准出来的。这也是下一课的引子:一个技巧可不可信,全看它有没有拿真实数据量过。

够用判断线

一句话总结:LLM 的 API 是无状态的,每次请求都要把整坨上下文重新驮一遍,所以真正的账单大头是 system prompt、工具定义、对话历史和 tool_result;而 Claude 的图像 token 按像素尺寸固定计价、与图里的字数无关,于是「把高密度上下文渲染成 PNG」成了一次针对计价规则的套利(约 1.9 → 19 chars/token),由一个跑在 127.0.0.1 的本地代理靠改写 ANTHROPIC_BASE_URL 无侵入地实现,并用一条盈亏线决定哪些内容值得转。

对你的现实指导:现在别急着装。 你日常主要是让 AI 写课程和代码,账单还没到需要动这种手术的量级——但「我的钱花在反复重发的上下文上,而不是我打的那几个字上」这个认知,从今天起就该影响你怎么用 AI(比如:长会话该开新窗口了、别让 AI 反复读同一个大文件)。值得深学的信号:哪天你要给学径接一个有真实用户的 AI 功能、每月账单开始肉疼时,回来看这两课——上一课教你账单为什么会涨,本课教你账单具体涨在哪块内容上

至于「这个 59-70% 的省钱数字到底该不该信、代价是什么」——下一课专门算这笔账。

随堂测验

随堂测验0 / 4 题正确

1. 为什么说「跟 AI 聊天时,真正花钱的往往不是你打的那句话」?

2. 「把上下文渲染成 PNG 能省 token」的原理是什么?

3. pxpipe 内置了一条约 19 chars/token 的「盈亏线」,只对密度低于此线的内容转图片。这个设计说明了什么工程观念?

4.挖空

本地代理的三件套: 表示「本机」,数据不出网卡;后面的 47821 是,用来定位机器上的哪个程序;而改写环境变量 ANTHROPIC_ 就能让 Claude Code 把请求发给代理而不是官方 API——整个过程不用改客户端一行

划选正文任意文字可高亮、批注或加入复习卡

讨论

载入中…