Agent 记忆架构演进:从全量上下文到层次化存储

发布时间:2026/7/16 18:25:32

Agent 记忆架构演进:从全量上下文到层次化存储 Agent 记忆架构演进从全量上下文到层次化存储一、个性化深度引言Agent 对话到第 20 轮时模型开始遗忘第 3 轮提到的关键约束。因为上下文窗口已经被之前的对话历史填满了第 3 轮的信息被 FIFO 机制无情地挤出了注意力范围。这就是全量上下文记忆的天花板它把所有历史当作同等重要的信息不区分主次、不归档、不索引。当 Agent 需要执行跨多轮的多步任务时这种记忆方式的脆弱性暴露无遗。见证奇迹的时刻不是在换了个更大窗口的模型之后。而是意识到人类的记忆不是线性的日志文件。我们有短期记忆、工作记忆、长期记忆每一层有不同的保留策略和检索机制。Agent 的记忆架构应该向这个方向演进。二、个性化原理剖析记忆架构的演进路径第一代全量上下文记忆所有历史消息按顺序拼接每轮追加到 prompt 中。结构简单但随对话增长迅速超出窗口限制且不区分信息重要性。第二代摘要压缩记忆使用模型对历史对话做定期摘要只保留摘要 最近 N 轮。缓解了 Token 膨胀问题但摘要可能丢失精确细节如具体的数字、规则、代码片段。第三代层次化存储记忆模仿人类记忆的多层结构按信息寿命和检索频率分为三层。三层记忆的分工工作记忆层保存最近 N 轮完整对话默认 5-8 轮保证当前上下文的连贯性。这一层不压缩、不摘要。短期记忆层对超出工作记忆窗口的历史做滑动摘要。同时提取关键实体人名、数字、约束条件单独存储避免摘要丢失精确值。长期记忆层跨会话持久化存储。向量数据库支持语义相似度检索知识图谱维护实体关系规则引擎管理显式约束。三、个性化代码实践import hashlib import json import time from dataclasses import dataclass, field from typing import Dict, List, Optional dataclass class MemoryItem: 设计原因统一记忆数据结构所有记忆层共用。 type 区分记忆类型priority 控制检索排序。 content: str memory_type: str # working | short_term | long_term priority: float 0.0 timestamp: float field(default_factorytime.time) metadata: Dict field(default_factorydict) property def memory_id(self) - str: 设计原因用内容哈希做唯一ID支持去重。 return hashlib.md5( self.content.encode() ).hexdigest()[:16] class HierarchicalMemoryManager: 设计原因统一管理三层记忆的写入、检索、衰减。 对外暴露单一接口内部处理三层之间的协调。 def __init__( self, working_memory_size: int 8, summary_interval: int 10, ): # 设计原因工作记忆用固定长度队列 # 超出窗口自动出队不需要手动淘汰。 self._working_memory: List[MemoryItem] [] self._working_memory_size working_memory_size # 设计原因短期摘要列表定期合并。 self._short_term_summaries: List[MemoryItem] [] # 设计原因长期记忆用字典存储 # 实际场景应使用向量数据库如 Milvus。 self._long_term_store: Dict[str, MemoryItem] {} # 设计原因显式约束独立存储 # 每次 Prompt 组装时强制注入不会丢失。 self._constraints: Dict[str, str] {} self._summary_interval summary_interval self._message_count 0 self._summary_model None # 摘要模型引用 def add_message(self, role: str, content: str) - None: 设计原因每收到一条消息先写入工作记忆。 超出窗口触发短期记忆归档。 item MemoryItem( contentf{role}: {content}, memory_typeworking, ) self._working_memory.append(item) self._message_count 1 # 设计原因超出工作记忆窗口最旧的消息归档到短期记忆。 if len(self._working_memory) self._working_memory_size: oldest self._working_memory.pop(0) oldest.memory_type short_term self._short_term_summaries.append(oldest) # 设计原因达到摘要间隔触发短期记忆压缩。 if self._message_count % self._summary_interval 0: self._compress_short_term() def add_constraint(self, key: str, value: str) - None: 设计原因显式约束独立存储 不受窗口大小影响永久保留直到主动删除。 self._constraints[key] value def add_long_term(self, content: str, metadata: Dict None) - None: 设计原因跨会话持久化记忆。 使用内容哈希作为 Key天然支持去重。 item MemoryItem( contentcontent, memory_typelong_term, metadatametadata or {}, ) self._long_term_store[item.memory_id] item def retrieve_long_term( self, query: str, top_k: int 5 ) - List[MemoryItem]: 设计原因基于关键词匹配的简易检索。 实际应用应替换为向量语义检索embedding相似度。 results [] query_lower query.lower() for item in self._long_term_store.values(): score self._keyword_match_score( query_lower, item.content.lower() ) if score 0: item.priority score results.append(item) results.sort(keylambda x: x.priority, reverseTrue) return results[:top_k] def _compress_short_term(self) - None: 设计原因将短期记忆合并为一条摘要。 使用摘要模型而非简单截断保留语义完整性。 if not self._short_term_summaries: return combined \n.join([ item.content for item in self._short_term_summaries ]) # 设计原因摘要合并后清空短期记忆列表 # 但合并结果持久化到长期记忆。 summary f[摘要] {combined[:200]}... summary_item MemoryItem( contentsummary, memory_typelong_term, priority0.8, ) self._long_term_store[summary_item.memory_id] summary_item self._short_term_summaries.clear() def build_context( self, current_query: str ) - str: 设计原因组装三层记忆到最终 Prompt 上下文。 顺序约束 工作记忆 检索到的长期记忆。 约束必须排在最前面确保模型优先遵守。 parts [] # 设计原因显式约束最高优先级。 if self._constraints: constraints_text \n.join([ f- {k}: {v} for k, v in self._constraints.items() ]) parts.append(f【必须遵守的约束】\n{constraints_text}) # 设计原因最近对话保证连贯性。 if self._working_memory: working_text \n.join([ item.content for item in self._working_memory ]) parts.append(f【最近对话】\n{working_text}) # 设计原因相关长期记忆补充背景知识。 relevant self.retrieve_long_term(current_query, top_k3) if relevant: long_term_text \n.join([ item.content for item in relevant ]) parts.append(f【相关历史信息】\n{long_term_text}) return \n\n.join(parts) staticmethod def _keyword_match_score(query: str, content: str) - float: 设计原因简易关键词匹配避免依赖外部库。 query_words set(query.split()) content_words set(content.split()) intersection query_words content_words if not query_words: return 0.0 return len(intersection) / len(query_words)四、个性化边界权衡1. 摘要粒度轮次触发 vs Token 触发按轮次触发摘要每 10 轮一次实现简单但精度粗糙——有的轮次信息量大有的很少。按 Token 触发每 2000 Token 一次更精确但需要实时计算 Token 数量。推荐混合方案轮次优先Token 超标时提前触发。2. 向量检索 vs 全文检索向量检索Embedding 余弦相似度对语义匹配效果好但需要额外的 Embedding 模型和向量数据库。全文检索关键词匹配实现简单但无法理解同义替换。长期记忆规模 1000 条时向量检索的收益超过其成本。3. 约束存储显式声明 vs 隐式学习显式约束规则引擎保证 100% 遵守但需要人工定义。隐式约束从对话中学习更灵活但模型可能遗忘或误用。建议核心业务约束用显式存储用户偏好用隐式学习。4. 跨会话持久化本地文件 vs 云存储本地文件适合单机部署但多实例间无法共享记忆。云存储Redis/数据库支持分布式但增加网络延迟约 1-5ms。推荐生产环境用 Redis开发环境用本地 JSON 文件。5. 记忆衰减固定窗口 vs 重要性衰减固定窗口简单但粗暴可能丢失重要但较早的信息。重要性衰减每轮乘以衰减因子 0.95保留重要信息更久但衰减函数设计需要经验调整。建议固定窗口作为基线重要性衰减作为增强。五、总结Agent 记忆架构从全量上下文演进到层次化存储核心改进在于按信息生命周期分层管理工作记忆保证对话连贯性短期记忆做摘要压缩长期记忆支持跨会话检索。三层配合实现了在有限 Token 预算内的信息保留最大化。工程实践中需要权衡摘要粒度、检索方式、衰减策略核心原则是让重要的信息保留得足够久让不重要的信息节省 Token 预算。

相关新闻