AI Agent 记忆系统的认知架构:工作记忆、情景记忆与语义记忆的融合工程

从人类认知科学出发,构建真正具备持续学习能力的 AI Agent 记忆系统

引言:为什么 AI Agent 需要认知记忆模型?

当前的 AI Agent 记忆系统大多停留在简单的 RAG(检索增强生成)层面——将历史对话向量化后存入数据库,查询时取 top-K 相似片段作为上下文。这种方式虽然工程上可行,但存在一个根本缺陷:它没有区分不同类型的记忆,也无法模拟人类记忆的巩固、遗忘和关联机制。

认知科学将人类记忆分为多个子系统:工作记忆(Working Memory)负责即时信息处理,情景记忆(Episodic Memory)记录经历的事件及其时空背景,语义记忆(Semantic Memory)存储抽象知识和事实。这三者协同工作,使人类能够高效学习、推理和适应环境。

本文将深入探讨如何借鉴认知科学的记忆分层理论,构建下一代 AI Agent 记忆系统,实现从"信息检索"到"认知记忆"的范式转变。

一、认知记忆分层模型与工程映射

1.1 三层记忆架构

认知心理学的 Atkinson-Shiffrin 模型将记忆分为三个存储系统:

  • 感觉记忆(Sensory Memory):持续几百毫秒,容量极大但迅速衰退
  • 短期记忆(Short-term / Working Memory):持续数秒到数分钟,容量极为有限(7±2 个信息块)
  • 长期记忆(Long-term Memory):持续数天到永久,容量几乎无限

在 AI Agent 场景中,我们可以将其映射为:

认知记忆层 AI Agent 映射 数据特征 典型实现
感觉记忆 原始输入流 未处理、高吞吐、滑动窗口 Token Buffer、事件流
工作记忆 当前上下文窗口 高度关联、实时更新、有限容量 KV Cache、Attention Window
情景记忆 交互历史 时间戳、因果链、情感标记 图数据库、事件溯源
语义记忆 知识库 结构化、去时序、抽象表示 知识图谱、向量数据库

1.2 工程参考架构

┌─────────────────────────────────────────────────────────────────┐
│                        用户 / 环境输入                           │
└────────────────────────────┬────────────────────────────────────┘
                             ▼
┌─────────────────────────────────────────────────────────────────┐
│                    感觉记忆层(Sensory Buffer)                   │
│  ┌─────────────────────────────────────────────────────────┐    │
│  │  滑动窗口 Token Bufffer  │  多模态流 (文本/语音/图像)     │    │
│  └─────────────────────────────────────────────────────────┘    │
└────────────────────────────┬────────────────────────────────────┘
                             ▼
┌─────────────────────────────────────────────────────────────────┐
│                    工作记忆层(Working Memory)                   │
│  ┌───────────────┐  ┌──────────────┐  ┌─────────────────────┐  │
│  │  当前对话状态   │  │  注意力焦点   │  │  即时推理缓存        │  │
│  └───────────────┘  └──────────────┘  └─────────────────────┘  │
│                    (容量:受限的 Context Window)                  │
└────────┬───────────────────────────────────────────┬────────────┘
         │ 巩固(Consolidation)                       │ 提取
         ▼                                           ▼
┌─────────────────────────┐         ┌─────────────────────────┐
│   情景记忆(Episodic)    │         │   语义记忆(Semantic)    │
│  ┌───────────────────┐  │         │  ┌───────────────────┐  │
│  │ 事件序列 + 时间线   │  │         │  │ 结构化知识 + 本体    │  │
│  │ 情感标记 + 因果关系  │  │◄────────┤  │ 抽象规则 + 程序性知识 │  │
│  └───────────────────┘  │  泛化    │  └───────────────────┘  │
│     (图数据库 + 向量)     │         │   (知识图谱 + 嵌入索引)   │
└─────────────────────────┘         └─────────────────────────┘

这个架构的核心洞察在于:记忆不是静态存储,而是动态转换过程。Agent 需要将工作记忆中的"经历"通过巩固机制转化为长期记忆中的"知识",同时在需要时能够将长期记忆提取回工作记忆中。

二、工作记忆工程:超越 Context Window

2.1 当前 Context Window 的问题

大多数 AI Agent 的工作记忆本质上就是一个环形缓冲区:最新的 token 不断挤入,最旧的 token 被截断。这种"先进先出"的遗忘机制完全不符合认知科学对人类工作记忆的理解。

认知心理学研究表明,工作记忆的关键特征不是"记住所有东西",而是:

  • 注意力驱动的选择性保持:只有被注意到的信息才能进入工作记忆
  • 主动刷新与维护:通过复述(rehearsal)保持信息活跃
  • 执行控制:工作记忆的执行系统负责信息操纵和任务切换

