生产级 AI Agent 的上下文压缩

从消息裁剪、工具结果清理、结构化检查点,到 Hermes Agent 的分层 Compaction

摘要

随着 AI Agent 不断调用搜索、文件、终端、浏览器和数据库工具,其上下文会持续增长。真正的问题不只是“最终装不下”,还包括:

  • 每一轮输入 token 越来越多,成本和首 token 延迟上升;
  • 大量旧工具输出、重复日志和已经解决的问题稀释了有效信息;
  • 模型可能忘记约束、重复调用工具、重新尝试已经失败的方案;
  • 粗暴删除历史又会破坏长任务的连续性。

生产级上下文压缩的目标并不是生成一段尽可能短的摘要,而是:

用尽可能少的活跃 token,保留足以让 Agent 正确、安全、可验证地继续执行任务的状态。

本文以《深入理解 AI Agent:设计原理与工程实践》第 2.7 节为阅读主线,并结合截至 2026 年 7 月的 OpenAI、Anthropic、LangChain v1、Google ADK、Hermes Agent 官方资料和当前源代码重新核查。文中会区分:

  • 书中的方法论;
  • 当前主流产品与框架的实现;
  • Hermes Agent 当前 main 分支的真实行为;
  • 可直接用于生产系统的工程建议。

一、为什么需要上下文压缩

1. 硬限制:上下文窗口终究有限

典型 Agent 循环会不断追加:

用户请求
→ 模型工具调用
→ 工具结果
→ 模型分析
→ 再次工具调用
→ 新工具结果
→ ...

其中真正容易“撑爆”窗口的,往往不是用户说的话,而是:

  • 一次返回数万 token 的网页或 PDF;
  • 大型日志和测试输出;
  • 多个源代码文件;
  • 浏览器快照、图片和多模态附件;
  • 工具调用参数中的整段文件内容;
  • 历史 reasoning、元数据和供应商回放字段。

超过模型上下文窗口后,请求可能直接失败。即使没有超过,也不代表系统处于健康状态。

2. 软退化:能装下,不等于能用好

LangChain v1 官方文档明确指出,长历史即使仍能放进上下文,模型也会受到陈旧、离题内容干扰,同时带来更高延迟和成本。Anthropic 将这种随着上下文膨胀而发生的有效信息利用下降称为 context rot1 2

可以把它理解成:

上下文容量:还有空间
信息密度:持续下降
模型注意力:被旧日志、重复结果和无关细节分散

因此,压缩不只是为了避免 context_length_exceeded,也为了提高模型每次决策时看到的信息密度。

3. 长程 Agent 需要“任务交接”,而不是聊天摘要

普通聊天摘要可以写成:

用户和助手讨论了退款问题,助手查询了订单并给出建议。

但这样的摘要无法让 Agent 继续工作。长程 Agent 真正需要的是一个 checkpoint / handoff

active_goal: 修复退款接口的重复扣款问题

constraints:
  - 不修改数据库 schema
  - 保持 API 向后兼容

completed:
  - 已复现并发请求下的重复扣款
  - 已定位到 payment/idempotency.py
  - 已添加幂等键校验

failed_attempts:
  - 仅依赖 Redis TTL,仍存在竞态条件

verification:
  unit_tests: "47/50 passed"
  failing:
    - test_concurrent_refund
    - test_retry_after_timeout
    - test_duplicate_webhook

modified_files:
  - payment/idempotency.py
  - tests/test_refund.py

remaining:
  - 修复 3 个并发测试
  - 运行完整回归测试

这份内容回答的是:

任务现在处于什么状态,下一轮 Agent 怎样继续,而不是过去聊过什么。


二、先区分四个概念

上下文压缩经常与缓存、记忆、RAG 混在一起。它们解决的是不同问题。

上下文压缩 / Compaction

改变模型下一轮真正看到的活跃上下文:

压缩前:80,000 tokens
压缩后:22,000 tokens

旧内容可能被删除、外置或替换为摘要。

Prompt Cache

不一定减少上下文长度,而是复用相同前缀已经完成的 Prefill 计算。

请求仍然有 80,000 tokens
但其中 60,000-token 的相同前缀可以命中缓存

缓存解决“不要重复算”;压缩解决“不要一直带着这么多内容”。

长期记忆

跨会话保存用户偏好、业务事实或经验。它解决的是:

新会话开始后,Agent 还记不记得?

长期记忆不应替代当前任务状态,也不应把所有历史永久塞进系统提示词。

RAG 与 Artifact Retrieval

完整原文保存在模型上下文之外,只在需要时取回:

