📐 Harness 工程 · 中文翻译

9 记忆与上下文管理

我们考察的每个智能体最终都会撞上同一个问题:对话超出了上下文窗口。 文献给出两大类解决方案:分层记忆架构(如 MemGPT [74],在上下文内的工作集与外部存储之间倒腾数据)和提示词压缩方法(如 LLMLingua [75],在文本到达模型之前缩短它)。 语料库中的 11 个系统实现了四种实用策略(图 4),我们按复杂度大致递增的顺序呈现。

9.1 策略分类体系

LinearNo pruningSummarizationRecursive halvingCondensation10 →\to 3 condensersCompactionThreshold-basedMini-SWE-AgentAider, OpenClawOpenHands Claude Code, Codex, Gemini CLI, Mistral Vibe, Hermes, Pi, OpenCode SimpleSophisticated
图 4:按精巧程度排序的记忆管理策略。11 个系统中的 7 个——四个厂商原生 Harness 与本修订版新增的全部三个系统——收敛于阈值触发的 LLM 压缩:这是生产级上下文管理的事实标准,不过每个新来者都把它与其他策略的特质混合(迭代式摘要合并、可插拔引擎、会话树基底)。

9.2 线性历史(Mini-SWE-Agent)

Mini-SWE-Agent 完全不试图管理上下文。 完整的消息列表无界增长,依赖 LLM 原生的上下文窗口(Claude 4 家族可达 100 万 token)。 这种简单性带来完美的可复现性和直接的轨迹分析——对研究基线系统而言是刻意为之的选择。

9.3 递归摘要(Aider)

Aider 的 ChatSummary 类实现递归折半算法。 当消息历史超过 max_tokens(默认 1024)时,它按 token 数把消息分成两半,尾部(最近的 50%)原样保留。 头部经一次 LLM 调用生成摘要(summarize_all())。 若“摘要 + 尾部”仍超限,过程递归最多 3 层。 可配置一个单独的“弱模型”(如 GPT-3.5-turbo)以低成本完成摘要。

9.4 可插拔压缩(OpenHands)

OpenHands 用抽象的 Condenser 基类开创了可插拔记忆管理。 V0 应用带了 10 个实现;V1 SDK 把这个动物园精简为 3 个(NoOpCondenser、LLMSummarizingCondenser、PipelineCondenser),都架在 RollingCondenser 基类之上——一次意味深长的简化,大多数专用变体被证明并不必要。 整合带来两个升级:压缩凝聚本身是事件溯源的(日志里有 CondensationRequest/Condensation 事件,压缩历史可重放),而且凝聚器兼任错误恢复——上下文窗口溢出与畸形历史错误触发一次压缩而不是崩溃。 摘要凝聚器还在事件数阈值之外增加了 token 计数触发器(max_tokens),使 OpenHands 与下文的阈值压缩家族对齐。

9.5 阈值压缩(七个系统)

Claude Code 的压缩在运行中的 token 估计进入模型有效上下文窗口下方的缓冲区时触发(AUTOCOMPACT_BUFFER_TOKENS = 13 000,另有可用环境变量覆盖的百分比阈值供测试)。 流程:(1) 从消息中剥离图片(替换为 [image] 标记),(2) 按 API 轮次对消息分组,(3) 调用 LLM 生成会话摘要,(4) 创建一条 SystemCompactBoundaryMessage,把压缩前的历史与摘要分开。 压缩后清理恢复最多 5 个文件(POST_COMPACT_TOKEN_BUDGET = 50 000),并把技能截断到每技能 25 000 token 的预算。

Codex 经专门的 /responses/compact 端点同时支持本地进程内摘要与云端摘要,由 model_auto_compact_token_limit 控制摘要何时触发(单独的 /memories/trace_summarize 端点服务于第 9.6 节的记忆管线);远程压缩 v2 路径与按线程铺开的 token 预算(带余量提醒与耗尽时的轮次中止)在 2026 年春季版本中加入。

Gemini CLI:多阶段上下文管线。

Gemini CLI 的上下文管理比简单压缩精巧得多。 顶层,当历史超过模型 token 上限的 50% 时,ChatCompressionService 触发,调用 Gemini 生成状态快照,并逐字保留最近 30% 的历史(token 预算截断预趟和一个 PreCompress Hook 现在会在压缩前先行触发)。 其下,一个专门的上下文处理器模块实现多阶段上下文蒸馏管线,带可插拔处理器(滚动摘要、节点蒸馏、节点截断、块降级、工具遮蔽、状态快照),在 v0.43–0.45 中整合为一个 ContextManager——在工作缓冲区里维护原始对活动(pristine-versus-active)的上下文图,用带迟滞触发阻尼的编排器跑处理器,并用按观测 API token 计数校准的自适应 token 计算器取代静态的每 token 字符估计。 另一个 ContextCompressionService 跟踪逐文件的压缩级别(FULL、PARTIAL、SUMMARY、EXCLUDED),粒度细于 Claude Code 的“已压缩/未压缩”二分;一个可插拔的 AgentHistoryProvider 接口让扩展替换自己的压缩逻辑。

