Claude Code 源码分析(五):分层记忆体系 —— AI Agent 的知识持久化架构

本系列文章基于 Claude Code 2.1.88 版本的 TypeScript 源码进行分析。源码版权归 Anthropic 所有,本文仅用于技术研究。

引言

AI Agent 的记忆管理是一个尚未被充分解决的工程问题。单次对话中的上下文会随着压缩而丢失,跨会话的知识无法自动积累,不同 Agent 之间的经验无法共享。Claude Code 实现了一套三层记忆架构------会话内记忆、跨会话记忆、Agent 级记忆------在不同时间尺度上解决知识持久化问题。

涉及的核心源码文件:

  • src/services/SessionMemory/ ------ 会话内记忆(3 个文件)
  • src/services/extractMemories/ ------ 跨会话记忆提取
  • src/tools/AgentTool/agentMemory.ts ------ Agent 级记忆目录
  • src/tools/AgentTool/agentMemorySnapshot.ts ------ 记忆快照与同步

一、会话内记忆(Session Memory)

src/services/SessionMemory/ 负责在单次会话内提取和管理记忆。

1.1 提取时机判断

typescript 复制代码
function shouldExtractMemory(messages: Message[]): boolean { ... }
function countToolCallsSince(messages: Message[], lastMessageId: string): number { ... }

系统根据工具调用次数和消息量判断是否需要提取记忆。这种基于活动量的触发机制避免了过于频繁的提取(浪费 API 调用)和过于稀疏的提取(丢失重要信息)。

1.2 并发控制

typescript 复制代码
function markExtractionStarted(): void { ... }
function markExtractionCompleted(): void { ... }
async function waitForSessionMemoryExtraction(): Promise<void> { ... }

记忆提取过程有锁机制,防止并发提取。waitForSessionMemoryExtraction 允许其他操作等待提取完成后再继续,确保后续操作能看到最新的记忆状态。

1.3 记忆模板与 Prompt

typescript 复制代码
async function loadSessionMemoryTemplate(): Promise<string> { ... }
async function loadSessionMemoryPrompt(): Promise<string> { ... }
function getDefaultUpdatePrompt(): string { ... }

记忆提取使用专门的 prompt 模板,指导模型从对话中提取结构化的知识。

1.4 记忆大小分析

typescript 复制代码
function analyzeSectionSizes(content: string): Record<string, number> { ... }
function generateSectionReminders(sizes: Record<string, number>): string[] { ... }

系统会分析记忆各部分的大小,当某个部分过大时生成优化建议。这防止了记忆文件无限膨胀。

1.5 位置追踪

typescript 复制代码
function getLastSummarizedMessageId(): string | undefined { ... }
function setLastSummarizedMessageId(id: string | undefined): void { ... }

系统追踪"上次总结到哪条消息",确保增量提取不会重复处理已总结的内容。当对话被压缩时,这个标记会被重置(因为旧的消息 UUID 不再存在)。


二、跨会话记忆(Extract Memories)

src/services/extractMemories/ 负责从对话中提取可跨会话复用的知识,持久化到 CLAUDE.md 等记忆文件中。

CLAUDE.md 是 Claude Code 的项目级记忆文件,类似于 .editorconfig.eslintrc,但存储的是 AI 助手需要了解的项目知识:编码规范、架构决策、常用命令等。

跨会话记忆的提取发生在会话结束时或用户显式触发时,提取的知识被追加到 CLAUDE.md 中,供后续会话使用。


三、Agent 级记忆

3.1 记忆目录管理

agentMemory.ts 为每个 Agent 类型维护独立的记忆目录:

typescript 复制代码
function sanitizeAgentTypeForPath(agentType: string): string { ... }
function getLocalAgentMemoryDir(dirName: string): string { ... }
function getAgentMemoryDir(agentType: string, scope: AgentMemoryScope): string { ... }
function isAgentMemoryPath(absolutePath: string): boolean { ... }
function getAgentMemoryEntrypoint(agentType: string, scope: AgentMemoryScope): string { ... }

sanitizeAgentTypeForPath 将 Agent 类型名转换为安全的文件系统路径。isAgentMemoryPath 用于判断一个路径是否属于 Agent 记忆目录,这在权限检查中很重要------Agent 对自己的记忆目录有特殊的读写权限。

3.2 记忆快照

agentMemorySnapshot.ts 实现了记忆的快照与同步机制:

typescript 复制代码
function getSnapshotDirForAgent(agentType: string): string { ... }
function getSnapshotJsonPath(agentType: string): string { ... }
function getSyncedJsonPath(agentType: string, scope: AgentMemoryScope): string { ... }
async function readJsonFile<T>(path: string): Promise<T | null> { ... }
async function copySnapshotToLocal(agentType: string): Promise<void> { ... }