活跃上下文:摘要 + artifact_id + 来源
外部存储:完整日志、文件、网页、截图、数据库结果
需要细节:按 ID 或查询条件重新读取

这是降低压缩损失最重要的基础设施。


三、当前最主流的上下文压缩方案

现实中的生产系统通常同时使用多种方案。下面按“从最便宜到最智能”的顺序说明。


方案一:消息裁剪与滑动窗口

怎么压缩

只保留最近的若干消息或 token:

系统提示词          保留
最初用户任务        可选保留
旧消息 1~80        删除
最近 20 条消息      保留

常见规则包括:

  • 保留最后 N 条消息;
  • 保留最后 K 个 token;
  • 始终保留系统提示词;
  • 始终保留最近一个真实用户请求;
  • 不拆开 tool_call 与对应的 tool_result

LangChain v1 把 trim messages、永久删除消息和摘要列为三种基础的短期记忆管理模式。1

优点

  • 不需要额外 LLM 调用;
  • 快、便宜、确定性强;
  • 不会产生摘要幻觉;
  • 适合作为最后一道防止请求溢出的安全网。

缺点

  • 信息损失最大;
  • 早期约束和关键决策可能消失;
  • Agent 可能忘记已经完成的操作;
  • 可能重复调用工具或重新尝试失败方案;
  • 不适合长程 Coding、Research 和业务办理任务单独使用。

适用场景

  • 普通聊天;
  • 最近消息占主导的轻量客服;
  • 每轮相对独立的简单 Agent;
  • 作为其他压缩方案失败时的兜底。

方案二:确定性过滤与删除噪声

怎么压缩

用代码识别明确低价值的信息并删除,例如:

  • 重复的日志行;
  • 网页导航栏、页脚和广告;
  • 空结果;
  • 已处理的流式增量片段;
  • 重复发送的状态通知;
  • 可以由数据库重新计算的统计;
  • 已经过期的临时进度消息。
def should_drop(message) -> bool:
    return (
        message.is_empty
        or message.is_duplicate
        or message.kind in {"heartbeat", "stream_delta"}
        or message.expired
    )

优点

  • 无 LLM 成本;
  • 行为稳定、容易测试;
  • 对明确噪声几乎没有语义损失;
  • 应当优先于 LLM 摘要。

缺点

  • 只能处理规则能够识别的噪声;
  • 规则可能过度删除;
  • 需要针对具体工具和业务持续维护;
  • 删除历史中间位置会破坏该位置之后的 Prompt Cache。

适用场景

几乎所有生产 Agent。它通常应当是压缩流水线的第一层。


方案三:工具结果清理与降级

也称:

  • Tool-result clearing
  • Tool-output pruning
  • Context editing
  • Tool-result demotion

怎么压缩

保留“Agent 调用过这个工具”的记录,但删除或缩短巨大的结果正文:

assistant:
  read_file("server.log")

tool:
  30,000-token 完整日志

替换为:

assistant:
  read_file("server.log")

tool:
  [read_file] server.log,50,000 行;
  发现 DatabaseTimeout 127 次、PermissionDenied 3 次;
  完整内容:artifact://logs/run-103

Anthropic 当前的 Context Editing 和 Tool-result Clearing 就属于这一类:保留 tool_use 记录,清除旧的、可重新获取的 tool_result 内容。2

优点

  • 工具密集型 Agent 的收益通常非常高;
  • 可以完全不用 LLM;
  • 用户请求、模型决定和工具调用轨迹仍在;
  • 比简单滑动窗口更有针对性;
  • 文件、API 或搜索结果可按需重新获取。

缺点

  • “可重新获取”是前提,不是所有结果都满足;
  • 外部 API 可能昂贵、限流或结果随时间变化;
  • 删除一次性结果实际上是有损的;
  • 清理时必须维持工具调用/结果配对合法;
  • 修改旧结果会使后面的 Prompt Cache 失效。

重要修正

“Tool clearing 是无损的”只能在下面条件下成立:

工具仍可调用
+ 相同输入能得到相同或等价结果
+ 重取成本可接受
+ 数据源仍然可访问

对实时价格、一次性授权结果、短期网页、不可重复的交易响应,清理后未必能恢复。


方案四:大型内容外置为 Artifact

怎么压缩

从源头避免把完整大对象放进主上下文:

工具得到 200 MB 日志
保存到文件、对象存储或数据库
上下文只放:
- artifact_id
- 类型和大小
- 结构化统计
- 少量预览
- 可用的查询方式

示例:

artifact_id: "artifact://pytest/run-20260726-103"
type: "test_log"
lines: 58321
summary:
  passed: 128
  failed: 2
failures:
  - test_refund_timeout
  - test_duplicate_webhook
