🧸 为什么 AI Agent 需要记忆?
如果你用过 ChatGPT、Claude 或任何 LLM,一定遇到过这个场景:
聊到第 50 条消息时,AI 已经忘了第 3 条你告诉它的事情。
这就是 无状态上下文窗口 的局限。当前主流方案是 RAG(检索增强生成)——把所有信息塞进向量数据库,用的时候搜一下。但 RAG 有个致命问题:
它不像人。
人类的记忆不是这样工作的:
- 你不会把所有事情记成一模一样的"向量"
- 有些事你记得很清楚,有些事你慢慢忘了
- 情绪激动的事情更容易记住
- 常做的事情会变成"下意识"的技能
Memory Bear 就是试图回答一个问题:如果 AI 的记忆系统更像人类大脑,会怎样?
🏛️ 三大认知科学基石
Memory Bear 的设计融合了三个经典认知科学理论:
1. ACT-R 激活扩散模型
ACT-R(Adaptive Control of Thought–Rational)是 Anderson 等人提出的认知架构,其核心公式:
$$A_i = B_i + \sum_j W_j \cdot S_{ji} + \varepsilon$$
- $A_i$:记忆 $i$ 的总激活值
- $B_i$:基础激活值(取决于访问频率和时效性)
- $W_j \cdot S_{ji}$:从关联节点 $j$ 扩散来的激活
- $\varepsilon$:噪声项(实现中省略以保证确定性)
直觉理解:当你想到"咖啡",与咖啡关联的记忆(比如"你最喜欢的咖啡馆"、“上次和朋友喝咖啡聊天”)都会被"激活"。关联越近,激活越强。
2. 艾宾浩斯遗忘曲线
1885 年,Ebbinghaus 通过自我实验发现了遗忘的规律:
$$S = e^{-t/k}$$
记忆强度随时间指数衰减。但关键在于 间隔重复效应(Spaced Repetition)——每次复习都会让衰减变慢。
Memory Bear 的实现:
$$S = e^{\frac{-k \cdot \Delta t}{1 + 0.5n}} \times (1 + 0.3\sigma)$$
其中 $n$ 是访问次数,$\sigma$ 是情绪显著性。访问越多、情绪越强烈 → 记得越牢。
3. 情绪神经科学
McGaugh (2004) 的研究表明,杏仁核-海马体交互会增强情绪鲜明事件的编码。Memory Bear 使用 Russell (1980) 的 效价-唤醒度二维模型:
- 效价(Valence):积极/消极,范围 [-1, 1]
- 唤醒度(Arousal):平静/激动,范围 [0, 1]
- 显著性 = $|valence| \times 0.4 + arousal \times 0.6$
正面和负面高唤醒事件都会被优先编码和巩固。
🏗️ 四层架构设计
自底向上解读
| 层级 | 职责 | 类比人类 |
|---|---|---|
| Encoding | 感知原始输入,提取标签、检测情绪 | 感觉器官 + 知觉 |
| Storage | 存储显性记忆(事实/事件)和隐性记忆(技能/习惯) | 海马体 / 基底神经节 |
| Orchestration | 激活扩散、多策略检索、记忆巩固 | 前额叶皮层执行控制 |
| Application | 对外暴露简洁 API | 你的主观体验 |
🔩 核心实现解析
数据模型:Memory
每条记忆是系统中的一等公民:
class Memory(BaseModel):
id: str # 内容哈希,用于去重
type: MemoryType # EPISODIC / SEMANTIC / PROCEDURAL / WORKING
content: str # 自然语言内容
tags: list[str] # 语义标签
associations: list[str] # 关联记忆 ID(激活扩散图边)
emotion: Emotion # 效价 × 唤醒度
activation: Activation # ACT-R 激活状态
created_at: float # 创建时间
last_accessed: float # 最后访问时间
access_count: int # 访问次数
decay_rate: float = 0.3 # 艾宾浩斯衰减常数
strength: float = 1.0 # 编码强度
设计要点:
id由内容的 SHA-256 哈希生成 → 相同内容自动去重type对应 Tulving (1972) 的记忆分类法- 衰减不是简单的时间函数,而是频率 × 时效性 × 情绪的综合
编码层:从文本到结构化记忆
class Encoder:
def encode(self, content, memory_type, tags, emotion, ...):
# 1. 自动标签提取(CJK + Latin 关键词)
auto_tags = self._extract_tags(content)
# 2. 情绪检测(关键词启发式)
if emotion is None:
emotion = self._detect_emotion(content)
# 3. 生成内容哈希 ID
mem_id = self._generate_id(content, memory_type)
return Memory(id=mem_id, content=content, tags=all_tags, ...)
自动标签提取同时处理中文和英文:
# 中文:连续 2+ 个汉字作为一个 token
# 英文:2+ 字母的单词
tokens = re.findall(r"[\u4e00-\u9fff]{2,}|[a-zA-Z]{2,}\d*", content.lower())
情绪检测基于关键词词典——正面词(好/棒/excellent)、负面词(错/失败/crash)、高唤醒词(紧急/重要/critical)。虽然简单,但为后续的情绪调节提供了基础信号。
存储层:显性记忆(知识图谱)
显性记忆使用加权邻接表构建知识图谱:
class ExplicitMemory:
_nodes: dict[str, Memory] # id → Memory
_adj: dict[str, dict[str, float]] # 邻接表(带权重)
_tag_index: dict[str, set[str]] # 标签倒排索引
边的构建规则:
- 共享标签:两个记忆有相同标签 → 建立边,权重随共享标签数对数增长
- 显式关联:记忆的
associations列表 → 直接建边,权重 1.0
# 共享标签权重:log1p 增长,避免边权爆炸
weight = 1.0 + math.log1p(count - 1) if count > 1 else 1.0
图遍历使用 BFS(广度优先搜索),支持多跳邻居查询——这正是激活扩散的基础设施。
存储层:隐性记忆(模式匹配)
隐性记忆模拟"下意识"的技能和习惯:
class ImplicitMemory:
_patterns: dict[str, [response, confidence]] # pattern → response
学习机制——重复学习增强信心(饱和更新):
new_conf = old_conf + (1.0 - old_conf) * incoming_confidence
匹配机制——使用 difflib.SequenceMatcher 做模糊匹配:
# "早安" 匹配已学模式 "早上好" → 相似度 0.67 → 触发响应
ratio = SequenceMatcher(None, query, stored_key).ratio()
effective_confidence = confidence * ratio
这意味着即使输入不是精确匹配,相似的模式也能触发已学响应。
编排层:扩散激活引擎
这是 ACT-R 理论的核心实现:
class SpreadingActivation:
def activate(self, seed_ids, now):
# BFS 遍历
queue = deque([(sid, 0) for sid in seed_ids])
while queue:
current_id, depth = queue.popleft()
if depth >= self.max_depth:
continue
for nid in neighbors:
# 激活随深度衰减 × 节点自身记忆强度
spread = current_activation * self.decay_factor
received = spread * neighbor.current_strength(now)
if received >= self.threshold:
activation_map[nid] = received
queue.append((nid, depth + 1))
关键参数:
decay_factor = 0.85:每跳衰减 15%max_depth = 3:最多扩散 3 跳threshold = 0.15:低于此激活值不再继续扩散
编排层:多策略检索
检索引擎融合三路信号:
class RetrievalEngine:
KEYWORD_WEIGHT = 0.4 # 关键词匹配
TAG_WEIGHT = 0.2 # 标签匹配
ACTIVATION_WEIGHT = 0.4 # 扩散激活
def retrieve(self, query, tags, now, limit):
# 1. 关键词搜索(AND 语义)
keyword_scores = ...
# 2. 标签过滤(OR 语义)
tag_scores = ...
# 3. 从命中种子扩散激活
seed_ids = set(keyword_scores) | set(tag_scores)
activation_scores = self.spreading.activate(seed_ids, now)
# 4. 分数融合
for mid in all_ids:
score = (0.4 * kw + 0.2 * tg + 0.4 * ac)
为什么要三路融合?
| 策略 | 擅长 | 弱点 |
|---|---|---|
| 关键词 | 精确匹配 | 语义盲区 |
| 标签 | 粗粒度分类 | 缺乏关联 |
| 扩散激活 | 发现隐含关联 | 冷启动问题 |
三者互补:关键词保证精度,标签提供召回,扩散激活发现"意料之外"的关联。
编排层:记忆巩固(模拟睡眠)
巩固引擎模拟人脑的睡眠整理过程:
class MemoryConsolidation:
def consolidate(self, now):
for mid, mem in all_mems.items():
strength = mem.current_strength(now)
# 遗忘:强度低于阈值 → 删除
if strength < 0.05:
self.explicit.remove(mid)
# 增强(LTP):强度高 + 访问频繁 → 激活值提升
if strength > 0.7 and mem.access_count > 3:
mem.activation.base_level *= 1.2 # 饱和上限 2.0
# 模式提取:3+ 条相似记忆 → 提炼为隐性模式
self.extract_pattern(all_mems)
三个过程:
- 遗忘:长时间不用的记忆自然衰减、最终被清除
- LTP(长时程增强):频繁访问的记忆被强化
- 模式提取:重复出现的经验被蒸馏为自动化技能
🎯 完整使用示例
from memory_bear import MemoryBear, MemoryType
bear = MemoryBear()
# ── 存储记忆 ──
bear.remember("用户喜欢喝美式咖啡", tags=["偏好", "咖啡"])
bear.remember("用户是软件工程师", tags=["职业"])
bear.remember(
"项目上线当天出了严重 bug,团队通宵修复",
tags=["项目", "bug"],
# 情绪会自动检测到"严重""通宵"等高唤醒词
)
# ── 检索记忆 ──
result = bear.recall("咖啡")
for mem, score in result.memories:
print(f" [{score:.2f}] {mem.content}")
# 不仅找到"咖啡"那条,还通过共享标签"偏好"激活了相关记忆
# ── 学习技能(隐性记忆)──
bear.learn_pattern("早上好", "提醒用户喝咖啡")
match = bear.match_pattern("早安") # 模糊匹配!
# → ("提醒用户喝咖啡", 0.35)
# ── 记忆巩固(模拟睡眠)──
report = bear.consolidate()
print(f"遗忘 {report.forgotten} 条,增强 {report.reinforced} 条")
# ── 持久化 ──
bear.save("/tmp/memories.json")
📐 设计决策与权衡
为什么不用向量数据库?
| 维度 | 向量数据库 (RAG) | Memory Bear |
|---|---|---|
| 检索方式 | 语义相似度 | 关键词 + 标签 + 图扩散 |
| 遗忘 | 不会遗忘 | 自然衰减 + 巩固 |
| 情绪 | 无 | 效价/唤醒度调节 |
| 关联发现 | embedding 空间距离 | 显式图结构(可解释) |
| 依赖 | 需要嵌入模型 | 零依赖(纯算法) |
| 适用场景 | 大规模文档检索 | Agent 个人记忆 |
Memory Bear 不替代 RAG,而是互补:RAG 擅长检索外部知识,Memory Bear 擅长管理 Agent 的"个人经历"。
为什么用 Pydantic v2?
- 类型安全:所有模型都有完整的类型标注和验证
- 序列化:内置 JSON 序列化/反序列化,持久化零成本
- 不可变选项:
ConfigDict(extra="forbid")防止意外字段注入 - 计算字段:
emotion.salience自动从 valence/arousal 计算
为什么 BFS 而不是 PageRank?
扩散激活需要的是即时性——从种子节点出发,快速评估哪些邻居最相关。PageRank 是全局静态排序,计算成本高且不响应实时查询。BFS + 衰减因子在精确度和性能之间取得了良好平衡。
📊 项目数据
- 代码量:~1200 行(含注释和文档字符串)
- 测试覆盖:23 个测试(核心模型 11 + 存储层 12)
- 依赖:仅
pydantic+numpy - Python 版本:3.10+
🚀 未来方向
Memory Bear 目前是一个概念验证级别的实现,有几个明显的扩展方向:
- 接入真正的 Embedding:目前
embedding字段为None,可以接入 OpenAI/Claude 的嵌入 API,在检索时增加语义相似度这一路信号 - 时间感知检索:加入"时间衰减加权"——越近的记忆得分越高
- 多模态编码:扩展 Encoder 支持图片、音频输入
- 层级化存储:短期记忆(Working Memory)→ 长期记忆的迁移机制
- 与 LLM 集成:提供 LangChain/LlamaIndex 适配器,让 Agent 无缝使用
📝 总结
Memory Bear 证明了一件事:给 AI Agent 加上认知科学启发的记忆系统,不仅是可行的,而且代码量可控、效果可感知。
核心收获:
- ✅ ACT-R 激活扩散让记忆检索有了"联想"能力
- ✅ 艾宾浩斯遗忘曲线让系统自动管理记忆生命周期
- ✅ 情绪建模让重要事件得到优先处理
- ✅ 显性/隐性双系统让 Agent 同时拥有"事实记忆"和"技能记忆"
这不是终局,而是一个起点。当 AI Agent 真正走向长期运行、持续交互的场景,记忆系统将成为最核心的基础设施。
Memory Bear — 让 AI Agent 拥有人类般的记忆。
项目灵感来自论文 Memory Bear (arXiv:2512.20651)。