快照机制支持记忆的版本管理和跨作用域同步。copySnapshotToLocal 将远程或共享的记忆快照复制到本地,确保 Agent 在离线环境中也能访问其记忆。


四、记忆与压缩的协同

记忆系统与上下文压缩系统之间有紧密的协同关系。

4.1 会话记忆压缩

src/services/compact/sessionMemoryCompact.ts 实现了基于会话记忆的压缩策略:

typescript 复制代码
function setSessionMemoryCompactConfig(config: SessionMemoryCompactConfig): void { ... }
function getSessionMemoryCompactConfig(): SessionMemoryCompactConfig { ... }
async function initSessionMemoryCompactConfig(): Promise<void> { ... }

当上下文需要压缩时,系统优先尝试会话记忆压缩------将对话中的关键信息提取为记忆,然后用记忆替代原始对话内容。这比简单的截断保留了更多有价值的信息。

4.2 压缩后的记忆重置

在自动压缩完成后,会话记忆的位置标记会被重置:

typescript 复制代码
// autoCompact.ts 中
setLastSummarizedMessageId(undefined)

因为压缩会替换消息列表,旧的消息 UUID 不再存在。


五、记忆在 Agent 派生中的传递

5.1 记忆加载事件

当 Agent 加载其记忆时,系统会记录遥测事件:

typescript 复制代码
if (selectedAgent.memory) {
  logEvent('tengu_agent_memory_loaded', {
    agent_type: selectedAgent.agentType,
    scope: selectedAgent.memory,
    source: 'subagent',
  })
}

5.2 CLAUDE.md 的选择性加载

不同类型的 Agent 对 CLAUDE.md 的需求不同。例如 Explore Agent 设置了 omitClaudeMd: true

typescript 复制代码
export const EXPLORE_AGENT: BuiltInAgentDefinition = {
  omitClaudeMd: true,  // 不加载项目记忆文件
}

Explore Agent 是一个快速的只读搜索代理,不需要了解项目的编码规范或架构决策。主 Agent 拥有完整的上下文,会在 Explore Agent 的结果基础上做出判断。

5.3 嵌套记忆去重

ToolUseContext 中维护了一个去重集合,防止同一个 CLAUDE.md 文件被重复注入:

typescript 复制代码
loadedNestedMemoryPaths?: Set<string>
// 源码注释:readFileState is an LRU that evicts entries in busy 
// sessions, so its .has() check alone can re-inject the same 
// CLAUDE.md dozens of times.

在繁忙的会话中,LRU 缓存会驱逐条目,导致 readFileState.has() 检查失效,同一个 CLAUDE.md 可能被注入数十次。独立的去重集合解决了这个问题。


六、总结

Claude Code 的分层记忆体系在三个时间尺度上解决了知识持久化问题:

其一,会话内记忆通过增量提取保留对话中的关键信息,与压缩系统协同工作,确保上下文压缩不会丢失重要知识。

其二,跨会话记忆通过 CLAUDE.md 等文件实现项目级知识的积累,使得 AI 助手能够在多次会话中逐步"了解"一个项目。

其三,Agent 级记忆为每个 Agent 类型维护独立的知识库,支持快照和同步,使得专业化的 Agent 能够积累领域经验。

三层记忆之间的协同设计(压缩时的记忆重置、Agent 派生时的选择性加载、嵌套记忆去重)确保了整个系统的一致性。对于正在构建 AI Agent 记忆系统的团队,这套分层架构提供了一个清晰的参考框架。

相关推荐
zhangfeng11334 小时前
利用WorkBuddy 国产小龙虾 制作视频 1 Remotion 方案 2 备选:moviepy 方案渲染视频
人工智能
冬奇Lab5 小时前
RAG 系列(十四):Self-RAG——让模型决定要不要检索
人工智能·llm
chatexcel5 小时前
AI工具里的知识库是什么?定义、原理、场景与ChatExcel示例解析
人工智能
冬奇Lab5 小时前
一天一个开源项目(第99篇):AiToEarn - 用 AI 把内容变成收入的一站式平台
人工智能·开源·资讯
千叶风行5 小时前
Text-to-SQL 技术设计与注意事项
前端·人工智能·后端
夜郎king5 小时前
Spring AI 对接大模型开发易错点总结与实战解决办法
java·人工智能·spring
从孑开始5 小时前
manyspeech-cli 语音识别命令行工具
人工智能·语音识别·工具·asr
hans汉斯5 小时前
计算机科学与应用|基于大模型深度语义理解的智能内容纠错系统
人工智能·计算机视觉·视觉检测·数据·病虫害检测
Mr数据杨5 小时前
【CanMV K210】视觉识别 颜色阈值分割与色块检测实验
人工智能·硬件开发·canmv k210
Bruce_Liuxiaowei5 小时前
OpenClaw 网关启动失败:配置文件权限错误的排查与修复
人工智能·智能体