available_operations:
  - grep
  - read_lines
  - download

OpenAI 当前建议把大型资源放进容器文件系统或数据库,让 Agent 有选择地打开文件、运行查询,而不是把所有内容直接塞进 Prompt。3

优点

  • 接近无损;
  • 大对象不会一开始就污染上下文;
  • 可对代码、日志、PDF、网页、表格和截图统一处理;
  • 支持按行、按字段、按查询条件回溯。

缺点

  • 需要 Artifact Store、访问控制和生命周期管理;
  • 引用失效会导致信息不可恢复;
  • 重新读取增加工具调用和延迟;
  • Agent 必须拥有良好的检索工具和描述。

适用场景

  • 代码文件;
  • 终端日志;
  • 浏览器页面;
  • PDF 和多模态文件;
  • 数据库查询结果;
  • 大型 JSON;
  • 图片和截图。

方案五:滚动结构化摘要

怎么压缩

将上下文划分为:

稳定头部         原样保留
较旧的中间轨迹   用 LLM 压缩为检查点
最近尾部         原样保留

压缩后:

System Prompt
+ 初始任务/关键约束
+ Structured Checkpoint
+ 最近若干条原始消息

LangChain v1 的 SummarizationMiddleware、Google ADK 的 Context Compaction,以及 Hermes 默认压缩器都使用了这一类设计。1 4 5

优点

  • 能显著降低上下文长度;
  • 比滑动窗口更能维持长任务连续性;
  • 能保留任务目标、决策、进度和未完成工作;
  • 摘要可以人类审查;
  • 跨供应商可移植。

缺点

  • 本质上有损;
  • 需要额外 LLM 调用;
  • 可能漏掉数字、路径、错误信息和边界条件;
  • 多轮“摘要再摘要”可能产生漂移;
  • 压缩点之后的 Prompt Cache 需要重建。

最佳实践:摘要必须是检查点,不是散文

推荐字段:

historical_task:
goal:
constraints:
completed_actions:
active_state:
blocked:
key_decisions:
resolved_questions:
relevant_files:
critical_context:
remaining_work:
source_refs:

不推荐:

用户进行了一些修改,运行了测试,目前还有少量问题。


方案六:任务感知压缩

怎么压缩

普通摘要只输入:

请总结这些历史。

任务感知摘要还输入:

当前任务是什么?
现阶段需要回答什么?
已经确认哪些事实?
下一步还缺什么?
哪些字段绝不能改写?
哪些来源以后需要回溯?

例如,“确认某位联合创始人的现任职业”和“撰写这个人的完整传记”应保留不同信息。

《深入理解 AI Agent》的实验中,任务感知压缩在该特定研究任务上使用了更少 token、完成迭代也更少;但这是一个实验结果,不应被解释为所有 Agent 上的普遍排名。

优点

  • 信息密度通常高于通用摘要;
  • 能明确区分已知、未知、冲突和下一步;
  • 适合阶段明确的研究与分析任务;
  • 可以对不同信息设置不同保留优先级。

缺点

  • 任务改变后,之前删除的信息可能重新变得重要;
  • 摘要 Prompt 更复杂;
  • 强依赖模型正确理解当前目标;
  • 容易过度围绕短期目标压缩。

适用场景

  • Deep Research;
  • 调研与尽职调查;
  • 故障排查;
  • 有明确验收标准的 Coding Agent;
  • 长流程业务办理。

方案七:带引用、可回溯的摘要

怎么压缩

每条关键事实同时保留来源句柄:

facts:
  - claim: "服务在 14:32 后开始出现超时"
    source_ids:
      - "artifact://logs/prod-103#L820-L912"
    confidence: high
    verified: true

摘要是有损的,但来源索引尽量无损。

优点

  • 可验证摘要是否失真;
  • 可以重新读取原始证据;
  • 适合需要 citation 和审计的 Agent;
  • 任务改变后仍有机会恢复细节。

缺点

  • 比纯摘要占用更多 token;
  • 需要稳定的 Artifact ID 和权限系统;
  • 来源可能过期或被删除;
  • 引用存在不代表摘要一定正确。

适用场景

企业 RAG、法律、金融、研究、运维、数据分析和其他高审计要求系统。


方案八:供应商原生 Compaction

OpenAI

OpenAI Responses API 已提供原生 compaction,并通过 responses.compact 供 Agents SDK 的 OpenAIResponsesCompactionSession 使用。OpenAI 说明,当前原生 compaction 可以产生包含不透明 encrypted_contenttype=compaction item;Codex 依赖该机制维持长程编码任务。3 6 7

