AI Agent Harness Engineering 记忆机制解析:短期记忆、长期记忆与上下文管理

关键词

  • AI Agent
  • 记忆机制
  • 短期记忆
  • 长期记忆
  • 上下文管理
  • 提示工程
  • 检索增强生成

摘要

本文深入探讨AI Agent系统中的记忆机制设计与实现,将其类比为人类记忆系统,详细解析短期记忆、长期记忆以及上下文管理的核心概念、技术原理和工程实践。我们将通过一步步推理的方式,从基础概念到高级应用,全面剖析如何构建高效的AI Agent记忆系统。文章包含丰富的代码示例、数学模型、架构设计和实际应用场景,为AI工程师和研究者提供完整的记忆机制工程指南。


1. 背景介绍

1.1 主题背景和重要性

在人工智能技术快速发展的今天,AI Agent(人工智能代理)正逐渐成为下一代智能系统的核心形态。与传统的静态模型不同,AI Agent具备感知环境、做出决策、执行行动并从经验中学习的能力,这使得它们能够完成更加复杂和动态的任务。

然而,要实现真正的智能行为,一个关键的挑战是如何让AI Agent记住过去的经历、知识和交互。就像人类如果失去记忆将无法正常生活一样,AI Agent如果缺乏有效的记忆机制,也只能在每个任务上"重新开始",无法积累经验,无法进行连贯的对话,更无法实现真正的长期规划和学习。

记忆机制是AI Agent系统的核心组件之一,它决定了Agent能否:

  • 维持对话的连贯性
  • 从历史交互中学习
  • 存储和检索领域知识
  • 制定和执行长期计划
  • 适应个性化需求

1.2 目标读者

本文主要面向以下读者:

  • AI工程师和研究者,希望构建具备记忆能力的AI Agent系统
  • 产品经理和技术决策者,了解记忆机制对AI应用的价值
  • 对AI前沿技术感兴趣的开发者和爱好者
  • 自然语言处理和机器学习领域的学生和学者

我们假设读者具备基本的机器学习和编程知识,但会用通俗易懂的方式解释复杂概念。

1.3 核心问题或挑战

在设计AI Agent的记忆系统时,我们面临着几个核心挑战:

  1. 记忆容量限制:如同人类大脑无法记住所有细节,AI模型也有上下文窗口的限制,如何在有限容量内存储和检索最相关的信息?

  2. 记忆时效性:不同信息的重要性随时间变化,如何确定哪些信息应该保留,哪些应该遗忘?

  3. 记忆组织与索引:如何结构化存储记忆,使得在需要时能够高效检索?

  4. 上下文连贯性:如何在多轮交互中保持上下文的一致性,避免"失忆"现象?

  5. 个性化适应:如何让记忆系统适应不同用户的特点和偏好?

在接下来的章节中,我们将一步步解析这些问题,并提供工程化的解决方案。


2. 核心概念解析

2.1 使用生活化比喻解释关键概念

让我们先通过一个生活化的比喻来理解AI Agent的记忆系统。想象你是一位咖啡馆的咖啡师,每天接待各种各样的顾客:

  • 短期记忆:就像你正在制作一杯咖啡时,记得顾客要的是拿铁还是美式,要加多少糖,是否需要外带。这些信息只在当前交互中有用,完成订单后可能很快就会忘记。

  • 长期记忆:就像你记得常客王先生总是在每周三下午3点左右来,喜欢喝不加糖的冰美式,而且他对猫毛过敏,所以你会确保他的座位附近没有猫。这些信息会长期保存,每次王先生来都能派上用场。

  • 上下文管理:就像你在同时接待几位顾客时,能够分清谁点了什么,谁在等待,谁已经结账离开。你会根据当前情况调整注意力,确保每位顾客都能得到连贯的服务。

  • 记忆检索:就像当一位顾客提到"上次我在这里喝的那杯带有果香的咖啡"时,你能够回忆起那是一款哥伦比亚单品手冲,然后为他再次准备。

这个比喻虽然简单,但抓住了AI Agent记忆系统的核心要素。现在让我们更深入地解析这些概念。

2.2 概念间的关系和相互作用

2.2.1 核心概念定义

短期记忆(Short-Term Memory, STM)

  • 也称为工作记忆(Working Memory)
  • 存储当前任务相关的临时信息
  • 容量有限,持续时间短
  • 直接参与当前的推理和决策过程

长期记忆(Long-Term Memory, LTM)

  • 存储积累的知识、经验和历史交互
  • 容量大,持续时间长
  • 需要通过检索机制才能使用
  • 可以进一步分为程序性记忆(技能)和陈述性记忆(事实)

