Caveman Engine 压缩引擎深度解析:四操作 API、fail-closed 流水线与可恢复压缩设计
Caveman Engine 是 caveman 项目中的本地 Go 压缩引擎,负责在字节到达模型之前检测输入形态、路由到带安全分级的压缩器、计算 token 缩减并保留原始数据以便恢复。本篇基于 技术文档 与仓库源码展开,读者读完后可掌握 Engine 的 Compress/Retrieve/Detect/Stats 核心 API、其 fail-closed 流水线设计、内容自动检测规则、15 个压缩器注册表与恢复存储(CCR)的配置方式,并能在本地构建、测试和扩展 Engine。
引擎定位与许可
Caveman Engine 是一个本地的 Go 库和命令行运行时,目标是削减模型上下文。它检测输入形态(shape),选择匹配的压缩器,当有损变换(lossy transform)需要恢复时先存储精确的原始字节,并且只有当结果通过大小与安全校验时才输出压缩产物。
许可方面需要注意:Engine 源码采用 Business Source License 1.1(BSL 1.1),而接口与采纳(adoption)包使用各自的包级许可。详见 LICENSING.md。从 engine/README.md 可确认补充事实:Engine 源码是 source-available,在 2030-06-21 的 Change Date 之前不是 OSI 开源许可;Agent SDK、轻量 CLI、契约与 evals 等采纳面是 MIT。
核心 API:四个稳定操作
Engine 的公开 API 由四个操作构成,这是 proxy、SDK、CLI、MCP 服务器和浏览器构建共同依赖的稳定契约(见 engine/engine.go 的包注释):
| 操作 | 用途 |
|---|---|
Compress |
在给定模式与策略下检测并压缩输入 |
Retrieve |
根据 handle 恢复精确的原始字节 |
Detect |
只分类输入形态,不改变它 |
Stats |
读取本地压缩统计 |
Simulate 是辅助操作:它评估某个变换会带来什么效果,但不产生任何常规运行时副作用。从源码看(engine/engine.go),Simulate 与 Compress 走完全相同的 detect → route → compress → count 流水线,但不写 CCR 存储、不发任何网络请求,是一个纯 dry-run。它唯一刻意的差异是:对于无存储后端时的有损(S4)压缩器,Compress 会 fail-closed 直通,而 Simulate 仍会报告理论缩减量并以 Recoverable=false 标记"必须先配置 CCR 才能真正输出该压缩"。
一个重要约定:调用方必须把"返回原始字节"视为一个合法结果——它意味着没有任何合格变换通过全部闸门(gates)。这在 Result 结构上有专门辅助:PassedThrough() 通过检查 RecoveryHandle == "" && Method == "" && Ratio == 0 来判定本次调用是否直通(见 engine/result.go)。
Compress 的完整决策链
阅读 engine/engine.go 中的 Compress 实现,可以确认文档中"fail-closed"描述的具体顺序:
record模式永不变换,直接返回原始字节(Mode为空或未知值时都归一化为record,即未知枚举值也直通);- 按内容类型查注册表,找不到压缩器 → 直通;
- 查安全类表(
safety.Lookup),未知安全类 → 直通; - S4(有损)压缩器要求能存储原始字节:没有恢复存储且未声明
ExternalRecovery时 → 直通; - 压缩器报告解析问题 → 直通;
- 压缩后 token 数不小于压缩前,或输出与输入字节相同 → 直通,"claim nothing";
- 需要 CCR 时先
store.Put写入原始字节,写入失败则整体结果回退为直通并返回错误——调用方永远拿不到"没有持久化 handle 的变换字节"; - 只有 CCR 成功之后,才把变换后的
Output、TokensAfter、Ratio等字段发布到结果上。
Options 结构(engine/result.go)中还有两个值得注意的字段:Type 用于强制内容类型(空值表示自动检测),Query 允许实现了 QueryAwareCompressor 接口的压缩器按相关性查询偏置保留内容(确定性 BM25,不用 embedding);未实现该接口的压缩器会完全忽略它。
压缩流水线
文档给出的流水线为:
flowchart LR
A["Input bytes"] --> B["Detect shape"]
B --> C["Select compressor"]
C --> D["Transform"]
D --> E{"Smaller and valid?"}
E -- No --> A
E -- Yes --> F{"Recovery required?"}
F -- No --> G["Emit compact bytes"]
F -- Yes --> H["Store exact original"]
H --> I{"Store succeeded?"}
I -- No --> A
I -- Yes --> G
对应到代码,"Smaller and valid?" 闸门就是 engine/engine.go 中的 after >= before || bytes.Equal(out, input) 检查;"Store succeeded?" 闸门对应 e.store.Put 的失败处理(engine/engine.go)。
因此完整的直通条件清单是:
- 没有匹配的内容类型压缩器;
- 压缩器解析失败(malformed input、不支持的结构);
- 结果不比原输入小;
- 有损结果无法建立恢复存储;
record模式(总是直通);- 未知模式(同样直通)。
自动检测规则
自动检测可识别以下十类输入:JSON、终端输出、diff、HTML、表格数据(tabular)、源代码、日志、搜索结果、配置文本、通用文本。
从 engine/detect.go 的 Detect 实现看,检测顺序是刻意设计的,且是确定性的、fail-open 的(不确定的输入一律落入 text,路由到保守的压缩器):
- 严格 JSON:去空白后首字符为
{或[且通过json.Valid; - 终端输出:优先于 diff/code/log 判断,因为原始 ANSI/CSI 转义序列是"结论性信号"——没有日志或代码会合法地嵌入它;次要信号是连续裸
\r(进度条原地重绘),CRLF 行尾被排除以免误伤普通文本; - diff:需要至少 4 个匹配行(
diff --git、@@、---/+++等)且至少存在一个结构性标记; - HTML:
<!doctype html>或<html前缀是结论性的;否则要求容器标签 + 足够标签密度,且必须不像源代码(避免把 JSX/TSX 组件误判为 HTML); - tabular:委托
compressors.LooksTabular; - 源代码:要求至少 3 个关键词 + 结构性信号(花括号、Python suite、缩进块),且先排除日志——注释里明确说这是"价值最高的误路由修复",避免消息中包含
return/class的日志被路由到 code 压缩器; - 日志:至少 4 行,且级别词/时间戳匹配行
matched >= 3 && matched*2 >= len(lines)(占绝对多数); - 搜索结果:
path:line:line?或 URL 形式的行占多数; - 配置文本:
compressors.LooksConfig; - 兜底
text。
此外,Detect 会先 unwrapInput 剥离 agent 文件标签和行号边栏(line-number gutters)再分类——注释说明"分类文件是什么,而不是 agent 如何打印它"。
文档特别强调:部分压缩器仅限显式调用,因为自动选择会产生歧义或不安全。源码印证了这一点——engine/compressors/compressor.go 的 Default() 注释写明:tool-schema、lossless tool-schema、TOON、accessibility-tree(a11y)和 repetition 永远不会被自动检测命中,只能通过 Options.Type 强制路由。
压缩器注册表
默认注册表包含 15 个压缩器,与 engine/compressors/compressor.go 中 Default() 的实际注册顺序完全一致:
- JSON
- log
- code
- diff
- search result
- text
- HTML
- tabular
- configuration
- tool schema
- tool-schema annotations
- TOON
- accessibility tree(a11y)
- repetition
- terminal output
两点实现细节值得展开:
- code 压缩器按构建时选择实现:启用 cgo 时用 tree-sitter 支持版本,否则用纯 Go 的
go/ast版本(对应 code_cgo.go 与 code_nocgo.go)。 - JSON 策略变体是实验性的:engine/engine.go 中,只有环境变量
CAVE_ENGINE_TOON=best-of时才会额外注册NewJSONStrategy。
每个压缩器都声明一个安全类(safety class)并自行实现解析与输出规则。安全类定义在 engine/safety/safety.go 的 S0–S4 阶梯中:
| 类 | 语义 | ByteSafe | RequiresCCR |
|---|---|---|---|
| S0 | 字节安全(元数据、记账) | 是 | 否 |
| S1 | provider 原生提示(cache、路由) | 是 | 否 |
| S2 | 需要 SDK 配合的结构变更 | 否 | 否 |
| S3 | 行为变更(路由、推理),Cloud 中由 eval 门控 | 否 | 否 |
| S4 | 有损结构压缩:改变模型可见字节,必须 opt-in、必须可恢复(CCR)、必须披露丢弃内容 | 否 | 是 |
文档强调:当前所有注册压缩器都属于有损类 S4——即使某个特定输入在结构上可以往返(round-trip)也不改变这一点。调用方绝不能从压缩器名称推断字节安全。S4 类的 RequiresCCR: true 正是 Compress 第 4 步闸门(无存储则直通)的依据。
Compressor 接口本身(engine/compressors/compressor.go)只有三个方法:ContentType()、SafetyClass()、Compress()。包注释明确约束压缩器是纯字节变换:不数 token、不存恢复、不触网——这些全由引擎核心在它外围完成。这正是"新增一个压缩器只需一个新文件 + 测试"的原因。
恢复要求(CCR)
有损结果只有在能精确恢复原始字节时才能输出。这与 S4 安全类的 RequiresCCR 约束直接对应:
- 原生调用方提供恢复存储(主机平台使用 SQLite,见 engine/ccr/store_sqlite.go);
- 浏览器/WASM 构建使用内存存储(engine/ccr/store_wasm.go,因为
modernc.org/sqlite不能为 js/wasm 构建); - 没有恢复存储时,Engine 保留原始输入(直通),绝不输出不可恢复的有损字节。
从 engine/ccr/store.go 的包注释可补充两个设计细节:
- handle 是内容寻址的——原始字节的 sha256。这使引擎幂等:同一负载压缩两次得到同一 handle,只存储一次;
- 存储"从不猜测恢复":未知 handle 是显式的 miss(
ErrNotFound),而不是近似匹配。
Retrieve 本身还处理了双 ID 空间问题(engine/engine.go):压缩产生 blob handle(ccr_…,走 store.Get),而原生运行时的工具输出掩码产生 typed OBJECT id(展示为 ccr://<id>,走 store.GetObject)。查不到 blob 表时会先落到 object 表再失败,确保"恢复永远不会指向另一个死指针"。handle 的详细语义、上限与对象指针见 上下文恢复文档。
Token 计量
Engine 使用离线的 o200k_base 计数器(如果可用),否则退回基于字符的估算。从 engine/tokens/tokens.go 的实现看:
- 默认计数器是真正的 BPE tokenizer(OpenAI
o200k_base,GPT-4o 家族编码),词表内嵌在二进制中,计数完全离线且确定; - 计数器接口(
Counter)允许按 provider 替换 tokenizer 而无需改动任何压缩器; - BPE 计数失败时降级到确定性的
approx-chars/4估算(~4 字符/token),保证计数错误绝不打断压缩。
因此本地计数一律使用 inferred 口径(Result.Basis,常量 BasisInferred),除非 provider 提供自己的 usage。文档明确其用途边界:这些数字适合比较与容量规划,不适合与 provider 账单对账。
输入限制
- CLI 压缩输入上限 64 MiB:读取 stdin 的命令在超过时失败并报
cave_input_too_large(见 engine/README.md); - 恢复存储有独立配置容量,默认 payload 上限 512 MiB(engine/ccr/store_sqlite.go 中
DefaultMaxStorageBytes = 512 << 20)。启动前设置环境变量CAVEMAN_CCR_MAX_BYTES为正字节数可改该上限; - 达到上限时,新的有损变换 fail-closed 为原始字节直通;已有 handle 从不被驱逐,保持可恢复(预算超限返回显式的
ErrBudgetExceeded); - 超限输入按调用方契约被拒绝或直通,永远不会被静默截断。
构建与运行:原生与 WebAssembly
Engine 有三种运行形态:
- Go 库;
- 原生 CLI(供 JavaScript launcher 调用);
- 浏览器兼容消费者的 WebAssembly 模块(WASM 使用内存恢复,因为浏览器运行时无法直接暴露主机 SQLite 存储)。
从仓库根目录构建原生 Engine 与运行测试:
go build ./engine/cmd/caveman-engine
go test ./engine/...
构建好的 CLI 提供如下子命令(见 engine/README.md):
caveman-engine compress < input
caveman-engine detect < input
caveman-engine retrieve <handle>
caveman-engine stats
caveman-engine registry
caveman-engine toon encode|decode
caveman-engine pixel render|simulate
caveman-engine evals run [--fixtures DIR]
其中 evals run 的调用方 fixtures 被限制在指定目录内,路径穿越与逃逸 symlink 会 fail-closed。
如何新增一个压缩器
文档给出六条要求,与源码结构一一对应:
- 无歧义的名称与声明的安全类——对应
Compressor接口的ContentType()与SafetyClass();安全类未知时safety.Lookup返回ok=false,引擎 fail-closed; - 有界解析与确定性输出——包注释要求每个压缩器 structural、deterministic、idempotent、fail-closed;
- 无效输入时回退原始字节——
Compress返回ok=false时调用方必须原样转发; - 有损输出集成恢复——S4 必须能写入 CCR,否则引擎根本不会运行它;
- fixtures 覆盖合法、非法、更大输出与边界用例——仓库中的
zz_adversarial_probe*_test.go(如 engine/compressors/zz_adversarial_probe_test.go)展示了这类对抗性测试的形态; - 只有当自动或显式选择行为明确时才注册进默认注册表——即
Default()中的Register调用(engine/compressors/compressor.go)。
公开的 Performance 声明必须有已提交的 fixtures、方法说明、token 口径与质量检查作为支撑。详见 测试与基准文档。
小结
Caveman Engine 的核心设计哲学可以用一句话概括:任何不能保证"更小、有效、可恢复"的变换都不输出。四个操作(Compress/Retrieve/Detect/Stats)加一个 Simulate dry-run 构成跨所有部署面(proxy、SDK、CLI、MCP、WASM)的稳定契约;15 个压缩器按内容类型注册,全部位于 S4 有损安全类,因此每一条压缩路径都强制经过 CCR 恢复闸门;本地 token 计数以 o200k_base BPE 离线估算为准,inferred 口径用于比较与容量规划。理解这套 fail-closed 机制后,你既可以把它作为库嵌入自己的网关,也可以按"六条要求"为新的内容形态添加压缩器。
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 StartedRust0623
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