AI Agent Harness Engineering 记忆机制解析:短期记忆、长期记忆与上下文管理
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的记忆系统时,我们面临着几个核心挑战:
-
记忆容量限制:如同人类大脑无法记住所有细节,AI模型也有上下文窗口的限制,如何在有限容量内存储和检索最相关的信息?
-
记忆时效性:不同信息的重要性随时间变化,如何确定哪些信息应该保留,哪些应该遗忘?
-
记忆组织与索引:如何结构化存储记忆,使得在需要时能够高效检索?
-
上下文连贯性:如何在多轮交互中保持上下文的一致性,避免"失忆"现象?
-
个性化适应:如何让记忆系统适应不同用户的特点和偏好?
在接下来的章节中,我们将一步步解析这些问题,并提供工程化的解决方案。
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 概念间的关系
这些记忆组件不是孤立工作的,而是形成一个相互协作的系统:
[环境输入/用户交互] → [感知处理] → [短期记忆]
↓
[生成响应/执行动作] ← [推理决策] ← [上下文管理]
↑
[记忆检索] ← [长期记忆]
↑
[记忆巩固] ← [短期记忆]
这个流程说明了信息如何在系统中流动:
- 环境输入首先被处理并进入短期记忆
- 上下文管理器决定需要哪些额外信息
- 从长期记忆中检索相关信息
- 结合所有信息进行推理和决策
- 同时,重要的短期记忆被巩固到长期记忆中
2.3 概念结构与核心要素组成
2.3.1 短期记忆的核心要素
短期记忆系统通常包含以下核心要素:
- 上下文窗口(Context Window):模型能够直接处理的最大token数量,如GPT-4的8K或32K版本
- 对话历史(Dialog History):最近的交互记录
- 当前任务状态(Current Task State):任务执行的进度和中间结果
- 即时感知(Instant Perception):当前环境的最新信息
2.3.2 长期记忆的核心要素
长期记忆系统通常包含:
- 记忆库(Memory Bank):存储记忆项的数据库或向量存储
- 记忆编码(Memory Encoder):将记忆内容转化为可存储和检索的表示
- 索引结构(Index Structure):用于高效检索的数据结构
- 元数据(Metadata):关于记忆的附加信息,如时间戳、重要性评分等
2.3.3 上下文管理的核心要素
上下文管理系统通常包含:
- 信息优先级(Information Prioritization):评估信息重要性的机制
- 信息时效性(Information Temporal Relevance):评估信息新旧程度的机制
- 上下文压缩(Context Compression):减少信息占用空间的技术
- 上下文选择(Context Selection):选择最相关信息的策略
2.4 概念核心属性维度对比
让我们通过一个表格来对比这些核心概念的关键属性:
| 维度 | 短期记忆 | 长期记忆 | 上下文管理 |
|---|---|---|---|
| 主要功能 | 临时存储当前任务信息 | 长期保存知识和经验 | 协调各记忆组件,优化信息使用 |
| 容量 | 有限(通常几千到几万token) | 近乎无限 | 不直接存储信息,而是管理信息流 |
| 持续时间 | 短暂(当前会话或任务) | 长期(跨会话) | 持续进行 |
| 访问速度 | 极快(直接访问) | 较慢(需要检索) | 取决于管理的组件 |
| 信息类型 | 原始、详细、即时 | 抽象、概括、结构化 | 所有类型的信息 |
| 遗忘机制 | 自然脱落(超出窗口) | 主动遗忘或衰减 | 动态调整优先级 |
| 与推理关系 | 直接参与推理 | 通过检索间接参与 | 影响推理的信息基础 |
| 实现复杂度 | 较低 | 较高 | 最高 |
| 关键挑战 | 容量限制 | 检索相关性 | 信息平衡与协调 |
2.5 概念联系的ER实体关系图
2.6 交互关系图
3. 技术原理与实现
3.1 算法或系统工作原理
3.1.1 短期记忆工作原理
短期记忆主要是通过维护一个固定大小的上下文窗口来工作的。当新信息到来时,它会被添加到窗口中;当窗口满了,最旧的信息会被移出("先进先出"原则),或者根据某些策略移除最不相关的信息。
从技术角度看,短期记忆通常实现为一个简单的列表或队列结构,每个元素代表一个交互轮次或信息片段。
3.1.2 长期记忆工作原理
长期记忆的工作原理更为复杂,通常涉及以下步骤:
- 记忆编码:将原始信息转换为向量嵌入(embeddings)或其他结构化表示
- 记忆存储:将编码后的记忆存储在向量数据库或其他索引结构中
- 记忆索引:构建索引以便高效检索
- 记忆检索:根据查询找到最相关的记忆
- 记忆更新:随着时间推移更新记忆的重要性评分或元数据
现代长期记忆系统通常基于向量相似性搜索,这使得它们能够找到语义上相关的记忆,而不仅仅是关键词匹配。
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−λ⋅(t−tm)
其中 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∥∥b∥a⋅b=∑i=1nai2∑i=1nbi2∑i=1naibi
其中 aaa 和 bbb 是两个向量,a⋅ba \cdot ba⋅b 是它们的点积,∥a∥\|a\|∥a∥ 和 ∥b∥\|b\|∥b∥ 是它们的范数。
3.2.3 上下文优化模型
上下文管理可以建模为一个优化问题,目标是在有限的上下文窗口中选择最有价值的信息组合:
maxS⊆M∑m∈SI(m,t) \max_{S \subseteq M} \sum_{m \in S} I(m, t) S⊆Mmaxm∈S∑I(m,t)
subject to:∑m∈SC(m)≤Cmax \text{subject to:} \sum_{m \in S} C(m) \leq C_{\text{max}} subject to:m∈S∑C(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 记忆检索流程
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 系统功能设计
我们的学习助手系统将包含以下核心功能:
- 用户档案管理:创建和维护学生的学习档案
- 学习进度跟踪:记录学生已学习的内容和掌握程度
- 个性化内容推荐:根据学生的水平和偏好推荐学习材料
- 自适应问答:根据学生的历史表现调整问题难度和解释方式
- 复习提醒:根据间隔重复原则提醒学生复习
4.1.4 系统架构设计
4.1.5 系统接口设计
让我们定义系统的主要API接口:
-
创建/更新用户档案
POST /api/user/profile { "user_id": "string", "name": "string", "learning_style": "visual|auditory|reading|kinesthetic", "subjects": ["math", "physics", "cs"], "difficulty_preference": "beginner|intermediate|advanced" } -
发送学习问题
POST /api/learning/question { "user_id": "string", "session_id": "string", "question": "string", "subject": "string" } -
获取学习推荐
GET /api/learning/recommendations?user_id=string&subject=string -
记录学习进度
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
更多推荐


所有评论(0)