Appearance
很多系统谈上下文压缩,讨论都会滑向一个很窄的问题:上下文窗口快满了,怎么把旧消息缩短一点,省点 token。Hermes Agent 这篇关于 Context Compression and Caching 的文档,真正有价值的地方不在“怎么摘要”,而在它把上下文问题重新定义成了一个长期运行时问题。对于一个支持多平台接入、具备工具调用、长期记忆、技能系统和持续会话能力的 agent 来说,上下文管理不是某个补丁模块,而是决定系统能不能持续活下去的基础设施。Hermes 的设计思路很明确:它宁愿牺牲一部分“当前对话里看起来什么都还记得”的即时性,也要换取长会话可持续性、提示词缓存命中率、状态表达稳定性,以及跨多轮任务的执行连续性。这和很多系统把压缩当成“窗口快炸了时的临时抢救”完全不是一个层级
https://hermes-agent.nousresearch.com/docs/developer-guide/context-compression-and-caching/
hermes在这篇文档里提到,它们没有把所有的上下文风险都给一个压缩器,而是明确做了dual compression system,双层压缩,第一层是Gateway Session Hygiene,默认在上下文使用达到85%的时候触发,作用是pre-agent的安全网, 第二层是agent contextCompressor,默认在50%阈值的时候触发,属于是agent loop自身内部的主压缩机制,该分层在架构上承认了防止系统崩溃和优化长任务运行质量是两件不同的事情,Gateway那层做的职责不是最优压缩,而是在某些可能会把会话拉的很长的入口前,先做最低限度的风险控制,防止请求还没真正进入 agent 核心循环就因为上下文膨胀而崩溃,而 agent 内部的 50% 压缩则完全不同,它不是急救,而是日常治理。它之所以要比 85% 小得多,是因为 agent 不是只需要再塞下一条用户消息,它还需要为后续的 system prompt、memory snapshot、skills index、工具调用结果、多步推理循环和中间响应留出足够预算。Hermes 把 in-loop 压缩阈值设在 50%,本质上是在为未来的任务链条预留执行空间,而不是面向单轮问答的文本容纳问题。这一点非常关键,因为它说明 Hermes 的上下文管理是按 agent execution budget 来思考的,而不是按聊天机器人那种“这一轮还能不能回复”来思考的
如果只把 Hermes 的压缩理解成“旧消息摘要”,也会读偏。文档里明确给出了它的压缩流程:先 prune 老旧的 tool results,再划分 head / middle / tail,然后主要对 middle 区域做结构化总结,tail 则根据 token budget 或 protect_last_n 规则保留,后续重复压缩时还会把 previous summary 一起带入,做递进更新。这套流程最值得研究的地方,不是技术动作本身,而是它背后对历史语义结构的判断。Hermes 显然不把历史消息视为同质文本,而是默认不同位置、不同类型的信息在继续执行任务时有不同价值。工具输出往往是高体积低长期价值的数据,尤其在 shell、文件读取、网页抓取、代码扫描这类操作中,真正有价值的往往不是原始输出全文,而是它支持了什么决策、暴露了什么线索,因此 Hermes 才会优先 prune old tool results。这个顺序非常工程化,因为在真实 agent 场景里,最先把上下文拖死的通常不是对话,而是工具产物。接着用 head / middle / tail 进行分区,其实也是一种执行语义判断:head 往往保留任务初始目标和背景,tail 保留最近上下文和正在展开的动作,而最容易膨胀、也最适合做压缩的是中间那段已经“发生过但仍有延续影响”的任务历史。Hermes 并没有试图把所有东西都压成一团,而是在维持一个任务骨架:起点还在,当前还在,中间折叠成可工作的摘要。这不是文本压缩,而是状态重构。
真正能体现 Hermes 思路深度的,是它要求 middle 区域生成的不是自由叙事,而是固定结构的 operational summary。文档中提到的字段包括 Goal、Constraints & Preferences、Progress、Key Decisions、Relevant Files、Next Steps、Critical Context。这七项看起来像摘要模板,实际上对应的是一个长期 agent 在压缩后还能继续工作的最低必要状态。Goal 解决“现在到底在做什么”,没有它,压缩后的上下文就只剩碎片;Constraints & Preferences 解决“有什么边界不能踩”,比如用户要求优先本地方案、不允许联网、不改某些文件、必须保持某种输出方式,这类约束一旦丢失,后续 agent 可能逻辑上连贯,却任务上越走越偏;Progress 记录的是进度,不是故事,它防止压缩之后 agent 重新从头开始;Key Decisions 保留的是任务过程中已经做出的关键判断以及背后的路径选择,这一项比过程细节更重要,因为很多重复劳动恰恰来自 agent 压缩后忘了“为什么之前不走那条路”;Relevant Files 直接体现了 Hermes 对真实工程任务的重视,在代码库、配置排查、环境调试这类任务中,文件路径和模块位置本身就是执行上下文的一部分;Next Steps 则是最具有执行意味的字段,它不是在回顾,而是在告诉未来的 agent 下一步该从哪里继续;Critical Context 相当于一个兜底槽位,保留那些暂时不适合抽进别的字段、但又绝不能丢的信息。把这些字段合在一起看,你会发现 Hermes 压缩保留的不是“历史说了什么”,而是“任务如何继续执行”。这也是我认为这篇文档最重要的地方:Hermes 压缩的是可执行状态,而不是可阅读叙事。
另一个容易被低估的设计,是文档提到的 previous summary iterative update。很多系统做上下文压缩时,每次快到上限了就从零重新总结一次,看起来简单,但长期来看非常危险。因为长会话中的真正风险,不是某一次压缩少了一点信息,而是多次压缩之后,摘要表达会逐步漂移。模型每次重新总结都会改变措辞、抽象层次和重点,时间一长,系统就不是在保留历史,而是在不断重写历史。Hermes 让后续压缩带上 previous summary 一起做 update,本质上是在给摘要建立一种连续性约束,让它不是每次重新解释过去,而是在已有状态上增量演化。这非常像数据库里的 compaction 或状态机里的 snapshot lineage。它不保证完全无损,但至少在设计上承认了一个重要现实:长期 agent 的状态压缩不能只追求“当前这次够短”,还必须考虑“压缩链条本身是否稳定”。如果说 head / middle / tail 分区解决的是空间结构,那么 previous summary 的迭代更新解决的就是时间结构。
Hermes 把 compression 和 caching 放在同一篇文档里,也不是顺手并列,而是在强调这两个问题本来就是一体的。只看 Prompt Assembly 文档就能知道,Hermes 有意把 cached system prompt state 和 ephemeral API-call-time additions 分开管理,memory 与 user profile 在 session 开始时注入 frozen snapshot,中途更新写回磁盘,但不会立即重建已经缓存好的系统前缀。这个设计和压缩机制是直接联动的。因为一旦系统把所有状态都热更新到 prompt 里,provider-side cache 很快就会失效,每轮成本和延迟都会上升;但如果什么都不动,又会在长会话中迅速爆掉上下文窗口。Hermes 的答案是:稳定的东西尽量冻结并缓存,膨胀的东西进入压缩流水线,长期状态则通过持久层维持,而不是全靠当前 prompt 保存。 这是一种非常清晰的状态分层哲学。它默认 prompt 不是唯一真相来源,session DB、compression summary、memory snapshot 各自承担不同职责。也正因为如此,Hermes 的上下文压缩不能单独看,它其实是在配合整个 agent runtime 的状态管理体系运作。
这里必须把一个边界讲清楚,否则很容易把 Hermes 误读成“压缩 summary 就是长期记忆”。不是。结合 Session Storage、Prompt Assembly 和这篇 Compression 文档,Hermes 至少区分了三层状态:第一层是原始会话历史,保存在 SQLite 和 FTS5 里,负责可追溯和可检索;第二层是会话级压缩摘要,负责让当前长对话还能继续运行;第三层是长期 memory / user profile snapshot,作为跨 session 的稳定状态在新会话启动时注入。压缩 summary 的功能是维持当前任务的执行连续性,不是正式的长期知识沉淀;长期 memory 的功能是提供跨 session 的稳定背景,不是代替当前任务推进;而原始 session DB 则是系统的完整轨迹底座,必要时还能用于回溯、检索和重新总结。正因为 Hermes 把这三层分开,它才没有走上很多 agent 系统常见的歧路:把所有状态都塞进 prompt,然后在窗口快满时被迫做语义不清的临时截断。
如果从优点和代价的角度评价,这套设计的强点很明显。第一,它让 Hermes 面对无限延长的消息线程时更稳,不容易在平台级会话里被历史拖死;第二,它特别适合多步 agent 执行,因为 50% 的内部压缩阈值给后续工具调用和推理链留出了余量;第三,它保留的是 Goal、Decisions、Relevant Files、Next Steps 这类真正决定任务续航能力的结构,而不是泛泛叙事;第四,它与 prompt caching 一起被设计,因此不是每轮都从零重建世界。与此同时,代价也不能回避。压缩永远意味着信息损失,结构化 summary 再好,也不可能等价于原始轨迹;多次压缩依旧存在摘要漂移风险,previous summary 只能缓解,不能根治;frozen snapshot 和缓存机制提升了稳定性,但也牺牲了部分 mid-session 的即时一致性,新写入的 memory 不会立刻成为系统前缀;整套体系的复杂度也远高于普通聊天系统,需要 gateway、agent loop、storage、compression、caching 多层联动。也就是说,Hermes 不是没有代价地解决了上下文问题,而是选择了一条更像真实系统工程的路线:接受状态分层与局部不一致,用可治理的结构换取长期稳定。