优点:

  • 与模型训练和供应商内部状态格式配合;
  • 集成成本低;
  • 不需要开发者自己维护摘要 Prompt;
  • 可通过 response chain 或本地 input 模式压缩。

缺点:

  • 内容不透明,难以人工审计;
  • 供应商锁定;
  • 不利于跨模型迁移;
  • 自动压缩可能阻塞流式结束,低延迟场景更适合在空闲或轮次之间手动执行。7

Anthropic

Anthropic 当前推荐长期对话优先使用服务端 Compaction;它会生成可回传的 compaction block。Context Editing 则用于更精细地清理工具结果等具体内容。该功能目前仍属于 beta,接口和支持范围应以最新官方文档为准。8 2

优点:

  • 服务端自动处理 token 计算和触发;
  • Compaction block 是明确的消息类型;
  • 可自定义摘要指令;
  • 能与 Tool-result Clearing、Memory 组合。

缺点:

  • 仍然是有损摘要;
  • beta API 可能变化;
  • 自定义指令若完全替换默认 Prompt,开发者需要自己提供完整保留规则;
  • 额外采样会产生费用和延迟。

选择建议

  • 深度绑定单一供应商、追求快速落地:优先评估原生 compaction;
  • 要求可审计、跨供应商、精确控制字段:使用客户端结构化检查点;
  • 也可以并用:客户端维护 canonical state,供应商原生 compaction 管理其模型轨迹。

方案九:Token 级 Prompt Compression

代表方法包括 LLMLingua、LongLLMLingua 和 LLMLingua-2。

怎么压缩

不是重新写一篇摘要,而是判断哪些 token 或短语信息量较低,并将其删除或重排:

原文:
The system encountered a very serious database connection timeout.

压缩后:
system encountered serious database connection timeout

LLMLingua 使用小型语言模型评估 token 重要性;LLMLingua-2 将压缩建模为 token 分类问题。相关论文在特定数据集上报告了较高压缩率。9 10

优点

  • 抽取式方法不需要完全重写事实;
  • 可用于压缩 RAG 的自然语言背景材料;
  • 在匹配的模型、硬件和长度区间内可能减少成本和延迟;
  • Query-aware 版本可以提高相关信息密度。

缺点

  • 输出对人类不友好;
  • 可能删除否定词、限定词或精确数字;
  • 可能破坏 JSON、代码、SQL 和工具参数;
  • 需要额外压缩模型,压缩本身也有延迟;
  • 研究中的高压缩率不是生产性能承诺。

2026 年的一项大规模实测指出,Prompt Compression 只有在输入长度、压缩率和硬件条件匹配时才会获得端到端加速;在其他区间,压缩器开销可能抵消全部收益。11

最佳实践

适合压缩:

  • RAG 返回的自然语言段落;
  • 会议记录;
  • 背景材料;
  • 可通过原文回溯的文本。

不要未经专门评估就压缩:

  • Tool Call JSON;
  • Tool Result 的结构字段;
  • 代码和 SQL;
  • UUID、hash、路径和端口;
  • 安全策略和业务硬约束;
  • 金额、日期、法律条款。

方案十:子 Agent 上下文隔离

严格来说,它不是事后压缩,而是让噪声根本不进入主上下文。

怎么做

主 Agent:
“找出支付回调入口、调用链和测试文件。”

搜索子 Agent:
读取大量文件
运行 grep
分析调用关系
仅返回:
- 入口文件
- 关键函数
- 调用点
- 测试位置
- 置信度

优点

  • 主上下文污染最少;
  • 中间探索轨迹可直接丢弃;
  • 特别适合代码搜索和多源研究;
  • 主 Agent 只处理高密度结论。

缺点

  • 子任务必须描述得足够完整;
  • 子 Agent 报告可能遗漏细节;
  • 需要额外模型调用;
  • 多 Agent 调度、超时和错误处理更复杂。

《深入理解 AI Agent》将其概括为“隔离优于压缩”:能在进入主上下文之前隔离的内容,不要等进入后再做有损摘要。


四、方案对比

方案是否有损额外 LLM压缩能力主要风险最适合
滑动窗口丢失关键历史简单聊天、最后兜底
确定性过滤低~中规则误删所有 Agent 第一层
工具结果清理条件性低损结果不可重取工具密集 Agent
Artifact 外置很高引用失效文件、日志、网页、图片
结构化滚动摘要很高摘要遗漏与漂移通用长程 Agent
任务感知摘要中~高很高任务切换后信息不足研究、排障、Coding
带引用摘要较低中~高基础设施复杂企业与审计场景
供应商原生 Compaction实现相关服务端很高不透明或锁定单供应商长任务
Token 级压缩小模型破坏精确结构RAG 自然语言材料
子 Agent 隔离很高报告遗漏Coding、Deep Research