Mistral Vibe:中间件触发,现已两层且响应式。

Mistral Vibe 的 AutoCompactMiddleware 在每轮之前检查 context_tokens >= auto_compact_threshold;压缩例程本身已抽成 CompactionManager,自 4 月以来长了三处精细改进:压缩后的状态是一个上下文信封,把此前的用户消息连同摘要重新注入(原始任务目标因此在重置中幸存);缓存友好的主摘要回退到一个专用的无工具摘要器;同一例程还会在某轮中途撑爆上下文窗口时响应式触发。 经中间件管线的集成在架构上仍比循环内检查干净:压缩只是又一个轮次策略。 Mistral Vibe 互补的 RewindManager 按用户消息建立文件系统级检查点,支持带回退(可选恢复文件)——如今还能分叉到新会话,并经 ACP 暴露,IDE 客户端可以驱动回退。 曾经独一无二的检查点机制如今有了更细粒度的兄弟:OpenCode 为每个项目维护一个影子 git 仓库(在真实工作树上用独立的 --git-dir),在流开始前、步骤开始、步骤结束时打快照,产出逐步骤的补丁部件和“对话 + 文件系统”的完整还原。

Hermes:谱系压缩。

Hermes 落在阈值家族(触发点为上下文的 50% 减去 max-tokens,64K 下限;保护前三条消息加一个有 token 预算的尾部;迭代式辅助模型摘要上限为 min(上下文的 5%, 12K token)),但增加了一个其他系统都没有的构造:压缩不重写转录——它终结会话。 每次压缩关闭当前 SQLite 会话(end_reason=’compression’),轮换到经 parent_session_id 链接的子会话;谱系助手沿祖先遍历,会话搜索在谱系上去重。 上下文管理与会话持久化变成一个机制,任何历史都不会被销毁。 引擎可插拔(一个 ContextEngine 抽象基类),呼应 OpenHands 的凝聚器。

Pi:会话树上的压缩。

Pi 在 contextWindow −- 16,384 token 处触发(保留最近 20K),并借了其他两种策略的特质:摘要是迭代合并的——更新提示词重新吃进上一个摘要,而非从零重新总结(递归摘要特质)——一个 session_before_compact Hook 让扩展完全否决或替换结果(可插拔压缩特质)。 独特的基底是会话本身:一棵只追加的 JSONL树,每个条目带 id/parentId,可移动的叶指针定义活动分支。 /tree 导航、/fork 与 /clone 把其他 Harness 实现为三个独立功能的东西(检查点、回退、替代探索)统一起来;放弃一个分支时可选择生成一段 LLM分支摘要拼接到新位置,探索因此永不丢失——代价是文件系统状态不予恢复,这是明文写下的权衡。 累积的 <read-files>/<modified-files> 列表作为结构化记忆跨压缩持久存在。

OpenCode:锚定式增量摘要。

OpenCode 在 limit.input 减去预留输出余量处触发,用 chars/4 估计(整棵代码树里找不到任何分词器),并产出语料库中最显式增量式的摘要:上一个摘要经 <previous-summary> 块传回,由一个隐藏的、被剥夺全部工具的 compaction 智能体合并(“保留仍然成立的细节,删除过时的细节”),写进强制的 Markdown 分节(目标 / 重要细节 / 工作状态 / 下一步 / 相关文件)。 两个用户轮次的逐字尾部被保留;可选的修剪软删除旧工具输出,保护最新的 40K token,且只在可回收超过 20K 时触发。

9.6 持久记忆管线

本研究的 4 月版可以每个系统用一句话描述跨会话记忆:这里一个 Markdown 上下文文件,那里一个转录存储。 三个月后,持久记忆成了厂商原生系统差异化最激烈的战场,而各设计在一个轴上分歧得颇有教益:谁来写记忆,谁来审它。

Codex 跑着最自主的设计。 一个后台两阶段管线从最近的会话铺开(rollout)中抽取结构化记忆(每 rollout 一次 LLM 抽取,写入 SQLite 状态库,带租约任务、重试退避与密钥脱敏),然后整合成文件系统工件,放在以 git 为基线的 ~/.codex/memories/ 根下——整合由一个沙箱化的内部子智能体完成(无审批、无网络、只许本地写),审查一个 git 风格的工作区 diff。 记忆注入新会话时带引用跟踪与基于使用量的排序。 Codex 因此是语料库中第一个长期记忆由智能体而非代码维护的系统;一个实验性的“编年史”(chronicle)边车把同一套机制延伸到被动的屏幕上下文。

Gemini CLI 朝相反的治理方向移动。 它 4 月时那个可调用的 save_memory 工具已经消失——系统提示词现在直白声明不存在这样的工具——取而代之的是:(a) 模型用普通编辑工具直接编辑 GEMINI.md 或私有的每项目 MEMORY.md 索引;(b) 一个异步的技能抽取子智能体,挖掘已完成的会话转录,把规范的补丁文件写进每项目的 .inbox/,由用户审查并经 /memory 应用。 Codex 让智能体自主整合记忆,Gemini CLI 则在抽取与持久化之间插入一个人工把关的审查收件箱——语料库中唯一这样的设计。

