8.2.1记忆系统的工作流程
在进入代码实现阶段前,我们需要先定义记忆系统的工作流程。该流程参考了认知科学中的记忆模型,并将每个认知阶段映射为具体的技术组件和操作。理解这一映射关系,有助于我们后续的代码实现。
图 8.3 记忆形成的认知过程
如图8.3所示,根据认知科学的研究,人类记忆的形成经历以下几个阶段:
- 编码(Encoding) :将感知到的信息转换为可存储的形式
- 存储(Storage) :将编码后的信息保存在记忆系统中
- 检索(Retrieval) :根据需要从记忆中提取相关信息
- 整合(Consolidation) :将短期记忆转化为长期记忆
- 遗忘(Forgetting) :删除不重要或过时的信息
基于该启发,我们为 HelloAgents 设计了一套完整的记忆系统。其核心思想是模仿人类大脑处理不同类型信息的方式,将记忆划分为多个专门的模块,并建立一套智能化的管理机制。图8.4详细展示了这套系统的工作流程,包括记忆的添加、检索、整合和遗忘等关键环节。
图 8.4 HelloAgents记忆系统的完整工作流程
我们的记忆系统由四种不同类型的记忆模块构成,每种模块都针对特定的应用场景和生命周期进行了优化:
首先是工作记忆 (Working Memory) ,它扮演着智能体“短期记忆”的角色,主要用于存储当前对话的上下文信息。为确保高速访问和响应,其容量被有意限制(例如,默认50条),并且生命周期与单个会话绑定,会话结束后便会自动清理。
其次是情景记忆 (Episodic Memory) ,它负责长期存储具体的交互事件和智能体的学习经历。与工作记忆不同,情景记忆包含了丰富的上下文信息,并支持按时间序列或主题进行回顾式检索,是智能体“复盘”和学习过往经验的基础。
与具体事件相对应的是语义记忆 (Semantic Memory) ,它存储的是更为抽象的知识、概念和规则。例如,通过对话了解到的用户偏好、需要长期遵守的指令或领域知识点,都适合存放在这里。这部分记忆具有高度的持久性和重要性,是智能体形成“知识体系”和进行关联推理的核心。
最后,为了与日益丰富的多媒体交互,我们引入了感知记忆 (Perceptual Memory) 。该模块专门处理图像、音频等多模态信息,并支持跨模态检索。其生命周期会根据信息的重要性和可用存储空间进行动态管理。
8.2.2快速体验:30秒上手记忆功能
8.2.2 快速体验:30秒上手记忆功能
在深入实现细节之前,让我们先快速体验一下记忆系统的基本功能:
from hello_agents import SimpleAgent, HelloAgentsLLM, ToolRegistry
from hello_agents.tools import MemoryTool
# 创建LLM实例
llm = HelloAgentsLLM()
# 创建记忆工具
memory_tool = MemoryTool(user_id="user123")
tool_registry = ToolRegistry()
tool_registry.register_tool(memory_tool)
# 创建具有记忆能力的Agent
agent = SimpleAgent(name="记忆助手", llm=llm, tool_registry=tool_registry)
# 体验记忆功能
print("=== 添加多个记忆 ===")
# 添加第一个记忆
result1 = memory_tool.run("add", content="用户张三是一名Python开发者,专注于机器学习和数据分析", memory_type="semantic", importance=0.8)
print(f"记忆1: {result1}")
# 添加第二个记忆
result2 = memory_tool.run("add", content="李四是前端工程师,擅长React和Vue.js开发", memory_type="semantic", importance=0.7)
print(f"记忆2: {result2}")
# 添加第三个记忆
result3 = memory_tool.run("add", content="王五是产品经理,负责用户体验设计和需求分析", memory_type="semantic", importance=0.6)
print(f"记忆3: {result3}")
print("\n=== 搜索特定记忆 ===")
# 搜索前端相关的记忆
print("🔍 搜索 '前端工程师':")
result = memory_tool.run("search", query="前端工程师", limit=3)
print(result)
print("\n=== 记忆摘要 ===")
result = memory_tool.run("summary")
print(result)
8.2.3MemoryTool详解
现在让我们采用自顶向下的方式,从MemoryTool支持的具体操作开始,逐步深入到底层实现。MemoryTool作为记忆系统的统一接口,其设计遵循了"统一入口,分发处理"的架构模式:
def execute(self, action: str, **kwargs) -> str:
"""执行记忆操作
支持的操作:
- add: 添加记忆(支持4种类型: working/episodic/semantic/perceptual)
- search: 搜索记忆
- summary: 获取记忆摘要
- stats: 获取统计信息
- update: 更新记忆
- remove: 删除记忆
- forget: 遗忘记忆(多种策略)
- consolidate: 整合记忆(短期→长期)
- clear_all: 清空所有记忆
"""
if action == "add":
return self._add_memory(**kwargs)
elif action == "search":
return self._search_memory(**kwargs)
elif action == "summary":
return self._get_summary(**kwargs)
# ... 其他操作复制到剪贴板错误已复制
这种统一的execute接口设计简化了Agent的调用方式,通过action参数指定具体操作,使用**kwargs允许每个操作有不同的参数需求。在这里我们会将比较重要的几个操作罗列出来:
(1)操作1:add
add操作是记忆系统的基础,它模拟了人类大脑将感知信息编码为记忆的过程。在实现中,我们不仅要存储记忆内容,还要为每个记忆添加丰富的上下文信息,这些信息将在后续的检索和管理中发挥重要作用。
def _add_memory(
self,
content: str = "",
memory_type: str = "working",
importance: float = 0.5,
file_path: str = None,
modality: str = None,
**metadata
) -> str:
"""添加记忆"""
try:
# 确保会话ID存在
if self.current_session_id is None:
self.current_session_id = f"session_{datetime.now().strftime('%Y%m%d_%H%M%S')}"
# 感知记忆文件支持
if memory_type == "perceptual" and file_path:
inferred = modality or self._infer_modality(file_path)
metadata.setdefault("modality", inferred)
metadata.setdefault("raw_data", file_path)
# 添加会话信息到元数据
metadata.update({
"session_id": self.current_session_id,
"timestamp": datetime.now().isoformat()
})
memory_id = self.memory_manager.add_memory(
content=content,
memory_type=memory_type,
importance=importance,
metadata=metadata,
auto_classify=False
)
return f"✅ 记忆已添加 (ID: {memory_id[:8]}...)"
except Exception as e:
return f"❌ 添加记忆失败: {str(e)}"复制到剪贴板错误已复制
这里主要实现了三个关键任务:会话ID的自动管理(确保每个记忆都有明确的会话归属)、多模态数据的智能处理(自动推断文件类型并保存相关元数据)、以及上下文信息的自动补充(为每个记忆添加时间戳和会话信息)。其中,importance参数(默认0.5)用于标记记忆的重要程度,取值范围0.0-1.0,这个机制模拟了人类大脑对不同信息重要性的评估。这种设计让Agent能够自动区分不同时间段的对话,并为后续的检索和管理提供丰富的上下文信息。
其中,对每个记忆类型,我们提供了不同的使用示例:
# 1. 工作记忆 - 临时信息,容量有限
memory_tool.run("add",
content="用户刚才问了关于Python函数的问题",
memory_type="working",
importance=0.6
)
# 2. 情景记忆 - 具体事件和经历
memory_tool.run("add",
content="2024年3月15日,用户张三完成了第一个Python项目",
memory_type="episodic",
importance=0.8,
event_type="milestone",
location="在线学习平台"
)
# 3. 语义记忆 - 抽象知识和概念
memory_tool.run("add",
content="Python是一种解释型、面向对象的编程语言",
memory_type="semantic",
importance=0.9,
knowledge_type="factual"
)
# 4. 感知记忆 - 多模态信息
memory_tool.run("add",
content="用户上传了一张Python代码截图,包含函数定义",
memory_type="perceptual",
importance=0.7,
modality="image",
file_path="./uploads/code_screenshot.png"
)复制到剪贴板错误已复制
(2)操作2:search
search操作是记忆系统的核心功能,它需要在大量记忆中快速找到与查询最相关的内容。它涉及语义理解、相关性计算和结果排序等多个环节。
def _search_memory(
self,
query: str,
limit: int = 5,
memory_types: List[str] = None,
memory_type: str = None,
min_importance: float = 0.1
) -> str:
"""搜索记忆"""
try:
# 参数标准化处理
if memory_type and not memory_types:
memory_types = [memory_type]
results = self.memory_manager.retrieve_memories(
query=query,
limit=limit,
memory_types=memory_types,
min_importance=min_importance
)
if not results:
return f"🔍 未找到与 '{query}' 相关的记忆"
# 格式化结果
formatted_results = []
formatted_results.append(f"🔍 找到 {len(results)} 条相关记忆:")
for i, memory in enumerate(results, 1):
memory_type_label = {
"working": "工作记忆",
"episodic": "情景记忆",
"semantic": "语义记忆",
"perceptual": "感知记忆"
}.get(memory.memory_type, memory.memory_type)
content_preview = memory.content[:80] + "..." if len(memory.content) > 80 else memory.content
formatted_results.append(
f"{i}. [{memory_type_label}] {content_preview} (重要性: {memory.importance:.2f})"
)
return "\n".join(formatted_results)
except Exception as e:
return f"❌ 搜索记忆失败: {str(e)}"复制到剪贴板错误已复制
搜索操作在设计上支持单数和复数两种参数形式(memory_type和memory_types),让用户以最自然的方式表达需求。其中,min_importance参数(默认0.1)用于过滤低质量记忆。对于搜索功能的使用,可以参考这个示例。
# 基础搜索
result = memory_tool.execute("search", query="Python编程", limit=5)
# 指定记忆类型搜索
result = memory_tool.execute("search",
query="学习进度",
memory_type="episodic",
limit=3
)
# 多类型搜索
result = memory_tool.execute("search",
query="函数定义",
memory_types=["semantic", "episodic"],
min_importance=0.5
)复制到剪贴板错误已复制
(3)操作3:forget
遗忘机制是最具认知科学色彩的功能,它模拟人类大脑的选择性遗忘过程,支持三种策略:基于重要性(删除不重要的记忆)、基于时间(删除过时的记忆)和基于容量(当存储接近上限时删除最不重要的记忆)。
def _forget(self, strategy: str = "importance_based", threshold: float = 0.1, max_age_days: int = 30) -> str:
"""遗忘记忆(支持多种策略)"""
try:
count = self.memory_manager.forget_memories(
strategy=strategy,
threshold=threshold,
max_age_days=max_age_days
)
return f"🧹 已遗忘 {count} 条记忆(策略: {strategy})"
except Exception as e:
return f"❌ 遗忘记忆失败: {str(e)}"复制到剪贴板错误已复制
三种遗忘策略的使用:
# 1. 基于重要性的遗忘 - 删除重要性低于阈值的记忆
memory_tool.execute("forget",
strategy="importance_based",
threshold=0.2
)
# 2. 基于时间的遗忘 - 删除超过指定天数的记忆
memory_tool.execute("forget",
strategy="time_based",
max_age_days=30
)
# 3. 基于容量的遗忘 - 当记忆数量超限时删除最不重要的
memory_tool.execute("forget",
strategy="capacity_based",
threshold=0.3
)复制到剪贴板错误已复制
(4)操作4:consolidate
def _consolidate(self, from_type: str = "working", to_type: str = "episodic", importance_threshold: float = 0.7) -> str:
"""整合记忆(将重要的短期记忆提升为长期记忆)"""
try:
count = self.memory_manager.consolidate_memories(
from_type=from_type,
to_type=to_type,
importance_threshold=importance_threshold,
)
return f"🔄 已整合 {count} 条记忆为长期记忆({from_type} → {to_type},阈值={importance_threshold})"
except Exception as e:
return f"❌ 整合记忆失败: {str(e)}"复制到剪贴板错误已复制
consolidate操作借鉴了神经科学中的记忆固化概念,模拟人类大脑将短期记忆转化为长期记忆的过程。默认设置是将重要性超过0.7的工作记忆转换为情景记忆,这个阈值确保只有真正重要的信息才会被长期保存。整个过程是自动化的,用户无需手动选择具体的记忆,系统会智能地识别符合条件的记忆并执行类型转换。
记忆整合的使用示例:
# 将重要的工作记忆转为情景记忆
memory_tool.execute("consolidate",
from_type="working",
to_type="episodic",
importance_threshold=0.7
)
# 将重要的情景记忆转为语义记忆
memory_tool.execute("consolidate",
from_type="episodic",
to_type="semantic",
importance_threshold=0.8
)复制到剪贴板错误已复制
通过以上几个核心操作协作,MemoryTool构建了一个完整的记忆生命周期管理体系。从记忆的创建、检索、摘要到遗忘、整合和管理,形成了一个闭环的智能记忆管理系统,让Agent真正具备了类人的记忆能力。
8.2.4MemoryManager详解
理解了MemoryTool的接口设计后,让我们深入到底层实现,看看MemoryTool是如何与MemoryManager协作的。这种分层设计体现了软件工程中的关注点分离原则,MemoryTool专注于用户接口和参数处理,而MemoryManager则负责核心的记忆管理逻辑。
MemoryTool在初始化时会创建一个MemoryManager实例,并根据配置启用不同类型的记忆模块。这种设计让用户可以根据具体需求选择启用哪些记忆类型,既保证了功能的完整性,又避免了不必要的资源消耗。
class MemoryTool(Tool):
"""记忆工具 - 为Agent提供记忆功能"""
def __init__(
self,
user_id: str = "default_user",
memory_config: MemoryConfig = None,
memory_types: List[str] = None
):
super().__init__(
name="memory",
description="记忆工具 - 可以存储和检索对话历史、知识和经验"
)
# 初始化记忆管理器
self.memory_config = memory_config or MemoryConfig()
self.memory_types = memory_types or ["working", "episodic", "semantic"]
self.memory_manager = MemoryManager(
config=self.memory_config,
user_id=user_id,
enable_working="working" in self.memory_types,
enable_episodic="episodic" in self.memory_types,
enable_semantic="semantic" in self.memory_types,
enable_perceptual="perceptual" in self.memory_types
)复制到剪贴板错误已复制
MemoryManager作为记忆系统的核心协调者,负责管理不同类型的记忆模块,并提供统一的操作接口。具体的存储与检索能力由各记忆类型在内部实现。
class MemoryManager:
"""记忆管理器 - 统一的记忆操作接口"""
def __init__(
self,
config: Optional[MemoryConfig] = None,
user_id: str = "default_user",
enable_working: bool = True,
enable_episodic: bool = True,
enable_semantic: bool = True,
enable_perceptual: bool = False
):
self.config = config or MemoryConfig()
self.user_id = user_id
# 存储和检索功能由各记忆类型内部实现
# 初始化各类型记忆
self.memory_types = {}
if enable_working:
self.memory_types['working'] = WorkingMemory(self.config)
if enable_episodic:
self.memory_types['episodic'] = EpisodicMemory(self.config)
if enable_semantic:
self.memory_types['semantic'] = SemanticMemory(self.config)
if enable_perceptual:
self.memory_types['perceptual'] = PerceptualMemory(self.config)
8.2.5四种记忆类型
现在让我们深入了解四种记忆类型的具体实现,每种记忆类型都有其独特的特点和应用场景:
(1)工作记忆(WorkingMemory)
工作记忆是记忆系统中最活跃的部分,它负责存储当前对话会话中的临时信息。工作记忆的设计重点在于快速访问和自动清理,这种设计确保了系统的响应速度和资源效率。
工作记忆采用了纯内存存储方案,配合TTL(Time To Live)机制进行自动清理。这种设计的优势在于访问速度极快,但也意味着工作记忆的内容在系统重启后会丢失。这种特性正好符合工作记忆的定位,存储临时的、易变的信息。
class WorkingMemory:
"""工作记忆实现
特点:
- 容量有限(默认50条)+ TTL自动清理
- 纯内存存储,访问速度极快
- 组合词法检索:TF-IDF 词项权重相似度 + 关键词匹配
"""
def __init__(self, config: MemoryConfig):
self.max_capacity = config.working_memory_capacity or 50
self.max_age_minutes = config.working_memory_ttl or 60
self.memories = []
def add(self, memory_item: MemoryItem) -> str:
"""添加工作记忆"""
self._expire_old_memories() # 过期清理
if len(self.memories) >= self.max_capacity:
self._remove_lowest_priority_memory() # 容量管理
self.memories.append(memory_item)
return memory_item.id
def retrieve(self, query: str, limit: int = 5, **kwargs) -> List[MemoryItem]:
"""组合词法检索:TF-IDF 词项权重相似度 + 关键词匹配"""
self._expire_old_memories()
# 计算 TF-IDF 词项权重相似度
vector_scores = self._try_tfidf_search(query)
# 计算综合分数
scored_memories = []
for memory in self.memories:
vector_score = vector_scores.get(memory.id, 0.0)
keyword_score = self._calculate_keyword_score(query, memory.content)
# 混合评分
base_relevance = vector_score * 0.7 + keyword_score * 0.3 if vector_score > 0 else keyword_score
time_decay = self._calculate_time_decay(memory.timestamp)
importance_weight = 0.8 + (memory.importance * 0.4)
final_score = base_relevance * time_decay * importance_weight
if final_score > 0:
scored_memories.append((final_score, memory))
scored_memories.sort(key=lambda x: x[0], reverse=True)
return [memory for _, memory in scored_memories[:limit]]复制到剪贴板错误已复制
工作记忆采用组合词法检索策略:使用 TF-IDF 将文本表示为稀疏词项向量并计算词法相似度,同时结合关键词匹配;当 TF-IDF 不可用或未产生有效得分时,则使用关键词得分。TF-IDF 的向量化表示来自词频和逆文档频率,并不等同于基于稠密嵌入的语义检索。评分算法结合了词法相关性、时间衰减和重要性权重,最终得分公式为:(相关性 × 时间衰减) × (0.8 + 重要性 × 0.4)。
(2)情景记忆(EpisodicMemory)
情景记忆负责存储具体的事件和经历,它的设计重点在于保持事件的完整性和时间序列关系。情景记忆采用了SQLite+Qdrant的混合存储方案,SQLite负责结构化数据的存储和复杂查询,Qdrant负责高效的向量检索。
class EpisodicMemory:
"""情景记忆实现
特点:
- SQLite+Qdrant混合存储架构
- 支持时间序列和会话级检索
- 结构化过滤 + 语义向量检索
"""
def __init__(self, config: MemoryConfig):
self.doc_store = SQLiteDocumentStore(config.database_path)
self.vector_store = QdrantVectorStore(config.qdrant_url, config.qdrant_api_key)
self.embedder = create_embedding_model_with_fallback()
self.sessions = {} # 会话索引
def add(self, memory_item: MemoryItem) -> str:
"""添加情景记忆"""
# 创建情景对象
episode = Episode(
episode_id=memory_item.id,
session_id=memory_item.metadata.get("session_id", "default"),
timestamp=memory_item.timestamp,
content=memory_item.content,
context=memory_item.metadata
)
# 更新会话索引
session_id = episode.session_id
if session_id not in self.sessions:
self.sessions[session_id] = []
self.sessions[session_id].append(episode.episode_id)
# 持久化存储(SQLite + Qdrant)
self._persist_episode(episode)
return memory_item.id
def retrieve(self, query: str, limit: int = 5, **kwargs) -> List[MemoryItem]:
"""混合检索:结构化过滤 + 语义向量检索"""
# 1. 结构化预过滤(时间范围、重要性等)
candidate_ids = self._structured_filter(**kwargs)
# 2. 向量语义检索
hits = self._vector_search(query, limit * 5, kwargs.get("user_id"))
# 3. 综合评分与排序
results = []
for hit in hits:
if self._should_include(hit, candidate_ids, kwargs):
score = self._calculate_episode_score(hit)
memory_item = self._create_memory_item(hit)
results.append((score, memory_item))
results.sort(key=lambda x: x[0], reverse=True)
return [item for _, item in results[:limit]]
def _calculate_episode_score(self, hit) -> float:
"""情景记忆评分算法"""
vec_score = float(hit.get("score", 0.0))
recency_score = self._calculate_recency(hit["metadata"]["timestamp"])
importance = hit["metadata"].get("importance", 0.5)
# 评分公式:(向量相似度 × 0.8 + 时间近因性 × 0.2) × 重要性权重
base_relevance = vec_score * 0.8 + recency_score * 0.2
importance_weight = 0.8 + (importance * 0.4)
return base_relevance * importance_weight复制到剪贴板错误已复制
情景记忆的检索实现展现了复杂的多因素评分机制。它不仅考虑了语义相似度,还加入了时间近因性的考量,最终通过重要性权重进行调节。评分公式为:(向量相似度 × 0.8 + 时间近因性 × 0.2) × (0.8 + 重要性 × 0.4),确保检索结果既语义相关又时间相关。
(3)语义记忆(SemanticMemory)
语义记忆是记忆系统中最复杂的部分,它负责存储抽象的概念、规则和知识。语义记忆的设计重点在于知识的结构化表示和智能推理能力。语义记忆采用了Neo4j图数据库和Qdrant向量数据库的混合架构,这种设计让系统既能进行快速的语义检索,又能利用知识图谱进行复杂的关系推理。
class SemanticMemory(BaseMemory):
"""语义记忆实现
特点:
- 使用HuggingFace中文预训练模型进行文本嵌入
- 向量检索进行快速相似度匹配
- 知识图谱存储实体和关系
- 混合检索策略:向量+图+语义推理
"""
def __init__(self, config: MemoryConfig, storage_backend=None):
super().__init__(config, storage_backend)
# 嵌入模型(统一提供)
self.embedding_model = get_text_embedder()
# 专业数据库存储
self.vector_store = QdrantConnectionManager.get_instance(**qdrant_config)
self.graph_store = Neo4jGraphStore(**neo4j_config)
# 实体和关系缓存
self.entities: Dict[str, Entity] = {}
self.relations: List[Relation] = []
# NLP处理器(支持中英文)
self.nlp = self._init_nlp()复制到剪贴板错误已复制
语义记忆的添加过程体现了知识图谱构建的完整流程。系统不仅存储记忆内容,还会自动提取实体和关系,构建结构化的知识表示:
def add(self, memory_item: MemoryItem) -> str:
"""添加语义记忆"""
# 1. 生成文本嵌入
embedding = self.embedding_model.encode(memory_item.content)
# 2. 提取实体和关系
entities = self._extract_entities(memory_item.content)
relations = self._extract_relations(memory_item.content, entities)
# 3. 存储到Neo4j图数据库
for entity in entities:
self._add_entity_to_graph(entity, memory_item)
for relation in relations:
self._add_relation_to_graph(relation, memory_item)
# 4. 存储到Qdrant向量数据库
metadata = {
"memory_id": memory_item.id,
"entities": [e.entity_id for e in entities],
"entity_count": len(entities),
"relation_count": len(relations)
}
self.vector_store.add_vectors(
vectors=[embedding.tolist()],
metadata=[metadata],
ids=[memory_item.id]
)复制到剪贴板错误已复制
语义记忆的检索实现了混合搜索策略,结合了向量检索的语义理解能力和图检索的关系推理能力:
def retrieve(self, query: str, limit: int = 5, **kwargs) -> List[MemoryItem]:
"""检索语义记忆"""
# 1. 向量检索
vector_results = self._vector_search(query, limit * 2, user_id)
# 2. 图检索
graph_results = self._graph_search(query, limit * 2, user_id)
# 3. 混合排序
combined_results = self._combine_and_rank_results(
vector_results, graph_results, query, limit
)
return combined_results[:limit]复制到剪贴板错误已复制
混合排序算法采用了多因素评分机制:
def _combine_and_rank_results(self, vector_results, graph_results, query, limit):
"""混合排序结果"""
combined = {}
# 合并向量和图检索结果
for result in vector_results:
combined[result["memory_id"]] = {
**result,
"vector_score": result.get("score", 0.0),
"graph_score": 0.0
}
for result in graph_results:
memory_id = result["memory_id"]
if memory_id in combined:
combined[memory_id]["graph_score"] = result.get("similarity", 0.0)
else:
combined[memory_id] = {
**result,
"vector_score": 0.0,
"graph_score": result.get("similarity", 0.0)
}
# 计算混合分数
for memory_id, result in combined.items():
vector_score = result["vector_score"]
graph_score = result["graph_score"]
importance = result.get("importance", 0.5)
# 基础相似度得分
base_relevance = vector_score * 0.7 + graph_score * 0.3
# 重要性权重 [0.8, 1.2]
importance_weight = 0.8 + (importance * 0.4)
# 最终得分:相似度 * 重要性权重
combined_score = base_relevance * importance_weight
result["combined_score"] = combined_score
# 排序并返回
sorted_results = sorted(
combined.values(),
key=lambda x: x["combined_score"],
reverse=True
)
return sorted_results[:limit]复制到剪贴板错误已复制
语义记忆的评分公式为:(向量相似度 × 0.7 + 图相似度 × 0.3) × (0.8 + 重要性 × 0.4)。这种设计的核心思想是:
- 向量检索权重(0.7) :语义相似度是主要因素,确保检索结果与查询语义相关
- 图检索权重(0.3) :关系推理作为补充,发现概念间的隐含关联
- 重要性权重范围[0.8, 1.2] :避免重要性过度影响相似度排序,保持检索的准确性
(4)感知记忆(PerceptualMemory)
感知记忆支持文本、图像、音频等多种模态的数据存储和检索。它采用了模态分离的存储策略,为不同模态的数据创建独立的向量集合,这种设计避免了维度不匹配的问题,同时保证了检索的准确性:
class PerceptualMemory(BaseMemory):
"""感知记忆实现
特点:
- 支持多模态数据(文本、图像、音频等)
- 跨模态相似性搜索
- 感知数据的语义理解
- 支持内容生成和检索
"""
def __init__(self, config: MemoryConfig, storage_backend=None):
super().__init__(config, storage_backend)
# 多模态编码器
self.text_embedder = get_text_embedder()
self._clip_model = self._init_clip_model() # 图像编码
self._clap_model = self._init_clap_model() # 音频编码
# 按模态分离的向量存储
self.vector_stores = {
"text": QdrantConnectionManager.get_instance(
collection_name="perceptual_text",
vector_size=self.vector_dim
),
"image": QdrantConnectionManager.get_instance(
collection_name="perceptual_image",
vector_size=self._image_dim
),
"audio": QdrantConnectionManager.get_instance(
collection_name="perceptual_audio",
vector_size=self._audio_dim
)
}复制到剪贴板错误已复制
感知记忆的检索支持同模态和跨模态两种模式。同模态检索利用专业的编码器进行精确匹配,而跨模态检索则需要更复杂的语义对齐机制:
def retrieve(self, query: str, limit: int = 5, **kwargs) -> List[MemoryItem]:
"""检索感知记忆(可筛模态;同模态向量检索+时间/重要性融合)"""
user_id = kwargs.get("user_id")
target_modality = kwargs.get("target_modality")
query_modality = kwargs.get("query_modality", target_modality or "text")
# 同模态向量检索
try:
query_vector = self._encode_data(query, query_modality)
store = self._get_vector_store_for_modality(target_modality or query_modality)
where = {"memory_type": "perceptual"}
if user_id:
where["user_id"] = user_id
if target_modality:
where["modality"] = target_modality
hits = store.search_similar(
query_vector=query_vector,
limit=max(limit * 5, 20),
where=where
)
except Exception:
hits = []
# 融合排序(向量相似度 + 时间近因性 + 重要性权重)
results = []
for hit in hits:
vector_score = float(hit.get("score", 0.0))
recency_score = self._calculate_recency_score(hit["metadata"]["timestamp"])
importance = hit["metadata"].get("importance", 0.5)
# 评分算法
base_relevance = vector_score * 0.8 + recency_score * 0.2
importance_weight = 0.8 + (importance * 0.4)
combined_score = base_relevance * importance_weight
results.append((combined_score, self._create_memory_item(hit)))
results.sort(key=lambda x: x[0], reverse=True)
return [item for _, item in results[:limit]]复制到剪贴板错误已复制
感知记忆的评分公式为:(向量相似度 × 0.8 + 时间近因性 × 0.2) × (0.8 + 重要性 × 0.4)。感知记忆的评分机制还支持跨模态检索,通过统一的向量空间实现文本、图像、音频等不同模态数据的语义对齐。当进行跨模态检索时,系统会自动调整评分权重,确保检索结果的多样性和准确性。此外,感知记忆中的时间近因性计算采用了指数衰减模型:
def _calculate_recency_score(self, timestamp: str) -> float:
"""计算时间近因性得分"""
try:
memory_time = datetime.fromisoformat(timestamp)
current_time = datetime.now()
age_hours = (current_time - memory_time).total_seconds() / 3600
# 指数衰减:24小时内保持高分,之后逐渐衰减
decay_factor = 0.1 # 衰减系数
recency_score = math.exp(-decay_factor * age_hours / 24)
return max(0.1, recency_score) # 最低保持0.1的基础分数
except Exception:
return 0.5 # 默认中等分数复制到剪贴板错误已复制
这种时间衰减模型模拟了人类记忆中的遗忘曲线,确保了感知记忆系统能够优先检索到时间上更相关的记忆内容。