上下文管理(Context Management)

  • 负责在不同记忆组件间协调信息流动
  • 决定哪些信息进入短期记忆,哪些存入长期记忆
  • 管理对话或任务的连贯性
  • 处理信息的优先级和时效性

记忆检索(Memory Retrieval)

  • 从长期记忆中找到与当前任务相关的信息
  • 基于相似度、时效性、重要性等因素排序
  • 将检索到的信息注入到当前上下文中

记忆巩固(Memory Consolidation)

  • 将短期记忆中的重要信息转化为长期记忆
  • 可能涉及信息的抽象、总结和重组
  • 决定哪些信息值得长期保存
2.2.2 概念间的关系

这些记忆组件不是孤立工作的,而是形成一个相互协作的系统:

[环境输入/用户交互] → [感知处理] → [短期记忆] 
                                          ↓
[生成响应/执行动作] ← [推理决策] ← [上下文管理]
                                          ↑
                                    [记忆检索] ← [长期记忆]
                                          ↑
                                    [记忆巩固] ← [短期记忆]

这个流程说明了信息如何在系统中流动:

  1. 环境输入首先被处理并进入短期记忆
  2. 上下文管理器决定需要哪些额外信息
  3. 从长期记忆中检索相关信息
  4. 结合所有信息进行推理和决策
  5. 同时,重要的短期记忆被巩固到长期记忆中

2.3 概念结构与核心要素组成

2.3.1 短期记忆的核心要素

短期记忆系统通常包含以下核心要素:

  1. 上下文窗口(Context Window):模型能够直接处理的最大token数量,如GPT-4的8K或32K版本
  2. 对话历史(Dialog History):最近的交互记录
  3. 当前任务状态(Current Task State):任务执行的进度和中间结果
  4. 即时感知(Instant Perception):当前环境的最新信息
2.3.2 长期记忆的核心要素

长期记忆系统通常包含:

  1. 记忆库(Memory Bank):存储记忆项的数据库或向量存储
  2. 记忆编码(Memory Encoder):将记忆内容转化为可存储和检索的表示
  3. 索引结构(Index Structure):用于高效检索的数据结构
  4. 元数据(Metadata):关于记忆的附加信息,如时间戳、重要性评分等
2.3.3 上下文管理的核心要素

上下文管理系统通常包含:

  1. 信息优先级(Information Prioritization):评估信息重要性的机制
  2. 信息时效性(Information Temporal Relevance):评估信息新旧程度的机制
  3. 上下文压缩(Context Compression):减少信息占用空间的技术
  4. 上下文选择(Context Selection):选择最相关信息的策略

2.4 概念核心属性维度对比

让我们通过一个表格来对比这些核心概念的关键属性:

维度短期记忆长期记忆上下文管理
主要功能临时存储当前任务信息长期保存知识和经验协调各记忆组件,优化信息使用
容量有限(通常几千到几万token)近乎无限不直接存储信息,而是管理信息流
持续时间短暂(当前会话或任务)长期(跨会话)持续进行
访问速度极快(直接访问)较慢(需要检索)取决于管理的组件
信息类型原始、详细、即时抽象、概括、结构化所有类型的信息
遗忘机制自然脱落(超出窗口)主动遗忘或衰减动态调整优先级
与推理关系直接参与推理通过检索间接参与影响推理的信息基础
实现复杂度较低较高最高
关键挑战容量限制检索相关性信息平衡与协调

2.5 概念联系的ER实体关系图

uses

uses

controls

provides_info

retrieves_from

manages

stores_to

AI_AGENT

string

agent_id

string

name

string

purpose

SHORT_TERM_MEMORY

string

memory_id

list

content

int

token_count

timestamp

created_at

timestamp

expires_at

LONG_TERM_MEMORY

string

memory_id

string

content

vector

embedding

float

importance

timestamp

created_at

int

access_count

CONTEXT_MANAGER

string

manager_id

list

prioritization_rules

list

retrieval_strategies

int

max_context_size

2.6 交互关系图

长期记忆上下文管理器短期记忆AI Agent用户长期记忆上下文管理器短期记忆AI Agent用户alt[需要长期存储]发送请求/问题将最新交互存入短期记忆请求上下文管理查询当前上下文返回当前对话历史和状态请求相关记忆检索返回相关记忆优化和整合上下文提供最终上下文生成响应更新短期记忆评估是否需要长期存储存储重要信息返回响应

3. 技术原理与实现

3.1 算法或系统工作原理

3.1.1 短期记忆工作原理

短期记忆主要是通过维护一个固定大小的上下文窗口来工作的。当新信息到来时,它会被添加到窗口中;当窗口满了,最旧的信息会被移出("先进先出"原则),或者根据某些策略移除最不相关的信息。

