自我进化:AI 记忆的自动整理与巩固
前三期聊了记忆系统的"为什么"、"存什么"、"怎么存"和"怎么找"。这一期聊一个更有趣的问题:记忆系统怎么自我进化?
人会遗忘,但人的大脑会在睡眠时自动整理记忆——把短期记忆巩固成长期记忆,把零散信息整合成知识网络。Claude Code 的记忆系统也有类似的能力,叫做 Dream。
一、Dream:睡眠时间的记忆巩固
Dream 是记忆系统的自动整理机制。它的灵感来自人类睡眠时的记忆巩固过程:
白天积累零散的记忆碎片,晚上大脑自动整理——合并重复、强化关联、淘汰无用信息。第二天醒来,记忆更清晰。
1.1 触发条件
Dream 不是随时运行的,它有两个门控条件:
时间门控:
- 两次 Dream 之间最少间隔 24 小时——一天整理一次就够了,太频繁浪费资源
- 最长间隔 168 小时(7 天)——超过一周没整理,记忆会膨胀失控
会话门控:
- 至少 5 个会话后才触发 Dream——一个会话产生的信息太少,不值得整理
- 每 10 分钟扫描一次——检查是否满足触发条件
两个条件必须同时满足。时间到了但会话不够,不触发。会话够了但时间没到,也不触发。
这个设计很聪明。太频繁整理浪费计算,太少整理记忆质量下降。一天一次、至少五个会话,是经验上的最优平衡点。
锁机制:
// 锁机制防止并发 Dream
const lock = await this.lockManager.acquire({
key: 'dream-consolidation',
ttl: 3600000, // 锁过期时间 1 小时
retry: {
attempts: 3,
backoff: 1000 // 1 秒后重试
}
})
if (!lock) {
// 另一个 Dream 进程正在运行,跳过
return
}
文件锁防止多个 Dream 进程同时运行。锁持有者过期时间 1 小时——如果 Dream 进程崩溃了,锁会自动释放,不会永久阻塞。
1.2 Dream 流程
触发 Dream
│
▼
获取整理锁
│
▼
读取所有 CCB 记忆文件
│
▼
合并重复记忆(基于内容哈希)
│
▼
去重(保留最新版本)
│
▼
增量整理(只处理变化的部分)
│
▼
更新 MEMORY.md 索引
│
▼
更新元数据文件
│
▼
释放锁,记录整理时间
整个流程分六步:获取锁 → 读取记忆 → 合并重复 → 去重 → 增量整理 → 更新索引。
每一步都是幂等的——如果中途失败,下次 Dream 会从头重来,不会产生不一致。
1.3 增量整理
不是每次 Dream 都全量重写。增量整理的核心逻辑:
async processIncremental(memories) {
const lastConsolidatedAt = await this.getLastConsolidatedAt()
let skipped = 0, updated = 0, added = 0
for (const memory of memories) {
// 检查这条记忆上次整理后有没有变化
const hasChanged = await this.hasMemoryChanged(memory, lastConsolidatedAt)
if (!hasChanged) {
skipped++ // 没变化,跳过
continue
}
if (existsSync(metadataPath)) {
updated++ // 已有但变化了,更新
} else {
added++ // 新增的,创建
}
await this.processMemory(memory)
}
console.log(`Dream 完成:${skipped} 跳过,${updated} 更新,${added} 新增`)
}
增量整理的效率很高。一个项目可能有几百条记忆,但每次 Dream 可能只有几条新记忆或变化的记忆。跳过未变化的部分,把计算集中在真正需要整理的记忆上。
这跟 git commit 的思路一样——只提交变更,不重复提交没改的文件。
二、配置体系
记忆系统的所有行为都可以通过配置文件控制。
2.1 核心配置
{
"cache": {
"enabled": true,
"ttlHours": 24,
"maxSize": 10000,
"semanticThreshold": 0.9
},
"obsidian": {
"mode": "auto",
"cli": { "enabled": true, "timeout": 5000 },
"direct": { "atomicWrites": true },
"fallback": { "enabled": true, "maxRetries": 2 }
},
"autoDream": {
"enabled": true,
"timeGate": {
"minHoursBetweenDream": 24,
"maxHoursBetweenDream": 168
},
"sessionGate": {
"minSessionsForDream": 5,
"scanIntervalMs": 600000
}
},
"retrieval": {
"defaultStrategy": "both-priority-ccb",
"intentAnalysis": {
"enableLLM": true,
"enableRules": true,
"llmConfidenceThreshold": 0.7,
"ruleConfidenceThreshold": 0.5
},
"progressiveSearch": {
"enabled": true,
"stages": [
{ "name": "ccb-fast", "limit": 5, "timeout": 100 },
{ "name": "magma-extend", "limit": 10, "timeout": 300 },
{ "name": "full-fusion", "enableFusion": true, "timeout": 800 }
]
}
},
"fusion": {
"maxTokens": 4000,
"enableSemanticDeduplication": true,
"semanticSimilarityThreshold": 0.85,
"tokenBudget": { "dynamic": true, "maxTokensPerMemory": 500 }
}
}
配置分为五个部分:
- cache:意图分析结果的缓存配置。TTL 24 小时,最多缓存 10000 条
- obsidian:Obsidian 集成配置。支持 CLI 和 direct 两种模式,带重试和降级
- autoDream:Dream 自动整理的触发条件。时间门控和会话门控的参数都在这里
- retrieval:检索配置。意图分析、渐进式检索的策略参数
- fusion:融合配置。Token 预算、去重阈值、排序参数
2.2 双 LLM 配置
记忆系统使用了两个不同的 LLM,各自承担不同职责:
| 模型 | 用途 | 特点 |
|---|---|---|
| 硅基流动 (Qwen3-8B) | FusionVerifier | 无并发限制,响应快(3-5s) |
| 智谱 AI (glm-4.7-flash) | 意图分析 | 并发=1,需限流保护(2s 间隔) |
为什么用两个模型?因为意图分析和融合验证是两个不同的任务,对模型的要求不同:
- 意图分析需要准确理解语义,用更强的模型(智谱 AI)
- FusionVerifier需要快速验证结果,用更快的模型(硅基流动)
而且两个模型有各自的限制——智谱 AI 只允许并发 1,硅基流动没有并发限制。根据每个任务的调用频率选择合适的模型,是成本优化的典型做法。
2.3 环境差异配置
{
"environments": {
"development": {
"autoDream.timeGate.minHoursBetweenDream": 1,
"retrieval.intentAnalysis.cacheEnabled": false,
"retrieval.progressiveSearch.enabled": false
},
"production": {
"autoDream.timeGate.minHoursBetweenDream": 48,
"retrieval.intentAnalysis.cacheEnabled": true,
"retrieval.progressiveSearch.enabled": true,
"metrics.enabled": true
}
}
}
开发环境和生产环境的配置差异很大:
- Dream 频率:开发环境 1 小时一次(方便调试),生产环境 48 小时一次(节省成本)
- 缓存:开发环境禁用缓存(方便看到最新结果),生产环境启用缓存
- 渐进式检索:开发环境禁用(直接走最慢但最全面的方式,方便调试),生产环境启用
三、Shared Memory System:代码实战
shared-memory-system 是从 Claude Code 主项目中独立出来的记忆管理库,提供 CCB 和 MAGMA 的互操作功能。
3.1 项目结构
shared-memory-system/
├── src/
│ ├── CCBReader.ts # CCB 记忆读取器
│ ├── MagmaAdapter.ts # MAGMA 记忆适配器
│ ├── crossSystem.ts # 跨系统互操作
│ ├── index.ts # 主导出文件
│ │
│ ├── agents/ # Agent 系统
│ │ ├── ExtractorAgent.ts # 提取者 Agent
│ │ └── RefinerAgent.ts # 提炼者 Agent
│ │
│ ├── autoDream/ # 自动记忆整理
│ │ ├── CCBConsolidator.ts
│ │ ├── MAGMAConsolidator.ts
│ │ ├── CCBToMAGMARefiner.ts
│ │ └── ConsolidationLock.ts
│ │
│ ├── consistency/ # 一致性检查
│ │ ├── ConsistencyChecker.ts
│ │ └── ConflictArbiter.ts
│ │
│ ├── routing/ # 智能路由
│ │ ├── IntelligentRouter.ts
│ │ └── IntentClassifier.ts
│ │
│ ├── retrieval/ # 检索和融合
│ │ ├── CrossSystemRetriever.ts
│ │ └── MemoryFusion.ts
│ │
│ ├── versioning/ # 版本控制
│ │ ├── MemoryVersioning.ts
│ │ └── ExpirationHandler.ts
│ │
│ └── utils/ # 工具函数
│ ├── debug.ts
│ ├── errors.ts
│ ├── frontmatterParser.ts
│ └── readFileInRange.ts
项目结构很清晰,按功能模块划分:
- agents/:Agent 系统,负责记忆的提取和提炼
- autoDream/:Dream 自动整理,包括 CCB 和 MAGMA 各自的整理器
- consistency/:一致性检查,确保 CCB 和 MAGMA 的记忆不冲突
- routing/:路由系统,意图分类和决策
- retrieval/:检索和融合
- versioning/:版本控制和过期处理
3.2 核心 API
import { CCBReader, MagmaAdapter, CrossSystemInterop } from 'shared-memory-system'
// 1. 读取 CCB 记忆
const ccbReader = new CCBReader('path/to/ccb/memory')
const ccbDir = await ccbReader.readMemoryDirectory()
console.log(`找到 ${ccbDir.memoryFiles.length} 个记忆文件`)
// 2. 读取 MAGMA 记忆
const magmaAdapter = new MagmaAdapter({
lancedbPath: 'path/to/lancedb',
obsidianPath: 'path/to/obsidian'
})
await magmaAdapter.initialize()
// 3. 跨系统检索
const interop = new CrossSystemInterop('path/to/ccb/memory', magmaConfig)
await interop.initialize()
const results = await interop.retrieve({
query: '用户偏好设置',
limit: 10,
searchCCB: true,
searchMAGMA: true
})
三层 API 分别对应三个层次:
- CCBReader——直接读取 CCB 记忆,适合精确查询
- MagmaAdapter——直接操作 MAGMA 向量数据库,适合语义搜索
- CrossSystemInterop——跨系统互操作,封装了意图分析、路由、检索、融合的全流程
3.3 一致性检查
CCB 和 MAGMA 两个引擎可能存储同一份记忆的不同版本。一致性检查器负责发现并解决冲突:
// 一致性检查
async checkConsistency(): Promise<ConsistencyReport> {
const ccbMemories = await this.ccbReader.readAll()
const magmaMemories = await this.magmaAdapter.readAll()
const conflicts: Conflict[] = []
for (const ccbMemory of ccbMemories) {
// 在 MAGMA 中查找语义相似的记忆
const similar = await this.magmaAdapter.findSimilar(ccbMemory)
for (const magmaMemory of similar) {
if (this.isConflicting(ccbMemory, magmaMemory)) {
conflicts.push({
ccb: ccbMemory,
magma: magmaMemory,
type: 'content-mismatch',
severity: 'high'
})
}
}
}
return { conflicts, resolved: [] }
}
// 冲突裁决
async resolveConflict(conflict: Conflict) {
// 策略 1:CCB 优先(结构化记忆更精确)
if (conflict.ccb.type === 'user' || conflict.ccb.type === 'feedback') {
await this.magmaAdapter.update(conflict.ccb)
return 'ccb-wins'
}
// 策略 2:MAGMA 优先(非结构化知识更全面)
if (conflict.magma.layer === 'L5') {
await this.ccbReader.update(conflict.magma)
return 'magma-wins'
}
// 策略 3:保留两者,标记为待人工处理
return 'manual-review'
}
冲突裁决有三种策略:
- CCB 优先:用户记忆和反馈记忆以 CCB 为准(更精确、更可解释)
- MAGMA 优先:参考记忆以 MAGMA 为准(更全面、更新)
- 人工处理:无法自动裁决的冲突,标记为待人工处理
3.4 版本控制
每条记忆都有版本信息:
interface MemoryVersion {
id: string
version: number // 版本号,每次更新 +1
createdAt: Date
updatedAt: Date
previousVersions: string[] // 历史版本的 ID 列表
changeLog: string // 本次变更的说明
}
// 版本回滚
async rollback(memoryId: string, targetVersion: number) {
const history = await this.versionStore.getHistory(memoryId)
const target = history.find(v => v.version === targetVersion)
if (!target) {
throw new Error(`版本 ${targetVersion} 不存在`)
}
await this.ccbReader.update(target.content)
await this.magmaAdapter.update(target.content)
}
版本控制保证记忆的可追溯性。每次更新都记录版本号和变更说明,支持回滚到任意历史版本。
3.5 过期处理
不是所有记忆都永远有效。项目结束了、用户换了角色、工具更新了——过时的记忆比没有记忆更危险:
// 过期检测
async checkExpiration() {
const allMemories = await this.readAll()
for (const memory of allMemories) {
// 基于类型的过期规则
switch (memory.type) {
case 'project':
// 项目记忆:检查项目是否仍然活跃
if (await this.isProjectInactive(memory)) {
await this.archive(memory, 'project-inactive')
}
break
case 'reference':
// 参考记忆:检查外部资源是否仍然可达
if (!await this.isResourceReachable(memory)) {
await this.markBroken(memory)
}
break
case 'feedback':
// 反馈记忆:不过期,但降低权重
await this.decayPriority(memory, factor = 0.95)
break
}
}
}
过期策略因类型而异:
- 项目记忆:检查项目是否仍然活跃,不活跃就归档
- 参考记忆:检查外部资源是否仍然可达,不可达就标记为断链
- 反馈记忆:不过期(用户说过的话永远有价值),但随时间降低权重
四、Agent 系统
记忆系统内部有两个 Agent 负责记忆的提取和提炼:
4.1 ExtractorAgent(提取者)
负责从对话中提取值得记住的信息:
class ExtractorAgent {
async extract(conversation: Conversation): Promise<Memory[]> {
const prompt = `
分析以下对话,提取值得记住的信息。
规则:
1. 只提取不可从代码/文件推导的信息
2. 按四种类型分类:user / feedback / project / reference
3. 如果对话中没有值得记住的信息,返回空数组
对话:${conversation.text}
`
const result = await this.llm.chat(prompt)
return result.memories
}
}
提取规则很严格:只提取不可推导的信息。对话里说"这个项目的架构是微服务"——这是可从代码推导的,不提取。对话里说"集成测试不要用 mock"——这是不可推导的,提取为 feedback。
4.2 RefinerAgent(提炼者)
负责把提取的原始记忆精炼成高质量的记忆条目:
class RefinerAgent {
async refine(rawMemory: RawMemory): Promise<Memory> {
const prompt = `
将以下原始信息精炼成高质量的记忆条目。
要求:
1. name:简短描述(不超过 50 字)
2. description:一句话总结
3. content:包含 What、Why、How to apply 三部分
4. 相对日期转为绝对日期
5. 去除冗余和口语化表述
原始信息:${rawMemory.text}
`
return await this.llm.chat(prompt)
}
}
提炼的关键动作包括:
- 结构化——把口语化的对话整理成 What / Why / How to apply 的标准格式
- 绝对日期——"下周"→"2026-06-12"
- 去冗余——去除重复和无关信息
- 精炼——保留核心信息,去掉废话
五、设计哲学
回顾整个记忆进化系统,有几个设计哲学值得总结:
1. 自动而非手动。 Dream 自动整理,不需要用户手动触发。好的基础设施是透明的用户不应该需要知道它的存在。
2. 增量而非全量。 增量整理、增量更新、增量检查。每次只处理变化的部分,把计算资源集中在真正需要的地方。
3. 分层而非一锅。 五层记忆架构、三层渐进检索、两层去重。每一层解决一个特定问题,层与层之间职责清晰。
4. 约束驱动质量。 200 行索引上限、Token 预算、锁机制。好的系统不是靠用户自觉,而是靠工程约束保证质量。
5. 可观测可回滚。 版本控制、变更日志、冲突仲裁。记忆系统必须有可追溯性——要知道一条记忆从哪来、怎么变的、为什么被删除。
这期完成了记忆系统四篇系列的最后一篇。回顾一下整个系列:
- AI 记忆系统:让 AI 拥有长期记忆——为什么需要记忆、四种记忆类型、双引擎架构概览
- 双引擎架构:文件 vs 向量数据库——CCB 和 MAGMA 的内部实现、知识图谱、跨系统协同
- 意图驱动:AI 如何理解你要找什么——意图分类、路由决策、渐进式检索、去重和排序
- 自我进化:AI 记忆的自动整理与巩固——Dream 机制、配置体系、代码实战
记忆系统是 AI 助手的"大脑"。没有记忆系统的 AI,再聪明也只是金鱼的伙伴。有了记忆系统,AI 才能真正成为长期协作的伙伴。
系列:
