> For the complete documentation index, see [llms.txt](https://tinyhumans.gitbook.io/openhuman/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://tinyhumans.gitbook.io/openhuman/zh/gong-neng/token-compression.md).

# 智能 Token 压缩

LLM 令牌很昂贵，而冗长的工具输出正是它们大多“送命”的地方。A `git status` 在一个繁忙的仓库里，一个 `cargo build` 日志、一个 600 条消息的邮件线程、一个 `docker ps -a` 对着真实集群。每一个都可能把上下文窗口撑大，却几乎不带来任何信息增益。

OpenHuman 随附 **TokenJuice**，这是一个直接接入代理工具执行路径的压缩路由器。在任何工具结果到达模型之前，TokenJuice 会对其分类，将其路由到专门的压缩器，必要时把完整原文卸载到可恢复缓存中，并记录它节省了多少令牌（以及多少钱）。

它最初是对 [vincentkoc/tokenjuice](https://github.com/vincentkoc/tokenjuice)的移植。那个 JSON 规则覆盖层仍然作为日志/命令压缩器留在这里，但此后它已成长为一个多阶段、感知内容的管道。

***

## 逐步看这条管道

每一个流经具备策略感知能力的 TokenJuice 工具输出适配器的数据块，都会沿着 vendored TinyJuice 路由器（`vendor/tinyjuice/src/compress.rs`):

```
原始工具结果
        │
        ▼
1. 大小门控          路由器已启用？输入 ≥ min_bytes_to_compress（2 KB）？
        │  是
        ▼
2. 检测种类        Json · Diff · Html · Search · Code · Log · PlainText
        │
        ▼
3. 选择压缩器      每种类型对应一个专用压缩器（+ 每种类型的开关）
        │
        ▼
4. 压缩             运行它；如果它拒绝或输出变大，则回退 / 直接透传
        │
        ▼
5. CCR 资格         有损且 ≥ ccr_min_tokens（≈500）？→ 将原文卸载到缓存
        │
        ▼
6. 追加标记        ⟦tj:<hash>⟧ 页脚，以便代理可以检索完整原文
        │
        ▼
7. 记录节省        按模型和按压缩器记录节省的令牌 + 成本
        │
        ▼
   压缩文本 → LLM 上下文
```

1. **大小门控。** 如果路由器被禁用，或者输入低于 `min_bytes_to_compress` （默认 **2048 字节**），它会原样透传。太小的输出不值得压缩。
2. **内容检测** (`detect/kind.rs`）。该数据块会被分类为七种 `ContentKind`之一。优先级：显式提示 → MIME/扩展名标签 → 按工具的先验（例如 `grep` → Search， `git_operations` → Diff， `run_tests` → Log）→ 低成本结构启发式（JSON → Diff → HTML → Search → Code → Log → PlainText）。热路径上不使用正则。
3. **压缩器选择。** 每种类型都会路由到一个专用压缩器，并遵循每种类型的开关（`search_enabled`, `code_enabled`, `html_enabled`, `ml_compression_enabled`).
4. **压缩。** 压缩器开始运行。如果它拒绝，或者其输出并不比输入更小，TokenJuice 就回退到通用压缩器，或直接透传原文。它绝不会让内容变得更大。
5. **CCR 卸载。** 对于 **有损** 压缩，且原文足够大（`ccr_min_tokens`，默认约 500 个令牌），完整原文会被存入 **Compress-Cache-Retrieve** 存储中，因此不会永久丢失。
6. **恢复标记。** 会附加一个携带规范标记 `⟦tj:<hash>⟧` 的页脚，告诉代理它看到的是部分视图，以及如何取回其余内容。
7. **节省统计。** 会记录节省的令牌和估算节省成本，并按模型和压缩器归因。

***

## 这些压缩器

每种内容类型都有一个专门构建的压缩器（`vendor/tinyjuice/src/compressors/`):

