> 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 令牌很昂贵，而冗长的工具输出正是它们大多被耗尽的地方。一个 `git status` 在一个繁忙的仓库中，一个 `cargo build` 日志、一个 600 条消息的邮件线程、一个 `docker ps -a` 针对真实集群。每个都可能把上下文窗口撑得很大，却几乎没有信息增益。

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

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

***

## 流水线逐步说明

流经策略感知的 TokenJuice 工具输出适配器的每个数据块，都会通过供应的 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/`):

| Compressor       | 类型        | 功能                                                                                                          |
| ---------------- | --------- | ----------------------------------------------------------------------------------------------------------- |
| **SmartCrusher** | JSON      | 将对象数组重新渲染为紧凑表格；在约 40 行之后，会保留头部 + 尾部 + 错误行 + 数值异常值。                                                          |
| **代码**           | 代码        | 保留签名和导入，将深层函数体折叠为 `{ … N 行 … }` （可用时使用 tree-sitter，否则使用括号深度启发式）。保留 `TODO`/`FIXME`/`错误`/`panic`/`unsafe` 标记。 |
| **日志**           | 日志        | 对于 **命令输出**，交由下面的 JSON 规则引擎处理。对于其他日志，则保留错误 / 警告 / 堆栈跟踪 / 摘要，并丢弃噪音。                                          |
| **搜索**           | 搜索        | 按文件分组 grep/ripgrep `path:line:body` 命中，按查询词密度排序，保留每个文件的最佳匹配，并统计 `[+N more]`.                                |
| **diff**         | diff      | 保留变更行和 hunk 标头，将很长的未变更区段折叠为一个锚点；锁文件的 hunk 会缩减为一行 `+A/-B` 摘要。                                                |
| **Html**         | HTML      | 去除标记，转为可读文本，并在合适的块边界处插入换行，同时进行实体解码（轻量分配，无 DOM）。                                                             |
| **MlText**       | PlainText | 可选启用的 ML 显著性压缩（见下文）。                                                                                        |
| **通用**           | 回退        | 用于没有匹配到特定规则的命令输出的头尾摘要器；会对结构化数据块拒绝处理，以便保留它们。                                                                 |

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

***

## ML 压缩（可选启用）

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

* **默认关闭。** 使用以下设置启用 `ml_compression_enabled = true` 在 `[tokenjuice]`.
* **本地运行** ，作为 `kompress` 共享 Python 运行时 sidecar 的后端。不会有数据离开你的机器。
* **可调：** `ml_model_id` （默认 `answerdotai/ModernBERT-base`), `ml_target_ratio` （默认 `0.5`), `ml_max_input_chars` （默认 `200000`), `ml_device` (`cpu`/`自动`), `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`，可在内存驱逐后仍然保留。可选 TTL 通过 `ccr_ttl_secs`.
* **标记：** 压缩后的输出以如下页脚结束 `[已压缩的工具输出 — PARTIAL 视图；完整原始内容可通过 tokenjuice_retrieve with token "…" 获取]` 携带 `⟦tj:<hash>⟧` 令牌。
* **检索工具：** 代理使用只读的 **`tokenjuice_retrieve`** 工具和该令牌（可选字节/行 `范围`）来拉回完整原始内容或其片段。该令牌是无法猜测的 SHA-256 摘要。

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

***

## 节省跟踪

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

使用以下方式通过 RPC 读取： `openhuman.tokenjuice_savings_stats`；使用以下方式清除： `openhuman.tokenjuice_savings_reset`.

***

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

最初的三层 JSON 规则覆盖层仍然驱动着 Log/命令压缩器。规则按顺序合并，后面的层覆盖前面的层：

| 层级     | 路径                            | 目的                                               |
| ------ | ----------------------------- | ------------------------------------------------ |
| **内置** | 随二进制文件一起发布                    | 约 96 条供应的规则，适用于 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::inference::tokenjuice=debug` 以观察检测、匹配，以及每个数据块被压缩了多少。

***

## 这为何重要

代理的生死取决于上下文预算。一次工作会话可能会扩散到几十次工具调用：grep、build、测试运行、 `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) 摄取流水线。构建 [记忆树](/openhuman/zh/gong-neng/obsidian-wiki/memory-tree.md) 的 20 分钟同步任务有自己的一套规范化和分块机制，目前不会将负载通过 TokenJuice 路由。

***

## 另请参阅

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