从技术角度看,短期记忆通常实现为一个简单的列表或队列结构,每个元素代表一个交互轮次或信息片段。

3.1.2 长期记忆工作原理

长期记忆的工作原理更为复杂,通常涉及以下步骤:

  1. 记忆编码:将原始信息转换为向量嵌入(embeddings)或其他结构化表示
  2. 记忆存储:将编码后的记忆存储在向量数据库或其他索引结构中
  3. 记忆索引:构建索引以便高效检索
  4. 记忆检索:根据查询找到最相关的记忆
  5. 记忆更新:随着时间推移更新记忆的重要性评分或元数据

现代长期记忆系统通常基于向量相似性搜索,这使得它们能够找到语义上相关的记忆,而不仅仅是关键词匹配。

3.1.3 上下文管理工作原理

上下文管理是一个决策系统,它不断回答以下问题:

  • 当前上下文中应该包含哪些信息?
  • 哪些信息应该从短期记忆移到长期记忆?
  • 当需要更多信息时,应该如何从长期记忆中检索?
  • 如何在有限的上下文窗口中平衡不同类型的信息?

上下文管理器通常使用启发式规则、强化学习或其他决策算法来做出这些决定。

3.2 数学模型解释

3.2.1 记忆重要性评分

我们可以使用一个数学模型来计算记忆的重要性评分,这个评分可以帮助决定哪些信息应该保留在短期记忆中,哪些应该被存储到长期记忆中,以及在检索时如何排序。

I(m,t)=α⋅R(m)+β⋅T(m,t)+γ⋅F(m) I(m, t) = \alpha \cdot R(m) + \beta \cdot T(m, t) + \gamma \cdot F(m) I(m,t)=αR(m)+βT(m,t)+γF(m)

其中:

  • I(m,t)I(m, t)I(m,t) 是记忆 mmm 在时间 ttt 的重要性评分
  • R(m)R(m)R(m) 是记忆 mmm 的内在相关性(基于内容和当前任务)
  • T(m,t)T(m, t)T(m,t) 是记忆 mmm 的时效性因子(随时间衰减)
  • F(m)F(m)F(m) 是记忆 mmm 的频率因子(被访问的频繁程度)
  • α,β,γ\alpha, \beta, \gammaα,β,γ 是权重系数,满足 α+β+γ=1\alpha + \beta + \gamma = 1α+β+γ=1

时效性因子可以定义为:
T(m,t)=e−λ⋅(t−tm) T(m, t) = e^{-\lambda \cdot (t - t_m)} T(m,t)=eλ(ttm)
其中 tmt_mtm 是记忆创建的时间,λ\lambdaλ 是衰减率。

3.2.2 向量相似度计算

在长期记忆检索中,我们通常使用向量相似度来找到最相关的记忆。最常用的相似度度量是余弦相似度:

cosine similarity(a,b)=a⋅b∥a∥∥b∥=∑i=1naibi∑i=1nai2∑i=1nbi2 \text{cosine similarity}(a, b) = \frac{a \cdot b}{\|a\| \|b\|} = \frac{\sum_{i=1}^{n} a_i b_i}{\sqrt{\sum_{i=1}^{n} a_i^2} \sqrt{\sum_{i=1}^{n} b_i^2}} cosine similarity(a,b)=a∥∥bab=i=1nai2i=1nbi2i=1naibi

其中 aaabbb 是两个向量,a⋅ba \cdot bab 是它们的点积,∥a∥\|a\|a∥b∥\|b\|b 是它们的范数。

3.2.3 上下文优化模型

上下文管理可以建模为一个优化问题,目标是在有限的上下文窗口中选择最有价值的信息组合:

max⁡S⊆M∑m∈SI(m,t) \max_{S \subseteq M} \sum_{m \in S} I(m, t) SMmaxmSI(m,t)

subject to:∑m∈SC(m)≤Cmax \text{subject to:} \sum_{m \in S} C(m) \leq C_{\text{max}} subject to:mSC(m)Cmax

其中:

  • MMM 是所有可用记忆的集合
  • SSS 是选中的记忆子集
  • C(m)C(m)C(m) 是记忆 mmm 的成本(如token数量)
  • CmaxC_{\text{max}}Cmax 是上下文窗口的最大容量

这是一个经典的背包问题,可以通过动态规划或启发式算法解决。

3.3 算法流程图

让我们通过Mermaid流程图来表示记忆系统的核心算法:

3.3.1 记忆处理流程

用户交互

环境感知

内部推理

接收新信息

判断信息类型

添加到对话历史

更新当前状态

记录思考过程

信息编码

是否超出短期记忆容量?

添加到短期记忆

评估记忆重要性

移除最不重要的记忆

被移除的记忆是否重要?

