一个梗长成的生意:别让 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),觉得不够再上 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 handleCLI 匿名统计默认开(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_* 字段……状态栏也不再显示那个数字化的节省后缀。」

同一页还列了三个「它是负收益」的场景:

再看它引用的两个第三方测试,数字比标题诚实得多:

谁测的测什么结果
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 仓库自己的 eval10 个开发问题 vs Answer concisely. 对照组中位输出 token 少 50%(只测长度,不测正确性)
caveman 自己的 54 次 wrap benchmark六类 Agent 负载,provider 报的输入 token885,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 挑。我自己的判断:

最后说句实在话。我对这个项目的评分是「引擎 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 行之后。