
Headroom 图像压缩深度解析用训练的 ML 路由器把视觉 Token 成本压低 40-90%【免费下载链接】headroomCompress tool outputs, logs, files, and RAG chunks before they reach the LLM. 20% fewer tokens for coding agents, 60-95% fewer tokens for JSON, same answers. Library, proxy, MCP server.项目地址: https://gitcode.com/GitHub_Trending/head/headroomHeadroom 的图像压缩Image Compression模块会在 LLM 请求进入模型之前自动压缩其中的图片将视觉 token 消耗降低 40-90%同时保持回答准确性。本文基于仓库中的 image-compression 文档结合 headroom/image 目录下的实际源码实现完整讲清楚它的技术路线Trained Router SigLIP 图像分析 分厂商压缩策略、三种接入方式Proxy / HeadroomClient / 直接 API、配置与参数、厂商支持矩阵以及从源码可确认的 tile 边界优化、OCR 回退逻辑等实现细节帮助你在编码代理与多模态应用里直接落地这一能力。为什么图像压缩是必要的视觉模型按 token 计费而图片非常昂贵。文档中给出的成本基线是一张 1024x1024 的图片约消耗 765 tokensOpenAI一张 2048x2048 的图片约消耗 2,900 tokensHeadroom 的应对方式不是简单的一律缩放而是用一个训练好的 ML 路由器分析你的查询意图自动选择最优压缩技术技术节省比例适用场景full_low~87%一般性问题这是什么preserve0%需要精细细节数一数胡须crop50-90%区域性问题角落里有什么transcode~99%文字提取读一下牌子工作原理三步流水线文档给出的整体流程是User uploads image asks question ↓ [Query Analysis] TrainedRouter (MiniLM from HuggingFace) Classifies: What animal is this? → full_low ↓ [Image Analysis] SigLIP analyzes image properties (has text? complex? fine details?) ↓ [Apply Compression] OpenAI: detaillow Anthropic: Resize to 512px Google: Resize to 768px ↓ Compressed request to LLM对照源码实际流水线在 ImageCompressor.compress 中实现比文档描述的还多了一步零质量损失的前置优化Tile 边界对齐纯数学无 ML零质量损失调用 tile_optimizer.optimize_images_in_messages把图片尺寸调整到落回厂商 tile 边界纯数学缩放即可省 tokenML 技术路由提取最后一条 user 消息的文本查询_extract_query和第一张图片的 base64 字节_extract_image_data交给路由器分类应用压缩技术_apply_compression 按路由结果与目标厂商改写消息体统计结果压缩前用 _estimate_tokens 估算原 token 数压缩后用 _count_result_tokens 按结果实际形态OCR 文本 / 缩放后图片 / detaillow重新计数写入last_result。值得注意的两个源码级事实路由失败时宁保不损无论 ONNX 路由器还是 PyTorch 路由器抛异常都会捕获并回退到Technique.PRESERVEconfidence0见 compress 路由段。这保证了压缩模块故障永远不会破坏原始请求。模型惰性加载与缓存_router/_onnx_router都是懒加载并缓存在实例上L144-L154避免每次compress()都重建 ONNX 原生会话导致内存泄漏源码注释中引用的 #2513 问题。四种技术详解full_low87% 节省适合一般理解类问题What is this?、Describe the scene、Is this indoors or outdoors?。模型回答这些问题不需要精细细节。对 OpenAI 厂商实现就是给image_url加上detail: lowL587-L596成本从 765 直接降到 85 tokens。preserve0% 节省精细细节很重要时使用Count the whiskers、What brand is shown?、Read the serial number、What time does the clock show?。源码中preserve分支直接原样返回消息L530-L531。crop50-90% 节省区域性问题Whats in the top-right corner?、Focus on the background。注意文档明确说明目前crop实际按 resize 实现真正的裁剪功能尚未上线。从源码也能印证——_apply_compression中crop与full_low走同一条降质分支L586。transcode99% 节省文字提取场景Read the sign、What does it say?、Transcribe the document。实现是对图片跑 OCRRapidOCR并把图片块整体替换为[OCR from image]\n文本文本块L573-L583。关键回退逻辑文档有强调源码可确认OCR 失败或平均置信度低于 0.7 时回退到full_low而不是preserve——即宁可降质保留图片也不返回低质量文本。OCR 后端解析见 _resolve_rapidocr优先rapidocr-onnxruntime1.x回退rapidocr3.x两者都未安装则整个 transcode 能力自动失效并走回退路径。训练的 ML 路由器MiniLM SigLIP 双信号路由决策由一个微调过的MiniLM 分类器做出。文档给出的模型档案模型HuggingFace 上的chopratejas/technique-router大小~128MB精度验证集 93.7%训练数据4 种技术共 1,157 条样本首次使用时自动下载并本地缓存训练数据示例QueryTechniqueWhat animal is this?full_lowCount the spotspreserveRead the text on the signtranscodeWhats in the corner?crop源码中的两级实现PyTorch 版路由trained_router.pyTrainedRouter.classify先跑 MiniLM 得到 (technique, query_confidence)再用 SigLIP 提取图片 embedding与 4 组预计算的文本描述 embeddinghas_text/is_document/is_complex/has_small_details做余弦相似度sigmoid 后得到ImageSignalsL280-L304。随后有明确的信号融合规则L327-L352查询判为transcode但图片文本信号很弱has_text 0.4 且 is_document 0.4→ 置信度 ×0.8保留技术但提示检测到低文本查询判为full_low但图片细碎细节信号 0.7 → 在 reason 中提示考虑 PRESERVE查询判为preserve且图片确实复杂/细节多 → 置信度 ×1.1封顶 1.0确认图片有精细细节。ONNX INT8 版路由onnx_router.py从源码结构看这是生产环境默认路径——compress()优先使用OnnxTechniqueRouter仅在不可用时才回退 PyTorch 版compressor.py L699-L727。ONNX 版完全不依赖 PyTorch/GPUchopratejas/technique-router-onnxINT8 量化模型~32 MB~5ms 推理chopratejas/siglip-image-encoder-onnxINT8 图像编码器~95 MB~30ms预计算的文本 embedding~25 KB总计 ~127 MB纯 CPU onnxruntime 即可运行模型通过hf_hub_download_local_firstonnx_router.py L64首次使用时从 HuggingFace 下载并本地缓存。模型 ID 也可通过环境变量覆盖集中定义在 headroom/models/config.pyHEADROOM_TECHNIQUE_ROUTER控制分类器默认chopratejas/technique-routerHEADROOM_SIGLIP控制图像编码器默认google/siglip-base-patch16-224约 400MB。Tile 边界优化不耗 ML 的免费 token这是文档流程图中未展开、但源码里排在 ML 路由之前的第一步。tile_optimizer.py 用厂商官方的 token 计费公式反推最省 token 的尺寸OpenAItokens 85 170 × ceil(w/512) × ceil(h/512)先按最长边 ≤2048、最短边 ≤768 缩放见 estimate_openai_tokens。比如一张 770px 图原本占 4 个 tile765 tokens缩到 512px 就是 1 个 tile255 tokens。find_optimal_openai_dimensions会枚举更少 tile 的候选尺寸但要求保留至少 40% 原始像素L140-L143避免牺牲观感Anthropictokens (w × h) / 750官方会自动把最长边缩到 1568px、总像素缩到 1.15MPestimate_anthropic_tokens。预缩放到官方上限并不能减少 token官方反正会缩但能省上传带宽。该模块被 tests/test_image_compression.py 覆盖例如 1920x1080 的 OpenAI 图片经 tile 优化后 token 明显下降、512x512 小图保持不变等断言。快速上手方式一Headroom Proxy零代码改动# Start the proxy headroom proxy --port 8787 # Connect your client ANTHROPIC_BASE_URLhttp://localhost:8787 claude图片会根据你的查询自动压缩。在 proxy 进程中图像压缩运行在一个独立的单 worker 子进程池里image_isolation.py 用持久化的ProcessPoolExecutor承载ImageCompressorworker 内把实例标记为_is_singleton True以跨请求复用已加载的模型——这既隔离了原生内存也避免了每请求重载模型的开销。方式二HeadroomClientfrom headroom import HeadroomClient, OpenAIProvider from openai import OpenAI client HeadroomClient(original_clientOpenAI(), providerOpenAIProvider()) response client.chat.completions.create( modelgpt-4o, messages[ { role: user, content: [ {type: text, text: What animal is this?}, {type: image_url, image_url: {url: data:image/jpeg;base64,...}}, ], } ], ) # Image automatically compressed with detaillow (87% savings)方式三Direct APIfrom headroom.image import ImageCompressor compressor ImageCompressor() # Compress images in messages compressed_messages compressor.compress(messages, provideropenai) # Check savings print(fSaved {compressor.last_savings:.0f}% tokens) print(fTechnique: {compressor.last_result.technique.value})此外init.py 还导出了便利函数compress_images(messages, provideropenai)内部创建实例、压缩、并在finally中close()释放模型。配置Proxy 配置# Image compression runs as part of the image built-in compressor and is # enabled by default. There is no dedicated --image-optimize toggle; select # compressors explicitly to disable it (flag is singular: --compressor): headroom proxy --compressor smart_crusher,kompress,code_aware,search,log,tabular,config,html即图像压缩是image内置压缩器的一部分默认开启没有独立的--image-optimize开关要用显式的单数形式的--compressor白名单把它排除在外。程序化配置from headroom.image import ImageCompressor compressor ImageCompressor( model_idchopratejas/technique-router, # HuggingFace model use_siglipTrue, # Enable image analysis devicecuda, # Use GPU if available )对应 ImageCompressor.initmodel_id为空时解析为默认模型ONNX 路由则直接使用 INT8 量化仓库use_siglipFalse可跳过图像分析此时路由只依赖查询分类device支持cuda/cpu/None自动选择。厂商支持矩阵Provider检测方式压缩方法OpenAIimage_url设置detaillowAnthropic带source的image缩放到 512pxGoogleinlineData缩放到 768pxtile 最优OpenAI使用原生detail参数# Before {type: image_url, image_url: {url: data:...}} # After (full_low technique) {type: image_url, image_url: {url: data:..., detail: low}}Anthropic用 PIL 缩放图片LANCZOS 重采样、统一转 JPEG quality85见 _resize_image# Before: 1024x1024 image (~1,398 tokens) # After: 512x512 image (~349 tokens) - 75% savingsGoogle Gemini缩放到 768px正好对齐 Gemini 的 768x768 tile 体系L618-L631# Before: 1536x1536 image (4 tiles × 258 1,032 tokens) # After: 768x768 image (1 tile × 258 258 tokens) - 75% savings性能数据按查询类型的 Token 节省Query TypeBeforeAfterSavingsGeneral (What is this?)7658589%Detail (Count items)7657650%Region (Top corner?)7658589%Text (Read the sign)7658589%延迟路由器推理~10msCPU~2msGPU图片缩放~5-20ms视尺寸而定首次请求2-3 秒模型下载之后本地缓存这些数字与 onnx_router.py 中给出的量级一致分类器 ~5ms、SigLIP 编码器 ~30ms均为 INT8 CPU 推理。故障排查模型下载问题HuggingFace 模型首次使用时下载可强制指定缓存目录# Force a specific cache directory import os os.environ[HF_HOME] /path/to/cache from headroom.image import ImageCompressor compressor ImageCompressor()GPU 显存SigLIP 约需 400MB GPU 显存与 headroom/models/config.py 中google/siglip-base-patch16-224的 400MB 估算吻合。若只想用 CPUcompressor ImageCompressor(devicecpu)注意生产路径的 ONNX INT8 路由本来就只跑 CPUproviders[CPUExecutionProvider]显存压力主要来自 PyTorch 回退路径下的 SigLIP。禁用图像压缩# Proxy (flag is singular: --compressor) headroom proxy --compressor smart_crusher,kompress,code_aware,search,log,tabular,config,html# Direct # Simply dont call compress()API 参考ImageCompressorclass ImageCompressor: def __init__( self, model_id: str | None None, # resolves to chopratejas/technique-router if unset use_siglip: bool True, device: str | None None, ): ... def has_images(self, messages: list[dict]) - bool: Check if messages contain images. def compress( self, messages: list[dict], provider: str openai, ) - list[dict]: Compress images in messages. property def last_result(self) - CompressionResult | None: Result of last compression. property def last_savings(self) - float: Savings percentage from last compression.补充两点源码事实has_images同时识别三种厂商格式OpenAIimage_url、Anthropicimage、GoogleinlineData见 L209-L225实例还提供close(unload_modelsTrue)用于释放模型进程内共享实例如 proxy worker会自动忽略它L191-L207。CompressionResultdataclass class CompressionResult: technique: Technique # full_low, preserve, crop, transcode original_tokens: int # Estimated tokens before compressed_tokens: int # Estimated tokens after confidence: float # Router confidence (0-1) property def savings_percent(self) - float: Percentage of tokens saved.Techniqueclass Technique(Enum): FULL_LOW full_low # 87% savings PRESERVE preserve # 0% savings CROP crop # 50-90% savings TRANSCODE transcode # 99% savings该枚举定义在无重型依赖的 image_types.py 中同文件还有ImageSignals与RouteDecisiondataclass刻意与 torch/transformers/ONNX 解耦——这样仅导入压缩器类型不会触发整个 ML 栈的加载源码注释指出这在 Python 3.13 的 proxy 进程中曾因torch.compiler提前访问而崩溃即 #2513。延伸阅读Compression Guide - 文本压缩技术CCR Guide - 带检索的可逆压缩Proxy Guide - 零代码部署Architecture - 系统设计实现入口headroom/image/compressor.py、headroom/image/onnx_router.py、headroom/image/tile_optimizer.py测试tests/test_image_compression.py、tests/test_tile_optimizer 相关断言【免费下载链接】headroomCompress tool outputs, logs, files, and RAG chunks before they reach the LLM. 20% fewer tokens for coding agents, 60-95% fewer tokens for JSON, same answers. Library, proxy, MCP server.项目地址: https://gitcode.com/GitHub_Trending/head/headroom创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考