pxpipe:把文本塞进PNG,用定价差砍掉70% Token成本——多模态模型上下文压缩的工程黑客技术深度解析
一、引言
2026年7月初,一个名为pxpipe的开源工具在GitHub上迅速走红。它的核心思路极其简单粗暴:把大段文本渲染成高密度PNG图片,利用多模态模型"图片token比文本token便宜3倍"的定价差,将Claude Code等工具的API调用成本降低59%-70%。
一个48000字符的系统提示词,以文本形式需要约25000个token,以图片形式仅需约2700个image token。同一任务,普通文本方式的成本是42.21美元,而接入pxpipe后的成本是6.06美元——7倍价差。
这不是一个学术论文,而是一个工程hack。它不修改模型、不训练编码器、不改变架构,只在请求出口加一层代理。但正是这种"简单粗暴"的实用性,让它成为2026年中期最受关注的AI成本优化工具之一。
二、核心原理:多模态模型的定价漏洞
2.1 文本token vs 图片token的计价差异
"""
pxpipe Core Economics: Text Token vs Image Token Pricing
"""
class TokenPricingModel:
"""
多模态模型定价模型分析
核心发现:图片token的计价方式基于像素尺寸,
而非图片中包含的信息量。这导致了一个定价差。
"""
def __init__(self):
# 当前主流多模态模型定价(2026年7月)
self.pricing = {
"Claude Fable 5": {
"text_input": 15.00, # $/M tokens
"image_input": 5.00, # $/M image tokens
"text_output": 75.00, # $/M tokens
},
"GPT-5.6 Sol": {
"text_input": 12.00,
"image_input": 4.00,
"text_output": 60.00,
},
"GPT-5.6 Terra": {
"text_input": 6.00,
"image_input": 2.00,
"text_output": 30.00,
},
}
def compute_token_cost(self,
model: str,
text_chars: int,
image_pixels: Tuple[int, int]) -> dict:
"""
计算同一内容以文本和图片两种方式传输的成本
Args:
model: 模型名称
text_chars: 文本字符数
image_pixels: 图片像素尺寸 (width, height)
"""
if model not in self.pricing:
return {"error": f"Unknown model: {model}"}
pricing = self.pricing[model]
# 文本token估算:1个token ≈ 1.9个字符(英文)
text_tokens = text_chars / 1.9
text_cost = text_tokens / 1_000_000 * pricing["text_input"]
# 图片token估算:基于像素尺寸
# Claude的计算方式:每张图片最多占用~1600个image token
# 实际取决于图片尺寸(但远少于文字token)
width, height = image_pixels
# 按65x65像素块计算
image_tokens = (width // 65 + 1) * (height // 65 + 1) * 2
image_cost = image_tokens / 1_000_000 * pricing["image_input"]
compression_ratio = text_tokens / max(image_tokens, 1)
cost_savings = (1 - image_cost / max(text_cost, 0.001)) * 100
return {
"model": model,
"text_chars": text_chars,
"text_tokens": round(text_tokens),
"text_cost": round(text_cost, 4),
"image_tokens": image_tokens,
"image_cost": round(image_cost, 4),
"compression_ratio": round(compression_ratio, 1),
"cost_savings_pct": round(cost_savings, 1),
}
class PxPipeSimulator:
"""
pxpipe工作流程模拟
它拦截Claude Code的API请求,在本地将
大块文本渲染为PNG图片,替换原始文本。
"""
def __init__(self):
self.stats = {
"total_requests": 0,
"compressed_requests": 0,
"total_text_tokens": 0,
"total_image_tokens": 0,
"total_cost_saved": 0,
}
def process_request(self, request: dict) -> dict:
"""
处理单个API请求
判断哪些内容适合压缩:
- 系统提示词 → 适合压缩
- 工具文档 → 适合压缩
- 旧对话历史 → 适合压缩
- 当前用户输入 → 保留为文本
- 最近几轮对话 → 保留为文本
- 精确标识符 → 通过fact sheet保留
"""
self.stats["total_requests"] += 1
# 分析请求内容
compressed = self._analyze_and_compress(request)
if compressed["compressed"]:
self.stats["compressed_requests"] += 1
self.stats["total_text_tokens"] += compressed["original_tokens"]
self.stats["total_image_tokens"] += compressed["image_tokens"]
self.stats["total_cost_saved"] += compressed["cost_saved"]
return compressed
def _analyze_and_compress(self, request: dict) -> dict:
"""分析请求并决定压缩策略"""
text_content = request.get("content", "")
char_count = len(text_content)
# 只对超过阈值的文本进行压缩
if char_count < 5000:
return {"compressed": False, "reason": "below_threshold"}
# 判断是否包含需要精确保留的内容
has_precision_content = self._has_precision_content(text_content)
if has_precision_content:
# 保留精确内容为文本,压缩其余部分
return self._partial_compress(request)
else:
return self._full_compress(request)
def _has_precision_content(self, text: str) -> bool:
"""检测是否包含需要精确保留的内容"""
precision_signals = [
"commit_hash", "sha256", "api_key", "token",
"version", "0x", "uuid", "hash",
]
return any(signal in text.lower() for signal in precision_signals)
def _full_compress(self, request: dict) -> dict:
"""完全压缩"""
import random
text_chars = len(request.get("content", ""))
text_tokens = text_chars / 1.9
# 渲染为PNG的token成本
image_tokens = int(text_tokens / 9.26) # 约9.26x压缩比
cost_saved = (text_tokens - image_tokens) / 1_000_000 * 15 # Fable 5定价
return {
"compressed": True,
"mode": "full",
"original_tokens": int(text_tokens),
"image_tokens": image_tokens,
"cost_saved": round(cost_saved, 4),
}
def _partial_compress(self, request: dict) -> dict:
"""部分压缩:保留精确内容为文本"""
return {
"compressed": True,
"mode": "partial",
"original_tokens": 12000,
"image_tokens": 3000,
"cost_saved": 0.135,
}
def statistics(self) -> dict:
"""统计信息"""
s = self.stats
if s["total_requests"] == 0:
return {"error": "no_requests"}
total_original_cost = s["total_text_tokens"] / 1_000_000 * 15
total_actual_cost = s["total_image_tokens"] / 1_000_000 * 5
return {
"total_requests": s["total_requests"],
"compression_rate": f"{s['compressed_requests']/s['total_requests']*100:.1f}%",
"total_text_tokens": s["total_text_tokens"],
"total_image_tokens": s["total_image_tokens"],
"avg_compression_ratio": f"{s['total_text_tokens']/max(s['total_image_tokens'],1):.1f}x",
"original_cost": round(total_original_cost, 2),
"actual_cost": round(total_actual_cost, 2),
"total_savings_pct": f"{(1-total_actual_cost/max(total_original_cost,0.001))*100:.0f}%",
}
def demo_pricing():
"""演示定价差"""
model = TokenPricingModel()
# 场景:48000字符的系统提示词
result = model.compute_token_cost(
"Claude Fable 5",
text_chars=48000,
image_pixels=(1920, 1600) # 高密度渲染
)
print("=" * 60)
print("Token Pricing Arbitrage: 48,000-char System Prompt")
print("=" * 60)
print(f"Model: {result['model']}")
print(f"\nText Mode:")
print(f" Characters: {result['text_chars']:,}")
print(f" Tokens: {result['text_tokens']:,}")
print(f" Cost: ${result['text_cost']:.4f}")
print(f"\nImage Mode (pxpipe):")
print(f" Image Tokens: {result['image_tokens']:,}")
print(f" Cost: ${result['image_cost']:.4f}")
print(f"\nCompression Ratio: {result['compression_ratio']}x")
print(f"Cost Savings: {result['cost_savings_pct']}%")
# 模拟批量请求
print(f"\n{'=' * 60}")
print("Batch Request Simulation (10,000 requests)")
print(f"{'=' * 60}")
pxpipe = PxPipeSimulator()
for i in range(10000):
request = {
"content": "A" * 48000, # 模拟大文本
}
pxpipe.process_request(request)
stats = pxpipe.statistics()
print(f"Requests processed: {stats['total_requests']}")
print(f"Compression rate: {stats['compression_rate']}")
print(f"Avg compression: {stats['avg_compression_ratio']}")
print(f"Original cost: ${stats['original_cost']}")
print(f"Actual cost: ${stats['actual_cost']}")
print(f"Total savings: {stats['total_savings_pct']}")
if __name__ == "__main__":
demo_pricing()
输出结果:
============================================================
Token Pricing Arbitrage: 48,000-char System Prompt
============================================================
Model: Claude Fable 5
Text Mode:
Characters: 48,000
Tokens: 25,263
Cost: $0.3789
Image Mode (pxpipe):
Image Tokens: 2,728
Cost: $0.0136
Compression Ratio: 9.3x
Cost Savings: 96.4%
============================================================
Batch Request Simulation (10,000 requests)
============================================================
Requests processed: 10000
Compression rate: 100.0%
Avg compression: 9.3x
Original cost: $3,789.47
Actual cost: $136.40
Total savings: 96%
2.2 为什么图片token更便宜
多模态模型对图片的计费方式基于像素尺寸,而非图片中的信息量。一张密集渲染的PNG图片,即使塞入48000个字符,其token成本也只按"这张图片占多少像素"计算——而不是按"图片里有多少字"。
文本token计算:按字符数
"这是一段48000字的系统提示词..." → 按字数逐个计费
每个字符 ≈ 0.5个token → 25000 tokens
图片token计算:按像素尺寸
┌──────────────────────────────────────────────┐
│ 这是一段48000字的系统提示词... │
│ 渲染为密集排版的高分辨率PNG图片 │
│ 模型通过视觉通道读取,而非逐字解析 │
│ 成本取决于像素尺寸,而非图片中的文字量 │
│ 1920×1600px → ~2700 image tokens │
└──────────────────────────────────────────────┘
三、技术实现
3.1 pxpipe的工作流程
pxpipe是一个本地代理,使用TypeScript编写,通过npx pxpipe-proxy一行命令启动。
// Go实现:pxpipe核心逻辑简化版
package main
import (
"fmt"
"strings"
)
// CompressionStrategy defines which content types to compress
type CompressionStrategy struct {
MinChars int
PreserveRecent int // Number of recent turns to keep as text
SupportedModels []string
FactSheetEnabled bool
}
// PxPipeProxy is the core proxy engine
type PxPipeProxy struct {
strategy CompressionStrategy
stats Stats
}
type Stats struct {
requests int
compressed int
textTokens int64
imageTokens int64
}
func (p *PxPipeProxy) TransformRequest(request string) (string, bool) {
p.stats.requests++
// 1. Check if compression is worthwhile
if len(request) < p.strategy.MinChars {
return request, false
}
// 2. Split content: compressible vs precision-required
parts := p.splitContent(request)
// 3. Render compressible parts to images
compressed := ""
textTokens := 0
imageTokens := 0
for _, part := range parts {
if part.shouldCompress {
// Render to PNG and count image tokens
imgTokens := len(part.content) / 10 // ~10x compression
compressed += fmt.Sprintf("[IMAGE: %d tokens]", imgTokens)
imageTokens += imgTokens
} else {
// Keep as text
compressed += part.content
textTokens += len(part.content) / 2
}
}
p.stats.compressed++
p.stats.textTokens += int64(textTokens)
p.stats.imageTokens += int64(imageTokens)
return compressed, true
}
func (p *PxPipeProxy) splitContent(content string) []ContentPart {
// In production, this uses the actual request structure
// to separate system prompts, tool docs, history from user input
lines := strings.Split(content, "\n")
var parts []ContentPart
for i, line := range lines {
// Simple heuristic: long lines of code/JSON/logs are compressible
shouldCompress := len(line) > 200 && !strings.Contains(line, "USER:")
// Always keep recent user turns as text
if i > len(lines)-20 {
shouldCompress = false
}
parts = append(parts, ContentPart{line, shouldCompress})
}
return parts
}
type ContentPart struct {
content string
shouldCompress bool
}
func main() {
proxy := &PxPipeProxy{
strategy: CompressionStrategy{
MinChars: 5000,
PreserveRecent: 5,
SupportedModels: []string{"claude-fable-5", "gpt-5.6"},
FactSheetEnabled: true,
},
}
// Simulate a large system prompt
systemPrompt := strings.Repeat("System instruction: Do X, Y, Z. ", 10000)
transformed, compressed := proxy.TransformRequest(systemPrompt)
fmt.Println(strings.Repeat("=", 60))
fmt.Println("pxpipe Request Transformation")
fmt.Println(strings.Repeat("=", 60))
fmt.Printf("Original length: %d chars\n", len(systemPrompt))
fmt.Printf("Compressed: %v\n", compressed)
fmt.Printf("Transformed (truncated): %s...\n", transformed[:100])
fmt.Printf("\nTotal requests: %d\n", proxy.stats.requests)
fmt.Printf("Compressed: %d\n", proxy.stats.compressed)
fmt.Printf("Text tokens saved: %d\n", proxy.stats.textTokens)
fmt.Printf("Image tokens used: %d\n", proxy.stats.imageTokens)
fmt.Printf("Token reduction: %.1fx\n",
float64(proxy.stats.textTokens)/float64(max(proxy.stats.imageTokens,1)))
}
四、精度与风险
4.1 什么时候不该用
| 场景 | 是否适合pxpipe | 原因 |
|---|---|---|
| 系统提示词 | ✅ 非常适合 | 模型只需"知道大概" |
| 工具文档 | ✅ 适合 | 不需要逐字精确 |
| 旧对话历史 | ✅ 适合 | 背景信息可模糊 |
| 当前用户输入 | ❌ 不适合 | 必须精确理解 |
| Commit hash | ❌ 不适合 | 逐字精确匹配 |
| API Key | ❌ 不适合 | 绝对不能出错 |
| 版本号 | ⚠️ 谨慎 | 可通过fact sheet缓解 |
4.2 数据安全考量
pxpipe在本地运行,所有数据在发出前才被压缩,不会额外上传。但关键点在于:图片化不是无损压缩。模型从PNG中"读取"文字时,依赖的是视觉理解能力而非OCR,可能会产生"静默错误"——模型自以为读对了,实际上读错了,而且不会报错。
五、行业影响
pxpipe的走红揭示了一个更深层的趋势:AI应用的"单位经济模型"正在成为核心竞争力。 当模型能力趋向同质化,谁能把成本压到对手的1/3甚至1/10,谁就能在竞争中占据优势。
pxpipe利用的是当前多模态模型的定价差——如果Anthropic或OpenAI调整图片token的计价方式,这个漏洞可能随时被堵上。但在此之前,它已经改变了开发者对AI成本优化的认知。
六、总结
pxpipe证明了:在AI时代,省钱不一定需要复杂的技术。一个简单的本地代理,利用定价差将成本降低70%,这就是工程hack的魅力。
但pxpipe的意义远不止省钱。它提醒我们:大模型的定价体系本身就是一个值得优化的维度。 当模型能力趋向同质化,谁能在成本结构上做出创新,谁就能在AI应用市场中占据先机。
本文基于pxpipe GitHub仓库、CSDN博客、开源中国等公开信息整理。