2.2 工程实现:分层注意力工作记忆

from dataclasses import dataclass, field
from typing import Any
from enum import Enum
import time
import heapq

class AttentionLevel(Enum):
    """注意力层级,模拟认知心理学的工作记忆焦点"""
    FOCUS = 3       # 当前活跃推理焦点
    ACTIVE = 2      # 主动保持在工作记忆中
    AVAILABLE = 1   # 可被快速提取
    LRU = 0         # 待回收

@dataclass
class WorkingMemoryItem:
    """工作记忆条目"""
    content: Any
    attention: AttentionLevel
    created_at: float = field(default_factory=time.time)
    last_accessed: float = field(default_factory=time.time)
    access_count: int = 0
    relevance_score: float = 0.0
    
    def __lt__(self, other):
        """按注意力得分排序"""
        return self.relevance_score < other.relevance_score

class WorkingMemory:
    """
    受认知科学启发的 Agent 工作记忆系统
    - 容量限制:模拟工作记忆的 7±2 信息块限制
    - 注意力驱动:基于任务相关性的动态优先级
    - 主动遗忘:模拟记忆的衰减与干扰理论
    """
    
    def __init__(self, capacity: int = 9, decay_rate: float = 0.05):
        self.capacity = capacity  # 工作记忆容量(7±2 的扩展)
        self.decay_rate = decay_rate  # 衰减速率(每秒)
        self.items: list[WorkingMemoryItem] = []
        self.consolidation_callback = None  # 巩固到长期记忆的回调
        
    def attend(self, item: WorkingMemoryItem, reason: str = ""):
        """将新信息纳入工作记忆(注意力选择入口)"""
        # 计算初始相关性分数
        item.relevance_score = self._calc_relevance(item)
        item.attention = AttentionLevel.ACTIVE
        
        # 容量管理:如果超出容量,触发巩固或遗忘
        if len(self.items) >= self.capacity:
            self._evict_lowest_priority()
        
        self.items.append(item)
        self._rebalance_attention()
        
    def _calc_relevance(self, item: WorkingMemoryItem) -> float:
        """计算条目的相关性分数(综合考虑多因素)"""
        time_factor = 1.0 / (1.0 + self.decay_rate * (time.time() - item.created_at))
        attention_boost = item.attention.value * 0.5
        recency = 1.0 / (1.0 + time.time() - item.last_accessed)
        return time_factor * 0.3 + attention_boost * 0.4 + recency * 0.3
    
    def _evict_lowest_priority(self):
        """驱逐最低优先级的记忆项目"""
        if not self.items:
            return
        
        # 找到最低优先级项目并尝试巩固
        lowest = min(self.items, key=lambda x: x.relevance_score)
        
        if lowest.attention == AttentionLevel.FOCUS:
            # 焦点永不驱逐(执行任务所需)
            non_focus = [i for i in self.items if i.attention != AttentionLevel.FOCUS]
            if non_focus:
                lowest = min(non_focus, key=lambda x: x.relevance_score)
        
        # 触发巩固回调(转移到长期记忆)
        if self.consolidation_callback:
            self.consolidation_callback(lowest)
        
        self.items.remove(lowest)
    
    def _rebalance_attention(self):
        """重新平衡注意力分配(模拟执行控制)"""
        if not self.items:
            return
        
        # 排序并分配注意力层级
        self.items.sort(key=lambda x: x.relevance_score, reverse=True)
        
        for idx, item in enumerate(self.items):
            if idx == 0:
                item.attention = AttentionLevel.FOCUS
            elif idx < 3:
                item.attention = AttentionLevel.ACTIVE
            elif idx < 6:
                item.attention = AttentionLevel.AVAILABLE
            else:
                item.attention = AttentionLevel.LRU
    
    def focus_on(self, query: str, match_fn=None):
        """
        将注意力聚焦到特定信息
        模拟:当 Agent 需要在工作记忆中搜索特定信息时的执行控制过程
        """
        if match_fn is None:
            match_fn = lambda item, q: q.lower() in str(item.content).lower()
        
        for item in self.items:
            if match_fn(item, query):
                item.attention = AttentionLevel.FOCUS
                item.last_accessed = time.time()
                item.access_count += 1
                item.relevance_score = self._calc_relevance(item)
                return item
        
        return None
    
    def get_working_context(self) -> list:
        """获取当前工作记忆中的所有活跃项目"""
        return [item for item in self.items 
                if item.attention.value >= AttentionLevel.ACTIVE.value]

2.3 实践要点