Hermes 把持久记忆刻意做得极小且缓存友好:两个有界的 Markdown 文件(MEMORY.md,2,200 字符;USER.md,1,375 字符),作为冻结快照注入,会话中途写入落盘但不作废提示词缓存。 会话召回是确定性的——一个 session_search 工具跑在触发器维护的 SQLite FTS5 表上(BM25,外加面向中日韩文字的三元组索引),“任何地方都没有 LLM 调用”——嵌入只存在于可选的记忆插件里。 OpenClaw 出货一个 Active Memory 插件(留档说明:它早在我们上一版审计的那个 4 月发布里就有),在主回复之前立即运行一个专用的记忆子智能体,另加它更早的可选 LanceDB 会话记忆扩展。 OpenHands 把记忆折进它的上下文文件约定:一个 <MEMORY> 提示词节指示模型把持久事实写进 AGENTS.md 本身。 Claude Code 持久化每项目的 Markdown 事实记忆目录;Pi 与 Mini-SWE-Agent 刻意不持久化会话基底之外的任何东西。

观察 5。持久记忆已取代压缩,成为上下文工程的前沿。压缩设计已经趋同(11 个系统中的 7 个用阈值触发的 LLM 摘要,且越来越多地带增量合并);如今区分这个领域的是记忆的写入路径。四种治理模型并存:智能体自维护(Codex:沙箱化子智能体在 git 基线的存储上整合记忆)、人工把关(Gemini CLI:抽取子智能体写入补丁收件箱,用户经 /memory 审查)、模型直写但有界(Hermes:字符上限的 Markdown 快照,按会话冻结以保缓存卫生;OpenHands、Claude Code:上下文文件约定),以及轮前智能体召回(OpenClaw 的 Active Memory 子智能体)。值得注意的是,11 个系统中没有任何一个把基于嵌入的检索作为主要记忆基底——观察 13.2 的确定性检索发现从代码延伸到了记忆,生产级的天花板是 SQLite 全文检索(Hermes)。

9.7 仓库上下文

除会话历史外,智能体还必须管理代码上下文:

  • •

    Aider RepoMap:基于 tree-sitter 的符号索引,用 diskcache(SQLite v4)——仍是语料库中唯一的排序仓库地图。 符号按与当前对话的相关度排序。 Token 预算自适应(map_tokens,默认 1024),大仓库另有 map_mul_no_files 乘数。

  • •

    Claude Code 记忆系统:经专门的 claudemd 子系统自动发现 CLAUDE.md 文件(从工作目录起遍历受管理、用户与项目三个作用域),作为嵌套记忆附件注入并去重;独立的 memdir 机制管理每项目的持久自动记忆目录。

  • •

    Codex 指令:分层 AGENTS.md 指令——准确说是从项目根到工作目录的拼接(嵌套内容追加在最后,所以“优先级”只靠位置成立),外加一个 AGENTS.override.md 逃生舱,以及可配置的根标记与回退文件名。

  • •

    Gemini CLI 上下文文件:由文件夹信任门控的三作用域 GEMINI.md 合并(全局、扩展、项目),加上经工具输出注入子目录上下文文件的 JIT 机制,以及私有的 MEMORY.md 项目索引。

  • •

    Mistral Vibe JIT 发现:提示词中的顶层 AGENTS.md(用户与项目作用域),并且——自 v2.19 起——当 read_file 触及其下文件时即时浮现嵌套的 AGENTS.md。

  • •

    Hermes 带威胁扫描的层级:先到先得的遍历(.hermes.md/HERMES.md 直到 git 根,然后 AGENTS.md、CLAUDE.md、.cursorrules);每个上下文文件都做提示词注入模式扫描,命中即整体拦截;一个子目录提示跟踪器把每目录的上下文文件附加到工具结果,保持缓存的提示词不动。

  • •

    Pi 祖先遍历:从 cwd 到根收集 AGENTS.md/CLAUDE.md 进 <project_context> 标签;仓库控制的配置(扩展、技能)的加载受信任门控,但上下文文件无条件加载——一个成文的、刻意的注入面接受。

  • •

    OpenCode 拉取式附加:AGENTS.md/CLAUDE.md/CONTEXT.md 向上遍历(首个文件名优先)加远程 URL 指令文件;当 read 工具触及其下文件时,嵌套的 AGENTS.md 惰性附加。

  • •

    OpenHands 第三方摄入:技能子系统把 AGENTS.md、.cursorrules 与嵌套的每目录 AGENTS.md 作为带作用域的规则摄入——一个系统读取三个其他生态的约定。

  • •

    OpenClaw 转录:JSONL 转录文件按智能体/会话持久化在 ~/.openclaw/agents/<agentId>/sessions/<sessionKey>.jsonl。