转移到长期记忆

丢弃

结束

3.3.2 记忆检索流程

语义检索

关键词检索

时间检索

接收检索请求

分析检索意图

生成查询向量

检索类型?

计算向量相似度

倒排索引查找

按时间范围过滤

获取初步候选集

综合评分排序

应用多样性过滤

选择Top-K结果

格式化检索结果

注入到上下文中

返回检索结果

3.4 算法源代码

接下来,让我们通过Python代码来实现这些核心算法。我们将创建一个简化但功能完整的AI Agent记忆系统。

3.4.1 基础记忆类结构
from abc import ABC, abstractmethod
from typing import List, Dict, Any, Optional, Tuple
from dataclasses import dataclass, field
from datetime import datetime
import numpy as np
from sklearn.metrics.pairwise import cosine_similarity
import json


@dataclass
class MemoryItem:
    """表示一个记忆项的基本数据结构"""
    id: str
    content: str
    embedding: Optional[np.ndarray] = None
    metadata: Dict[str, Any] = field(default_factory=dict)
    created_at: datetime = field(default_factory=datetime.now)
    last_accessed: datetime = field(default_factory=datetime.now)
    access_count: int = 0
    importance: float = 0.5  # 初始重要性评分 0-1


class BaseMemory(ABC):
    """记忆系统的抽象基类"""
    
    @abstractmethod
    def add(self, item: MemoryItem) -> str:
        """添加一个记忆项"""
        pass
    
    @abstractmethod
    def get(self, item_id: str) -> Optional[MemoryItem]:
        """根据ID获取记忆项"""
        pass
    
    @abstractmethod
    def retrieve(self, query: str, top_k: int = 5) -> List[MemoryItem]:
        """检索相关记忆"""
        pass
    
    @abstractmethod
    def update(self, item_id: str, **kwargs) -> bool:
        """更新记忆项"""
        pass
    
    @abstractmethod
    def delete(self, item_id: str) -> bool:
        """删除记忆项"""
        pass
3.4.2 短期记忆实现
class ShortTermMemory(BaseMemory):
    """短期记忆实现"""
    
    def __init__(self, max_tokens: int = 4000, token_estimator=None):
        self.max_tokens = max_tokens
        self.token_estimator = token_estimator or self._estimate_tokens
        self.memories: Dict[str, MemoryItem] = {}
        self.order: List[str] = []  # 保持记忆的顺序
        self.current_tokens = 0
    
    def _estimate_tokens(self, text: str) -> int:
        """估算文本的token数量(简化实现)"""
        # 实际应用中应使用模型特定的tokenizer
        return len(text.split())  # 简化:按单词数估算
    
    def _update_token_count(self):
        """更新当前使用的token总数"""
        self.current_tokens = sum(
            self.token_estimator(mem.content) 
            for mem in self.memories.values()
        )
    
    def _make_room_if_needed(self, required_tokens: int):
        """如果需要,移除最旧的记忆以腾出空间"""
        while (self.current_tokens + required_tokens > self.max_tokens 
               and self.order):
            oldest_id = self.order.pop(0)
            oldest_item = self.memories.pop(oldest_id)
            self.current_tokens -= self.token_estimator(oldest_item.content)
    
    def add(self, item: MemoryItem) -> str:
        """添加一个记忆项到短期记忆"""
        required_tokens = self.token_estimator(item.content)
        
        # 如果单个记忆项就超过了容量,我们仍然尝试添加它
        # 但可能需要移除其他所有记忆
        if required_tokens > self.max_tokens:
            # 清空记忆
            self.memories.clear()
            self.order.clear()
            self.current_tokens = 0
        else:
            # 为新记忆腾出空间
            self._make_room_if_needed(required_tokens)
        
        # 添加新记忆
        self.memories[item.id] = item
        self.order.append(item.id)
        self.current_tokens += required_tokens
        
        return item.id
    
    def get(self, item_id: str) -> Optional[MemoryItem]:
        """根据ID获取记忆项"""
        if item_id in self.memories:
            item = self.memories[item_id]
            item.access_count += 1
            item.last_accessed = datetime.now()
            return item
        return None
    
    def retrieve(self, query: str = None, top_k: int = 5) -> List[MemoryItem]:
        """检索短期记忆(按最新顺序)"""
        # 短期记忆通常按时间顺序检索,最新的在前
        items = [self.memories[id] for id in reversed(self.order)]
        
        # 更新访问信息
        for item in items[:top_k]:
            item.access_count += 1
            item.last_accessed = datetime.now()
        
        return items[:top_k]
    
    def get_all_in_order(self) -> List[MemoryItem]:
        """按顺序获取所有短期记忆"""
        return [self.memories[id] for id in self.order]
    
    def update(self, item_id: str, **kwargs) -> bool:
        """更新记忆项"""
        if item_id not in self.memories:
            return False
        
        item = self.memories[item_id]
        for key, value in kwargs.items():
            if hasattr(item, key):
                setattr(item, key, value)
        
        # 更新token计数(如果内容改变了)
        if 'content' in kwargs:
            self._update_token_count()
        
        return True
    
    def delete(self, item_id: str) -> bool:
        """删除记忆项"""
        if item_id not in self.memories:
            return False
        
        removed_item = self.memories.pop(item_id)
        self.order.remove(item_id)
        self.current_tokens -= self.token_estimator(removed_item.content)
        
        return True
    
    def clear(self):
        """清空短期记忆"""
        self.memories.clear()
        self.order.clear()
        self.current_tokens = 0