这种分层工作记忆的关键优势在于:

  1. 避免信息过载:通过注意力机制模拟人类的选择性注意,只保留与当前任务高度相关的信息
  2. 智能驱逐:不是简单地丢弃最旧信息,而是基于多维相关性决定保留什么
  3. 巩固触发:当信息即将被驱逐时,可以触发将其转移到情景记忆的回调

三、情景记忆工程:因果链与时间维度

3.1 为什么需要情景记忆?

语义记忆告诉我们"巴黎是法国首都",情景记忆则记得"2024年夏天,我在巴黎的塞纳河边散步,天气很好,阳光温暖"。

对于 AI Agent,情景记忆的核心价值在于:

  • 因果推理:理解事件之间的因果关系,而非仅仅统计相关性
  • 经验复现:从过去的交互中提取可复用的模式
  • 时序规划:基于历史事件的时序关系进行预测和规划

3.2 事件溯源与图存储

情景记忆的最佳工程实现是事件溯源(Event Sourcing)+ 图数据库:

from dataclasses import dataclass
from typing import Optional
import uuid
import json
from datetime import datetime

@dataclass
class Episode:
    """情景记忆条目 - 代表 Agent 经历的一个事件"""
    id: str = field(default_factory=lambda: str(uuid.uuid4())[:8])
    timestamp: str = field(default_factory=lambda: datetime.utcnow().isoformat())
    event_type: str = ""           # 事件类型:tool_call / user_interaction / observation
    actor: str = ""                # 执行者:agent / user / environment / tool
    action: str = ""               # 执行的动作
    context: dict = field(default_factory=dict)  # 上下文信息
    outcome: str = ""              # 结果描述
    emotion_tag: str = "neutral"   # 情感标记:success / failure / surprise / frustration
    causal_parent: Optional[str] = None  # 因果父事件 ID
    metadata: dict = field(default_factory=dict)
    
    def to_graph_node(self) -> dict:
        """转换为图数据库节点"""
        return {
            "id": self.id,
            "labels": ["Episode", self.event_type],
            "properties": {
                "timestamp": self.timestamp,
                "actor": self.actor,
                "action": self.action,
                "outcome": self.outcome,
                "emotion": self.emotion_tag,
                "context_json": json.dumps(self.context)
            }
        }
    
    def to_graph_relationship(self) -> dict:
        """生成因果关系到图数据库"""
        if self.causal_parent:
            return {
                "from": self.causal_parent,
                "to": self.id,
                "type": "CAUSED_BY",
                "properties": {"timestamp": self.timestamp}
            }
        return None

class EpisodicMemory:
    """
    情景记忆管理器
    
    设计灵感:Tulving 的情景记忆理论
    - 每个事件都有时空背景(when + where)
    - 事件之间通过因果链相连
    - 记忆提取依赖于"心理时间旅行"(Mental Time Travel)
    """
    
    def __init__(self, graph_db, vector_index):
        self.graph = graph_db          # 图数据库(Neo4j / Dgraph)
        self.vector_index = vector_index  # 向量索引(用于语义搜索)
    
    def record(self, episode: Episode):
        """记录一个新事件到情景记忆"""
        # 1. 写入图数据库
        node = episode.to_graph_node()
        self.graph.create_node(node)
        
        rel = episode.to_graph_relationship()
        if rel:
            self.graph.create_relationship(rel)
        
        # 2. 生成向量嵌入用于语义搜索
        embedding = self._embed_episode(episode)
        self.vector_index.upsert(
            id=episode.id,
            vector=embedding,
            metadata={
                "timestamp": episode.timestamp,
                "event_type": episode.event_type,
                "emotion": episode.emotion_tag
            }
        )
    
    def mental_time_travel(self, when: str = None, emotion: str = None, 
                          semantic_query: str = None, top_k: int = 5) -> list[Episode]:
        """
        心理时间旅行:情景记忆的核心提取机制
        
        三种提取路径(对应认知科学的三种情景记忆提取):
        1. 时间导航:按时间线回溯
        2. 情感导航:按情感标记搜索
        3. 语义导航:按语义相似度搜索
        """
        results = []
        
        if when:
            # 时间导航:查找特定时间段内的事件
            results.extend(self.graph.query_episodes(
                f"MATCH (e:Episode) WHERE e.timestamp CONTAINS '{when}' "
                f"RETURN e ORDER BY e.timestamp DESC LIMIT {top_k}"
            ))
        
        if emotion:
            # 情感导航:查找特定情感标记的事件
            results.extend(self.graph.query_episodes(
                f"MATCH (e:Episode) WHERE e.emotion = '{emotion}' "
                f"RETURN e ORDER BY e.timestamp DESC LIMIT {top_k}"
            ))
        
        if semantic_query:
            # 语义导航:基于向量相似度的语义搜索
            query_embedding = self._embed_text(semantic_query)
            vector_results = self.vector_index.search(query_embedding, top_k=top_k)
            for res in vector_results:
                episode = self.graph.get_episode_by_id(res["id"])
                if episode:
                    results.append(episode)
        
        # 去重并按时间排序
        seen = set()
        unique_results = []
        for ep in results:
            if ep.id not in seen:
                seen.add(ep.id)
                unique_results.append(ep)
        
        return sorted(unique_results, key=lambda x: x.timestamp, reverse=True)[:top_k]
    
    def get_causal_chain(self, episode_id: str, depth: int = 5) -> list[Episode]:
        """获取事件的因果链(对应认知科学的情景记忆组织方式)"""
        query = f"""
        MATCH path = (e:Episode)-[:CAUSED_BY*1..{depth}]->(root:Episode)
        WHERE e.id = '{episode_id}'
        RETURN path
        """
        return self.graph.query_paths(query)
    
    def _embed_episode(self, episode: Episode) -> list[float]:
        """将事件编码为向量嵌入"""
        text = f"{episode.actor} {episode.action} {episode.outcome}. Context: {json.dumps(episode.context)}"
        return self._embed_text(text)
    
    def _embed_text(self, text: str) -> list[float]:
        """文本向量化(实际实现调用嵌入模型)"""
        # 这里简化处理,实际部署使用 sentence-transformers 或 OpenAI Embedding
        pass