五、生产级最佳实践:不要选一个方案,要设计分层流水线

推荐顺序:

完整原始轨迹 / Artifact Store
1. Admission Control
   大内容从源头外置,工具返回结构化预览
2. Deterministic Cleanup
   去重、删噪声、清理可重取工具结果
3. Canonical State Projection
   TODO、计数、阶段、验证状态由代码维护
4. Structured Compaction
   对旧中部轨迹生成任务检查点
5. Recent Raw Tail
   保留最新用户请求和近期工具轨迹
6. LLM

原则一:模型上下文不是唯一事实源

生产系统至少应分成:

Canonical State
  PostgreSQL / LangGraph State / Redis
  确定性、结构化、可校验

Artifacts
  文件、日志、网页、截图、查询结果
  完整保留并可回溯

Active Context
  当前模型真正看到的精简投影

不要把“摘要文本”当成业务状态数据库。

原则二:Cheap-first

优先顺序通常是:

去重
→ 删除明确噪声
→ 外置大对象
→ 工具结果降级
→ 状态栏
→ LLM 摘要
→ 全量 Compaction

能够用代码完成的,不要先调用 LLM。

原则三:始终保留最近原始尾部

摘要擅长保留结论,不擅长保留最新交互中的细微语气、指代和临时状态。

因此通常采用:

Head + Summary + Recent Tail

尾部切分必须以合法消息组为单位,尤其不能拆开:

assistant.tool_call
tool.result

原则四:阈值不是固定的 50%、70% 或 80%

真正的安全触发点应满足:

trigger_tokens
<= context_window
 - reserved_output_tokens
 - expected_tool_burst
 - safety_margin

还需要考虑:

  • System Prompt 和工具 Schema 构成的不可压缩底座;
  • 多模态附件的 token;
  • reasoning 或供应商回放字段;
  • 下一轮工具结果可能突然很大;
  • 摘要过程自身需要空间。

建议先通过真实工作负载测量,再决定阈值,而不是照抄某个框架默认值。

原则五:使用滞回与最小回收量

每轮稍微超过阈值就压缩一次,会造成:

  • 摘要调用频繁;
  • Prompt Cache 反复失效;
  • 摘要不断重写;
  • 延迟和成本增加。

应同时设置:

触发阈值
目标压缩后水位
最小回收 token
压缩失败冷却时间
连续无效压缩熔断

原则六:压缩必须原子化

正确策略:

复制当前消息
→ 在副本上压缩
→ 验证摘要和消息结构
→ 成功后一次性提交

失败时:

保留原始会话
→ 上报告警
→ 冷却或切换摘要模型

不能在摘要失败后已经删除旧历史。

原则七:精确标识符不交给自由摘要

下列内容应由程序抽取、结构化保存或原样保留:

  • 文件路径;
  • URL;
  • UUID;
  • commit hash;
  • PR / issue 编号;
  • 数据库主键;
  • 金额、日期和端口;
  • 完整错误码;
  • 测试名称;
  • 版本号。

原则八:压缩摘要必须带时态和任务边界

历史摘要如果写成:

修复测试失败
发送邮件
部署服务

模型可能误以为这些仍然是待办事项。

更安全的表达:

2026-07-26 已修复 test_refund_timeout。
2026-07-26 已发送部署通知。
当前尚未完成:生产环境回归验证。

摘要应明确标记为历史参考,并声明最新真实用户消息具有最高优先级。


六、Hermes Agent:一个值得研究的分层压缩案例

1. 可插拔 Context Engine

Hermes 将上下文管理抽象成 ContextEngine。默认是有损的 ContextCompressor,也可以通过插件显式选择其他引擎,例如 LCM。插件不会自动启用,必须在配置中指定。5

这比把压缩逻辑写死在 Agent Loop 中更合理,因为:

  • 不同模型拥有不同上下文窗口和缓存特性;
  • 不同业务对可审计性和信息保真要求不同;
  • 压缩策略可以独立评估和替换。

2. 双层触发

Hermes 官方文档描述了两层保护:

Gateway Session Hygiene
- 在 Agent 处理消息前执行
- 约 85% 上下文时触发
- 作为防止会话直接爆窗的安全网

Agent ContextCompressor
- 在 Agent Loop 内执行
- 文档默认配置为 50%
- 使用 API 实际 token

