Hermes 压缩策略换新默认:大窗口模型不再"囤积"17 万 token 尾部,/compress 终于能省出真空间


假设你正在 1M 上下文的模型上跑一个马拉松式长会话,聊到 50 万 token 时感觉越来越慢,于是敲下 /compress 想压缩一下上下文——结果发现会话只缩了一点点,后面每轮对话还是把十几万 token 的“尾巴”原样发给模型,钱包肉眼可见地变薄。这不是你的错觉:旧版压缩算法的尾部预算会随着窗口大小和阈值线性膨胀,在大窗口模型上会悄悄囤积 10 万到 24 万 token 的逐字内容,每次压缩都动不了它。8 月 26 日合并的提交(6e5413844e)把这个默认值翻了过来:新默认的 lean 模式只保留一个受控的小尾巴,省下来的空间相当可观。

旧算法为什么会在新模型上“囤积”

压缩(compaction)发生时,Hermes 会把会话切成“摘要”和“尾部”两部分:摘要负责长期记忆,尾部保留最近的内容保证连续性。旧默认(legacy 模式)的尾部预算公式是 阈值 × 目标比例(threshold × target_ratio)——这套公式当年是围绕 128K 窗口、50% 触发设计的,算出来约 1.3 万 token 的尾部,很合理。

但模型窗口变大之后,公式还在按比例放大:一个 1M 窗口、阈值 0.85 的会话,legacy 模式会保留 17 万 token 的逐字尾部(软上限 25.5 万)。于是 54 万 token 的手动 /compress 只能压到大约 29 万——囤积的尾部让压缩形同虚设,而且每轮对话都要重新把这些 token 发给模型,等于双重烧钱。

新默认:lean 模式(#87326 compaction-v2)

lean 模式的目标是“尾部只是一个小的近期窗口,而不是上下文囤积”。具体规则:

  • 尾部预算 = 窗口大小的 2.5%,下限 1 万、上限 2.5 万 token;
  • 连续性不再依赖大尾部,而是由升级版摘要承担:内容摘要(digests)、锚点索引(anchor index)、逐字保留的用户消息、以及 session_search 恢复指针;
  • 这套设计的召回率经过了前后对比评估(evals/compaction/results/),不是拍脑袋。

实测对照(真实导入,1M 窗口 @ 0.85 阈值):

场景 逐字尾部预算
旧默认(legacy) 170,000(上限 255,000)
新默认(lean) 25,000(上限 37,500)
显式切回 legacy 170,000(退出机制完好)
会话中途切到 400K 模型(lean 保持) 10,000

顺带修了一个潜伏 bug:update_model() 之前在模型切换重算预算时直接套用 legacy 公式,导致 lean 压缩器每次中途换模型都被悄悄打回囤积模式;现在重算走模式感知的 tail_token_budget 路径(带回归测试)。

怎么查看和调整

hermes config get 查看当前设置:

hermes config get compression.tail_mode    # 现在默认返回 lean
hermes config get compression.threshold    # 默认 0.50(50% 触发)
hermes config get compression.target_ratio # 默认 0.20

想恢复旧行为,在 config.yaml 里显式写回:

compression:
  tail_mode: legacy   # 旧公式:0.20 × 阈值,大窗口模型下会囤积

注意:compression.tail_mode 现在也是 gateway 的缓存失效键之一——修改它会自动驱逐缓存的 gateway agent,和改 target_ratio 一样,不用重启整个 gateway。

什么时候该用哪个

对绝大多数人,保持默认的 lean 就好:省钱、压缩后确实腾出了空间、摘要里有恢复指针兜底。只有当你在压缩后确实遇到“重要信息丢了”的情况(比如长会话里某个关键工具输出没有被摘要覆盖),才值得切回 legacy 对比一下——legacy 的代价是每轮多付几万 token 的输入费用。

小结

压缩策略这次调整,本质上是把“保留多少原文”的权衡从公式推导改成了有上限的工程设计:连续性交给更聪明的摘要,尾部只留近期窗口。如果你之前觉得 /compress 在大模型上“压不动”,更新到最新开发版再试一次,感受会完全不同。压缩只是长会话续航的一环,配合 max_turns 不再设上限会话导出保存,长任务可以放心跑到天荒地老。想更精细地调上下文预算,长任务配置指南 里有完整的字段说明。