3.3 生产案例:事件链压缩

在高频交互场景中,情景记忆会迅速膨胀。认知科学中的"记忆痕迹衰减"理论告诉我们:不常被访问的记忆会逐渐失去细节,但核心的因果骨架会被保留。

def consolidate_episodic_memory(memory: EpisodicMemory, 
                                 consolidation_window_days: int = 7):
    """
    情景记忆巩固:压缩旧事件同时保留因果骨架
    
    认知科学基础:
    - 海马体在睡眠期间将短期记忆转化为长期记忆
    - 巩固过程中,细节被逐渐遗忘,但核心图式被保留
    """
    cutoff_date = (datetime.utcnow() - timedelta(days=consolidation_window_days)).isoformat()
    
    # 1. 找出需要巩固的旧事件
    old_episodes = memory.graph.query_episodes(
        f"MATCH (e:Episode) WHERE e.timestamp < '{cutoff_date}' "
        f"AND e.access_count < 2 RETURN e"
    )
    
    # 2. 因果链压缩:只保留因果骨干事件
    for episode in old_episodes:
        chain = memory.get_causal_chain(episode.id, depth=3)
        
        # 识别骨架事件(在因果链中出现多次的节点)
        skeleton_nodes = _identify_skeleton(chain)
        
        # 非骨架事件的细节被压缩为摘要
        if episode.id not in skeleton_nodes:
            # 保留:id, causal_parent, outcome_emotion
            # 丢弃:完整 context, action details
            _compress_episode_details(memory, episode.id)
    
    # 3. 将频繁访问的模式泛化到语义记忆
    frequent_patterns = _detect_frequent_patterns(memory, cutoff_date)
    for pattern in frequent_patterns:
        memory.transfer_to_semantic(pattern)

四、语义记忆工程:从知识图谱到向量检索

4.1 认知意义上的语义记忆

语义记忆是 Agent 关于世界的抽象知识,不依赖于特定的经历时间。它回答了"是什么"和"为什么"的问题,而非"什么时候"和"在哪里"。

4.2 双索引架构