但“默认 50%”不等于所有模型最终都在 50% 压缩。当前官方文档和源代码还支持:

  • 每模型阈值覆盖;
  • 小于 512K 上下文的模型,存在 raise-only 的 75% 阈值下限;
  • 特定 Codex 路由的自动阈值调整;
  • Codex app-server 使用原生线程 compaction,而不是重写 Hermes 本地镜像。5 12

因此,不应把 “Hermes = 固定 50%” 当成当前真实行为。

3. 当前源代码中的确定性预压缩

Hermes 当前 main 分支已经比高层文档中的“四阶段算法”更复杂。LLM 摘要前,它会执行多种确定性操作:

  • 对字节完全相同的工具结果去重;
  • 将旧的大型工具结果改写为工具相关的一行摘要;
  • 保留终端命令、退出码、行数;
  • 保留文件路径、读取起始行和内容大小;
  • 保留搜索条件、命中数量;
  • 截断超大的 Tool Call 参数,同时保持 JSON 合法;
  • 在严重压力下,连保护尾部内的已完成大型工具输出也会降级;
  • 旧图片可以替换成占位文本,避免每轮重复发送 Base64;
  • Skill 内容被裁剪后注入确定性 reload marker,防止模型误以为 Skill 仍完整加载。12

这比简单替换成:

[Old tool output cleared to save context space]

更能维持任务连续性。

4. Head / Middle / Tail

Hermes 的基础结构仍然是:

Head
  系统提示词和早期锚点,原样保留

Middle
  较旧任务轨迹,进入摘要

Tail
  最近消息,按 token 预算和最少消息数保护

边界会尽量保证工具调用和结果成组处理。

5. 当前摘要输入并非无限制发送“整个中部”

这是对旧文档和早期解释的重要修正。

当前 main 分支:

  • 对单条消息正文设置截断;
  • 对 Tool Call 参数设置截断;
  • 对发给摘要模型的总序列设置约 160,000 字符上限;
  • 同时保留输入头部和尾部,并标记中间省略;
  • 摘要输出目标比例约为被压缩内容的 20%;
  • 摘要 token 绝对上限当前为 10,000,而不是旧说明中的 12,000。12

因此,旧说法“摘要模型必须与主模型上下文一样大,否则整个中部直接超窗”已经不能完整描述当前 main 实现。摘要模型仍需有足够能力和窗口,但 Hermes 已增加输入边界和保护机制。

6. 摘要格式是 Agent Handoff,而不是聊天总结

当前源代码中的结构包括:

Historical Task Snapshot
Goal
Constraints & Preferences
Completed Actions
Active State
Blocked
Key Decisions
Resolved Questions
Relevant Files
Critical Context
Pruned Skills

它强调:

  • 具体文件路径;
  • 命令和执行结果;
  • 测试通过/失败数量;
  • 错误信息;
  • 技术决策及原因;
  • 当前环境和运行进程;
  • 被裁剪 Skill 的重载指令。12

7. 防止“旧任务重新复活”

Hermes 当前会把压缩摘要标记为:

REFERENCE ONLY

并强调:

  • 最新真实用户消息是当前任务的唯一权威;
  • 历史摘要中已经完成的请求不能被重新执行;
  • stopundonever mind 等最新信号必须终止旧任务;
  • 工具仍然可用,不能因为“仅供参考”而退化成只叙述不执行。12

它还用确定性代码从真正的用户消息中提取任务锚点,避免摘要模型从示例或旧摘要中“发明”当前任务。

8. 滚动更新

后续再次压缩时,Hermes 会把旧摘要和新增轨迹一起交给摘要器:

旧摘要
+ 新完成工作
+ 新错误
+ 新测试结果
更新后的 checkpoint

完成的工作从“进行中”移到“已完成”,过时状态被更新。

9. 安全与失败处理

当前源代码包含:

  • 压缩边界强制脱敏;
  • URL 凭据和 Secret 清理;
  • 去除内联 thinking,避免临时推理被当成事实长期保存;
  • 空摘要检测;
  • 认证、网络和部分失败路径的中止保护;
  • 失败冷却;
  • 连续 fallback 计数;
  • 无效压缩和反复压缩的 anti-thrashing;
  • 压缩后用供应商真实 token 验证是否真正降到阈值以下;
  • 工具调用与工具结果孤儿清理。12

因此,早期文档所描述的“摘要失败后静默丢掉中部”不再是对当前 main 分支的准确概括。更准确的说法是:

当前实现具有多层 fallback、abort、cooldown 和 anti-thrash 机制;具体行为仍应以部署版本的源代码和测试为准。

10. Hermes 方案的优势

  • 便宜方法优先;
  • 工具结果有针对性降级;
  • 最近任务轨迹原样保留;
  • 摘要是结构化交接文档;
  • 考虑 Prompt Cache 代价;
  • 支持每模型阈值;
  • 压缩器可替换;
  • 安全和失败路径较完善。

