进阶 📋 6 个步骤 第 554 / 554 篇

用 Headroom 把 Agent 的 token 账单压下来:wrap / proxy / SDK / MCP 四路线实操

Headroom 是一层跑在本机的上下文压缩中间件:按内容类型自动分派压缩器,把工具输出、日志、RAG 片段在进模型前压一遍,并用 CCR 保留可逆取回能力。本教程从命令行安装与体检、wrap 接管编码 Agent、零改代码的本地代理、SDK 内联自己的 Agent,到 MCP 三件套与隐私开关,四条路线逐一跑通。

2026.10.21· 11 分钟上手· 约 3509 字· 🗜️ Headroom / 💰 成本控制

长会话编码 Agent 最贵的开销往往不是模型问的那句话,而是它读回来的东西:一次代码搜索的一百条结果、一次事故排查的六万行日志、一次 RAG 检索捞回来的几十个文档块。这些 payload 里绝大部分是重复的样板结构——同样的键名、同样的日志前缀、同样的缩进与中括号。Headroom 的思路就是在这些内容进入模型之前先本地压缩一遍:它按内容类型自动分派压缩器(JSON 走结构化压缩,源代码走 AST 压缩,散文文本走模型压缩),压缩全程在本机进行,不把提示词或文件内容发出去做处理。对高度重复的 payload,官方给出的压缩幅度最高可以到 90% 以上;而里面的关键行(比如日志里的那行 FATAL)会被逐字节保留。本教程把它的四条落地路线——包装现有 Agent、本地代理、SDK 内联、MCP 工具——逐条跑一遍。

🧩 本教程适合:每天开着 Claude Code / Codex 跑长会话的开发者,以及工具输出与 RAG 结果很重的团队。你需要 Python 3.10 以上环境(走自包含命令行时官方建议用 Python 3.13),没有 GPU 要求;如果只想用 TypeScript,官方也提供了 npm 上的 SDK 包。项目为 Apache-2.0 许可。文中命令与环境变量以官方文档当前版本为准。

Step 1:装好命令行并做一次体检

1 命令行只在 PyPI 包里

安装这一步有两个容易踩的点。一是命令行的载体:headroom 这个命令随 PyPI 包发布,官方推荐用 uv 装成一个自包含的隔离环境(指定 Python 3.13);直接 pip 安装也能拿到同一个命令行。而 npm 上的同名包是 TypeScript SDK,import 进去就能用,但它不带命令行。二是系统与 wheel 的兼容:在 macOS 上如果你的默认 python3 比当前 wheel 集还新,请按官方建议显式指定 3.13,否则可能装不上或装错组合。装完之后,先跑体检命令确认链路通了,再进入使用环节。

# 推荐:自包含命令行环境
uv tool install --python 3.13 "headroom-ai[all]"

# 或者:直接 pip(同样带 headroom 命令)
pip install "headroom-ai[all]"

# 按需要装 extras
pip install "headroom-ai[proxy]"       # 代理服务器 + MCP 工具
pip install "headroom-ai[ml]"          # ML 压缩(Kompress,需 torch)
pip install "headroom-ai[langchain]"   # LangChain 集成
pip install "headroom-ai[agno]"        # Agno 集成

# TypeScript 只装 SDK(不带命令行)
npm install headroom-ai
# 装完先体检:确认分派链路可用
headroom doctor

# 想知道压缩花了多少时间
headroom perf

# 想看实时省了多少(需先跑着代理)
headroom dashboard

环境与依赖:文本压缩依赖托管在 Hugging Face 上的 Kompress 权重,离线或内网环境需要提前评估拉取通道;带 ML 的 extras 还会引入 torch,镜像体积会涨一大截,容器化时别盲 Full 安装。另外它只负责压缩环节,推理流量仍旧走你原来的 Anthropic / OpenAI / Bedrock 端点——它是链路上的一层,不是新的模型供应商。

Step 2:一条命令接管你的编码 Agent

2 wrap 与 unwrap 可逆

最省事的落地方式是 wrap:一条命令把某个编码 Agent 拉起来,它会在背后顺手带起本地代理并把 Agent 的流量指向那里,之后这个 Agent 的每次文件读取、搜索结果与工具输出都会先过一遍压缩再发往模型。官方支持的 targets 包括 Claude Code、OpenAI Codex、Cursor、Aider、Copilot 等,不想用了就用 unwrap 还原,属是可逆操作。需要注意的是,wrap 不是一个纯粹的转发器:它会顺带安装语义代码导航能力,作为本地作用域的 MCP 服务注册给被包装的项目,目的是让 Agent 用更少token 定位到代码位置;你可以把作用域放大到用户级,也可以完全不要这层。

# 接管某个编码 Agent
headroom wrap claude        # Claude Code
headroom wrap codex         # OpenAI Codex CLI
headroom wrap cursor        # Cursor
headroom wrap aider         # Aider