class SemanticMemory:
    """
    语义记忆系统
    
    认知科学启示:
    - 陈述性知识:可以快速检索的事实和概念
    - 程序性知识:如何执行任务的步骤和技能
    - 两者在脑中的存储机制不同,需要不同的工程实现
    """
    
    def __init__(self, knowledge_graph, embedding_store):
        self.kg = knowledge_graph         # 知识图谱:存储结构化知识
        self.embeddings = embedding_store  # 向量存储:支持模糊语义搜索
    
    # ========== 陈述性知识 ==========
    
    def store_fact(self, subject: str, predicate: str, 
                   object: str, confidence: float = 1.0,
                   source_episodes: list[str] = None):
        """
        存储一个事实三元组(从情景记忆泛化而来)
        
        核心设计:知识溯源
        - 每条知识都可以追溯到原始的情景记忆事件
        - 当原始事件被修正时,知识可以自动更新
        """
        triple = (subject, predicate, object)
        
        # 写入知识图谱
        self.kg.add_triple(
            *triple,
            properties={
                "confidence": confidence,
                "source_episodes": source_episodes or [],
                "created_at": datetime.utcnow().isoformat(),
                "last_verified": datetime.utcnow().isoformat()
            }
        )
        
        # 同时写入向量存储用于语义搜索
        textual_repr = f"{subject} {predicate} {object}"
        emb = self._embed(textual_repr)
        self.embeddings.upsert(
            id=f"fact_{hash(triple)}",
            vector=emb,
            metadata={
                "subject": subject,
                "predicate": predicate,
                "object": object,
                "confidence": confidence
            }
        )
    
    def query_with_reasoning(self, query: str, 
                             reasoning_depth: int = 2) -> dict:
        """
        基于知识图谱的多跳推理
        
        区别于纯向量检索:
        - 向量检索:找到语义相似但可能无关的事实
        - 知识图谱:沿着关系边进行逻辑推理
        """
        # 第一步:实体链接(将自然语言查询映射到知识图谱实体)
        entities = self._link_entities(query)
        
        if not entities:
            # 回退到向量搜索
            return self._vector_fallback_search(query)
        
        # 第二步:从链接到的实体开始多跳推理
        results = {}
        for entity in entities:
            # BFS 探索知识图谱
            neighborhood = self.kg.bfs(
                start_node=entity,
                max_depth=reasoning_depth,
                min_confidence=0.5
            )
            results[entity] = neighborhood
        
        # 第三步:将推理路径转换为自然语言答案
        answer = self._synthesize_answer(query, results)
        return {
            "answer": answer,
            "reasoning_chains": results,
            "confidence": self._calc_overall_confidence(results)
        }
    
    # ========== 程序性记忆 ==========
    
    def store_procedure(self, name: str, steps: list[dict],
                        preconditions: list[str] = None,
                        postconditions: list[str] = None,
                        success_rate: float = None):
        """
        存储程序性知识(如何完成任务)
        
        认知科学基础:
        - 程序性记忆通过反复执行而强化
        - 技能从"有意识执行"逐渐变为"自动化执行"
        """
        procedure = {
            "name": name,
            "steps": steps,  # 泛化后的步骤序列
            "preconditions": preconditions or [],
            "postconditions": postconditions or [],
            "success_rate": success_rate,
            "execution_count": 0,
            "last_successful": None
        }
        
        self.kg.add_node(
            labels=["Procedure"],
            properties=procedure
        )
    
    def select_procedure(self, goal: str, context: dict) -> Optional[dict]:
        """
        根据目标选择最合适的执行程序
        
        认知科学对应:技能选择的"针对性激活"
        - 相似目标激活相似的程序性记忆
        - 成功执行历史影响程序选择的优先级
        """
        # 基于目标语义匹配
        procedures = self.kg.query_procedures_by_goal(goal)
        
        if not procedures:
            return None
        
        # 按成功率和最近使用排序
        scored = []
        for proc in procedures:
            # 检查前置条件是否满足
            if self._check_preconditions(proc, context):
                score = (
                    proc["success_rate"] * 0.4 +
                    self._recency_score(proc) * 0.2 +
                    self._goal_similarity(goal, proc["name"]) * 0.4
                )
                scored.append((score, proc))
        
        scored.sort(key=lambda x: x[0], reverse=True)
        return scored[0][1] if scored else None
    
    def update_procedure(self, name: str, execution_result: dict):
        """
        执行后的程序性记忆更新
        
        认知科学:学习的三条定律
        - 练习律:反复执行强化记忆
        - 效果律:成功结果强化行为
        - 近因律:最近的经验影响最大
        """
        proc = self.kg.get_procedure(name)
        if not proc:
            return
        
        # 更新成功率(指数移动平均)
        alpha = 0.3
        success = 1.0 if execution_result["success"] else 0.0
        proc["success_rate"] = (
            alpha * success + (1 - alpha) * proc["success_rate"]
        )
        proc["execution_count"] += 1
        
        if execution_result["success"]:
            proc["last_successful"] = datetime.utcnow().isoformat()
            
            # 效果律:成功执行可能简化/优化步骤
            if execution_result.get("faster_path"):
                self._consider_step_optimization(proc, execution_result["faster_path"])
        
        self.kg.update_node(proc)

五、记忆巩固:从经历到知识

5.1 海马体启发的巩固机制

认知神经科学发现,人类大脑的海马体在睡眠期间扮演关键角色:它重新激活白天经历的神经模式,将这些信息从海马体(短期存储)转移到新皮层(长期存储),并与已有知识整合。

5.2 工程实现

