For the complete documentation index, see llms.txt. This page is also available as Markdown.

智能令牌压缩

TokenJuice——一个多阶段压缩路由器,在冗长工具输出进入 LLM 上下文之前先将其压缩。

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

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

它最初是对 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 结果。TokenJuice 位于该工具执行路径上,在每个结果进入上下文之前先将其压缩,因此代理可以扫过嘈杂的仓库或冗长的网页,而不会让每一步都把窗口撑大。节省会在整个会话中累积,并以真实美元计量(见 计费、成本与使用情况).

范围说明。 TokenJuice 运行在代理的 工具结果上,而不是后台 自动抓取 摄取流水线。构建 记忆树 的 20 分钟同步任务有自己的一套规范化和分块机制,目前不会将负载通过 TokenJuice 路由。


另请参阅

最后更新于