3.4.3 长期记忆实现
class LongTermMemory(BaseMemory):
    """长期记忆实现"""
    
    def __init__(self, embedding_model=None):
        self.embedding_model = embedding_model or self._simple_embedding
        self.memories: Dict[str, MemoryItem] = {}
        self.embeddings_matrix: Optional[np.ndarray] = None
        self.id_to_index: Dict[str, int] = {}
        self.index_to_id: Dict[int, str] = {}
    
    def _simple_embedding(self, text: str) -> np.ndarray:
        """简单的嵌入函数(实际应用中应使用真正的嵌入模型)"""
        # 这里使用简单的字符级统计作为示例
        # 实际应用中应该使用OpenAI Embeddings、Sentence-Transformers等
        embedding = np.zeros(128)  # 128维向量
        for i, char in enumerate(text):
            embedding[i % 128] += ord(char)
        # 归一化
        norm = np.linalg.norm(embedding)
        if norm > 0:
            embedding = embedding / norm
        return embedding
    
    def _update_embeddings_matrix(self):
        """更新嵌入矩阵"""
        if not self.memories:
            self.embeddings_matrix = None
            self.id_to_index = {}
            self.index_to_id = {}
            return
        
        ids = list(self.memories.keys())
        embeddings = []
        
        for i, mem_id in enumerate(ids):
            self.id_to_index[mem_id] = i
            self.index_to_id[i] = mem_id
            embeddings.append(self.memories[mem_id].embedding)
        
        self.embeddings_matrix = np.vstack(embeddings)
    
    def _calculate_importance(self, item: MemoryItem) -> float:
        """计算记忆项的重要性评分"""
        # 这里使用一个简化的重要性计算方法
        # 实际应用中可以结合更多因素
        recency_factor = 1.0 / (1.0 + (datetime.now() - item.created_at).days)
        frequency_factor = min(1.0, item.access_count / 10.0)  # 假设访问10次后达到最大值
        
        # 结合多个因素
        importance = (
            0.5 * item.importance +  # 初始重要性
            0.3 * recency_factor +   # 时效性
            0.2 * frequency_factor   # 访问频率
        )
        return min(1.0, importance)  # 确保不超过1.0
    
    def add(self, item: MemoryItem) -> str:
        """添加一个记忆项到长期记忆"""
        # 生成嵌入(如果还没有)
        if item.embedding is None:
            item.embedding = self.embedding_model(item.content)
        
        # 存储记忆
        self.memories[item.id] = item
        
        # 更新嵌入矩阵
        self._update_embeddings_matrix()
        
        return item.id
    
    def get(self, item_id: str) -> Optional[MemoryItem]:
        """根据ID获取记忆项"""
        if item_id in self.memories:
            item = self.memories[item_id]
            item.access_count += 1
            item.last_accessed = datetime.now()
            return item
        return None
    
    def retrieve(self, query: str, top_k: int = 5) -> List[MemoryItem]:
        """根据查询检索相关记忆"""
        if not self.memories:
            return []
        
        # 生成查询的嵌入
        query_embedding = self.embedding_model(query).reshape(1, -1)
        
        # 计算相似度
        similarities = cosine_similarity(query_embedding, self.embeddings_matrix)[0]
        
        # 结合相似度和重要性进行排序
        scored_items = []
        for i, sim in enumerate(similarities):
            mem_id = self.index_to_id[i]
            item = self.memories[mem_id]
            importance = self._calculate_importance(item)
            
            # 综合评分:相似度 * 重要性
            score = sim * importance
            scored_items.append((score, item))
        
        # 按评分排序
        scored_items.sort(key=lambda x: x[0], reverse=True)
        
        # 更新访问信息并返回top-k
        results = []
        for score, item in scored_items[:top_k]:
            item.access_count += 1
            item.last_accessed = datetime.now()
            results.append(item)
        
        return results
    
    def update(self, item_id: str, **kwargs) -> bool:
        """更新记忆项"""
        if item_id not in self.memories:
            return False
        
        item = self.memories[item_id]
        content_updated = False
        
        for key, value in kwargs.items():
            if hasattr(item, key):
                setattr(item, key, value)
                if key == 'content':
                    content_updated = True
        
        # 如果内容更新了,重新生成嵌入
        if content_updated:
            item.embedding = self.embedding_model(item.content)
            self._update_embeddings_matrix()
        
        return True
    
    def delete(self, item_id: str) -> bool:
        """删除记忆项"""
        if item_id not in self.memories:
            return False
        
        del self.memories[item_id]
        self._update_embeddings_matrix()
        
        return True
    
    def get_all_memories(self) -> List[MemoryItem]:
        """获取所有记忆项"""
        return list(self.memories.values())
    
    def save_to_disk(self, filepath: str):
        """将长期记忆保存到磁盘"""
        data = {
            'memories': {
                mem_id: {
                    'id': mem.id,
                    'content': mem.content,
                    'embedding': mem.embedding.tolist() if mem.embedding is not None else None,
                    'metadata': mem.metadata,
                    'created_at': mem.created_at.isoformat(),
                    'last_accessed': mem.last_accessed.isoformat(),
                    'access_count': mem.access_count,
                    'importance': mem.importance
                }
                for mem_id, mem in self.memories.items()
            }
        }
        
        with open(filepath, 'w', encoding='utf-8') as f:
            json.dump(data, f, ensure_ascii=False, indent=2)
    
    def load_from_disk(self, filepath: str):
        """从磁盘加载长期记忆"""
        with open(filepath, 'r', encoding='utf-8') as f:
            data = json.load(f)
        
        for mem_id, mem_data in data['memories'].items():
            embedding = np.array(mem_data['embedding']) if mem_data['embedding'] is not None else None
            memory = MemoryItem(
                id=mem_data['id'],
                content=mem_data['content'],
                embedding=embedding,
                metadata=mem_data['metadata'],
                created_at=datetime.fromisoformat(mem_data['created_at']),
                last_accessed=datetime.fromisoformat(mem_data['last_accessed']),
                access_count=mem_data['access_count'],
                importance=mem_data['importance']
            )
            self.memories[mem_id] = memory
        
        self._update_embeddings_matrix()