class MemoryConsolidationEngine:
    """
    记忆巩固引擎
    
    核心功能:
    1. 事件 → 情景记忆:实时持续进行
    2. 情景 → 语义记忆:基于触发条件的批量巩固
    3. 知识更新:基于新的情景证据修正语义记忆
    """
    
    def __init__(self, working_memory: WorkingMemory, 
                 episodic_memory: EpisodicMemory,
                 semantic_memory: SemanticMemory):
        self.wm = working_memory
        self.em = episodic_memory
        self.sm = semantic_memory.kg
        self.emb_sm = semantic_memory.embeddings
        
        # 设置工作记忆的巩固回调
        self.wm.consolidation_callback = self._consolidate_from_working
    
    def _consolidate_from_working(self, item: WorkingMemoryItem):
        """工作记忆 → 情景记忆的巩固"""
        # 创建一个情景记忆条目
        episode = Episode(
            event_type=item.metadata.get("event_type", "processing"),
            actor="agent",
            action=str(item.content)[:200],
            outcome="consolidated_from_working_memory",
            emotion_tag=item.metadata.get("emotion", "neutral"),
            context={"working_memory_metadata": item.metadata}
        )
        self.em.record(episode)
    
    def run_consolidation_cycle(self, trigger: str = "scheduled"):
        """
        执行一次完整的巩固周期
        
        触发条件:
        - scheduled: 定时触发(如每天凌晨)
        - capacity_pressure: 记忆接近容量上限
        - insight_detected: 检测到值得巩固的新模式
        """
        logger.info(f"Running consolidation cycle, trigger={trigger}")
        
        # ========== Phase 1: 模式检测 ==========
        patterns = self._detect_recurrent_patterns()
        
        for pattern in patterns:
            if pattern["frequency"] >= 3:  # 至少重复3次才视为模式
                self._generalize_to_semantic(pattern)
        
        # ========== Phase 2: 知识修正 =========#
        conflicts = self._detect_knowledge_conflicts()
        for conflict in conflicts:
            self._resolve_conflict(conflict)
        
        # ========== Phase 3: 遗忘与压缩 =========
        self._apply_forgetting_curve()
        
        logger.info(f"Consolidation complete: {len(patterns)} patterns, "
                    f"{len(conflicts)} conflicts resolved")
    
    def _detect_recurrent_patterns(self) -> list[dict]:
        """
        检测反复出现的模式(海马体重放的工程对应)
        
        实现方式:
        - 在情景记忆中寻找相似的事件序列
        - 使用序列匹配或频繁子图挖掘
        """
        recent_episodes = self.em.mental_time_travel(
            when=(datetime.utcnow() - timedelta(days=7)).strftime("%Y-%m-%d")
        )
        
        # 按类型分组
        by_type = defaultdict(list)
        for ep in recent_episodes:
            by_type[ep.event_type].append(ep)
        
        patterns = []
        for event_type, episodes in by_type.items():
            if len(episodes) < 3:
                continue
            
            # 提取事件序列中的不变部分
            sequence_signature = _extract_signature(episodes)
            
            # 匹配历史中是否存在类似序列
            historical_matches = self.em.graph.find_similar_sequences(
                sequence_signature
            )
            
            if len(historical_matches) >= 2:
                patterns.append({
                    "signature": sequence_signature,
                    "frequency": len(historical_matches) + len(episodes),
                    "example_events": episodes[:3]
                })
        
        return patterns
    
    def _generalize_to_semantic(self, pattern: dict):
        """
        将泛化的模式转化为语义记忆
        
        认知科学:图式理论(Schema)
        - 反复的经历形成抽象的图式
        - 图式是去个性化、去时序化的
        """
        signature = pattern["signature"]
        examples = pattern["example_events"]
        
        # 提取泛化的规则/程序
        generalized = _generalize_from_examples(examples)
        
        if generalized["type"] == "fact":
            self.kg.store_fact(
                subject=generalized["subject"],
                predicate=generalized["predicate"],
                object=generalized["object"],
                confidence=min(0.9, pattern["frequency"] * 0.1),
                source_episodes=[ep.id for ep in examples]
            )
        elif generalized["type"] == "procedure":
            self.kg.store_procedure(
                name=generalized["name"],
                steps=generalized["steps"],
                success_rate=0.5  # 初始成功率,通过实践提高
            )
    
    def _detect_knowledge_conflicts(self) -> list[dict]:
        """检测语义记忆中的知识冲突"""
        return self.kg.query(
            """
            MATCH (a:Fact)-[:CONTRADICTS]->(b:Fact)
            RETURN a, b
            """
        )
    
    def _resolve_conflict(self, conflict: dict):
        """
        知识冲突的认知解决策略:
        1. 证据论:哪条知识有更多证据支持?
        2. 时效性:哪条知识更新?
        3. 特异性:更具体的知识一般更可靠
        """
        fact_a, fact_b = conflict
        
        # 评分机制
        score_a = fact_a["confidence"] * 0.4 + \
                  self._recency_score(fact_a) * 0.3 + \
                  self._specificity_score(fact_a) * 0.3
        
        score_b = fact_b["confidence"] * 0.4 + \
                  self._recency_score(fact_b) * 0.3 + \
                  self._specificity_score(fact_b) * 0.3
        
        # 降分而非删除,保留两种可能
        loser = fact_b if score_a > score_b else fact_a
        loser["confidence"] *= 0.5
    
    def _apply_forgetting_curve(self):
        """
        艾宾浩斯遗忘曲线的工程实现
        
        关键:遗忘不是简单的删除,而是降低可提取性
        - 高频访问的记忆保持高激活水平
        - 低频访问但高重要性的记忆标记为"待复习"
        - 既低频又不重要的记忆自然衰减
        """
        all_facts = self.kg.get_all_facts()
        
        for fact in all_facts:
            days_since_access = (datetime.utcnow() - 
                               datetime.fromisoformat(fact["last_accessed"])).days
            
            # 艾宾浩斯遗忘公式: R = e^{-t/S}
            # R: 记忆保留率, t: 时间, S: 记忆强度
            S = fact["access_count"] * 0.3 + fact["confidence"] * 2.0
            retention = math.exp(-days_since_access / S)
            
            # 衰减对象的嵌入权重(降低搜索优先级但不删除)
            self.emb_sm.update_weight(fact["id"], weight=retention)
            
            # 如果保留率过低且非核心知识,标记为可清理
            if retention < 0.1 and fact["confidence"] < 0.3:
                fact["archived"] = True
                self.kg.update_node(fact)