11. Hermes 方案的风险

  • 结构化摘要仍然有损;
  • 多次滚动更新仍可能发生摘要漂移;
  • 源代码变化快,高层文档可能滞后;
  • 辅助摘要模型太弱会损害连续性;
  • 精确标识符仍应由程序和 Artifact 系统保护;
  • System Prompt + Tool Schema 可能已经构成很大的不可压缩底座;
  • 过低阈值会造成频繁压缩和缓存失效。

七、在 LangChain v1 / LangGraph v1 中怎样落地

1. 简单场景:直接使用 SummarizationMiddleware

from langchain.agents import create_agent
from langchain.agents.middleware import SummarizationMiddleware
from langgraph.checkpoint.memory import InMemorySaver

agent = create_agent(
    model="gpt-5.4",
    tools=[],
    middleware=[
        SummarizationMiddleware(
            model="gpt-5.4-mini",
            trigger=("tokens", 40_000),
            keep=("messages", 20),
        )
    ],
    checkpointer=InMemorySaver(),
)

这适合快速原型和一般聊天 Agent。生产环境应使用 PostgreSQL 等持久化 checkpointer,而不是内存存储。1

2. 工具密集 Agent:自定义分层 Middleware

推荐数据结构:

from typing import TypedDict


class AgentState(TypedDict):
    messages: list
    active_goal: str
    constraints: list[str]
    todo: list[dict]
    tool_counts: dict[str, int]
    modified_files: list[str]
    verification: dict
    artifact_refs: list[dict]
    compaction_version: int

伪代码:

from copy import deepcopy


def compact_context(messages, state, policy):
    original = messages

    # 1. 在副本上操作,保证原子性
    working = deepcopy(messages)

    # 2. 确定性 Cheap-first
    working = deduplicate_tool_results(working)
    working = externalize_large_payloads(working)
    working = demote_old_refetchable_tool_results(working)
    working = strip_old_images(working)

    if estimate_tokens(working) < policy.trigger_tokens:
        return working

    # 3. 按合法消息组切分
    head, middle, tail = split_head_middle_tail(
        working,
        keep_recent_messages=policy.keep_recent_messages,
        keep_recent_tokens=policy.keep_recent_tokens,
        preserve_tool_pairs=True,
    )

    # 4. 生成结构化 checkpoint
    try:
        checkpoint = summarize_middle(
            middle=middle,
            canonical_state=state,
            required_exact_fields={
                "paths",
                "ids",
                "hashes",
                "errors",
                "test_names",
                "amounts",
                "dates",
            },
        )
        validate_checkpoint(checkpoint, state)
    except Exception:
        # 失败时不提交半成品
        return original

    # 5. 重新组装并验证
    compacted = head + [checkpoint.to_message()] + tail
    compacted = sanitize_tool_pairs(compacted)

    if estimate_tokens(compacted) >= estimate_tokens(original):
        return original

    return compacted

3. 状态和摘要分离

不要让摘要模型自己计算所有事实。

例如:

state["tool_counts"]["pytest"] += 1
state["verification"] = {
    "passed": 128,
    "failed": 2,
    "source": "artifact://pytest/run-103",
}

摘要模型只负责把这些可信状态与非结构化历史组织成便于模型继续工作的上下文。


八、怎样选择触发阈值

不要直接复制某个框架的百分比。可以用下面的预算模型:

context_window
- 最大预计输出
- 下一轮最大工具结果
- 系统提示词与工具定义
- 多模态预算
- 安全余量
= 最晚允许的输入水位

推荐监控:

context:
  real_prompt_tokens: 82000
  rough_prompt_tokens: 87000
  static_prefix_tokens: 18000
  recent_tail_tokens: 12000
  summary_tokens: 6000
  tool_result_tokens: 41000
  artifactized_tokens: 95000

同时设置:

  • trigger_tokens
  • target_tokens_after_compaction
  • minimum_reclaim_tokens
  • cooldown_seconds
  • max_compactions_per_task
  • ineffective_compaction_limit

九、压缩系统必须怎样评估

不要只测“压缩率”。

核心质量指标

  • 压缩后任务完成率;
  • 压缩前后下一步动作一致性;
  • 原始用户目标保留率;
  • 安全和业务约束保留率;
  • 未完成 TODO 保留率;
  • 已失败方案保留率;
  • 精确 ID / 路径 / hash 保真率;
  • 引用可回溯率;
  • 压缩后重复工具调用率;
  • 多次压缩后的摘要漂移。

