上下文压缩这件事,做过长会话 Agent 的人基本都踩过坑。你不是不知道要压缩,而是不知道在哪一层压缩、压到什么程度、压完之后工具调用还能不能配对。最近翻了几份实现细节,Claude Code 的分层思路和 Hermes Agent 的双重压缩系统比较有代表性,把它们放在一起对比,取舍会清楚很多。
先承认压缩一定有损
Manus 团队在《Context Engineering for AI Agents》里给过一个很硬的判断:Agent 本质上要根据所有先前状态预测下一个动作,而你无法可靠预测哪个观察结果在十步之后会变得关键。所以任何不可逆压缩都带风险。
这句话直接决定了工程上该怎么设计。既然无法无损,目标就不是“压得干净”,而是压缩必须可回溯、可分层、可降级。一次压缩造成的错误,最好能在下一轮被发现并补回来,而不是永久失踪。
Claude Code:按代价从低到高排队
Claude Code 的实现里有一套四段式顺序,被整理成一个很形象的收纳类比:先收起不再穿的,再压缩换季衣服,再真空封存大件,最后才做全面整理丢弃。落到具体动作上大致是:
- Snip:消息级裁剪,去掉明显的冗余轮次
- MicroCompact:旧工具结果正文替换成语义摘要或占位
- Collapse:更大粒度的块级收纳
- AutoCompact:整体重写对话历史
关键不在于有几档,而在于它把最便宜的动作放在最前面。裁剪和工具结果清理不需要调模型,成本近乎为零;只有在前面几档都不够时才引入摘要调用。这避免了“每遇到一点压力就叫一次大模型”的浪费,也让高频触发的场景不会变成成本黑洞。
这份整理里还留了一个练习:让 Agent 连续读 8-10 个文件,观察 token 变化,到 60% 时手动 /compact。这个练法比看文档更快让人建立直觉——长上下文里涨得最快的基本都是文件正文和终端输出,而不是对话本身。
Hermes:用户可索引的副本
Hermes 的结构是真正下过工程功夫的。它采用两级压缩,两级的目的完全不同。
| 层级 | 触发阈值 | 作用 |
|---|---|---|
| Gateway 会话清理 | 上下文长度的 85%(固定) | 兜底安全网,在 Agent 处理消息此前先跑一轮,防止跨轮积累太快导致 API 报错 |
| Agent ContextCompressor | 默认 50%(可配置) | 工具循环内的主压缩,能用 API 实际报告的准确 token 数 |
把兜底阈值设得比主子压缩更高,是有意为之:如果两者都设 50%,长 gateway 会话几乎每轮都会触发提前压缩。只有 len(history) >= 4 且压缩启用,兜底才会动。
主压缩分四个阶段:
- 把尾部之外的旧工具结果(超过 200 字符)替换为 [Old tool output cleared to save context space],纯规则、不调模型
- 确定边界:前
protect_first_n=3(硬编码,系统提示词加首次交互)与尾部强制保留;protect_last_n默认 20 - 中间轮次用辅助 LLM 生成结构化摘要,模板固定为 Goal、Done、Blocked、Next Steps 等字段,摘预算随被压内容动态调整,约 0.20 倍,下限 2000、上限 min(context_length × 0.05, 12000)
- 组装并用
_sanitize_tool_pairs()清理孤立的 tool_call/tool_result 对
第二阶段有一个实现上的硬细节:边界不能切开 tool_call 与 tool_result 的配对,必须先回退到父级 assistant 消息。否则压出院会看到“孤儿工具结果”式的一堆拼接消息,直接引发 API 报错。这不是审美问题,是能不能跑的问题。
tail_mode 的真实账单
Hermes 还提供了一个更细的尾部策略开关,值得单独说。
legacy 模式保留约 threshold_tokens × 0.20 的逐字尾部,对大窗口模型大致是 100K token 级别。lean 模式则删减到窗口的 2.5%,下限 10K、上限 25K,并把连续性挪进摘要:压缩区域保留分块保留标识符、用正则机械提取的锚点索引(PR 编号、SHA、路径、原始报错文本,绝不改写),并强制逐字保留全部真实用户消息。
实测数据干脆:一个 500K token 的真实会话,legacy 保留 162K,lean 只保留约 49K。代价是压缩边界会多几次摘要模型调用。也就是说,lean 是用延迟和额外调用于换尾部空间,不想更小尾巴的通告信。我用在代码审查类会话时,这条取舍很清楚:用户原话和列号必须逐字留,其他叙述可以再重写。
三个真实失败点
论文清单容易写好看,写压院故障就不那么取巧了。下面这三条在实际排查中都出现过。
1. 摘要模型的窗口比主模型小
Hermes 的文档直说这个过程——要求摘要模型的上下文窗口不得小于主转模型,否则 API 会返回上下文程度错误。代码 _generate_summary() 会捕获它,记一条警告,返回 None,然后压缩器在没有摘要的情况下静默丢弃中间轮次,无声地丢掉对话上下文,这是压缩质量下降最常被引用的原因。设计上没有硬失败保护、只吞下异常,是压院里的典型事故。如果要落成产线系统,压缩策略的异常路径得向主流程暴露指标,不能悄悄产生残缺版本的通知。
2. 轮次重复压缩把原话丢了
Hermes 在后续压缩时把前一次摘要连同指令交给 LLM,要求其更新而不是从头摘要,条目方向从进行中搬到已完成。这解决长期遗忘,但有一个容易被忽略的风险:如果摘要把一句用户强约束改写成近拟说法,下一轮再改写,一旦回合可前就飘了。真实用户消息一定要压到不进去的原话里,不能进摘要。
3. 判型上太晚
Hermes 在 Agent 内层设 50%。Claude Code 的作法是先找最便宜的层。要是在管道中落进 gateway 层,85% 才触发,对话已经快爆,压缩窗口里的信息密度太高,摘要模型自身也顶不住。一个别少踩的建议:单次工具结果特别长的场景,会压缩总是比事后整段摘要划算。
怎么选
如果要给一个新版排队表,我把它归成三系:
- 短程开发者助手(轮次在几十万 token 以内):按 Claude Code 式多段、低成本动作权重大、摘要调得越少越好
- 长期驻留、多通道、大工程:上双阈值,内部主压缩小轮追迹,外层 gateway 85% 兜底
- 审查、决策、判断:把尾部偏向原话与控制输入,lean 尾部、正则锚点,摘要说明只负责必要内容并标出不可重写部分
最后一条没有证据就不多追。只能确定一件事:怎么压,比压到什么比例重要得多。
转载请注明出处: 皮哈皮阿
本文的链接地址: https://blog.phpat.com/ai-dev/616.html
微信或手机浏览器扫一扫,随时随地随心阅读与分享
-
上下文工程:从 Prompt 到 Context 的工程化实践
客服 Agent 答错时,团队第一反应是换模型。把那次请求的上下文打印出来才发现,模型看到的是一份过期政策、两份互相矛盾的条款,还有一长串无关日志。上下文工程要解决的,就是这类问题。
2026/10/06
-
RAG 的下一站:Agentic Retrieval
用户问“我们去年买的套餐现在还能退吗”,经典 RAG 检索出一段通用退款政策就结束了。可这个问题至少要拆成订单时间、地区、套餐版本三件事。Agentic Retrieval 要解决的,就是这种“一次检索不够用”的场景。
2026/10/12
-
约束解码让 JSON 不再崩,但它会改坏推理
约束解码让 JSON 解析失败率归零,工程师可以删掉一堆重试和修复代码。但它会挤占模型的推理预算:强制格式在部分任务上带来10%以上的准确率下降。文章梳理 OpenAI、Anthropic、Gemini 和其他自托管引擎的现状,以及 schema 设计、两阶段模式与编译缓存几个实操要点。
1天前
-
Agent 上下文压缩:四层策略与失败代价
把 Claude Code 的四段分层与 Hermes Agent 的双阈值压缩系统并排看重:200K 窗口下的 50%/85%、legacy 与 lean 尾部的实测差池、未处理到的摘要模型窗口溢出,以及工具对配对边界为什么是能不能跑的问题。
10小时前
京公网安备11011402053654 
@muffin:链接已更新,分类图像功能...
AI网址导航模版图标库更换指南
作者大大,图标库邀请链接失效了,麻烦更新...
AI网址导航模版图标库更换指南
太好看了,快点更新!
友情链接
@戴墨镜的刘备:哈喽,路过点赞。
vue.js组件之手写签名板vue-signature-simple
太好看了,快点更新!太棒了!👍真的很赞!
vue.js组件之手写签名板vue-signature-simple
你写得非常清晰明了,让我很容易理解你的观...
Emlog插件RSS订阅器发布