六、系统集成:统一记忆接口

6.1 Agent 的"自我"

class CognitiveMemorySystem:
    """
    认知记忆系统 - Agent 的统一记忆接口
    
    封装三层记忆,对外提供统一的操作接口
    
    类脑对应:
    - 工作记忆 ≈ 前额叶皮层的执行控制
    - 情景记忆 ≈ 海马体的事件记录
    - 语义记忆 ≈ 新皮层的抽象知识存储
    """
    
    def __init__(self, config: dict):
        self.working = WorkingMemory(
            capacity=config.get("wm_capacity", 9),
            decay_rate=config.get("wm_decay", 0.05)
        )
        self.episodic = EpisodicMemory(
            graph_db=config["graph_db"],
            vector_index=config["episodic_vector_index"]
        )
        self.semantic = SemanticMemory(
            knowledge_graph=config["kg"],
            embedding_store=config["semantic_vector_index"]
        )
        self.consolidation = MemoryConsolidationEngine(
            self.working, self.episodic, self.semantic
        )
    
    # ========== 输入接口 ==========
    
    def experience(self, event_type: str, action: str, 
                   context: dict, outcome: str):
        """记录一段经历 → 情景记忆 + 工作记忆"""
        # 情景记忆
        episode = Episode(
            event_type=event_type,
            actor="agent",
            action=action,
            context=context,
            outcome=outcome,
            emotion_tag=_classify_emotion(outcome)
        )
        self.episodic.record(episode)
        
        # 进入工作记忆
        wm_item = WorkingMemoryItem(
            content=episode,
            attention=AttentionLevel.ACTIVE,
            metadata={"emotion": episode.emotion_tag, "event_type": event_type}
        )
        self.working.attend(wm_item)
    
    # ========== 提取接口 ==========
    
    def recall(self, query: str, context: dict = None,
               recall_strategy: str = "auto") -> dict:
        """
        统一的记忆召回入口
        
        提取策略(对应认知科学的双重过程理论):
        - fast: 直觉式 → 工作记忆直接匹配(Type 1)
        - slow: 深思式 → 语义记忆推理(Type 2)
        - auto: 自动选择(先快后慢)
        """
        results = {"working_memory": None, "episodic": None, "semantic": None}
        
        if recall_strategy in ["fast", "auto"]:
            # 先在工作记忆中查找(快速通道)
            wm_result = self.working.focus_on(query)
            results["working_memory"] = wm_result
        
        if recall_strategy in ["slow", "auto"] or results["working_memory"] is None:
            # 工作记忆未命中,启动慢速搜索
            if _is_factual_query(query):
                # 事实型查询 → 语义记忆
                semantic_result = self.semantic.query_with_reasoning(query)
                results["semantic"] = semantic_result
            else:
                # 经验型查询 → 情景记忆
                episodic_results = self.episodic.mental_time_travel(
                    semantic_query=query
                )
                results["episodic"] = episodic_results
        
        return results
    
    # ========== 维护接口 ==========
    
    def consolidate(self, trigger: str = "manual"):
        """触发记忆巩固(可从定时任务调用)"""
        self.consolidation.run_consolidation_cycle(trigger)
    
    def sleep(self):
        """
        模拟睡眠周期的记忆整理(可部署在低峰期定时任务)
        
        认知科学发现:
        - 慢波睡眠:海马体-新皮层对话,短期记忆巩固为长期记忆
        - REM 睡眠:情绪记忆处理和创造性关联
        """
        logger.info("Entering sleep-like consolidation cycle...")
        
        # 阶段1:因果链重放与压缩(慢波睡眠)
        self.consolidation.run_consolidation_cycle(trigger="sleep")
        
        # 阶段2:跨域关联发现(REM 睡眠的类联想加工)
        self._discover_cross_domain_associations()
        
        # 阶段3:工作记忆初始化(为新的一天做准备)
        self.working.items.clear()
        
        logger.info("Sleep cycle complete, working memory refreshed")