# 还原(可逆)
headroom unwrap claude

# 调整随附的语义代码导航能力的作用域
headroom wrap claude --code-memory-scope user   # 所有项目可用
headroom wrap claude --code-memory none         # 完全不装

# 一条命令做托管式本地部署 + Agent 配置
headroom deploy
💡 每次会话都用 wrap 方式拉起,不要指望「配置一次永久生效」。官方说明 wrap 的动作是「起本地代理 + 注册语义导航 + 以指向代理的配置启动 Agent」这套组合拳,绕开它直接启动 Agent,就不会经过压缩链路。

包装会改配置:wrap 会向 Agent 的配置文件里写入服务注册与环境变量。团队机器上批量铺开之前,先在一台机器上确认写的是什么、unwrap 能否干净还原,再决定要不要进标准镜像。

Step 3:代理模式,应用代码一行不改

3 改一个环境变量就够了

如果你不想包装某个具体工具,或者要给自己写的程序加上压缩,代理模式是最干净的形态:起一个本地监听端口,把客户端的 base URL 指过去,应用代码完全不用动。它兼容 OpenAI 兼容接口与 Anthropic 接口,也支持把后端直接指向 Bedrock、Vertex AI、Azure OpenAI 或 OpenRouter,走 LiteLLM 时还能覆盖上百家供应商。这种形态特别适合接进已有的 CI 或后端服务——不用改任何调用代码,把环境变量换成代理地址就行。

# 起本地代理(默认端口 8787)
headroom proxy

# 指定云后端
headroom proxy --backend bedrock     --region us-east-1
headroom proxy --backend vertex_ai   --region us-central1
headroom proxy --backend azure
headroom proxy --backend openrouter

# 把现有客户端指过来(应用代码零改动)
ANTHROPIC_BASE_URL=http://localhost:8787 claude
OPENAI_BASE_URL=http://localhost:8787/v1 your-app

代理模式还能顺手解决一个常被忽视的成本项:前缀缓存。它的 CacheAligner 会标记那些会导致 provider KV 缓存失效的易变内容(比如时间戳、随机 ID),让前缀尽量稳定,从而拿到命中缓存时的折扣价。很多人只盯着 token 数而忽略了这部分收益,实际账单上的差距有时比压缩本身还明显。

代理就是中间人:你的全部请求体与返回体都会经过这个本地进程,它虽然在本机跑,但仍然是链路上的一个信任点。别把它暴露到公网端口,团队成员共用一个代理实例时要想清楚日志与原文的存放位置;处理敏感数据的场景先过一遍自己的合规要求。

Step 4:SDK 内联,把压缩写进自己的 Agent

4 压什么、压多少,由你说了算

自己写 Agent 循环的场景(也就是不与某种框架耦合的情况)推荐直接用 SDK:在调用模型之前把消息数组过一遍 compress(),拿到压缩后的消息与省下的 token 统计,再照常发给供应商。这种做法的优势是粒度可控——你可以只对「工具结果」这个角色的消息做压缩,把系统提示与用户指令原样保留;也可以按预算决定是否这一轮要压。TypeScript 侧形态几乎一致,可以接进 Vercel AI SDK、OpenAI Node SDK 或 Anthropic TS SDK。

from headroom import compress
from openai import OpenAI

client = OpenAI()
messages = [{"role": "user", "content": "分析这份结果"}]

# 在发往模型之前压缩一次
result = compress(messages, model="gpt-4o")
response = client.chat.completions.create(
    model="gpt-4o",
    messages=result.messages,
)
print(f"省下 {result.tokens_saved} tokens(压缩率 {result.compression_ratio:.0%})")
# TypeScript 侧:同样的形态
# npm install headroom-ai
import { compress } from 'headroom-ai';

const result = await compress(messages, { model: 'claude-sonnet-4-5-20250929' });
console.log('省下 ' + result.tokensSaved + ' tokens');
// 之后把 result.messages 交给任意 LLM 客户端

# 走 LiteLLM 时,一个 callback 覆盖上百家供应商
import litellm
from headroom.integrations.litellm_callback import HeadroomCallback

litellm.callbacks = [HeadroomCallback()]
💡 别把「压缩」和「截断」混为一谈。截断是丢信息,而它走的是可逆路线:原文会在本地缓存起来,模型需要细节时通过一个检索工具按标识符取回。本质上它把「是不是要把原文放进上下文」这个决定延后了,交给模型按需来问。

Step 5:MCP 三件套与可逆取回

5 让 Agent 自己决定何时压缩

装成 MCP 服务之后,任何 MCP 客户端都能拿到三个工具:compress(压缩一段内容)、retrieve(把之前压掉的内容按标识符取回原文)、stats(看这一路压了多少、省了多少)。这条路线与前面几条并不冲突——包装与代理是「自动全量压缩」,MCP 是「按需手动压缩」,适合那种「大部分时间不需要、偶尔冒出一坨巨大数据块」的场景。三个工具要一起装,模型才知道压掉的东西还能取回来,否则它只会以为信息丢了。