3.4.4 上下文管理器实现
class ContextManager:
    """上下文管理器,协调短期和长期记忆"""
    
    def __init__(
        self, 
        short_term_memory: ShortTermMemory, 
        long_term_memory: LongTermMemory,
        max_context_tokens: int = 3000,
        consolidation_threshold: int = 5  # 交互次数阈值,触发记忆巩固
    ):
        self.stm = short_term_memory
        self.ltm = long_term_memory
        self.max_context_tokens = max_context_tokens
        self.consolidation_threshold = consolidation_threshold
        self.interaction_count = 0
        self.token_estimator = short_term_memory.token_estimator
    
    def _estimate_tokens(self, text: str) -> int:
        """估算token数量"""
        return self.token_estimator(text)
    
    def add_interaction(self, user_input: str, agent_response: str, metadata: Dict[str, Any] = None):
        """添加一次交互到记忆系统"""
        import uuid
        
        metadata = metadata or {}
        
        # 创建用户输入记忆项
        user_memory = MemoryItem(
            id=str(uuid.uuid4()),
            content=f"用户: {user_input}",
            metadata={**metadata, "type": "user_input"}
        )
        
        # 创建助手响应记忆项
        assistant_memory = MemoryItem(
            id=str(uuid.uuid4()),
            content=f"助手: {agent_response}",
            metadata={**metadata, "type": "assistant_response"}
        )
        
        # 添加到短期记忆
        self.stm.add(user_memory)
        self.stm.add(assistant_memory)
        
        # 增加交互计数
        self.interaction_count += 1
        
        # 检查是否需要进行记忆巩固
        if self.interaction_count % self.consolidation_threshold == 0:
            self._consolidate_memories()
    
    def _consolidate_memories(self):
        """将重要的短期记忆巩固到长期记忆"""
        import uuid
        
        # 获取所有短期记忆
        stm_memories = self.stm.get_all_in_order()
        
        if not stm_memories:
            return
        
        # 生成对话摘要(简化实现)
        conversation_text = "\n".join([mem.content for mem in stm_memories])
        
        # 这里应该调用摘要模型,为简化示例,我们只取前几句
        summary = f"对话摘要({datetime.now().strftime('%Y-%m-%d')}):\n{conversation_text[:500]}..."
        
        # 创建摘要记忆项
        summary_memory = MemoryItem(
            id=str(uuid.uuid4()),
            content=summary,
            metadata={"type": "conversation_summary", "turns": len(stm_memories)},
            importance=0.7  # 摘要通常比较重要
        )
        
        # 添加到长期记忆
        self.ltm.add(summary_memory)
        
        # 也可以选择性地将重要的单个交互添加到长期记忆
        # 这里简化处理,只添加摘要
    
    def build_context(self, query: str, **kwargs) -> str:
        """构建用于生成响应的上下文"""
        context_parts = []
        current_tokens = 0
        
        # 1. 首先添加系统提示(如果有)
        system_prompt = kwargs.get('system_prompt', '')
        if system_prompt:
            sys_prompt_tokens = self._estimate_tokens(system_prompt)
            if current_tokens + sys_prompt_tokens <= self.max_context_tokens:
                context_parts.append(system_prompt)
                current_tokens += sys_prompt_tokens
        
        # 2. 从长期记忆中检索相关信息
        relevant_memories = self.ltm.retrieve(query, top_k=3)
        for mem in relevant_memories:
            mem_text = f"[记忆] {mem.content}\n"
            mem_tokens = self._estimate_tokens(mem_text)
            
            if current_tokens + mem_tokens <= self.max_context_tokens:
                context_parts.append(mem_text)
                current_tokens += mem_tokens
            else:
                break
        
        # 3. 添加短期记忆(对话历史)
        # 我们按倒序添加,这样最新的对话在前
        stm_memories = self.stm.get_all_in_order()
        
        # 预留一些空间给当前查询
        query_tokens = self._estimate_tokens(f"用户: {query}\n")
        available_tokens = self.max_context_tokens - current_tokens - query_tokens
        
        # 从最新的开始添加,直到填满可用空间
        temp_parts = []
        temp_tokens = 0
        
        for mem in reversed(stm_memories):
            mem_tokens = self._estimate_tokens(mem.content + "\n")
            if temp_tokens + mem_tokens <= available_tokens:
                temp_parts.insert(0, mem.content + "\n")  # 插入到前面以保持顺序
                temp_tokens += mem_tokens
            else:
                break
        
        context_parts.extend(temp_parts)
        current_tokens += temp_tokens
        
        # 4. 最后添加当前查询
        context_parts.append(f"用户: {query}")
        
        # 合并所有部分
        return "\n".join(context_parts)
    
    def clear_short_term(self):
        """清空短期记忆(但会先尝试巩固)"""
        if self.stm.get_all_in_order():
            self._consolidate_memories()
        self.stm.clear()
    
    def get_memory_stats(self) -> Dict[str, Any]:
        """获取记忆系统统计信息"""
        return {
            'short_term_count': len(self.stm.get_all_in_order()),
            'short_term_tokens': self.stm.current_tokens,
            'long_term_count': len(self.ltm.get_all_memories()),
            'interaction_count': self.interaction_count
        }
