AI Agent Harness Engineering 的记忆系统:短期记忆与长期记忆的实现

摘要/引言

你是否曾经想过,如果人工智能能够像人类一样记忆和学习,那将会是怎样的情景?在科幻电影中,我们经常看到拥有完美记忆的AI角色,它们能够回忆起每一个细节,从过去的经历中学习,并根据这些记忆做出决策。如今,这不再仅仅是科幻想象——随着AI Agent技术的快速发展,构建具有复杂记忆系统的人工智能实体正在成为现实。

问题陈述

在构建能够执行复杂任务、与环境持续交互的AI Agent时,记忆系统是一个核心挑战。人类的记忆系统精巧而复杂,分为感觉记忆、短期记忆和长期记忆,每种记忆都有其独特的特点和作用。而对于AI Agent来说,如何设计和实现一个高效、灵活且可扩展的记忆系统,使其能够存储、检索和利用信息,仍然是一个亟待解决的难题。

传统的AI系统往往缺乏有效的记忆机制,它们在处理任务时往往只能依赖当前的输入,而无法有效地利用过去的经验。这使得它们在处理需要长期规划、上下文理解和持续学习的任务时表现不佳。

核心价值

本文将深入探讨AI Agent记忆系统的设计与实现,特别是短期记忆和长期记忆的工作原理和技术方案。通过阅读本文,你将:

  1. 理解人类记忆系统与AI记忆系统的类比与区别
  2. 掌握短期记忆和长期记忆的核心概念和实现技术
  3. 学习如何设计一个完整的AI Agent记忆系统架构
  4. 获取可实践的代码示例和实现细节
  5. 了解记忆系统在实际AI Agent应用中的最佳实践

无论你是AI研究者、工程师,还是对这一领域感兴趣的技术爱好者,本文都将为你提供宝贵的见解和实用的指导。

文章概述

本文将按照以下结构展开:首先,我们将介绍AI Agent记忆系统的基本概念和理论基础;然后,我们将深入探讨短期记忆和长期记忆的实现技术;接着,我们将通过一个完整的案例研究,展示如何将这些技术应用到实际项目中;最后,我们将总结要点,并展望AI Agent记忆系统的未来发展方向。

正文

一、AI Agent记忆系统概述

核心概念

在深入探讨短期记忆和长期记忆的实现之前,我们首先需要理解AI Agent记忆系统的基本概念。AI Agent的记忆系统可以被定义为一种结构化的信息存储和检索机制,它使Agent能够:

  1. 存储经验:保存与环境交互过程中产生的信息
  2. 检索知识:在需要时快速访问相关信息
  3. 学习适应:基于过去的经验改进行为和决策
  4. 保持连贯:在长时间交互中保持上下文的一致性

与人类记忆类似,AI Agent的记忆系统也可以按照信息存储的时长和特点进行分类。通常,我们将其分为以下几个层次:

  1. 感觉记忆:极短时间内保存原始感知数据
  2. 短期记忆:短时间内保存有限容量的信息
  3. 长期记忆:长时间保存几乎无限容量的信息

这种分类方式借鉴了认知心理学中的记忆模型,但在AI实现中,我们需要根据技术特点进行调整和优化。

问题背景

AI Agent记忆系统的研究受到了多个领域的启发和影响,包括认知心理学、神经科学、计算机科学和人工智能等。让我们简要回顾一下这个领域的发展背景:

认知心理学视角
早在20世纪60年代,认知心理学家Atkinson和Shiffrin就提出了记忆的多存储模型,将记忆分为感觉记忆、短期记忆和长期记忆三个阶段。这一模型为后来AI记忆系统的设计提供了重要的理论基础。

神经科学视角
神经科学研究表明,人类大脑中的海马体在记忆形成和巩固过程中起着关键作用,而大脑皮层则负责长期记忆的存储。这些发现启发了AI研究者设计类似的记忆巩固机制。

AI发展视角
早期的AI系统,如专家系统,采用符号化的知识表示和推理方式,但缺乏灵活的记忆机制。随着深度学习的兴起,神经网络显示出了强大的模式识别能力,但在长期记忆和推理方面仍有局限。近年来,结合神经网络和外部记忆结构的研究成为热点,如记忆网络、神经图灵机等。

问题描述

设计和实现AI Agent的记忆系统面临着多个挑战:

  1. 容量与效率的平衡:记忆系统需要能够存储大量信息,同时又要保证检索的效率
  2. 信息的组织与索引:如何有效地组织记忆内容,使得相关信息能够被快速找到
  3. 记忆的更新与遗忘:如何处理新信息的加入,以及何时移除不再重要的信息
  4. 上下文理解与关联:如何理解信息之间的关联,并在适当的情境中唤起相关记忆
  5. 泛化与抽象:如何从具体经验中提取抽象知识,以便在新情境中应用