| 压缩器              | 类型        | 作用                                                                                                              |
| ---------------- | --------- | --------------------------------------------------------------------------------------------------------------- |
| **SmartCrusher** | JSON      | 将对象数组重新渲染为紧凑表格；在约 40 行之后，保留头部 + 尾部 + 错误行 + 数值离群项。                                                               |
| **Code**         | Code      | 保留签名和导入，将较深的函数体折叠为 `{ … N 行 … }` （可用时用 tree-sitter，否则使用大括号深度启发式）。保留 `TODO`/`FIXME`/`error`/`panic`/`unsafe` 标记。 |
| **Log**          | Log       | 对于 **命令输出**，委派给 JSON 规则引擎（见下）。对于其他日志，保留错误 / 警告 / 堆栈跟踪 / 摘要，并丢弃噪声。                                               |
| **Search**       | Search    | 按文件分组 grep/ripgrep `path:line:body` 命中，按查询词密度排序，保留每个文件的最佳匹配，并汇总 `[+N more]`.                                    |
| **Diff**         | Diff      | 保留改动行和块头，将很长的未改动片段折叠为一个锚点；锁文件的块可缩减为一行 `+A/-B` 摘要。                                                               |
| **Html**         | HTML      | 将标记剥离为可读文本，带有合理的块边界换行和实体解码（轻量分配，无 DOM）。                                                                         |
| **MlText**       | PlainText | 可选启用的 ML 显著性压缩（见下文）。                                                                                            |
| **通用**           | 回退        | 用于没有匹配到特定规则的命令输出的头/尾摘要器；对结构化数据块会拒绝，以便保留原文。                                                                      |

多字节文本（CJK、表情符号、组合标记）在整个流程中都按字素逐个处理，绝不会在字符中间切开。

***

## ML 压缩（可选启用）

除了确定性的压缩器之外，TokenJuice 还可以把纯文本路由到一个 **ModernBERT** 令牌显著性模型，由它评分并丢弃低信息量片段。TinyJuice 压缩器暴露了这个可选的 ML 插槽，而 OpenHuman 在 `src/openhuman/tokenjuice/ml/`.

* **默认关闭。** 用 `ml_compression_enabled = true` 在 `[tokenjuice]`.
* **本地运行** 作为共享 Python 运行时 sidecar 的 `kompress` 后端。没有数据会离开你的机器。
* **可调参数：** `ml_model_id` （默认 `answerdotai/ModernBERT-base`), `ml_target_ratio` （默认 `0.5`), `ml_max_input_chars` （默认 `200000`), `ml_device` (`cpu`/`auto`), `ml_sidecar_idle_timeout_secs`.
* **优雅降级：** 如果 sidecar 不可用，或者输入超过字符上限，它会降级到原生压缩器，而不会让代理循环失败。

***

## 没有丢失任何东西：CCR 缓存与检索

有损压缩通常意味着丢弃数据。TokenJuice 则会 **卸载** 完整原文到 **Compress-Cache-Retrieve (CCR)** 存储中，并留下一个线索（`vendor/tinyjuice/src/cache/`).

* **内存层** （始终启用）：一个进程全局存储，按 SHA-256 哈希键控，受条目数量（`max_cache_entries`，默认 256）和总字节数（`max_cache_bytes`，默认 64 MiB）限制，采用 FIFO 淘汰。
* **磁盘层** （可选）： `<workspace>/.tokenjuice/ccr/`，通过 `ccr_disk_enabled`启用，可在内存淘汰后继续保留。可通过 `ccr_ttl_secs`.
* **可选设置 TTL。** 标记： `压缩后的输出会以一个页脚结尾，例如` \[compacted tool output — PARTIAL view; full original available via tokenjuice\_retrieve with token "…"] `⟦tj:<hash>⟧` 所携带的
* **检索工具：** 代理使用只读的 **`tokenjuice_retrieve`** 工具配合该 token（可选地再加字节/行 `范围`）来取回完整原文或某个切片。该 token 是无法猜测的 SHA-256 摘要。

因此，代理默认获得的是廉价的压缩视图，只有在真正需要时，才能透明地“放大”查看完整文本。

***

## 节省跟踪