七、工程部署考量

7.1 存储技术选型

记忆层 推荐技术 选型理由
工作内存 Redis / 内存 极低延迟,天然支持 TTL 驱逐
情景记忆 Neo4j / Dgraph 原生图存储,高效关系查询
语义记忆 知识图谱 + pgvector 结构化推理 + 语义搜索双模式
向量索引 Milvus / Qdrant 混合检索(向量 + 元数据过滤)

7.2 延迟与一致性权衡

写入路径(在线):
  传感器输入 → 工作记忆 (5ms) → 异步写入情景记忆
  
读取路径(在线):
  查询 → 工作记忆检查 (2ms) → 语义记忆检索 (50ms) → 融合返回

异步路径(离线):
  巩固任务 → 批量处理情景记忆 → 提取模式 → 更新语义记忆

7.3 监控指标

MEMORY_METRICS = {
    # 工作记忆指标
    "wm.hit_rate": "工作记忆中直接命中的比例",
    "wm.capacity_usage": "当前工作记忆使用率",
    "wm.consolidation_rate": "每秒巩固到长期记忆的事件数",
    
    # 情景记忆指标  
    "em.recall_latency_p99": "情景记忆召回延迟 P99",
    "em.causal_chain_depth": "平均因果链长度",
    "em.storage_growth": "情景记忆日增长率",
    
    # 语义记忆指标
    "sm.fact_count": "知识库中的事实总数",
    "sm.confidence_avg": "知识平均置信度",
    "sm.conflict_count": "待解决的知识冲突数",
    
    # 巩固指标
    "consolidation.patterns_detected": "每次巩固发现的模式数",
    "consolidation.knowledge_growth": "每次巩固新增的知识条数",
}

八、未来方向

8.1 本体感觉记忆(Proprioceptive Memory)

除认知记忆外,Agent 还需要关于"自身能力"的元认知记忆——知道自己擅长什么、不擅长什么、刚从中学到了什么。这对应于认知科学中的元认知系统。

8.2 社会记忆(Social Memory)

多 Agent 系统中,共享记忆(Shared Memory)将成为关键基础设施。认知科学中的分布式认知(Distributed Cognition)理论为此提供了框架。

8.3 遗忘的主动利用

当前 AI 系统往往视遗忘为敌人,但认知科学表明,遗忘是一种适应性功能——它帮助系统抵抗过时信息的干扰,保持知识的泛化能力。可学习的遗忘机制(Learnable Forgetting)将是下一个研究热点。


总结

从认知科学的视角重构 AI Agent 记忆系统,不仅仅是换一个理论框架,而是带来了根本性的架构变化:

  1. 分层而非扁平:不同类型的记忆需要不同的数据结构、检索算法和更新策略
  2. 动态而非静态:记忆是持续转化的过程(工作记忆 → 情景记忆 → 语义记忆),不是一次性的存储检索
  3. 受控遗忘而非无限保留:像人类一样,Agent 需要主动遗忘无关信息以保持决策效率
  4. 因果理解而非统计相关:通过情景记忆的因果链组织,Agent 能够理解"为什么"而不只是记住"是什么"

工程上,这种架构已经可以在现有技术栈上实现:图数据库处理情景记忆,向量索引支持语义检索,知识图谱支撑推理,工作内存使用 Redis 缓存。关键在于这三个记忆子系统之间的协调接口和巩固机制——这是让 Agent 从"一次性问答机"进化为"持续学习者"的关键基础设施。

点赞(0) 打赏

评论列表 共有 0 条评论

暂无评论
立即
投稿

微信公众账号

微信扫一扫加关注

发表
评论
返回
顶部