这些挑战相互关联,需要我们在设计记忆系统时综合考虑。

AI Agent记忆系统的概念结构与核心要素组成

一个完整的AI Agent记忆系统通常包含以下核心要素:

  1. 记忆存储:负责信息的物理或逻辑存储
  2. 记忆编码:将感知信息转换为可存储的表示形式
  3. 记忆索引:创建高效的索引结构,便于信息检索
  4. 记忆检索:根据当前情境和需求,查找相关信息
  5. 记忆更新:添加新信息,修改现有信息,或移除过时信息
  6. 记忆巩固:将短期记忆转换为长期记忆的过程
  7. 记忆遗忘:选择性地清除不重要的信息,避免记忆过载

这些要素相互作用,共同构成了一个功能完整的记忆系统。在接下来的章节中,我们将详细探讨短期记忆和长期记忆的具体实现方式。

二、短期记忆的实现

核心概念

短期记忆(Short-Term Memory, STM)是AI Agent记忆系统中的一个关键组件,它负责在短时间内保存和处理有限容量的信息。在认知心理学中,短期记忆有时也被称为工作记忆,强调其在信息处理中的积极作用。

对于AI Agent而言,短期记忆具有以下核心特点:

  1. 有限容量:只能同时保存有限数量的信息项
  2. 短暂保持:信息在没有复述的情况下只能保持较短时间
  3. 活跃处理:与当前任务和推理过程紧密关联
  4. 易受干扰:新信息的进入容易导致旧信息的丢失

短期记忆在AI Agent中起着至关重要的作用,它是连接感知、推理和行动的桥梁,使Agent能够在处理复杂任务时保持上下文的连贯性。

短期记忆的数学模型

为了更好地理解和实现短期记忆,我们可以借助一些数学模型来描述其特性。以下是几个常用的模型:

1. 缓冲器模型

短期记忆可以被建模为一个固定大小的缓冲器,新信息进入时,旧信息可能会被挤出:

