Posted on ::

在当前的大语言模型应用开发中,尤其是在复杂编码、全自动项目重构等场景下,开发者面临的最棘手问题往往并非模型单次推理能力的不足,而是长任务漂移。典型的表现是:任务初期推进极为顺畅,但随着会话深度的增加和上下文的堆叠,系统会突发性地陷入无意义的循环,重复读取已经分析过的文件、遗忘前置步骤的进展。

常规的解决思路往往局限于期待底层模型提供更庞大的上下文窗口,或是简单粗暴地在达到 Token 阈值时触发全局对话摘要。然而分析 Claude code 源码后发现,cc 的核心解法是将压缩、状态续写、记忆提取与精准信息回灌等动作编排成了一套 Runtime(运行时)治理架构。


一、 上下文治理的边界

在讨论 Agent 的持久化能力时,业界常常倾向于使用多层记忆系统这一笼统的概念。虽然从宏观的数据流向来看,Claude Code 确实存在多达 6 到 7 层的上下文与记忆干预机制,但深入剖析可以发现,这套体系实际上是两条完全解耦、并行运作的链路。

1. 上下文窗口治理链路

这条链路的根本使命是保活。其解决的核心痛点是:当单次长任务引发海量代码读取和命令行输出,导致 Token 逼近物理极限时,如何通过逐级的数据丢弃和状态提炼,确保当前正在执行的工作流不断线、不崩溃。

2. 跨会话长期记忆链路

长期记忆完全脱离于当前的瞬时运算,旨在解决针对长期形成的记忆,系统如何留存的问题。如果以全链路的视角进行梳理,整个运行时的数据流转节点可以细分为以下七层:

  1. 大体积工具执行结果直接落盘
  2. 细粒度的微量压缩清理局部冗余
  3. 会话状态存储维护工作进度
  4. 达到 token 限制是开启全局压缩
  5. 基于文件系统的长期记忆库索引
  6. 回话结束时记忆提取
  7. 后台记忆巩固与重组

在这七层中,前四层负责应对瞬时上下文,后三层构建了跨对话的长期记忆管理。上下文窗口决定了系统单次能装载的体积,而 Runtime 机制负责管理哪些记忆能留在上下文空间中。

二、 渐进式上下文清理机制

Claude Code 依据逻辑先后,分阶段处理膨胀的上下文。

1. 工具结果落盘 (toolResultStorage) src/utils/toolResultStorage.ts 将大体量工具结果存入 tool-results/ 目录。上下文中仅保留预览,并使用 <persisted-output> 标记引用。这一步隔离了冗长的 Shell 输出和文件读取内容。

2. 微清理 (microcompact) microcompact.ts 负责清理低价值信息。COMPACTABLE_TOOLS 列表定义了可清理对象,包括旧的 Read 记录、Shell 输出、Grep 搜索结果以及 FileEdit 的执行反馈。系统优先删除过程数据,保留对话主线。

3. 自动压缩 (autocompact) 当 Token 占用率超过阈值,系统启动 autoCompact.ts。系统预留压缩输出空间并设置缓冲量。只有满足条件且未触发熔断机制时才会执行压缩。

4. 响应式压缩 (reactiveCompact) 如果系统报错提示 Prompt 太长,会执行最后一道压缩程序,确保当前回合存活。

约束: compact/prompt.ts 规定压缩 Agent 只能输出文本,严禁调用任何工具。压缩被定义为受限的系统动作,不允许模型在清理阶段产生新的操作。

三、 状态维系:SessionMemory 机制

压缩历史只能记录过去,无法指引未来。src/services/SessionMemory/ 负责维护任务运行状态。

1. 结构化字段 SessionMemory 使用固定模板记录关键信息:

  • Current State:反映最新进度。
  • Task specification:锁定任务目标。
  • Files and Functions:记录涉及的代码坐标。
  • Errors & Corrections:单独列出错误和修正记录,防止模型重复踩坑。
  • Worklog:记录具体操作流水。

2. 更新逻辑 SessionMemory 的更新受阈值控制:

  • 上下文超过 10,000 Token 时初始化。
  • 随后每增长 5,000 Token 评估更新。
  • 默认每执行 3 次工具调用尝试更新。
  • 任务到达逻辑停顿点时也会触发更新。

这一机制将长任务状态转化为结构化数据,确保模型在压缩后依然明确下一步行动。

四、 长期记忆的精准管理

Claude Code 的长期记忆不使用向量数据库,而是基于文件系统。

1. 存储结构 (memdir) 记忆存储在 src/memdir/ 下。每个项目有独立目录。MEMORY.md 是全局索引。系统为索引设置了 200 行或 25KB 的物理上限,超出部分会被截断。记忆分类包括 user、feedback、project 和 reference。系统明确禁止记录代码模式、文件路径、Git 历史等可推导信息。

2. 记忆召回 (findRelevantMemories) 系统不使用向量检索,而是通过 sideQuery 方式召回。

  • 扫描记忆文件头部形成清单。
  • 调用模型根据文件名和描述挑选相关记忆。
  • 单次召回文件上限为 5 个。 这种方式确保了召回过程的可解释性和 Token 预算。

3. 记忆提取与写入 (extractMemories) src/services/extractMemories/prompts.ts 指派专用子代理处理记忆。该代理权限受限,不可调用源码搜索工具。它仅根据最近的交互消息更新记忆,并在写入前校验重复项,防止记忆库腐烂。

4. 异步巩固 (autoDream) autoDream.ts 在后台运行,负责长周期的记忆重组。触发条件为:距离上次重组超过 24 小时,且至少积累了 5 个新会话。

五、 架构总结与工程建议

根据 Claude Code 的设计,开发 Agent 系统时可参考以下原则:

  1. 解耦历史与状态:将历史对话压缩与当前工作状态维护分为两个系统,不要混为一谈。
  2. 清理阶段禁工具:压缩 Agent 不应具备环境操作权限。
  3. 固定状态骨架:使用强类型字段记录当前进度和错误历史。
  4. 局部视野更新:记忆提取应仅基于最新增量,避免全局回顾引入噪音。
  5. 召回预算控制:长效记忆注入需经过筛选和去重,严禁全量回灌。
  6. 设置物理上限:为记忆索引设置硬性的容量限制。

Claude Code 的稳定性源于其 Runtime 治理体系。通过对遗忘、保留、交接与回灌的精密控制,系统在长任务中表现出极强的适应性。

Table of Contents