# 安装 MCP 服务,随后照常启动你的客户端
headroom mcp install && claude

# 暴露的三个工具
# headroom_compress   压缩一段内容,返回一个可取回的句柄
# headroom_retrieve   按句柄取回原文(CCR 可逆压缩)
# headroom_stats      查看压缩量、节省量与成本估算

可逆性(官方叫 CCR)是这套方案里最值得强调的一点:压缩是激进的,但它会把原文存在本地缓存里,同时给模型一个检索工具,需要细节时按需取回原文——也就是说,压缩掉的并不是被扔掉的信息,而是「延迟加载」的信息。这也是它与朴素折叠、粗暴截断最本质的区别:后者一旦执行,模型再也拿不回那部分内容,而前者保留了可能性。

缓存也是数据:原文缓存在本地磁盘上,日志原文、报错堆栈、可能含个人信息的内容都在里面。团队共享机器或容器镜像里要规划好缓存目录的生命周期与清理策略,别让「临时缓存」变成没人管的敏感数据堆积点。

Step 6:搞清它在哪儿省钱,以及该关掉的开关

6 重复度决定收益

要不要上这套东西,取决于你的 payload 长什么样。官方用真实 MCP 输出格式构造的场景里,代码搜索一百条结果的压缩幅度约两成多,而 SRE 事故排查这种重复日志为主的任务能到五成以上,某些高度重复的 JSON 数组与日志行在基准脚本里能打掉九成;反过来,散文明文与本来就紧凑的输出压缩幅度很小,日常短对话几乎看不到变化。官方也很坦诚:压缩率随 payload 的重复程度走,别拿别人的 benchmark 当自己的收益,跑一条自家真实流量的统计才是决策依据。

# 用它自己的能力测你的真实流量,而不是看第三方数字
headroom savings        # 输出你自己链路上的实际节省
headroom dashboard      # 实时看板(需先起代理)
headroom perf           # 压缩耗时(官方口径:万 token 级 JSON 亚毫秒)

上线前还有两件事。其一是隐私开关:默认会有一个匿名遥测信标,上报压缩比、计数器、供应商与模型 ID、操作系统与架构这类聚合指标(官方声明不含提示词、回答、代码与文件路径),在意的话用下面任何一种方式关掉。其二是它自带的两个「越界」功能要不要开:跨 Agent 共享记忆会把同一份记忆 store 暴露给多个 Agent 并自动去重,失败学习会去翻过去的失败会话、提炼成修正规则写进 CLAUDE.local.md(默认,通常已被 gitignore)或其他 Agent 规则文件——这些都很诱人,但它们会改动你的 Agent 记忆文件,团队里使用时需要先约定由谁来维护那份文件。

# 关掉遥测(任一即可)
export HEADROOM_TELEMETRY=off
export HEADROOM_BEACON=off
export DO_NOT_TRACK=1
export HEADROOM_OFFLINE=1

# 失败学习:从历史会话里提炼修正写进规则文件
headroom learn          # 默认写 CLAUDE.local.md,可改 CLAUDE.md / AGENTS.md / GEMINI.md

别让压缩替你做判断:官方的限制页也提醒了,压缩不是万金油——需要逐字引用、要做审计取证、涉及金额或法律条款的上下文,压了就别指望模型能准确复述;这类内容走 CCR 取回原文,或者干脆单独走一条不压缩的通道。同理,准确性 benchmark 只说明在那些测试集上没有可检测的退化,不代表你的任务不受影响,接入后务必用你自己的回归集验证一遍。

常见问题速查

现象原因与处理
输入 headroom 提示命令不存在命令行只随 PyPI 包发布;npm 包是 TypeScript SDK,不带命令行
macOS 上装不上或报 wheel 相关错默认 python3 比当前 wheel 集更新;用 uv tool install --python 3.13 重试
Agent 的流量没经过代理wrap 是一次性动作(起代理 + 改配置 + 启动),要每次用它拉起;或直接改 ANTHROPIC_BASE_URL / OPENAI_BASE_URL
压缩率远低于官方数字收益随重复度走,散文与紧凑输出几乎不省;先跑 headroom savings 拿自家数据
模型抱怨找不到刚才的内容确认 MCP 三个工具都装了;少装 retrieve 会导致压缩不可逆
账单没有明显下降检查前缀缓存是否被时间戳等易变字段打散;确认 CacheAligner 生效并观察命中率
不想让遥测外发用 HEADROOM_TELEMETRY=off、DO_NOT_TRACK=1 或 HEADROOM_OFFLINE=1 任一关闭
规则文件被自动改动headroom learn 会写 CLAUDE.local.md 等文件;团队里先约定归属与评审流程
← 返回教程中心