Mt={[It,Mt−1[0..N−2]]if ∣Mt−1∣=N[It,Mt−1]otherwiseM_t = \begin{cases} [I_t, M_{t-1}[0..N-2]] & \text{if } |M_{t-1}| = N \\ [I_t, M_{t-1}] & \text{otherwise} \end{cases}Mt={[It,Mt1[0..N2]][It,Mt1]if Mt1=Notherwise

其中,MtM_tMt表示时刻ttt的记忆状态,ItI_tIt表示时刻ttt的输入,NNN表示缓冲器的容量。

2. 激活衰减模型

这个模型认为记忆项具有不同的激活水平,激活水平随时间衰减,当激活水平低于阈值时,记忆项就会被遗忘:

ai(t)=ai(t0)⋅e−λ(t−t0)+∑t′∈Tiδ(t−t′)a_i(t) = a_i(t_0) \cdot e^{-\lambda(t-t_0)} + \sum_{t' \in T_i} \delta(t-t')ai(t)=ai(t0)eλ(tt0)+tTiδ(tt)

其中,ai(t)a_i(t)ai(t)表示记忆项iii在时刻ttt的激活水平,λ\lambdaλ表示衰减率,TiT_iTi表示记忆项iii被重新激活的时刻集合,δ\deltaδ表示脉冲函数。

3. 相似性干扰模型

这个模型考虑了记忆项之间的相互干扰,相似的记忆项会相互影响:

ri=si∑jsj+βr_i = \frac{s_i}{\sum_j s_j + \beta}ri=jsj+βsi

其中,rir_iri表示记忆项iii的可检索性,sis_isi表示记忆项iii与当前线索的相似性,β\betaβ表示干扰参数。

这些数学模型为我们实现短期记忆提供了理论指导,我们可以根据具体应用场景选择合适的模型或进行组合。

短期记忆的算法实现

基于上述模型,我们可以设计多种短期记忆的实现算法。以下是几种常用的算法:

1. 队列(FIFO)算法

这是最简单的短期记忆实现方式,使用先进先出队列来存储信息:

新信息输入

队列已满?

移除最早的信息

直接添加

更新队列

等待下一输入

这种方法实现简单,但缺乏灵活性,没有考虑信息的重要性。

2. 最近最少使用(LRU)算法

LRU算法会根据信息的使用情况来决定保留哪些信息,最近使用过的信息更有可能被保留:

新信息输入

信息已存在?

移到最前面

缓存已满?

移除最后一项

添加到最前面

更新使用记录

等待下一输入

LRU算法在很多场景下都表现良好,但它只考虑了使用时间,没有考虑信息的重要性。

3. 基于激活度的算法

这种算法为每个记忆项分配一个激活度,根据激活度来决定记忆的保留和检索:

新信息输入

计算与现有记忆的关联

更新相关记忆的激活度

添加新记忆项并初始化激活度

激活度低于阈值的项?

移除这些项

衰减所有记忆项的激活度

等待下一输入

基于激活度的算法更加灵活,可以综合考虑多种因素,但实现也更复杂。

短期记忆的Python实现

让我们通过Python代码来实现一个基于激活度的短期记忆系统:

import time
import numpy as np
from typing import List, Dict, Any, Tuple

class ShortTermMemory:
    def __init__(self, capacity: int = 10, decay_rate: float = 0.05, 
                 threshold: float = 0.1, similarity_weight: float = 0.3):
        """
        初始化短期记忆系统
        
        参数:
            capacity: 记忆容量上限
            decay_rate: 激活度衰减率
            threshold: 遗忘阈值
            similarity_weight: 相似性对激活度的影响权重
        """
        self.capacity = capacity
        self.decay_rate = decay_rate
        self.threshold = threshold
        self.similarity_weight = similarity_weight
        self.memories: List[Dict[str, Any]] = []  # 存储记忆项
        self.last_update = time.time()  # 上次更新时间
    
    def _compute_similarity(self, item1: Any, item2: Any) -> float:
        """
        计算两个记忆项之间的相似度
        
        参数:
            item1: 第一个记忆项
            item2: 第二个记忆项
            
        返回:
            相似度分数(0-1之间)
        """
        # 这里简化处理,实际应用中可以使用更复杂的相似度计算方法
        # 如余弦相似度、编辑距离等
        if isinstance(item1, str) and isinstance(item2, str):
            # 对于字符串,计算Jaccard相似度
            set1 = set(item1.lower().split())
            set2 = set(item2.lower().split())
            if not set1 or not set2:
                return 0.0
            return len(set1.intersection(set2)) / len(set1.union(set2))
        elif isinstance(item1, (int, float)) and isinstance(item2, (int, float)):
            # 对于数值,计算归一化距离
            max_val = max(abs(item1), abs(item2), 1e-10)
            return 1.0 - abs(item1 - item2) / max_val
        else:
            # 其他类型,直接比较是否相等
            return 1.0 if item1 == item2 else 0.0
    
    def _decay_activations(self):
        """衰减所有记忆项的激活度"""
        current_time = time.time()
        time_delta = current_time - self.last_update
        
        for memory in self.memories:
            # 指数衰减
            memory['activation'] *= np.exp(-self.decay_rate * time_delta)
        
        self.last_update = current_time
    
    def add(self, content: Any, metadata: Dict[str, Any] = None) -> int:
        """
        添加新的记忆项
        
        参数:
            content: 记忆内容
            metadata: 额外的元数据
            
        返回:
            新记忆项的索引
        """
        self._decay_activations()  # 先进行衰减
        
        # 计算新记忆项与现有记忆项的相似度,并更新相关记忆的激活度
        max_similarity = 0.0
        for memory in self.memories:
            similarity = self._compute_similarity(content, memory['content'])
            if similarity > 0.1:  # 只有相似度足够高时才影响
                memory['activation'] += similarity * self.similarity_weight
                max_similarity = max(max_similarity, similarity)
        
        # 初始化新记忆项的激活度
        initial_activation = 1.0 - max_similarity * 0.5  # 避免重复内容
        
        # 创建新记忆项
        new_memory = {
            'content': content,
            'metadata': metadata or {},
            'activation': initial_activation,
            'timestamp': time.time()
        }
        
        # 添加到记忆列表
        self.memories.append(new_memory)
        
        # 如果超出容量,移除激活度最低的项
        if len(self.memories) > self.capacity:
            self._remove_lowest_activation()
        
        # 移除激活度低于阈值的项
        self._forget_below_threshold()
        
        return len(self.memories) - 1
    
    def retrieve(self, query: Any, top_k: int = 5) -> List[Tuple[Any, float, Dict[str, Any]]]:
        """
        根据查询检索相关记忆
        
        参数:
            query: 查询内容
            top_k: 返回的最大结果数
            
        返回:
            记忆内容、激活度和元数据的列表
        """
        self._decay_activations()  # 先进行衰减
        
        # 计算查询与每个记忆项的匹配度
        results = []
        for memory in self.memories:
            similarity = self._compute_similarity(query, memory['content'])
            # 综合考虑相似度和激活度
            relevance = similarity * 0.7 + memory['activation'] * 0.3
            results.append((memory['content'], relevance, memory['metadata']))
        
        # 按相关性排序
        results.sort(key=lambda x: x[1], reverse=True)
        
        return results[:top_k]
    
    def _remove_lowest_activation(self):
        """移除激活度最低的记忆项"""
        if self.memories:
            min_idx = min(range(len(self.memories)), key=lambda i: self.memories[i]['activation'])
            del self.memories[min_idx]
    
    def _forget_below_threshold(self):
        """移除激活度低于阈值的记忆项"""
        self.memories = [m for m in self.memories if m['activation'] >= self.threshold]
    
    def get_all(self) -> List[Dict[str, Any]]:
        """获取所有记忆项(用于调试)"""
        self._decay_activations()
        return sorted(self.memories, key=lambda x: x['activation'], reverse=True)
    
    def clear(self):
        """清空所有记忆"""
        self.memories = []

这个实现包含了短期记忆的核心功能,包括添加记忆、检索记忆、激活度衰减和遗忘机制。在实际应用中,我们可以根据具体需求对其进行扩展和优化。

短期记忆的实际应用场景

短期记忆在AI Agent中有许多实际应用场景:

  1. 对话系统:在多轮对话中,短期记忆可以帮助系统理解上下文,记住之前的对话内容。
  2. 任务规划:在执行复杂任务时,短期记忆可以保存中间步骤和子目标。
  3. 状态跟踪:在与环境交互过程中,短期记忆可以跟踪环境状态的变化。
  4. 实时决策:在需要快速决策的场景中,短期记忆可以提供最近的相关信息。

例如,在一个客服对话系统中,短期记忆可以用来记住用户最近提到的问题、偏好和需求,从而提供更加个性化和连贯的服务。

三、长期记忆的实现

核心概念

长期记忆(Long-Term Memory, LTM)是AI Agent记忆系统中负责长期存储信息的组件。与短期记忆相比,长期记忆具有以下特点:

  1. 大容量:能够存储几乎无限量的信息
  2. 持久性:信息可以长期保存,甚至永久保存
  3. 结构化:信息通常以某种结构化的方式组织
  4. 联想性:信息之间存在关联,可以通过联想检索

在认知心理学中,长期记忆通常被进一步分为陈述性记忆(关于事实和事件的记忆)和程序性记忆(关于如何做事情的记忆)。在AI Agent中,我们可以借鉴这种分类,但也需要根据技术特点进行调整。

长期记忆的知识表示

长期记忆的一个关键问题是如何表示和组织知识。以下是几种常用的知识表示方法:

1. 语义网络

语义网络使用节点和边来表示概念和它们之间的关系:

is_a

is_a

is_a

instance_of

instance_of

can_do

can_do

ANIMAL

MAMMAL

DOG

CAT

FIDO

WHISKERS

BARKING

MEOWING

语义网络直观易懂,适合表示分类学知识和简单关系,但在处理复杂逻辑和不确定性时有局限。

2. 框架/脚本

框架(Frame)是一种结构化的知识表示方法,用于表示典型情境和对象:

# 简化的框架表示示例
restaurant_frame = {
    "name": "Restaurant",
    "slots": {
        "name": {"type": "str", "required": True},
        "cuisine": {"type": "str", "required": True},
        "location": {"type": "tuple", "required": False},
        "price_range": {"type": "int", "constraint": "1-5", "required": False},
        "menu": {"type": "list", "required": False}
    },
    "default_values": {
        "price_range": 3
    },
    "relations": {
        "is_a": "Business",
        "sells": "Food",
        "has_part": ["Kitchen", "Dining_Area"]
    }
}

脚本(Script)是框架的一种扩展,用于表示事件序列:

# 简化的脚本表示示例
restaurant_script = {
    "name": "Eating_at_Restaurant",
    "scene": "Restaurant",
    "roles": ["Customer", "Waiter", "Cook", "Cashier"],
    "props": ["Menu", "Table", "Food", "Check", "Money"],
    "events": [
        "Entering",
        "Seating",
        "Ordering",
        "Waiting",
        "Eating",
        "Paying",
        "Leaving"
    ],
    "entry_conditions": [
        "Customer is hungry",
        "Customer has money"
    ],
    "results": [
        "Customer is not hungry",
        "Customer has less money",
        "Restaurant has more money"
    ]
}

框架和脚本适合表示结构化知识和典型情境,但在处理灵活性和例外情况时可能不够。

3. 本体

本体(Ontology)是一种更加正式和结构化的知识表示方法,它定义了概念、关系和公理:

Thing

Entity

Event

Agent

Object

Person

Organization

Location

Artifact

Action

State

Communicative_Action

Physical_Action

本体具有严格的逻辑基础,适合知识共享和推理,但构建和维护成本较高。

4. 向量嵌入

随着深度学习的发展,向量嵌入(Vector Embedding)成为一种流行的知识表示方法:

embed:X→Rd\text{embed}: \mathcal{X} \rightarrow \mathbb{R}^dembed:XRd

其中,X\mathcal{X}X是输入空间,Rd\mathbb{R}^dRdddd维向量空间。

向量嵌入将各种类型的信息(文本、图像、音频等)映射到连续的向量空间中,使得相似的信息在向量空间中距离较近。这种表示方法非常适合语义检索和相似度计算。

长期记忆的数学模型

长期记忆的数学模型通常关注知识的组织、存储和检索。以下是几个重要的模型:

1. 联想记忆模型

联想记忆模型基于赫布学习规则(Hebb’s Rule),强调同时激活的神经元之间的连接会增强:

Δwij=η⋅ai⋅aj\Delta w_{ij} = \eta \cdot a_i \cdot a_jΔwij=ηaiaj

其中,Δwij\Delta w_{ij}Δwij是神经元iiijjj之间连接权重的变化,η\etaη是学习率,aia_iaiaja_jaj分别是神经元iiijjj的激活水平。

Hopfield网络是一种经典的联想记忆模型,它可以存储和检索模式:

E=−12∑i,jwijsisj+∑iθisiE = -\frac{1}{2} \sum_{i,j} w_{ij} s_i s_j + \sum_i \theta_i s_iE=21i,jwijsisj+iθisi

其中,EEE是能量函数,wijw_{ij}wij是连接权重,sis_isi是神经元状态,θi\theta_iθi是阈值。

2. 向量空间模型

向量空间模型将每个记忆项表示为一个向量,通过计算向量之间的相似度来进行检索:

sim(v⃗i,v⃗j)=v⃗i⋅v⃗j∥v⃗i∥∥v⃗j∥\text{sim}(\vec{v}_i, \vec{v}_j) = \frac{\vec{v}_i \cdot \vec{v}_j}{\|\vec{v}_i\| \|\vec{v}_j\|}sim(v i,v j)=v i∥∥v jv iv j

其中,sim\text{sim}sim是余弦相似度,v⃗i\vec{v}_iv iv⃗j\vec{v}_jv j是两个向量。

近年来,随着深度学习的发展,我们可以使用神经网络来学习高质量的向量表示,如Word2Vec、GloVe、BERT等。

3. 图神经网络模型

图神经网络(Graph Neural Networks, GNNs)可以处理图结构的数据,非常适合表示和推理结构化知识:

hv(k+1)=σ(Wk∑u∈N(v)hu(k)∣N(v)∣+Bkhv(k))\mathbf{h}_v^{(k+1)} = \sigma\left(\mathbf{W}_k \sum_{u \in \mathcal{N}(v)} \frac{\mathbf{h}_u^{(k)}}{|\mathcal{N}(v)|} + \mathbf{B}_k \mathbf{h}_v^{(k)}\right)hv(k+1)=σ WkuN(v)N(v)hu(k)+Bkhv(k)

其中,hv(k)\mathbf{h}_v^{(k)}hv(k)是节点vvv在第kkk层的表示,N(v)\mathcal{N}(v)N(v)是节点vvv的邻居,Wk\mathbf{W}_kWkBk\mathbf{B}_kBk是参数矩阵,σ\sigmaσ是激活函数。

长期记忆的算法实现

长期记忆的实现需要考虑存储、索引、检索和更新等多个方面。以下是几种关键算法:

1. 向量索引算法

对于向量嵌入表示的记忆,我们需要高效的索引算法来支持最近邻搜索:

KD树

球树

LSH

HNSW

记忆向量集合

构建索引结构

索引类型选择

构建KD树

构建球树

构建LSH哈希表

构建HNSW图

优化索引结构

保存索引

查询向量

加载索引

执行近似最近邻搜索

返回最相似的记忆

不同的索引算法有不同的优缺点,我们需要根据数据规模和查询需求进行选择。

2. 记忆巩固算法

记忆巩固是将短期记忆转换为长期记忆的过程:

重要性低

重要性中

重要性高

效果好

效果差

短期记忆

记忆重要性评估

直接遗忘

定期回放

立即巩固

回放效果评估

编码为长期记忆

与现有记忆关联

更新索引结构

记忆巩固算法可以帮助AI Agent选择性地保存重要信息,避免记忆过载。

3. 知识图谱构建与推理算法

对于结构化知识,我们可以使用知识图谱来表示和推理:

原始数据

信息抽取

实体识别

关系抽取

实体链接

关系整合

知识图谱构建

知识图谱补全

图谱嵌入

推理查询

答案生成

知识图谱可以支持复杂的推理查询,但构建和维护成本较高。

长期记忆的Python实现

让我们通过Python代码来实现一个基于向量嵌入和知识图谱的长期记忆系统:

import numpy as np
import networkx as nx
from typing import List, Dict, Any, Tuple, Optional
from sklearn.feature_extraction.text import TfidfVectorizer
from sklearn.metrics.pairwise import cosine_similarity
import faiss  # 用于高效向量检索
import json

class LongTermMemory:
    def __init__(self, embedding_dim: int = 300, use_faiss: bool = True):
        """
        初始化长期记忆系统
        
        参数:
            embedding_dim: 向量嵌入维度
            use_faiss: 是否使用FAISS进行高效检索
        """
        self.embedding_dim = embedding_dim
        self.use_faiss = use_faiss
        
        # 向量记忆部分
        self.vector_memories: List[Dict[str, Any]] = []
        self.vectorizer = TfidfVectorizer(max_features=embedding_dim)  # 简化的嵌入方法
        self.embedding_matrix: Optional[np.ndarray] = None
        self.faiss_index: Optional[faiss.Index] = None
        
        # 知识图谱部分
        self.kg = nx.DiGraph()
        
        # ID映射
        self.next_id = 0
    
    def _get_embedding(self, text: str) -> np.ndarray:
        """
        获取文本的向量嵌入
        
        参数:
            text: 输入文本
            
        返回:
            向量嵌入
        """
        if not self.vector_memories:
            # 没有记忆时,返回随机向量
            return np.random.randn(1, self.embedding_dim)
        
        # 简单的TF-IDF嵌入
        texts = [m['content'] for m in self.vector_memories] + [text]
        tfidf_matrix = self.vectorizer.fit_transform(texts)
        return tfidf_matrix[-1].toarray()
    
    def _update_vector_index(self):
        """更新向量索引"""
        if not self.vector_memories:
            return
        
        # 更新嵌入矩阵
        texts = [m['content'] for m in self.vector_memories]
        tfidf_matrix = self.vectorizer.fit_transform(texts)
        self.embedding_matrix = tfidf_matrix.toarray()
        
        # 更新FAISS索引(如果使用)
        if self.use_faiss:
            self.faiss_index = faiss.IndexFlatL2(self.embedding_dim)
            self.faiss_index.add(self.embedding_matrix.astype('float32'))
    
    def add_vector_memory(self, content: str, metadata: Dict[str, Any] = None, 
                         source: str = "observation") -> int:
        """
        添加向量记忆
        
        参数:
            content: 记忆内容
            metadata: 额外的元数据
            source: 记忆来源
            
        返回:
            记忆ID
        """
        memory_id = self.next_id
        self.next_id += 1
        
        # 创建记忆项
        memory = {
            'id': memory_id,
            'content': content,
            'metadata': metadata or {},
            'source': source,
            'timestamp': None,  # 这里可以添加时间戳
            'access_count': 0,
            'importance': 0.5  # 初始重要性
        }
        
        self.vector_memories.append(memory)
        self._update_vector_index()
        
        return memory_id
    
    def retrieve_vector_memory(self, query: str, top_k: int = 5, 
                               threshold: float = 0.0) -> List[Dict[str, Any]]:
        """
        检索向量记忆
        
        参数:
            query: 查询文本
            top_k: 返回的最大结果数
            threshold: 相似度阈值
            
        返回:
            相关记忆列表
        """
        if not self.vector_memories:
            return []
        
        query_embedding = self._get_embedding(query)
        
        if self.use_faiss and self.faiss_index is not None:
            # 使用FAISS进行检索
            distances, indices = self.faiss_index.search(
                query_embedding.astype('float32'), min(top_k * 2, len(self.vector_memories))
            )
            
            # 转换为相似度分数
            similarities = 1 / (1 + distances[0])
            
            # 准备结果
            results = []
            for idx, sim in zip(indices[0], similarities):
                if sim >= threshold and len(results) < top_k:
                    memory = self.vector_memories[idx].copy()
                    memory['similarity'] = sim
                    memory['access_count'] += 1  # 更新访问计数
                    results.append(memory)
            
            return results
        else:
            # 使用简单的余弦相似度
            similarities = cosine_similarity(query_embedding, self.embedding_matrix)[0]
            
            # 排序并返回结果
            result_indices = np.argsort(similarities)[::-1]
            results = []
            for idx in result_indices:
                if similarities[idx] >= threshold and len(results) < top_k:
                    memory = self.vector_memories[idx].copy()
                    memory['similarity'] = similarities[idx]
                    memory['access_count'] += 1  # 更新访问计数
                    results.append(memory)
            
            return results
    
    def add_kg_entity(self, entity_id: str, entity_type: str, 
                     attributes: Dict[str, Any] = None) -> bool:
        """
        添加知识图谱实体
        
        参数:
            entity_id: 实体ID
            entity_type: 实体类型
            attributes: 实体属性
            
        返回:
            是否成功添加
        """
        if entity_id in self.kg:
            # 实体已存在,更新属性
            if attributes:
                for key, value in attributes.items():
                    self.kg.nodes[entity_id][key] = value
            return False
        
        # 添加新实体
        self.kg.add_node(entity_id, type=entity_type, **(attributes or {}))
        return True
    
    def add_kg_relation(self, subject_id: str, object_id: str, 
                       relation_type: str, attributes: Dict[str, Any] = None) -> bool:
        """
        添加知识图谱关系
        
        参数:
            subject_id: 主体实体ID
            object_id: 客体实体ID
            relation_type: 关系类型
            attributes: 关系属性
            
        返回:
            是否成功添加
        """
        # 确保实体存在
        if subject_id not in self.kg:
            self.add_kg_entity(subject_id, "Unknown")
        if object_id not in self.kg:
            self.add_kg_entity(object_id, "Unknown")
        
        # 添加关系
        self.kg.add_edge(subject_id, object_id, type=relation_type, **(attributes or {}))
        return True
    
    def query_kg(self, query: Dict[str, Any]) -> List[Dict[str, Any]]:
        """
        查询知识图谱
        
        参数:
            query: 查询条件
            
        返回:
            查询结果
        """
        # 简化的查询实现
        results = []
        
        # 根据查询类型执行不同的查询
        if 'entity_type' in query:
            # 查询特定类型的实体
            for node, attrs in self.kg.nodes(data=True):
                if attrs.get('type') == query['entity_type']:
                    results.append({
                        'type': 'entity',
                        'id': node,
                        'attributes': attrs
                    })
        
        if 'relation_type' in query:
            # 查询特定类型的关系
            for u, v, attrs in self.kg.edges(data=True):
                if attrs.get('type') == query['relation_type']:
                    results.append({
                        'type': 'relation',
                        'subject': u,
                        'object': v,
                        'attributes': attrs
                    })
        
        if 'subject' in query and 'relation' in query:
            # 查询特定主体和关系的客体
            subject = query['subject']
            relation = query['relation']
            for u, v, attrs in self.kg.edges(data=True):
                if u == subject and attrs.get('type') == relation:
                    results.append({
                        'type': 'entity',
                        'id': v,
                        'attributes': self.kg.nodes[v]
                    })
        
        return results
    
    def consolidate_memory(self, short_term_memories: List[Dict[str, Any]], 
                          importance_threshold: float = 0.6):
        """
        巩固记忆,将短期记忆转换为长期记忆
        
        参数:
            short_term_memories: 短期记忆列表
            importance_threshold: 重要性阈值
        """
        for stm in short_term_memories:
            # 简单的重要性评估
            importance = stm.get('activation', 0.5)  # 使用激活度作为重要性指标
            
            # 可以添加更多的重要性评估因素
            # 例如:新奇性、情绪价值、与目标的相关性等
            
            if importance >= importance_threshold:
                # 添加到向量记忆
                content = str(stm.get('content', ''))
                metadata = stm.get('metadata', {})
                metadata['importance'] = importance
                metadata['original_activation'] = stm.get('activation', 0.5)
                
                memory_id = self.add_vector_memory(content, metadata, source="consolidation")
                
                # 尝试提取知识图谱信息(简化处理)
                # 在实际应用中,可以使用更复杂的信息抽取技术
                if 'entities' in metadata:
                    for entity in metadata['entities']:
                        self.add_kg_entity(entity['id'], entity.get('type', 'Unknown'))
                        
                        # 添加与记忆的关系
                        self.add_kg_relation(f"memory_{memory_id}", entity['id'], "mentions")
    
    def save(self, filepath: str):
        """
        保存长期记忆到文件
        
        参数:
            filepath: 文件路径
        """
        data = {
            'vector_memories': self.vector_memories,
            'kg_nodes': dict(self.kg.nodes(data=True)),
            'kg_edges': [(u, v, d) for u, v, d in self.kg.edges(data=True)],
            'next_id': self.next_id
        }
        
        with open(filepath, 'w', encoding='utf-8') as f:
            json.dump(data, f, ensure_ascii=False, indent=2)
    
    def load(self, filepath: str):
        """
        从文件加载长期记忆
        
        参数:
            filepath: 文件路径
        """
        with open(filepath, 'r', encoding='utf-8') as f:
            data = json.load(f)
        
        # 加载向量记忆
        self.vector_memories = data['vector_memories']
        self.next_id = data['next_id']
        
        # 重建知识图谱
        self.kg = nx.DiGraph()
        for node, attrs in data['kg_nodes'].items():
            self.kg.add_node(node, **attrs)
        for u, v, attrs in data['kg_edges']:
            self.kg.add_edge(u, v, **attrs)
        
        # 更新向量索引
        self._update_vector_index()

这个实现结合了向量记忆和知识图谱,提供了长期记忆的基本功能,包括添加记忆、检索记忆、记忆巩固和知识图谱操作。在实际应用中,我们可以使用更先进的嵌入方法(如BERT、Sentence-Transformers等)和更强大的图数据库(如Neo4j)来增强系统的能力。

长期记忆的实际应用场景

长期记忆在AI Agent中有广泛的应用场景:

  1. 用户建模:记住用户的偏好、习惯和历史行为,提供个性化服务
  2. 领域知识库:存储特定领域的事实知识,支持问答和推理
  3. 经验学习:保存过去的成功和失败经验,用于改进未来的决策
  4. 实体和关系记忆:记住现实世界中的实体及其关系,支持常识推理
  5. 任务记忆:记住过去执行过的任务和步骤,用于迁移学习

例如,在一个个人助理AI Agent中,长期记忆可以记住用户的日程安排、喜欢的餐厅、朋友的生日等信息,从而提供更加智能化的服务。

四、短期记忆与长期记忆的交互

核心概念

短期记忆和长期记忆并不是孤立工作的,它们之间存在着密切的交互。这种交互对于AI Agent的认知能力至关重要,类似于人类记忆系统中工作记忆与长期记忆的协同工作。

短期记忆与长期记忆的交互主要体现在以下几个方面:

  1. 编码与存储:短期记忆中的信息经过编码后可以存储到长期记忆中
  2. 检索与激活:长期记忆中的信息可以被检索并激活到短期记忆中
  3. 巩固与转化:通过复述和联想,短期记忆可以转化为长期记忆
  4. 上下文关联:当前情境(短期记忆)可以作为线索,帮助检索相关的长期记忆

理解这种交互机制对于设计高效的AI Agent记忆系统至关重要。

记忆交互的数学模型

我们可以用数学模型来描述短期记忆和长期记忆之间的交互:

1. 激活扩散模型

激活扩散模型描述了信息如何在记忆系统中传播和激活:

ai(t+1)=ai(t)+∑j∈N(i)wij⋅aj(t)−λ⋅ai(t)a_i(t+1) = a_i(t) + \sum_{j \in \mathcal{N}(i)} w_{ij} \cdot a_j(t) - \lambda \cdot a_i(t)ai(t+1)=ai(t)+jN(i)wijaj(t)λai(t)

其中,ai(t)a_i(t)ai(t)是记忆项iii在时刻ttt的激活度,N(i)\mathcal{N}(i)N(i)是记忆项iii的邻居,wijw_{ij}wij是连接权重,λ\lambdaλ是衰减率。

2. 记忆转移模型

记忆转移模型描述了信息在短期记忆和长期记忆之间的转移:

ΔMstm=E−C+R\Delta M_{stm} = E - C + RΔMstm=EC+R
ΔMltm=C−F\Delta M_{ltm} = C - FΔMltm=CF

其中,EEE是从环境进入短期记忆的信息,CCC是从短期记忆转移到长期记忆的信息,RRR是从长期记忆检索到短期记忆的信息,FFF是从长期记忆中遗忘的信息。

记忆交互的算法实现

以下是实现短期记忆和长期记忆交互的关键算法:

1. 记忆编码与巩固算法

感知输入

短期记忆存储

复述/处理?

激活增强

激活衰减

达到巩固阈值?

编码为长期记忆

激活>遗忘阈值?

从短期记忆中移除

与现有记忆关联

更新长期记忆索引

2. 基于上下文的记忆检索算法

当前情境

提取检索线索

短期记忆中的相关信息

生成查询表示

检索长期记忆

初步候选集

根据短期记忆上下文重排序

选择最相关的记忆

激活并添加到短期记忆

更新记忆激活度

完整记忆系统的Python实现

现在,让我们将短期记忆和长期记忆结合起来,实现一个完整的记忆系统:

import time
from typing import List, Dict, Any, Optional
import numpy as np

# 假设我们已经有了之前定义的ShortTermMemory和LongTermMemory类

class UnifiedMemorySystem:
    def __init__(self, stm_capacity: int = 10, stm_decay_rate: float = 0.05,
                 ltm_embedding_dim: int = 300, consolidation_threshold: float = 0.7,
                 retrieval_trigger: float = 0.5):
        """
        初始化统一记忆系统
        
        参数:
            stm_capacity: 短期记忆容量
            stm_decay_rate: 短期记忆衰减率
            ltm_embedding_dim: 长期记忆嵌入维度
            consolidation_threshold: 记忆巩固阈值
            retrieval_trigger: 检索触发阈值
        """
        # 初始化短期记忆
        self.stm = ShortTermMemory(
            capacity=stm_capacity,
            decay_rate=stm_decay_rate
        )
        
        # 初始化长期记忆
        self.ltm = LongTermMemory(
            embedding_dim=ltm_embedding_dim
        )
        
        # 参数设置
        self.consolidation_threshold = consolidation_threshold
        self.retrieval_trigger = retrieval_trigger
        
        # 上下文状态
        self.current_context = {}
        self.last_retrieval_time = 0
    
    def perceive(self, content: Any, metadata: Dict[str, Any] = None,
                importance: float = 0.5):
        """
        感知并处理新信息
        
        参数:
            content: 感知内容
            metadata: 额外的元数据
            importance: 重要性评分
        """
        #
Logo

Agent 垂直技术社区,欢迎活跃、内容共建。

更多推荐