teamchong/pxpipe

GitHub: teamchong/pxpipe

pxpipe 是一个本地代理,通过将 Claude Code 请求中的大量文本上下文渲染为 PNG 图片来削减输入 token 消耗,从而显著降低 API 费用。

Stars: 6146 | Forks: 523

# pxpipe **通过将庞大上下文渲染为图片来削减 Claude Code 的输入 token —— 相同的系统提示词、工具文档和历史记录,只需少量 token。** 图片的 token 成本由其像素尺寸固定,而不在于其中包含多少文本。密集内容(代码、JSON、工具输出)在真实的 Claude Code 流量中,每个图像 token 可承载约 3.1 个字符,而文本 token 仅约 1 个字符。pxpipe 是一个本地代理,它正是利用了这一差异:在请求离开你的机器之前,它将每个请求中庞大的部分重写为紧凑的 PNG 图片。按照当前的 Fable 目录价格,这可以实现**端到端账单降低约 59–70%** —— 但价格会变动,工作负载也不同,因此真正持久的指标是 token 削减量本身,它是通过 `~/.pxpipe/events.jsonl` 中免费的 `count_tokens` 反事实对照来针对每个请求进行测量的。 这是模型看到的画面,而不是文本: ![示例:真实的 `transformRequest` 输出:系统提示词 + 工具文档重新排版为一张密集的 1573×1248 页面,顶部有指令横幅,↵ 标记原始换行符](https://static.pigsec.cn/wp-content/uploads/repos/cas/25/2527a660423a77d2c77ecd1d8fe47fd61b84bac053502001817437eb0ac8efcb.png) *约 48k 字符的系统提示词 + 工具文档:作为文本约为 25k token,作为此页面约为 2.7k 图像 token。真实的流水线输出;模型在 100/100 下读取此类渲染图(见基准测试)。* ## 演示 **Fable 5(默认设置,100/100 读取器)—— 左侧为纯文本,右侧为 pxpipe:** https://github.com/user-attachments/assets/1c8ee63a-fcd7-4958-917b-da788d718349 pxpipe 在 39 个图像化填充文件中计算出精确的 token **10/10**(与 `grep` 逐行匹配),正确完成了多步骤的账本算术运算,并在上下文仍有结余(73.5k/1M)的情况下以 **$6.06** 结束会话,而对比在 96% 满载时为 **$42.21**。片段中有一个可见的警示:pxpipe 端需要稍微引导一下才能匹配所要求的一行输出格式。 **Opus 4.8(默认禁用)—— 相同布局:** https://github.com/user-attachments/assets/f4e50137-31b5-426f-a6ed-b83f829b4a2c 文本“大海捞针”测试在两端读取均正常;图像化的短语计数在 Opus 上无法读取 —— 而 pxpipe **会直接说明,而不是编造一个数字**。这种误读率就是 Opus 为选择性开启的原因。 ## 尝试一下(30秒) ``` npx pxpipe-proxy # proxy on 127.0.0.1:47821 ANTHROPIC_BASE_URL=http://127.0.0.1:47821 claude # point Claude Code at it ``` Dashboard 位于 :节省的 token、每次文本→图像转换的并排对比、紧急停止开关、实时的模型标签。响应正常流式传输 —— pxpipe 仅压缩*请求*,从不压缩模型的输出。 最近的对话保持文本形式;系统提示词、工具文档和较早的大量历史记录被图像化。 ## 诚实的一面 - **它是有损的。** 密集图像内容中的精确 12 字符十六进制字符串:在 Fable 5 上为 **13/15**,在 Opus 上为 **0/15** —— 并且错误是*无声的混淆虚构*,而不是报错。字节精确值(ID、哈希、密钥)必须保持文本形式;最近的对话也是如此。一个专门的字面风险防护尚未构建。 - **逃生舱:** 在非白名单模型上的 subagent 将以文本形式通过 —— 将字节精确的工作路由到那里(`CLAUDE_CODE_SUBAGENT_MODEL=claude-sonnet-4-6`,或在 agent 前置元数据中设置 `model: sonnet`)。 - **实际工作:** SWE-bench Lite 试点在请求大小减少 65% 的情况下**两端均为 10/10**;SWE-bench Pro 在减少 60% 的情况下为 **开启 14/19 对比 关闭 15/19**,判定结果一致为 18/19,唯一分歧的单项在复测中 3/3 重新解决 —— 这是运行间的方差,而非压缩导致。样本量 n 较小;收据在 `eval/` 中。 - **依赖于工作负载。** 在 token 密集内容(约 1 字符/token)上获胜,在稀疏长文本(约 3.5 字符/token)上亏本;盈利门控(基于 N=391 行生产数据校准)仅在对计算有利时进行图像化。 - **模型范围:** 默认 `PXPIPE_MODELS=claude-fable-5,gpt-5.6`。Opus 4.7/4.8 误读了约 7% 的渲染图,且 GPT 5.5 在图像化上下文上性能下降,因此两者均需通过 `PXPIPE_MODELS` 或 Dashboard 标签选择性开启。 `PXPIPE_MODELS=off` 可禁用图像化。所有其他内容均逐字节通过。在 GPT 路径上,工具定义保持原生 JSON,且未使用 Anthropic 的 `cache_control` 标记。 ## 基准测试(可复现) 使用模型无法记忆的新颖随机数问题进行测量: | 测试 | N | 文本 | pxpipe (图像) | token | |---|---:|---:|---:|---| | 新颖算术,`claude-fable-5` | 100 | 100% | **100%** | **−38%** | | 新颖算术,`claude-opus-4-8` | 100 | 100% | 93% | −38% | | gist 回忆 A/B(决策、值、路径、名称、否定;带干扰项;15k-45k 字符会话),Fable 5 | 98/端 | 98/98 | **98/98** | - | | 状态追踪(值变更 3 次,最终/首次/计数),Fable 5 | 18/端 | 18/18 | **18/18** | - | | 对未陈述事实的混淆虚构(越低越好),Fable 5 | 16/端 | 0/16 | **0/16** | - | | 字面 12 字符十六进制回忆,密集渲染,Opus | 15 | 15/15 | **0/15** | - | | 字面 12 字符十六进制回忆,密集渲染,Fable 5 | 15 | - | **13/15** | - | SWE-bench 运行总计、收据和注意事项: [`eval/swe-bench/`](eval/swe-bench/) · [`eval/swe-bench-pro/`](eval/swe-bench-pro/) · [`eval/needle-haystack/`](eval/needle-haystack/) · [`eval/gist-recall/`](eval/gist-recall/) · 分析见 [`FINDINGS.md`](FINDINGS.md)。(GSM8K 在图像化下得分为 96%,但它在训练数据中 —— 记忆的答案能在误读中存活 —— 因此我们以新颖数字评估作为主打。) ## 工作原理 ``` tool_result string ──► wrap at 1928px-wide columns ──► pack ~92,000 chars/page ──► PNG[] ``` 代理拦截 `/v1/messages`,将符合条件的大量内容重写为图像块,以对缓存友好的方式拼接回去(保留静态前缀,prompt caching 继续工作),然后转发。一张 1928×1928 的图像成本约为 4,761 个视觉 token,可容纳约 92,000 个字符,因此文本只有在高于约 19 字符/token 时才胜出 —— Claude Code 流量运行约为 1.91 (N=391)。由每个请求的估算器做出决定;稀疏长文本保持文本形式。事件记录到 `~/.pxpipe/events.jsonl`。 ## 库使用(无代理) ``` import { renderTextToPngs, transformAnthropicMessages } from "pxpipe"; const imgs = await renderTextToPngs(toolResultText); // RenderedImage[] const { body, applied, info } = await transformAnthropicMessages({ body: requestBytes, model: "claude-fable-5", }); ``` `options.keepSharp(block)` 将块固定为文本;`options.emitRecoverable` 返回图像化块的原始内容。纯 JS 运行时(Node 和 edge/Workers);`@napi-rs/canvas` 仅在构建时使用。完整 API:`src/core/index.ts`。 ## 开发 ``` pnpm install && pnpm test pnpm run build # regenerates dist/ ``` ## 常见问题 **标题数据是端到端的,还是仅针对你处理过的请求?** 是端到端的,即整个账单。大多数压缩工具仅报告它们处理过的输入切片上的节省量,这美化了这个数字。端到端的分母是*每一个*生产请求:pxpipe 正确地未触及的小请求、所有的缓存写入和读取,以及所有的输出 token(代理从不压缩这些)。在一个包含 13,709 个请求的快照中,节省了 59%($100 → ~$41);随后一个包含 8,904 个压缩请求的追踪测量显示约 70%。仅压缩部分的数据更高(约 72–74%),并且是单独引用的,绝不会作为标题数据。确切的数字取决于工作负载 —— 请在你自己的日志中复现它。 **数学是如何测量的?** 在相同的时刻测量同一个请求的两端。对于每一个 `/v1/messages` POST,代理在真实转发的同时,对原始未压缩主体(反事实对照)发起一个免费的 `count_tokens` 探测,并从响应中读取 Anthropic 实际计费的使用量块。两者都记录在 `~/.pxpipe/events.jsonl` 的同一行中,因此不存在对话计数或运行间的混淆。美元转换使用 Fable 5 目录比率:输入 ×1.0,缓存写入 ×1.25,缓存读取 ×0.1,输出 ×5。缓存定价对两端同等适用,因此缓存折扣相互抵消,不能被重复计算为“节省量”。你可以从事件日志中自行重新推导:公式和字段名称记录在 `src/core/baseline.ts` 中。 **它实际上压缩了什么?** 三种类型的*输入*块,每种都在盈利门控之后: 1. 大型 `tool_result` 主体(文件读取、命令输出、日志),包含超过约 6k 字符的 token 密集内容 2. 较早折叠的历史记录:实时尾部之后的对话被重新渲染为图像页面,最近的对话始终保持文本形式 3. 静态系统提示词 + 工具文档块 所有其他内容均逐字节通过:你的消息、最近的对话、模型的输出(它是响应,代理从不触及它)、稀疏长文本,以及任何太小而不值得转换的内容。白名单之外的模型完全通过 —— 默认范围仅限 Fable 5 和 GPT 5.6。Opus 4.8 和 GPT 5.5 读取图像化内容的效果明显较差(FINDINGS.md 2026-06-16),因此它们被特意设为通过 Dashboard 或 `PXPIPE_MODELS` 选择性开启,绝不进行隐式图像化。 **除了基准测试之外,它在现实中失败过吗?** 是的,在数周的日常使用中发生过一次:模型从图像化的聊天记录中回忆一个人的名字,并且自信地弄错了。没有报错,只是一个看起来合理的错误名字。这就是记录在案的失败模式:图像内容中的精确字符串并非字节安全的。编码会话对此有容忍度,因为 agent 在编辑前会重新读取文件;而纯聊天回忆没有这种检查。 这种失败模式是经过测量的,而不是轶事: [清晰度审计](docs/LEGIBILITY-AUDIT-2026-07-01.md) 量化了从渲染页面中提取精确字符串回忆的能力(盲读在密集标识符上的准确率最高可达 63%,每一次错误都能通过字形混淆矩阵进行预测),并记录了已发布的缓解措施 —— 页面几何结构限制在 API 的重采样上限内,以便计费的像素能够真正到达视觉编码器,并且精确标识符(SHA、数字)作为文本随附。 **为什么这个 README 读起来像是 AI 写的?** 因为确实是 AI 写的。这个 repo 的大部分 commit —— 代码和文档 —— 都是由在 pxpipe 本身后运行的 Opus/Fable agent 会话编写的,它们在工作时将自己折叠的历史记录作为图像页面进行读取。 ## 局限性 - 有损(见上文);从图像中进行字面回忆是不可靠的。 - PNG 编码会在大请求离开之前增加其延迟。 - ASCII/Latin-1 经过充分测试;CJK 可以工作,但处理较为保守。 ## 路线图 这些是假设,而非主张 —— 它们以带有样本量 n 的数据发布,否则就会被砍掉:更清晰字形渲染(`eval/glyph-matrix/`,运行中途暂停),图像化的大量内容是否会扩展有效上下文(在相同的 1M 窗口中容纳约 2 倍的真实内容),以及较小的活跃上下文是否会提高长任务准确性。 ## 许可证 MIT。
标签:AI开发工具, LLM辅助, MITM代理, Token优化, 成本优化, 文本转图像, 本地代理, 自动化攻击