Caveman Engine 深度解析:内容感知压缩、S0–S4 安全分级与 CCR 无损恢复
Caveman Engine 是 caveman 项目(一个以“用更少 token 完成同样的事”为目标的 Claude Code skill 生态)的核心压缩引擎:它检测一段载荷的内容类型,路由到按安全等级划分的压缩器,统计 token 缩减比例,并把原始字节存入 CCR 存储以备恢复。本文基于仓库文档 engine/CLAUDE.md 与对应源码,完整拆解其稳定四调用 API(Compress/Retrieve/Detect/Stats)的工作方式、S0–S4 安全分级的含义、15 个默认压缩器的注册机制,以及“fail-closed、只报 inferred、绝不宣称 verified”这套诚实性不变量背后的工程实现。
引擎核心:detect → route → compress → 计数 → CCR
引擎的入口类型是 engine.go 中的 Engine 结构体,由三部分构成:压缩器注册表(compressors.Registry)、token 计数器(tokens.Counter)和 CCR 存储(*ccr.Store)。New(store, counter) 构造时若传入 nil counter 会使用默认离线 BPE 计数器,store 允许为 nil——但此时引擎仍然能检测和无损压缩,只是永远不运行有损压缩器,因为有损结果若无法恢复就违背了可逆性契约(见 engine.go#L31-L41)。
Compress(input, opts) 的完整流水线与文档描述完全一致,且五个直通(pass-through)条件都能在源码中逐条对应:
- record 模式直通:
record模式下输出与输入逐字节相同,不做任何转换,也不存储恢复记录; - 无匹配压缩器直通:内容类型在注册表中找不到对应压缩器时原样返回;
- 解析失败直通:压缩器报 parse 问题(
ok=false)时转发原始字节; - 结果不更小直通:
after >= before || bytes.Equal(out, input)时原样放行、不声称任何缩减(见 engine.go#L110-L112); - 有损但不可恢复直通:S4(有损)压缩器只有在原始字节能先存入 CCR 后才可运行;没有 store 时 fail closed 到直通。
只有 CCR Put 成功之后,res.Output 才会被替换为压缩结果——这意味着调用方绝不可能收到“没有持久化 handle 的转换后字节”(见 engine.go#L116-L139)。Result 结构(result.go)还带有 Basis 字段:token 数字的计量基础永远是 inferred(本地估算),因为压缩发生在计费前,拿不到 provider 的 usage。PassedThrough() 用“无 handle、无 method、ratio 为 0”三条件判定本次是否直通。
Simulate 是 API 之外的一个补充:与 Compress 完全同管道但不做任何存储、不发起网络调用。它有意与 Compress 保留一处差异——S4 压缩器在无 store 时,Compress 直通,而 Simulate 会照报“将会实现的缩减”并标记 Recoverable=false,让调用方知道需要先配好 CCR 才能真正发出这个转换。
Mode 与 Options:未知值一律 fail closed
result.go 中只有两个模式:ModeRecord(默认,直通)和 ModeCompress(运行路由到的压缩器)。Mode.normalized() 对空值和任何未知模式都回落到 record——文档里“unknown mode fails closed to record”在实现里就是一行 default: return ModeRecord。
Options 的其余三个字段各有明确边界:
Type:强制指定内容类型,留空则自动检测;Query:非空时让实现了QueryAwareCompressor的压缩器用确定性 BM25(无 embedding)偏向保留相关内容;不实现该接口的压缩器完全忽略它,且查询永远不会让输出比无查询结果更大;ExternalRecovery:允许嵌入式网关在引擎本地 CCR 之外提供字节级恢复,前提是调用方在转发压缩字节前已自行存好原始字节。
另外,engine.go#L55-L61 显示环境变量 CAVE_ENGINE_TOON=best-of 会向注册表额外注册 JSONStrategy 压缩器——这是默认 15 个之外唯一的注册表变动入口。
内容路由器:12 种类型,低置信度一律落到 text
detect.go 定义了引擎的内容类型常量:json、log、code、diff、search-result、text、toon、html、a11y、terminal、tabular、config。Detect 是纯确定性函数,判断顺序与源码一致:严格 JSON → 终端 → diff → HTML → 表格 → 代码 → 日志 → 搜索结果 → 配置 → text,任何低置信度情形都开放到下一个检测器,最终兜底为 text(对应“low confidence → text”的文档声明)。
源码中有几处值得注意的误路由防护:
- 终端检测放在 diff/code/log 之前,因为裸 ANSI/CSI 转义序列是唯一性信号——只有真实终端输出才会携带它,不会抢走任何 log/code/JSON 流量;次要信号是密集裸
\r(进度条原地重绘),且排除了普通 CRLF; looksLikeCode先问“是不是日志”:由日志级别/时间戳行主导的载荷即使消息里含return、class等关键词,也路由到日志压缩器。注释称之为“最高价值的误路由修复”(见 detect.go#L106-L112);- HTML 检测会让位给源码:JSX/TSX 组件或内嵌标记字符串字面量的源文件,因为有
=>、className=、import等代码结构信号,会路由到代码压缩器而不是被按 HTML 抽成文本; - 代码判定要求“至少 3 个关键词 + 一个结构性信号”,避免一段恰好用了
class一词的散文被误判。
行号边栏(listing)剥离:agent 发来的是“文件清单”不是文件
listing.go 解决一个很具体的问题:编码 agent 交给引擎的不是文件本身,而是其 read 工具打印的结果——每行都带行号边栏(1\t{、2\t "unit")。这层边栏是展示格式,会直接击穿 Detect:JSON 文档不再以 { 开头,json.Valid 失败;源码变得不可解析。两者统统落到 text,压缩率约 0%。
因此解包放在引擎层而不是压缩器内部——边栏与内容类型正交,它可能包裹 JSON、源码、日志、CSV、配置中的任何一种,每种都必须按其真实类型路由。恢复规则有两条讲究:
- 保留每行原始的编号:压缩后存活的行仍带它在原文件中的行号,编号继续指向 agent 读到的那份文件;
- 对“重构式”转换整体放弃恢复:重编码的 JSON(如 TOON 输出)没有任何一行能被原编号所描述,此时直接返回裸压缩体。源码注释说得很直白:“描述不了任何东西的行号,比没有行号更糟。”
S0–S4 安全分级:类的固有属性,不是用户选项
safety/safety.go 是分级注册表,是一个无 engine 依赖的叶子包,让引擎核心和压缩器都能引用而不产生循环依赖。每个压缩器声明自己的类,注册表是回答两个诚实性问题的唯一地点:这个类是否改动模型可见字节?它是否必须先有 CCR 恢复记录才可运行?
| 级别 | ByteSafe | RequiresCCR | Reversible | 含义 |
|---|---|---|---|---|
| S0 | true | false | true | 字节安全行为(元数据、计量),模型可见字节不变 |
| S1 | true | false | true | provider 原生提示(缓存、路由),模型可见字节不变 |
| S2 | false | false | true | 需要 SDK 配合的结构性改动 |
| S3 | false | false | false | 行为性改动(路由、推理),Cloud 侧由 eval 门控 |
| S4 | false | true | false | 有损结构性压缩:改动模型可见字节,必须可逆(CCR)且披露丢了什么 |
Lookup 对未知类返回 ok=false,调用方 fail closed——文档中“Unknown class → fail closed”正对应 engine.go#L96-L99。文档特别提示:只把 byte-safe 一词留给 safety.Info.ByteSafe == true 的类(即 S0/S1),其余不要误称。
压缩器注册表:Default() 注册 15 个,forced-only 不进 Detect
compressors/compressor.go 的 Compressor 接口只有三个方法:ContentType()、SafetyClass()、Compress()。接口的包注释定义了核心纪律:压缩器是纯字节转换——它永远不数 token、不触碰 CCR、不访问网络,引擎核心在周围做这些事。这正是每个压缩器可以保持自包含、可单测、加一个压缩器只需“新文件 + 测试”的原因。
Default() 注册的 15 个压缩器为:JSON、log、code、diff、search-result、text、HTML、tabular、config、tool-schema、tool-schema-annotations、TOON、accessibility-tree(a11y)、repetition、terminal。其中后五个(tool-schema、tool-schema-annotations、TOON、a11y、repetition)从不被自动检测,只能通过 Options.Type 强制到达——这与文档“forced-only … must not be added to Detect”的约定一致。
两个可选能力接口值得了解:
MetadataCompressor:压缩器可报告本次实际使用的方法(Method)与LosslessToModel等元数据;QueryAwareCompressor:实现CompressQuery的压缩器支持查询导向压缩,引擎仅在Options.Query非空时类型断言并调用。
为什么 toolschema-annotations 被刻意排除在能力清单之外
manifestExcluded(compressors/compressor.go#L139-L148)把 toolschema-annotations 排除在 Cave Compiler 消费的 transform-capability ABI 之外。原因是:advertise 一个压缩器会旋转 RegistrySHA256,而每个已构建的 Cave Build lock 都钉着旧值,失配的 lock 会在运行时让 agent 失败。既然没有编译后的计划会路由到它,把它加进 ABI 换来的只是一行永远用不到的能力,代价却是使所有现场 lock 失效。
toolschema 转换目前是纯客户端侧的
文档专门用一段约定说明了这一点,值得逐条消化:
- 注册它只是让引擎调用方可以 force;并不让它从托管网关流量可达;
- provider 适配器刻意把 tool 数组保留在冻结的 prompt-cache 前缀里,没有任何计费路由调用这个压缩器;
- 引擎 API/CLI 调用方可以在本地 force 它,
caveman-shrink是它专门的产品面;这些缩减保持本地且inferred; - 托管网关另有一条独立的 S2 tool-search/deferral 路径,不要把它与压缩混为一谈;
- 未来若要为它开通网关路由,需要先做缓存对 schema 的成本算术、保证字节级稳定的前缀输出、并通过 eval 门。
重复剔除的正确性护栏:keepNonRedundant
compressors/redundancy.go 实现了文档“elide repetition, never a document”这条正确性规则。所有会丢单元的压缩器(text、log、json、tabular、config、searchresult、terminal)在输出前都调用 keepNonRedundant:一个即将被丢的单元,若没有已存活的单元与它相似,则被保留,其后的副本再对它折叠。
实现细节上有几个精心设计的常量:
- 词汇画像 + 数字掩码:
unitVocabulary把单元降为词汇集合,数字串折叠为#——这让只差时间戳的两行日志互相认得,同时保留原词,使只共享字段名的两条书目条目不会被误判为同类; - 无词单元不掩码:
redundancyMinWordTokens = 1。像6 ['1973.', 251]这样的单元掩码后只剩#,会让整张数据表看起来全同并整体被剔除——所以带至少一个词的单元才掩码,否则按原数字比较,因为那里的数字本身就是内容; - 掩码与未掩码画像不可互比:
representedBy中class.masked != dropped.masked直接跳过,防止“形状相同、数字不同”被读成“文本相同、数字相同”; - 90% 包含阈值:单个存活单元必须已携带待丢单元 90% 的词汇才算“已被代表”,宁严勿松——漏剔除损失的是缩减,错剔除改变的是答案;
- 128 次晋升上限:一个载荷里“首次出现即保留”的单元超过 128 个,说明它不是重复流而是文档,其余单元全部保留,最终由“输出不更小”检查让它整体直通、不声称任何缩减。注释特意提到计数陷阱:若把种子和晋升一起计数,任何超过 64 个存活单元的大数组都会静默变成直通。
文档引用了一个实测代价:若 agent 必须枚举的文档被剔除,agent bench 上会花掉基线 5.5 倍的开销(2026-08-06)。这条规则被明确定位为“正确性规则,不是调参旋钮”。
省略标记只陈述它验证过的事实:invariants
compressors/invariants.go(全文 806 行)为 log/tabular/JSON 的省略标记附加从被替换单元精确计算出的事实,且只陈述验证过的内容。源码头部注释与文档的 Gotchas 段落逐条对应,可归纳为:
标记可携带的三类事实
- 常量:某字段在被省略的每一个单元中字节级相同,记为
name=value(如all state=charged); - 枚举:可变字段在少量短值上变化时,完整列出并带精确计数,各桶之和恒等于被省略数;缺失该字段的单元进
absent×N桶(如status: fulfilled×15 shipped×3 processing×2); - 数值范围:用原始极值字符串打印(
range amount=5.00..199.99),从不做重格式化或舍入,因此边界绝不可能比实际更宽。
整体扣留的条件(永不截断,因为部分清单会被读成完整清单)
- 凭证形状的字段名;
- 含空格或超过 24 字节的值(源码常量
invariantMaxValueBytes = 40用于更长的单值拒绝,标记预算则另有上限); - 超过 5 个不同取值;
- 任何单元解析不出字段的 run——整个 run 的摘要禁用,标记退化为与裸
… N rows elided (caveman) …字节级相同。
标识符列表的 coverage 表达:每个桶恰好一个单元的枚举不是类不变量而是标识符列表,标记改为陈述其覆盖度——order_id: 25 distinct, ord-1000..ord-1024:精确不同计数 + 按字节序最小/最大原始值串,不声称中间无缺口。这是唯一能回答“ord-1043 是在被省略的行里,还是根本不在账本中”这一事实。若 run 恰好稠密(共享前缀、定宽数字、max-min+1 等于计数值),则改说 wh-5000..wh-5059 all 60 present——一个经核实的成员性答案;稠密是数出来的,绝不从端点推断,混合后缀宽度、两个前缀或单个缺口都退回计数形式。
预算与裁剪顺序:摘要上限 160 字节且不超过其替换字节数的四分之一(下限 64,永不超过一半);超预算时按顺序整体丢弃条目:标识符式枚举 → 范围 → 有界 coverage → 常量 → 稠密 coverage,类枚举最后;每条载荷最多追加一行尾部契约行,且仅当实际丢掉的字节 ≥4 KB 时。
小于 3 个单元的 run 根本不省略(除非折叠后既能摘要又使自身字节减半)——单个单元标记加恢复 handle 的成本约等于单元本身,且读起来像个洞。
文档给出的代价是刻意为之的:这套机制在 toolwork 语料上让 ratio 降了约 4 个点(0.83 → 0.79)。换来的是什么:2026-08-08 一次 bench 中,无法分辨被省略内容的 agent 连发 46 次 caveman_retrieve,开销是无压缩对照组的 3.3 倍;只陈述常量和范围的第一版修复让风暴停在 11–27 次(因为它对任务真正依赖的那个混合值字段保持沉默);第二轮仍在标识符枚举、无事实小类和 {"__caveman_elided__":1} 单例上漏恢复调用。
恢复视图由完整单元构成:retrieve_query
engine/retrieve_query.go 把 CCR 恢复收窄到匹配查询的单元,而“单元”是自定界的整体:完整 JSON 记录(绝不是字段行——"status": "unfulfilled", 是片段)、从原始字节切出的完整 CSV 记录(表头只显示一次)、完整 log/NDJSON 行、或非 JSON 散文的完整段落。关键规则:
- JSON 字段名从不是出处证据:
messages[].content、text、system永远附着在其完整对象记录上,因为工具输出可以与 provider 请求使用相同字段名; - 独立 JSON 数组之间有显式 gap 哨兵;被省略的信封/标量字节有首尾标记;
- 无法分解的内容(没有记录数组的 JSON)整体返回而非按行切开;收窄视图若不更小也返回完整原文——过度返回是安全的,片段不是;
- 视图中的任何间隙(两个返回单元之间、首单元之前、末单元之后)都打印
… [caveman: non-adjacent] …,保证视图中的相邻性从不暗示原始中的相邻性。
这段代码注释里的事故记录与文档一致:2026-08-08,query 模式返回了某 pretty-printed orders 页的 BM25 排序行,agent 把 "status": "unfulfilled"(属于 ord-1043)读成了紧邻其下的 "order_id": "ord-1047" 的字段,报告了 5 个未履约订单而实际只有 3 个——12 任务 bench 中答错两道。查询收窄本身有界:BM25 打分(复用 contextwindow 的确定性 packer 所用的打分器),top-k 上限 maxRetrieveSections = 20,命中后按原始顺序重排。
一个恢复面、两个 id 空间
这是文档中最反直觉的 Gotcha,源码注释(engine.go#L235-L266)给出了完整解释:CCR 存储同时保存压缩 blob handle(ccr_…,走 store.Get)和原生运行时的类型化对象(store.GetObject),而运行时在遮蔽整段工具输出时向 agent 展示的是 ccr://<objectID>。Engine.Retrieve 因此先查 blob 表、未命中再落 object 表、两者都未命中才失败;MCP 侧的 normalizeRecoveryHandle 接受 ccr_…、<<ccr:…>>、ccr:…、ccr://… 四种形式。
动机是循环:agent 只会复制它被展示的那个引用;一个无法解析的形式不会“降级”,而是循环——失败的工具结果本身又会被遮蔽成新的指针,“一个指向另一个指针的指针,无限循环”。文档引用的实测:2026-08-08,inventory-mismatch 与 webhook-delivery-gaps 两个任务拿到 ccr://<objectID> 后每次 retrieve 都回答 cave_unknown_handle,发生 27–97 次恢复调用、未写出任何答案、两任务 0/6;同构建下 rate-limit-forensics 却以约便宜 35% 的成本拿了 3/3。
CCR 存储:SQLite、单序列化连接、生命周期
ccr/ 目录提供 ~/.caveman/ccr.db(SQLite)恢复存储加原生会话存储:内容寻址 handle、字节级精确的 Get、会话作用域、依赖、current/stale 状态,以及 Hot/Warm/Cold/Archived 生命周期。文档强调的实现事实:嵌入式 SQLite 使用单条序列化连接,使并发 hook/仓库写入既不会撕裂内存中的 schema,也不会与 SQLITE_BUSY 竞态;store_sqlite.go 注释补充了为什么需要 journal_mode(WAL)——否则读者在写者持锁期间被完全锁出。JS/WASM 构建则使用 store_wasm.go 的内存存储。引擎层面的 CCR 联动规则在 engine.go#L94-L102:info.RequiresCCR && e.store == nil && !opts.ExternalRecovery 时直通——这就是“CCR-or-pass-through”的实现本体。
token 计数:离线 BPE,永远是 inferred
tokens/ 定义 Counter 接口,默认实现是词表内嵌的离线 BPE 分词器(OpenAI o200k_base 词表),Default() 返回共享实例(见 tokens.go#L87-L92)。所有 ratio 都是带 inferred 标签的本地估算:绝不是 verified,也绝不重新投影为 provider usage——因为压缩发生在请求计费之前,provider 侧数字在此时不可得。这也是 Result 中 TokenCountBasis 字段存在的理由:它标明前后两个数字用的是同一个估算器。
目录布局与构建约定
文档给出的完整布局与仓库一一对应:
- engine.go:Engine 核心,含 record/miss/parse-fail/not-smaller/no-store 五路直通;
- result.go:
Result/Options/Mode; - detect.go:内容路由器;
- listing.go:行号边栏剥离与恢复;
- safety/:S0–S4 注册表;
- tokens/:Counter 接口与默认 o200k_base BPE;
- contextwindow/:确定性 BM25 上下文打包器,带 recency/error/priority 信号与 token 预算计量;
- compressors/:接口 + 注册表,
Default()注册 15 个; - ccr/:SQLite 恢复 + 原生会话存储;
- pixel/:pxpipe 移植(MIT,见其 NOTICE):文本→PNG 请求压缩,内嵌字形图集 + 渲染器 + 盈利门 + 按 wire 格式的变换(Anthropic/OpenAI/Gemini)。它是 S4 有损、白名单门控(
CAVE_PIXEL_MODELS)、由 proxy 的 pixel 模式消费;从不接入 Detect,也从不被 WASM 构建导入(约 4 MB 资源)。applicability.go 验证了文档声明:CAVE_PIXEL_MODELS缺省时默认白名单就是claude-fable-5,gpt-5.6; - evals/:本地 eval 框架 + fail-closed grader + 内嵌 fixtures,
Run()是质量门,未知 grader 返回passed:false; - cmd/caveman-engine/:CLI shell 出来的二进制,子命令为
compress | detect | retrieve | stats | registry | toon encode|decode | evals run | pixel render|simulate。toon是无状态(无 CCR)的 JSON⇄TOON 转换器,双向都 fail closed。retrieve <handle> [query]带 query 时只返回最相关 section(BM25),与RetrieveQuery对应。
构建/测试约定为 make product-build PRODUCT=engine / make product-test PRODUCT=engine。新增压缩器是“compressors/ 下一个自包含文件 + 测试 + 在 Default() 中注册”;toolschema、toon 这类 forced-only 压缩器不得加入 Detect。
其余诚实性不变量速览
- cgo:完整代码压缩(Python/JS/TS)需要 tree-sitter 构建;无 cgo 构建只压缩 Go。内嵌 eval fixtures 在 cgo 下覆盖这三种语言(对应 compressors/code_cgo.go 与 code_nocgo.go 的构建期选择);
- fail-closed 三件套:未知模式 →
record;未知内容类型 →text;未知 grader →passed:false; - boundary:engine 处于
public/区,绝不导入cloud/…,由make check-boundaries强制; - 确定性要求贯穿始终:invariants 的渲染路径刻意保持顺序保留、无 map 迭代序依赖——因为压缩块必须在后续每个 turn 以相同方式重新序列化,否则 provider 前缀缓存会失效。
小结
Caveman Engine 的设计可以用 engine/CLAUDE.md 的一句话概括:“Everything it reports is inferred; it never says verified”。围绕这句话,仓库实现了完整的不变量体系:五个直通条件、S0–S4 分级与 RequiresCCR 门控、keepNonRedundant 的“剔除重复但不剔除文档”、invariants 标记“只陈述验证过的事实”、恢复视图“完整单元 + 非相邻哨兵 + 双 id 空间解析”,以及 CCR-or-pass-through 的存储前置。理解这套机制的实用价值在于:当你通过 CLI(caveman-engine compress / retrieve / stats)或 SDK 调用引擎时,每一个 inferred ratio、每一个 ccr_… handle、每一个省略标记里的计数,背后都有上面这些可定位到具体文件的护栏在支撑——而所有护栏的失效方向都一致:宁可不压缩,不压缩错。
atomcodeClaude Code 的开源替代方案。连接任意大模型,编辑代码,运行命令,自动验证 — 全自动执行。用 Rust 构建,极致性能。 | An open-source alternative to Claude Code. Connect any LLM, edit code, run commands, and verify changes — autonomously. Built in Rust for speed. Get StartedRust0622
Hy4-previewHy4 preview 是由腾讯混元团队研发的新一代混合专家(MoE)旗舰模型。模型总参数量 770B,每个 token 激活 49B,主干共包含78层,第一层采用标准 FFN,其余 77 层均为 MoE 结构,每层包含 256 个路由专家与 1 个共享专家,每个 token 激活 top-8 路由专家及共享专家。主干之外原生内置 1 层 MTP(总参数量 10B,激活 0.7B)以支持投机解码。Python00
GLM-5.3GLM-5.3 与 GLM-5.2 使用相同的基座模型——所有提升均来自后训练。与 GLM-5.2 相比,它在复杂编程和长程任务上的表现显著提升。Jinja00
GLM-5.3-FlashGLM-5.3-Flash (320B-A18B),是GLM-5系列的首个原生多模态模型。320B总参数,能力超过GLM-5.2Jinja00
Spark-X2.5-4BSpark-X2.5-4B 旨在让强大的 AI 更实用、更高效、更易获得。在广泛日常任务中表现强劲,涵盖对话、写作、翻译、推理、编码、工具调用以及智能体工作流,并在同等规模的开源模型中取得领先成绩。Spark-X2.5 将面向效率的架构与最高 1M tokens 的原生上下文窗口相结合,并支持 200 多种语言。Python00
Spark-X2.5-1.7BSpark-X2.5-1.7B 旨在让强大的 AI 更加实用、高效且易于获取。这些模型在广泛的日常任务中表现出色,涵盖对话、写作、翻译、推理、编程、工具调用和智能体工作流,并在同等规模的开源模型中取得领先结果。Spark-X2.5 将面向效率的架构与最高 1M tokens 的原生上下文窗口相结合,并支持 200 多种语言。Python00