一个梗长成的生意:别让 Agent 一边读废话一边写废话
先说这个项目让我坐下来的原因。它挂在 GitHub 上的自我介绍是「Your AI coding agent bills by the word and writes like it knows that」——一句话点到了所有人账单上最疼的地方:Agent 的钱主要花在读,不是花在写。
举个我自己的例子。我有一批 cron job,每天要读日志、读 JSON 报表、读 CI 输出。这些内容里真正有信息量的部分大概十几行,但每次都是几千行原样塞进上下文。之前工坊写过 Headroom(当时 61K Star,现在 73,226),讲的就是「在工具输出到达模型之前截一刀」这件事。Caveman 是同一个赛道里的另一个玩家,但它切的角度不一样——
Headroom 只动「Agent 读到的东西」。Caveman 分成三层,两个方向都动:
- skill(MIT,永久免费):一份规则文件,让模型回答时少说废话。管的是「Agent 嘴上说什么」。它不改你的 prompt,只改模型的输出风格。
- proxy(BSL-1.1):跑在你机器上的本地进程,Agent 连它、它连上游。管的是「Agent 眼里读到什么」——工具输出、日志、JSON、diff、网页。
- middleware(MIT,官方标 alpha):同样的压缩逻辑包一层给你自己写的 Agent 用。Vercel AI SDK、LangChain、OpenAI、Anthropic、LiteLLM、CrewAI、PydanticAI……十几套框架有原生适配。
这三层可以叠。官方推荐先上最小那颗石头(skill),觉得不够再上 proxy。这个分层设计我认为是它 Star 数拉到十万级的真正原因——同一套叙事,先用零成本的方式让所有人尝一口,再往下卖引擎。skill 是 MIT、引擎是 BSL-1.1 的商业化路径,摆得很明白。
赛道:2026 年「上下文压缩」已经是五家分立的局面
这个赛道现在不是「谁更好」,是「谁切在哪一层」。我把五个主要的拉出来,Star 数是我写这篇时的实时 API 数据(2026-09-21):
| 项目 | Star / open issues | 切哪一刀 | 原文能拿回来吗 | 默认行为 |
|---|---|---|---|---|
| caveman(Go,MIT+BSL-1.1) | 106,922 / 130 | 模型的嘴(skill)+ Agent 的眼(proxy:工具输出、日志、JSON、diff、网页) | 能。原始字节存本地 SQLite,给一个 recovery handle | CLI 匿名统计默认开(caveman telemetry off 关) |
| rtk-ai/rtk(Rust,Apache-2.0) | 81,111 / 1,578 | 只改 shell 命令输出(ls / cat / grep / git / 测试跑)Read、Grep 工具调用直接绕过 | 命令失败或截断时给;成功要 opt-in | 遥测默认关 |
| headroomlabs-ai/headroom(Python,Apache-2.0) | 73,226 / 689 | 工具输出、日志、文件、RAG 块、对话历史,走本地代理 | 能,可逆缓存 | 上报默认开 |
| mksglu/context-mode(TS) | 23,750 / 264 | 把工具输出扔进沙箱执行,原始数据永不进上下文 | 只能按匹配段从索引里搜回来,不是整份 | 不上报 |
| teamchong/pxpipe(TS,MIT) | 7,414 / 65 | 文本上下文渲染成图片给模型看 | 不能。官方自己写「It is lossy」,漏了不报警 | 只写本地日志 |
这里有个我没想到的细节:Star 数和 open issues 数的比例差得离谱。rtk 81K Star 挂着 1,578 个未关 issue,headroom 689,caveman 130。同样是「省 token」的工具,caveman 的 issue 密度低一个量级。我翻了一下它的 issue 列表,维护者回得挺勤,但更重要的原因可能是它把「我可能在哪些场景是负收益」写进了文档(下面细讲)——先把丑话说在前面,能少掉一大半「你这玩意在我这儿没用」的 issue。
装:两个命令,171 MB 二进制,然后第一分钟就翻车了
官方给了三条路,我先走 npm 这条:
npm install -g @caveman-ai/cli caveman setup --install
装完第一件事是看版本,输出让我愣了一下:
$ caveman --version
{
"version": "1.3.4",
"binary_release": "bin-v1.1.7"
}
而它的 README 和安装脚本指向的是 v2.7.0(install.sh 里写死了 tag)。也就是说 npm 上这个包和文档描述的版本不是一回事,README 里那些漂亮的命令(trial、learn implement、convert)在 npm 这条路上能用到多少,得自己按 help 输出对一遍。caveman help tools 显示本地工具是有的:compress、shrink、toon、convert、mem、retrieve、mcp、hooks、browse、skills、sdk、stats、trial、evals、config。够用。
setup --install 会拉六个本地二进制,加起来 171.4 MB:
caveman-proxy 39.1 MB cavemem 24.6 MB caveman-engine 26.6 MB caveman-browse 32.3 MB caveman-mcp 24.5 MB caveman-shrink 24.3 MB 全部落到 ~/.caveman/bin/ · 每个都校验了 checksum
然后我按 README 的强烈建议跑了第一条命令——caveman learn,README 的原话是「It is the most useful five minutes in this README」,读你机器上几个月的历史,本地排序出你的 token 黑洞。结果:
$ caveman learn spawnSync caveman-proxy ENOENT $ echo $? 0
刚装完,learn 找不到 proxy 就直接挂了,而且退出码是 0——它自己家 README 里当成头号推荐的功能,在新装机上静默失败,脚本化的场景里根本发现不了。我怀疑是 setup 装完二进制但没进 PATH 的时序问题,重新装一遍或重开 shell 可能就好了,但「第一次接触就遇到这个」本身就是很差的体验。
紧接着 caveman status 又给了一句:
$ caveman status caveman · compress on MCP recovery missing — streaming turns and Claude Pro/Max sessions pass through uncompressed (non-streaming API-key traffic still compresses) nothing has run on the layer yet seat not signed in telemetry off · anonymous usage ping
两条信息量很大。第一,流式请求和 Claude Pro/Max 订阅会话会整段绕过压缩,因为 MCP 恢复工具没注册上——这是个很关键的降级:你以为它在压,其实这一路没压。第二,telemetry off,而 README 里写的是「CLI 默认发送匿名统计」。两边对不上,我不确定是版本差异还是 npm 包的默认值不同,但这属于文档和实现打架。
实测:我用七类真实负载把引擎量了一遍
我不太信任「压了多少」这种话,所以自己造数据量。caveman tools compress 从 stdin 读、往 stdout 写,把统计信息走 stderr 给你一份 JSON,正好方便记账。所有数字是它自己报的 o200k_base token 数,不是我用字节数换算的。
第一类:JSON 事件流(400 行)
$ python3 gen_json.py | wc -c
74720
$ caveman tools compress < big.json > comp.json
{"content_type":"json","tokens_before":31446,"tokens_after":2135,
"ratio":0.9321,"token_count_basis":"o200k_base","method":"elision",
"recovery_handle":"ccr_a265268d4c365e58cbc8162cd48316e8",
"lossless_to_model":false}
31,446 → 2,135,压掉 93.2%。压完的形状挺有意思,它不是把字段名缩写,而是保留样本 + 报告不变量:
{"rows":[{"id":0,"latency_ms":158,"level":"ERROR","msg":"upstream timeout..."},
{"id":1,...},{"id":2,...},
{"__caveman_elided__":3,
"__caveman_invariants__":"all level=INFO; service: 3 distinct,
api-gateway..worker; +3 omitted"},
{"id":6,...}]}
注意 lossless_to_model 那个字段,它自己标了 false——送给模型的确实是残缺版。所以那个 recovery handle 不是装饰品,是这套设计成立的前提。我拿它取回来验了一遍:
$ caveman tools retrieve ccr_a265268d4c365e58cbc8162cd48316e8 > back.json $ cmp -s big.json back.json && echo "BYTE-EXACT" BYTE-EXACT
一个字不差。这一条我认为是这个项目最硬的技术点:压缩是破坏性的,但恢复是字节级的,所以「压错了」可以退回去,不像是摘要模型那种不可逆的赌博。
第二类:重复日志(3,000 行)
tokens_before: 74182 → tokens_after: 430 ratio: 0.9942 method: "log"
99.4%。压出来的东西保留每个 error 的完整堆栈、首尾若干行,中间全折叠成 … 498 lines elided (caveman) …。对「3000 行日志里 6 条报错」这种形状,这就是它最强的场景。
第三类:异构日志,它直接不压(这是好事)
我换了份「每行都不一样」的日志:120 行 WARN,每条的服务、依赖、延迟都不同,外加 15 条各不相同的 ERROR。这类内容压错了就是灾难。结果:
tokens_before: 3406 → tokens_after: 3406 ratio: 0
0%。原样透传,15 条 ERROR 一条不少。我特意 grep 了 UniqFault,15/15 全在。这个「认不出可压的结构就不动」的行为,比它压 99% 的那条数据更让我放心。
第四类:终端命令输出(这是我最推荐的用法)
$ caveman tools shrink -- ./noisy.sh INFO processed batch 1 in 11ms INFO processed batch 2 in 12ms INFO processed batch 3 in 13ms … 197 lines elided (caveman) … ERROR worker: TimeoutError shard-3 unresponsive … 197 lines elided (caveman) … INFO processed batch 398 in 48ms INFO processed batch 399 in 49ms INFO processed batch 400 in 10ms ‹caveman: shrank · 4011→95 estimated tokens · counter o200k_base · inferred · recover: caveman retrieve ccr_225aafeb...›
4,011 → 95(-97.6%),而且它把错误行单独拎出来放在了折叠块之间——没有一个简单截断工具会这么干。还原同样字节级一致(我 cmp 过)。「跑个测试输出 4000 行,Agent 只需要看那 1 行失败」这个场景,它做得比我见过的任何方案都干净。
第五类、第六类:代码和 HTML,一条没压
这两类让我有点意外,因为 README 的技术表里明明白白写着:code 类型保留 imports / 签名 / 类型、省略函数体,目标省 40-70%。我把同一份 TS 源文件重复堆到七个档位,从 538 token 一路到 200,750 token:
2000 bytes -> type=code before= 538 after= 538 ratio=0.000 8000 bytes -> type=code before= 1,971 after= 1,971 ratio=0.000 20000 bytes -> type=code before= 5,311 after= 5,311 ratio=0.000 60000 bytes -> type=code before= 15,349 after= 15,349 ratio=0.000 200000 bytes -> type=code before= 50,090 after= 50,090 ratio=0.000 400000 bytes -> type=code before=100,101 after=100,101 ratio=0.000 800000 bytes -> type=code before=200,750 after=200,750 ratio=0.000
七个档位,全部 ratio = 0.000,而且类型识别是对的(它自己报 content_type: code)——认得出来,但不动手。我试过 --type=code、--force、-t code,三种都是同一个结果;更微妙的是这三个 flag 一个报错都没有,被静默吞了。一份 400 个 alert div 的 HTML 看板(15,279 token)也是同样待遇,ratio 0。
我要说清楚这里的边界:我测的是 CLI 直连 tools compress 这条路,不代表 proxy 路径下代码压缩不生效——引擎可能有只在代理链路里才打开的开关。但一个客观事实是:README 那张「code 40-70% / HTML 50-80%」的表,在这台机器上、这条最直接的调用路径上,我一次都没复现出来。顺带一提,README 自己的 wrap benchmark 表里 HTML 那行是红的(+9.9%,越压越多),维护者还特意在下面写了一句「The HTML row is red and it stays red. The day I hide a red row is the day you should stop trusting the green ones.」——态度挺好,就是表格里的承诺和实际能力差得有点远。
第七类:TOON 编码器,一个意外好用的小东西
$ echo '{"a":[{"k":1,"n":"x"},{"k":1,"n":"y"}],"list":[1,2,3,4,5,6,7,8,9,10]}' | caveman tools toon encode
a[2]{k,n}:
1,x
1,y
list[10]: 1,2,3,4,5,6,7,8,9,10
把 JSON 的括号引号全省掉,用「表头 + 行」的紧凑形式表达。这个格式它当标准件独立提供(toon encode|decode),也可以当 MCP 工具单独调。如果你自己写的 Agent 有「反复把结构化数据塞进 prompt」的毛病,这个单独拎出来用是零成本的。
然后是最重要的部分:它自己把 65% 撤了
如果你只看 README 第一屏,你会记住「cuts 65% of tokens」,徽章、标题、YouTube 反应视频全在强化这个数字。但仓库里有一份 docs/HONEST-NUMBERS.md,我读完的第一反应是:这大概是整个项目里最值得读的一页。
它原话(我翻译):
「早期的统计版本在没有可复核原始结果的情况下,套用了固定的 65% 输出比例。现在的报告会忽略那些历史 est_saved_* 字段……状态栏也不再显示那个数字化的节省后缀。」
同一页还列了三个「它是负收益」的场景:
- 极简问答(issue #145):规则本身是每次都要带的输入 token,固定开销可能超过你省下的输出,有用户实测是净亏。
- 按次计费的产品(issue #506):GitHub Copilot 按 premium request 收钱,回答变短还是同一个 request,一分钱省不下来。
- 工具端计数可能反向(issue #550):一次 Cursor 的 A/B 实测是 带 caveman 4.3M token、不带 1M token,墙钟时间还翻倍。这次运行没能复现,所以文档只敢给一个结论——规则重注入、重试、缓存记账都可能把输出侧那点节省整个吃掉。
再看它引用的两个第三方测试,数字比标题诚实得多:
| 谁测的 | 测什么 | 结果 |
|---|---|---|
| JetBrains(86 个真实编码任务,配对 A/B,只有 skill、没有 proxy) | 输出侧 | 输出 token 少 8.5%,成本约 10%,质量测不出差别(符号检验 p = 0.82) |
| Adobe Research《Cavewoman》(8 个模型 × 5 个数据集 × 5 档压缩) | 输出侧 | 实现成本降 1.4 到 2.4 倍,最好情况 3 倍 |
| 同上,输入侧 | 把人写的 prompt 压成穴居人话 | 净成本反而变高,五个 benchmark 平均约 1.15 倍——严格的双输 |
| caveman 仓库自己的 eval | 10 个开发问题 vs Answer concisely. 对照组 | 中位输出 token 少 50%(只测长度,不测正确性) |
| caveman 自己的 54 次 wrap benchmark | 六类 Agent 负载,provider 报的输入 token | 885,793 → 591,673(-33.2%),18/18 答案校验通过 |
| 同一次测试里 Headroom | 同一批题、同模型 | 省 6.7%,18 题有 3 题答错 |
把这些放在一起,图景就清楚了:「聊天天花板很高、Agent 编码会话只有个位数百分比」。JetBrains 那个 8.5% 就是原文里说的「agentic 会话里大部分 token 是代码和工具调用,skill 根本碰不到」。这也是为什么项目转头去做了 proxy——他们自己说,JetBrains 那份测试是 proxy 存在的理由。
还有一个结论我建议所有人记住:Adobe 那篇论文发现「压缩你自己写的 prompt」是明确的负收益。穴居人风格用在模型嘴上能省钱,用在人的输入上会让模型答得更长更差。caveman 的做法是硬性不碰用户 prompt,这个边界划得对。
另外它的 GitHub 上挂着一条昨天(2026-09-20)刚开的 issue,标题就很扎眼:「evals: quality loss not measured; tokenizer mismatch inflates savings numbers」——评测没测质量损失,而且 tokenizer 对不上会虚报节省。也就是说,连它内部 eval 的口径都还在被质疑。
怎么用:三条命令起步,以及跟 Hermes 的关系
如果你只想要最小验证,这条路径最省事:
# 1) 先只上 skill(MIT,永久免费,30+ 个 Agent 都支持) npx skills add JuliusBrussee/caveman -g # 2) 觉得有用,再上 proxy npm install -g @caveman-ai/cli && caveman setup --install caveman claude # 或 codex / gemini / aider / kilo / qwen / opencode / hermes / openclaw / pi # 3) 只压一次命令输出,不接管整个会话(我最推荐的用法) caveman shrink -- pnpm test caveman retrieve ccr_xxxxxxxx # 需要原文的时候把它取回来
Caveman 原生 wrap 十个 Agent,其中一个是 Hermes Agent。我去扒了它的 profile 文件(agents/profiles/hermes.json):注入方式是把 CUSTOM_BASE_URL 指向本地代理的 /v1、CUSTOM_API_KEY 换成代理的 key,启动参数加 --provider custom,command hook 走 hermes-plugin,标着 tested_agent_version: 0.19.1。有意思的是它把自己标成 injection_completeness: builder-assisted 而不是「完全支持」——也就是自己承认这条路是拼出来的,不是一等公民。caveman status 里我的 Hermes 显示 available · tested。
但我第一次跑 caveman run -- ./noisy.sh 得到的反馈是:
your agent never reached the compression layer this session — routing may not have applied; run `caveman doctor <agent>` → Caveman proxy left running; inspect with `caveman stats`
代理起来了,但我的命令根本没走到压缩层——因为 proxy 是靠给 Agent 注入环境变量生效的,它拦的是模型 API 流量,不是命令的 stdout。这一点很容易被误解:「装个 proxy 就一切都省了」是错的,你必须让 Agent 走它的 base URL。另外 caveman stats 在我这儿读了几分钟还是「No routed requests in this window」——没接通就是没接通,它不会给你编一个好看的数字,这点倒是实在。
配置文件默认值(caveman tools config get,落在 ~/.caveman-cloud/config.json)也顺手贴一下,能看出它默认想干什么:
think.mode = compress # 压缩模式(不是只记录) think.toon = true # JSON 走 TOON 重编码 think.shrink = true # 终端输出压缩 execute.mcp = auto # 自动注册恢复工具 execute.proxy = true execute.browse_tool = true # 浏览器 a11y 树压缩 execute.delegate = false # 委派子任务,默认关
坑和取舍:我建议你先知道这四件事
一、引擎不是开源,是 source-available。skill、CLI、两个 SDK、provider 目录是 MIT;但 engine、proxy、cache engine、rewriter、browse、MCP server、shrink、cavemem 核心全是 BSL-1.1。自己一方流量自托管免费(含生产),但每个版本要等到 2030-06-21 或者发布满四年才转 Apache-2.0,替第三方托管需要商业授权。如果你打算把它包进产品卖给别人,这里有个明确的闸门。对比一下:rtk 和 headroom 都是完完整整的 Apache-2.0。
二、它吃的是「读」,你的账单不一定吃这套。按次计费(Copilot 类)一分钱省不到。纯代码生成、没有口语和日志的负载,压缩率是 0——我上面那七个代码档位不是极端例子,那是我能造出的最典型的负载,一次都没压动。
三、默认行为和文档不一致的地方,值得逐个对一遍。learn 静默失败退出码 0;status 说 telemetry off 而 README 说默认开;npm 包是 1.3.4 而文档描述 2.7.0 的功能;--force / -t 这类 flag 被静默吞掉。单看每条都是小事,合在一起的意思是:别照着 README 抄命令,照着 caveman help 抄。
四、装了 171 MB 的本地二进制。六个全是 Go/Rust 静态二进制,落在 ~/.caveman/bin/。不重,但对「只想压个测试输出」的需求来说,直接上 caveman shrink -- <cmd> 或者干脆只用那个 TOON 编码器,性价比更高。
我的选型建议
这个赛道不冲突,按你卡在哪一层挑,别按 Star 挑。我自己的判断:
- 讨厌 Agent 回话像写检讨、且按 token 计费 → 上 skill。免费、可逆、30+ Agent 通用。但心里有个数:编码会话大概只有个位数百分比的输出节省,别指望 65%。
- 天天被日志、CI 输出、JSON 报表淹 → caveman 的
shrink和 proxy 是我目前见过最干净的做法,字节级还原这条承诺我亲手验过。这是它真正的价值所在。 - 只想压 shell 命令输出、而且讨厌遥测 → rtk(81K Star,Apache-2.0,遥测默认关)。但 JetBrains 同一套方法测出来它在低 reasoning 档位让中位成本 +7.6%(p = 0.004),上之前务必自己 A/B。
- 已经有一套自己的 Agent 框架、想要可逆压缩 → headroom 的适配面更宽(Python 侧框架覆盖更全),但 caveman 自己的 benchmark 里它 18 题错 3 题;我们工坊那篇 Headroom 实测 里的数字也值得对照着看。
- 数据敏感、不能有任何原始内容离开本地 → context-mode 是唯一「原文永不进上下文也不上传」的路线,代价是你要接受「只能按匹配段搜回来」。
最后说句实在话。我对这个项目的评分是「引擎 85 分,叙事 60 分」。它的压缩引擎在结构化数据上确实做到了别人没做到的事——尤其是「保留不变量 + 字节级还原」这一对组合,我拿真实负载验过,不是 PPT。但那个 65% 已经变成了一个自己都不再维护的营销数字,README 第一屏和仓库里的 HONEST-NUMBERS 是两个气质完全不同的东西,而大多数人只会看到第一屏。
它的维护者在 HTML 那行红数据下面写的那句话,其实比整份 README 都值得学:「The day I hide a red row is the day you should stop trusting the green ones.」——那就别把红的藏在 300 行之后。