3.4.5 使用示例

让我们看看如何使用这些组件来构建一个简单的AI Agent记忆系统:

def create_simple_agent():
    """创建一个简单的AI Agent示例"""
    # 初始化记忆组件
    stm = ShortTermMemory(max_tokens=4000)
    ltm = LongTermMemory()
    
    # 初始化上下文管理器
    context_manager = ContextManager(
        short_term_memory=stm,
        long_term_memory=ltm,
        max_context_tokens=3000,
        consolidation_threshold=3
    )
    
    return context_manager


def demonstrate_memory_system():
    """演示记忆系统的工作原理"""
    # 创建Agent
    agent = create_simple_agent()
    
    # 模拟几次对话交互
    interactions = [
        ("你好,我叫李明,我是一名软件工程师。", "你好李明!很高兴认识你。作为软件工程师,你主要使用什么编程语言?"),
        ("我主要使用Python和JavaScript开发。最近我在学习AI相关的技术。", "很好!AI是一个很有前景的领域。你具体对AI的哪个方向感兴趣?"),
        ("我对自然语言处理和AI Agent特别感兴趣。你能给我介绍一下AI Agent的记忆系统吗?", "当然可以!AI Agent的记忆系统通常包括短期记忆和长期记忆..."),
        ("谢谢你的介绍!短期记忆和长期记忆有什么区别?", "简单来说,短期记忆容量有限但访问速度快,长期记忆容量大但需要检索..."),
        ("明白了。那么如何实现一个简单的记忆系统呢?", "你可以使用我们前面讨论的方法,先实现短期记忆和长期记忆的基本功能..."),
    ]
    
    # 添加交互到记忆系统
    for user_input, agent_response in interactions:
        agent.add_interaction(user_input, agent_response)
        print(f"用户: {user_input}")
        print(f"助手: {agent_response}\n")
    
    # 打印记忆统计信息
    print("=== 记忆统计 ===")
    stats = agent.get_memory_stats()
    for key, value in stats.items():
        print(f"{key}: {value}")
    
    # 构建上下文并演示检索
    print("\n=== 构建上下文示例 ===")
    query = "我叫什么名字?我的职业是什么?"
    context = agent.build_context(query, system_prompt="你是一个有记忆能力的AI助手。")
    print(f"查询: {query}")
    print(f"构建的上下文:\n{context}\n")
    
    # 演示长期记忆的保存和加载
    print("=== 长期记忆保存/加载 ===")
    ltm_file = "long_term_memory.json"
    agent.ltm.save_to_disk(ltm_file)
    print(f"长期记忆已保存到 {ltm_file}")
    
    # 创建新的Agent并加载记忆
    new_agent = create_simple_agent()
    new_agent.ltm.load_from_disk(ltm_file)
    print(f"新的Agent已加载长期记忆,记忆数量: {len(new_agent.ltm.get_all_memories())}")
    
    # 测试新Agent的记忆检索
    print("\n=== 新Agent记忆检索测试 ===")
    new_context = new_agent.build_context("AI Agent的记忆系统包括什么?")
    print(f"构建的上下文:\n{new_context}")