性能指标

  • 压缩前后输入 token;
  • Compaction 自身 token 与费用;
  • 首 token 延迟;
  • 端到端延迟;
  • Prompt Cache 命中变化;
  • Artifact 重新获取次数;
  • 每 100 轮压缩次数;
  • 无效压缩率;
  • 压缩失败和 fallback 比例。

必测故障场景

  • 摘要模型超时;
  • 摘要模型返回空内容;
  • 429 / 配额不足;
  • 认证失败;
  • 压缩后仍超过阈值;
  • 工具调用与结果被切断;
  • 最新用户说“停止”,但旧摘要仍有进行中任务;
  • 摘要中出现 Secret;
  • 多轮摘要后 commit hash 被改写;
  • 被清理的工具结果无法重新获取;
  • 图片和 Base64 反复进入请求。

十、选择指南

普通聊天 Agent

最近消息裁剪
+ 轻量滚动摘要
+ 会话数据库

Coding Agent

文件/日志 Artifact 外置
+ 工具结果降级
+ 结构化任务 checkpoint
+ 精确路径/hash 程序化保存
+ 子 Agent 搜索隔离

Deep Research

搜索结果外置
+ 任务感知摘要
+ 每条事实保留来源
+ 检索子 Agent 隔离
+ 必要时供应商原生 Compaction

高风险业务 Agent

Canonical State 数据库
+ Event Log
+ 可审计结构化摘要
+ Tool Result 引用
+ 代码层硬约束
+ 禁止仅依赖不透明 Compaction 状态

低延迟实时 Agent

尽量使用确定性清理
+ 在空闲时间 Compaction
+ 避免每轮自动摘要
+ 保留较小近期尾部

十一、对上一版回答的校订

重新核对后,以下内容需要修正或增加限定。

修正一:Hermes 的“50% 阈值”不是普遍实际触发点

高层配置默认是 50%,但当前实现支持每模型覆盖、小窗口 75% raise-only floor,以及特定 Codex 路由策略。本文已改为“有效阈值由模型和运行路线共同决定”。

修正二:Hermes 不再只是把旧工具输出换成通用占位符

当前 main 分支会:

  • 去重完全相同结果;
  • 生成工具特定的一行摘要;
  • 保留路径、命令和退出码;
  • 截断巨大参数;
  • 处理历史图片和 Skill 重载标记。

本文已按当前源代码更新。

修正三:Hermes 摘要输入和输出上限已经变化

旧说明把整个中部一次性发送给摘要模型,并提到 12K 最大摘要预算。当前源码:

  • 对每条消息和整体摘要输入做边界控制;
  • 总输入上限约 160K 字符;
  • 摘要绝对 ceiling 为 10K token。

修正四:“摘要失败会静默删除中部”已经不适合描述当前 Hermes main

当前源码具有 fallback、abort、cooldown、anti-thrash、空结果检测和真实 token 验证。具体版本仍可能不同,因此部署时应查看锁定版本,而不是只看高层文档。

修正五:Tool-result Clearing 不是天然无损

只有可重新获取、结果稳定且重取成本可接受时,它才接近无损。

修正六:供应商原生 Compaction 并非都不透明

  • OpenAI 当前原生 compaction item 可包含不透明加密表示;
  • Anthropic 当前返回明确的 compaction block,并允许自定义摘要指令。

因此应按供应商分别判断。

修正七:Prompt Compression 的实验加速不能直接当生产承诺

LLMLingua 等工作展示了高压缩率,但 2026 年实测表明,压缩器开销可能抵消收益。应先测量 break-even point。

修正八:Google ADK 当前同时支持 token 与事件窗口策略

当前文档将 token-based 作为主要安全策略,同时保留基于事件间隔和 overlap 的滑动窗口压缩。本文已按当前文档更新。


十二、最终建议

一套稳健的生产级默认方案是:

1. 原始数据完整存储在 Prompt 之外
2. 大工具结果从源头 Artifact 化
3. 用代码去重、删噪声、维护 Canonical State
4. 清理旧的、可重取的工具结果
5. 到达阈值后生成结构化任务检查点
6. 保留近期原始尾部
7. 摘要带来源和精确标识符
8. 压缩失败时保留原始会话
9. 使用滞回、冷却和无效压缩熔断
10. 用任务成功率而不是压缩率评估系统

可以把这套方法浓缩为一句话:

不要让模型背着整本流水账继续工作;给它一份可信的当前状态、一份可回溯的证据索引,以及足够完整的近期现场。


参考资料


核对日期:2026-07-26。Agent API、模型和框架变化很快,正式部署前应再次检查供应商官方文档以及所锁定依赖版本的源代码。