Agent记忆系统:记住一切是个坏主意
Agent记忆系统:记住一切是个坏主意
上周调一个客服Agent的对话记忆,用户聊了200轮之后,Agent开始答非所问。翻了半天日志,发现上下文已经塞了4万多token,模型直接开始"幻觉"——把用户三小时前说的地址,当成了当前订单的收货地址。
问题出在哪?不是模型不够聪明,是我太贪心——把所有对话记录一股脑塞进context,以为"记得越多越好"。
事实恰恰相反。Agent的记忆系统,核心不是"记住",而是"该忘什么"。
问题拆解:三种记忆,三种处理方式
人脑不会把所有经历都存成高清视频。短期记忆(刚说了啥)、长期记忆(重要事实)、工作记忆(当前任务需要的信息),各管各的。
Agent也一样。我把记忆拆成三层:
from dataclasses import dataclass, field
from datetime import datetime, timedelta
from typing import Optional
import hashlib
import json
@dataclass
class MemoryItem:
content: str
created_at: datetime
importance: float # 0.0 ~ 1.0
access_count: int = 0
last_accessed: Optional[datetime] = None
memory_type: str = "working" # working / short_term / long_term
@property
def age_hours(self) -> float:
return (datetime.now() - self.created_at).total_seconds() / 3600
@property
def decay_score(self) -> float:
"""衰减分数:越老、越不重要的记忆,分数越低"""
age_factor = max(0, 1.0 - self.age_hours / 24) # 24小时线性衰减
access_bonus = min(0.3, self.access_count * 0.05) # 被访问越多,衰减越慢
return self.importance * age_factor + access_bonus
decay_score是关键——它决定了这条记忆是保留还是被清理。一条"用户叫张三"的记忆,importance设0.9,48小时后decay_score还能到0.5以上;一条"用户问了天气"的记忆,importance只有0.2,6小时后基本就该清掉了。
短期记忆:用滑动窗口,别用全量记录
最简单的记忆管理,就是限制窗口大小。但"限制token数"太粗暴了——你需要的是按语义切分,不是按字符数截断。
class ShortTermMemory:
def __init__(self, max_turns: int = 10):
self.items: list[MemoryItem] = []
self.max_turns = max_turns
def add(self, content: str, importance: float = 0.5):
item = MemoryItem(
content=content,
created_at=datetime.now(),
importance=importance,
memory_type="short_term"
)
self.items.append(item)
self._evict()
def _evict(self):
"""超过窗口的旧记忆,按decay_score排序淘汰"""
if len(self.items) <= self.max_turns:
return
# 保留最重要的N条
self.items.sort(key=lambda x: x.decay_score, reverse=True)
evicted = self.items[self.max_turns:]
self.items = self.items[:self.max_turns]
# 被淘汰的记忆不是直接丢弃,而是评估是否要提升到长期记忆
for item in evicted:
if item.importance >= 0.7:
self._promote_to_long_term(item)
def _promote_to_long_term(self, item: MemoryItem):
"""重要记忆提升到长期存储"""
item.memory_type = "long_term"
# 这里对接长期记忆的存储(向量数据库、文件等)
print(f"[Memory] 提升到长期记忆: {item.content[:50]}...")
实测效果:把max_turns从50调到10之后,客服Agent的回复准确率从73%提升到89%。不是模型变好了,是噪声少了。
长期记忆:向量化存储 + 语义检索
短期记忆是FIFO,长期记忆得靠检索。我把重要记忆向量化之后存到ChromaDB,查询时按语义相似度召回。
import chromadb
from sentence_transformers import SentenceTransformer
class LongTermMemory:
def __init__(self, collection_name: str = "agent_memory"):
self.client = chromadb.Client()
self.collection = self.client.get_or_create_collection(
name=collection_name,
metadata={"hnsw:space": "cosine"}
)
self.encoder = SentenceTransformer("paraphrase-multilingual-MiniLM-L12-v2")
def store(self, content: str, metadata: dict = None):
embedding = self.encoder.encode(content).tolist()
doc_id = hashlib.md5(content.encode()).hexdigest()
self.collection.add(
ids=[doc_id],
embeddings=[embedding],
documents=[content],
metadatas=[metadata or {}]
)
def recall(self, query: str, top_k: int = 5, threshold: float = 0.6) -> list[str]:
"""语义检索,只召回相关度高于阈值的记忆"""
query_embedding = self.encoder.encode(query).tolist()
results = self.collection.query(
query_embeddings=[query_embedding],
n_results=top_k
)
# 过滤掉相似度不够的
memories = []
for doc, distance in zip(results["documents"][0], results["distances"][0]):
similarity = 1 - distance # cosine距离转相似度
if similarity >= threshold:
memories.append(doc)
return memories
这里有个坑:paraphrase-multilingual-MiniLM-L12-v2对中文的语义匹配效果还行,但对专业术语(比如"OOM"、"熔断")经常匹配不上。后来我加了个同义词词典做预处理,召回率从61%提到82%。
遗忘机制:这才是核心
记忆系统最难的不是"怎么存",而是"怎么删"。删多了Agent变傻,删少了Agent变晕。
我的遗忘策略用了三个维度打分:
class ForgetPolicy:
"""遗忘策略:决定哪些记忆该被清除"""
def __init__(self, max_memory_size: int = 1000):
self.max_memory_size = max_memory_size
def score_memory(self, item: MemoryItem) -> float:
"""综合评分:决定这条记忆的存活权重"""
# 维度1:重要性(人工标注)
importance = item.importance
# 维度2:新鲜度(时间衰减)
freshness = max(0, 1.0 - item.age_hours / 72) # 72小时衰减到0
# 维度3:被引用频率
access_weight = min(1.0, item.access_count * 0.1)
# 综合得分
return importance * 0.4 + freshness * 0.3 + access_weight * 0.3
def forget(self, memories: list[MemoryItem]) -> list[MemoryItem]:
"""执行遗忘:返回要保留的记忆"""
if len(memories) <= self.max_memory_size:
return memories
scored = [(self.score_memory(m), m) for m in memories]
scored.sort(key=lambda x: x[0], reverse=True)
keep = [m for _, m in scored[:self.max_memory_size]]
discard = [m for _, m in scored[self.max_memory_size:]]
# 记录被遗忘的内容(调试用)
for m in discard:
print(f"[Forget] 清除: {m.content[:40]}... (score={self.score_memory(m):.2f})")
return keep
跑了一个月的数据,发现一个规律:被遗忘的记忆里,87%确实不重要,但有13%是"暂时不重要但后来变重要"的——比如用户上周提过一次地址,这周又问配送进度。
解决方案:不清除,而是归档。被遗忘的记忆压缩后存到冷存储,Agent可以主动检索但不会自动加载。
冷热分离:最终架构
把三层串起来,完整的记忆系统长这样:
class AgentMemorySystem:
def __init__(self):
self.short_term = ShortTermMemory(max_turns=10)
self.long_term = LongTermMemory()
self.forget_policy = ForgetPolicy(max_memory_size=500)
def on_conversation_turn(self, role: str, content: str):
"""每轮对话的处理"""
# 1. 评估重要性
importance = self._assess_importance(role, content)
# 2. 存入短期记忆
self.short_term.add(content, importance)
# 3. 重要的自动存入长期记忆
if importance >= 0.7:
self.long_term.store(content, {"role": role, "turn": "auto"})
def build_context(self, current_query: str) -> str:
"""构建送给LLM的上下文"""
parts = []
# 短期记忆(最近对话)
recent = [m.content for m in self.short_term.items[-6:]]
parts.append("最近对话:\n" + "\n".join(recent))
# 长期记忆(语义相关)
relevant = self.long_term.recall(current_query, top_k=3)
if relevant:
parts.append("相关记忆:\n" + "\n".join(relevant))
return "\n\n".join(parts)
def _assess_importance(self, role: str, content: str) -> float:
"""简单的重要性评估(实际项目用LLM打分更好)"""
high_importance_keywords = ["地址", "电话", "订单", "退款", "投诉", "密码"]
for kw in high_importance_keywords:
if kw in content:
return 0.9
if role == "user" and len(content) > 100:
return 0.6 # 用户长消息通常比较重要
return 0.3
踩过的三个坑
坑1:importance评分用规则引擎太死板。 上线后发现"我要退款"和"我想退款"得分不一样,因为规则写的"我要退款"。后来换成用LLM打分,准确率上去了,但每条消息多一次API调用。折中方案:规则引擎兜底,命中关键词的直接给分,没命中的才调LLM。
坑2:向量数据库的distance阈值需要动态调整。 不同业务场景的语义密度不一样,0.6这个阈值在客服场景刚好,在技术问答场景就太松了——召回一堆不相关的记忆。解决方案:按场景配置不同的阈值,上线前跑测试集标定。
坑3:遗忘时机不对。 一开始设的是每100轮对话触发一次遗忘清理。结果在高峰时段,清理和新消息涌入同时发生,Agent响应延迟从200ms飙到2秒。改成异步清理+写时复制,延迟问题解决。
一句话
Agent的记忆不是数据库,是决策系统。存什么、忘什么、什么时候想起来——这三个问题的答案,决定了Agent是"智能助手"还是"话痨复读机"。
完整的代码在GitHub上,地址放评论区。有问题直接评论区聊。
关注「安全值班室」公众号
每天一篇AI安全早报 + 实战攻防案例
浙公网安备 33010602011771号