if __name__ == "__main__":
    demonstrate_memory_system()

4. 实际应用

4.1 案例分析:个性化学习助手

让我们通过一个具体案例来说明如何在实际应用中使用这些记忆机制。我们将设计一个个性化学习助手,它能够记住学生的学习进度、优势、劣势和偏好,从而提供更加个性化的学习体验。

4.1.1 项目概述

我们的个性化学习助手将具备以下能力:

  • 记住学生的学习历史和进度
  • 了解学生的知识掌握情况
  • 适应学生的学习风格和偏好
  • 根据过去的交互调整教学策略
  • 提供连贯的多会话学习体验
4.1.2 环境安装

首先,我们需要安装一些必要的库:

pip install openai numpy scikit-learn chromadb python-dotenv

我们将使用:

  • OpenAI API 用于生成回复和嵌入
  • ChromaDB 作为向量数据库(用于长期记忆)
  • scikit-learn 用于计算相似度
  • python-dotenv 用于管理环境变量
4.1.3 系统功能设计

我们的学习助手系统将包含以下核心功能:

  1. 用户档案管理:创建和维护学生的学习档案
  2. 学习进度跟踪:记录学生已学习的内容和掌握程度
  3. 个性化内容推荐:根据学生的水平和偏好推荐学习材料
  4. 自适应问答:根据学生的历史表现调整问题难度和解释方式
  5. 复习提醒:根据间隔重复原则提醒学生复习
4.1.4 系统架构设计

数据存储层

AI核心层

记忆管理层

应用服务层

用户界面层

Web/移动界面

API服务

用户认证

会话管理

短期记忆管理

长期记忆管理

用户档案管理

上下文构建器

大语言模型

嵌入模型

学习规划器

内容推荐引擎

向量数据库

用户数据库

内容库

4.1.5 系统接口设计

让我们定义系统的主要API接口:

  1. 创建/更新用户档案

    POST /api/user/profile
    {
      "user_id": "string",
      "name": "string",
      "learning_style": "visual|auditory|reading|kinesthetic",
      "subjects": ["math", "physics", "cs"],
      "difficulty_preference": "beginner|intermediate|advanced"
    }
    
  2. 发送学习问题

    POST /api/learning/question
    {
      "user_id": "string",
      "session_id": "string",
      "question": "string",
      "subject": "string"
    }
    
  3. 获取学习推荐

    GET /api/learning/recommendations?user_id=string&subject=string
    
  4. 记录学习进度

    POST /api/learning/progress
    {
      "user_id": "string",
      "content_id": "string",
      "completion_status": "started|in_progress|completed",
      "understanding_level": 1-5,
      "time_spent": minutes
    }
    
4.1.6 系统核心实现源代码

下面是我们个性化学习助手的核心实现代码:

import os
import uuid
from datetime import datetime, timedelta
from typing import List, Dict, Any, Optional
from dotenv import load_dotenv
import openai
import chromadb
from chromadb.utils import embedding_functions
import numpy as np
from dataclasses import dataclass, field
import json

# 加载环境变量
load_dotenv()
openai.api_key = os.getenv("OPENAI_API_KEY")

# 初始化ChromaDB客户端
chroma_client = chromadb.Client()

# 创建OpenAI嵌入函数
openai_ef = embedding_functions.OpenAIEmbeddingFunction(
    api_key=os.getenv("OPENAI_API_KEY"),
    model_name="text-embedding-ada-00
Logo

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

更多推荐