每一次压缩都会通过 OpenHuman 节省回调进行计量（`src/openhuman/tokenjuice/savings.rs`）。TokenJuice 报告事件和令牌差值；OpenHuman 应用按模型的输入定价，汇总 `total`, `by_model`，以及 `by_compressor`，并将统计信息持久化到 `<workspace>/state/tokenjuice_savings.json`.

可通过 RPC 使用 `openhuman.tokenjuice_savings_stats`读取；可用 `openhuman.tokenjuice_savings_reset`.

***

## 规则覆盖层（命令与日志输出）

原始的三层 JSON 规则覆盖层仍然为 Log/命令压缩器提供动力。规则按顺序合并，后面的层覆盖前面的层：

| 层      | 路径                            | 用途                                                      |
| ------ | ----------------------------- | ------------------------------------------------------- |
| **内置** | 随二进制一起发布                      | 约 96 条 vendored 规则，适用于 git、npm、cargo、docker、kubectl、ls… |
| **用户** | `~/.config/tokenjuice/rules/` | 个人覆盖，全局生效                                               |
| **项目** | `.tokenjuice/rules/`          | 仓库特定覆盖，已提交并与团队共享                                        |

每条规则都定义一个命令/工具模式和一种缩减策略（跳过/保留过滤器、如 strip-ANSI 和 dedupe 之类的转换、头/尾摘要、命名计数器、预设消息）。规则是 JSON。添加一条即可生效，无需重新编译。

***

## 配置、RPC 与工具

一切都位于 `[tokenjuice]` config 块（`src/openhuman/config/schema/tokenjuice.rs`）下，并且可以实时更改。

* **总开关：** `router_enabled` （默认 `true`).
* **阈值：** `min_bytes_to_compress`, `ccr_min_tokens`.
* **CCR：** `ccr_enabled`, `ccr_disk_enabled`, `max_cache_entries`, `max_cache_bytes`, `ccr_ttl_secs`.
* **按类型：** `search_enabled`, `code_enabled`, `html_enabled`，以及 `ml_*` 键。
* **RPC** (`openhuman.tokenjuice_*`): `detect`, `compress` （对管道进行 dry-run）， `settings_get` / `settings_update` （实时部分补丁）， `cache_stats`, `retrieve`, `savings_stats`, `savings_reset`.
* **代理工具：** `tokenjuice_retrieve` （只读）恢复已卸载的原文。
* **调试：** 用以下方式启动核心： `RUST_LOG=openhuman_core::openhuman::tokenjuice=debug` 以观察检测、匹配，以及每个数据块被裁剪了多少。

***

## 这为什么重要

代理的生死取决于上下文预算。一次工作会话可能会扩展到几十个工具调用：grep、构建、测试运行、 `git` 输出，以及代理拉取下来的大量 [web-fetch / scrape](/openhuman/zh/gong-neng/native-tools/web-scraper.md) 结果。TokenJuice 位于这条工具执行路径上，在每个结果进入上下文之前先将其压缩，因此代理可以扫过一个噪声很多的仓库或一整页很长的网页，而不会让每一步都把窗口撑大。节省会在整个会话中累积，并以真实美元计量（见 [计费、成本与使用情况](/openhuman/zh/gong-neng/billing-and-usage.md)).

> **范围说明。** TokenJuice 运行在代理的 **工具结果**上，而不是后台的 [自动抓取](/openhuman/zh/gong-neng/obsidian-wiki/auto-fetch.md) 摄取管道上。构建 [Memory Tree](/openhuman/zh/gong-neng/obsidian-wiki/memory-tree.md) 的 20 分钟同步有自己的规范化和分块流程，当前不会把负载通过 TokenJuice 路由。

***

## 另见

* [可用工具](/openhuman/zh/gong-neng/native-tools.md)：大多数沉重的工具输出都会经过 TokenJuice。
* [Memory Tree](/openhuman/zh/gong-neng/obsidian-wiki/memory-tree.md)：压缩输出的下游消费者。
* [计费、成本与使用情况](/openhuman/zh/gong-neng/billing-and-usage.md)：令牌节省如何体现为真实金钱的地方。
