引言
记忆是人类智能的基石,同样也是AI Agent的核心能力。一个没有记忆的Agent每次对话都从零开始,无法积累经验、学习偏好、维持连续性。OpenClaw在记忆系统设计上进行了深度工程探索,构建了一套从短期上下文到长期记忆的多层架构。本文将全面解析其设计与实现。
记忆的层次模型
OpenClaw将Agent记忆分为四个层次,类比人类认知科学中的记忆分类:
┌─────────────────────────────────────────────┐
│ Layer 4: 损失无关回忆 (Lossless Recall) │ ← LCM压缩与精确回溯
├─────────────────────────────────────────────┤
│ Layer 3: 长期记忆 (Long-term Memory) │ ← MEMORY.md 策略性记忆
├─────────────────────────────────────────────┤
│ Layer 2: 每日记忆 (Daily Memory) │ ← 按天组织的原始记录
├─────────────────────────────────────────────┤
│ Layer 1: 工作记忆 (Working Memory) │ ← 当前会话上下文窗口
└─────────────────────────────────────────────┘
Layer 1: 工作记忆
工作记忆即模型的上下文窗口,是最快但最有限的记忆层:
class WorkingMemory:
"""管理当前会话的上下文窗口"""
def __init__(self, max_tokens: int = 128000):
self.max_tokens = max_tokens
self.messages: list[Message] = []
self.token_counter = TokenCounter()
def add(self, message: Message):
"""添加消息,超出限制时触发压缩"""
self.messages.append(message)
if self.token_counter.count(self.messages) > self.max_tokens * 0.85:
self._compact()
def _compact(self):
"""上下文压缩策略"""
# 保留最近N轮完整对话
recent = self.messages[-10:]
# 将较早的消息压缩为摘要
older = self.messages[:-10]
summary = self._summarize(older)
self.messages = [summary] + recent
工作记忆的挑战在于上下文窗口的有限性。即使200K token的窗口也会在长对话中耗尽。OpenClaw的策略是渐进式压缩——先压缩最老的消息,保留最近对话的完整性。
Layer 2: 每日记忆
每日记忆以日期为维度,记录当天发生的事件:
# memory/2026-07-29.md
## 今日事件
### 10:30 - 项目讨论
- 用户要求设计一个RAG系统架构
- 讨论了向量数据库选型:Qdrant vs Milvus
- 决定使用Qdrant,原因是部署简单且性能足够
- 用户偏好:重视部署简洁性高于极致性能
### 14:00 - 代码审查
- 审查了同事提交的Python代码
- 发现3个潜在问题:SQL注入风险、N+1查询、缺失错误处理
- 已在PR中标注
### 16:30 - 学习记录
- 了解了vLLM的FP8-KV插件
- 关键发现:KV Cache量化可减少50%显存,质量几乎无损
- 后续需要测试在我们的场景下是否同样有效
class DailyMemory:
"""每日记忆管理"""
def __init__(self, memory_dir: str):
self.memory_dir = Path(memory_dir)
def append(self, event: MemoryEvent):
"""追加事件到当天记忆"""
today = datetime.now().strftime("%Y-%m-%d")
path = self.memory_dir / f"{today}.md"
timestamp = datetime.now().strftime("%H:%M")
entry = f"\n### {timestamp} - {event.title}\n{event.content}\n"
with open(path, "a", encoding="utf-8") as f:
f.write(entry)
def read_day(self, date: str) -> str:
"""读取指定日期的记忆"""
path = self.memory_dir / f"{date}.md"
if path.exists():
return path.read_text(encoding="utf-8")
return ""
def search(self, query: str, days: int = 7) -> list[MemoryEntry]:
"""搜索最近N天的记忆"""
results = []
for i in range(days):
date = (datetime.now() - timedelta(days=i)).strftime("%Y-%m-%d")
content = self.read_day(date)
if query.lower() in content.lower():
results.append(MemoryEntry(date=date, content=content))
return results
Layer 3: 长期记忆
长期记忆是策略性记忆——不是所有日常事件都值得长期保留,需要"遗忘"机制来提炼精华:
# MEMORY.md
## 用户画像
- 技术栈:Python, TypeScript, Go
- 偏好:优先选择开源方案,重视代码可维护性
- 工作风格:先调研再决策,喜欢看到对比数据
- 时区:Asia/Shanghai (UTC+8)
## 项目记忆
### RAG系统项目
- 架构决策:Qdrant + BGE-M3 + GPT-5
- 部署环境:8×A100-80G, Kubernetes
- 关键指标:P99延迟 < 1s, 吞吐量 > 50 QPS
- 已知问题:长查询时检索精度下降,待优化
## 经验教训
- vLLM的gpu_memory_utilization设置不要超过0.92,否则容易OOM
- LangChain的RetrievalQA在生产环境性能不佳,建议直接用原生SDK
- Qdrant的payload过滤比预过滤快3-5倍
class LongTermMemory:
"""长期记忆:策略性提炼与维护"""
def __init__(self, memory_file: str, daily_memory: DailyMemory):
self.memory_file = Path(memory_file)
self.daily_memory = daily_memory
self.content = self._load()
def _load(self) -> str:
if self.memory_file.exists():
return self.memory_file.read_text(encoding="utf-8")
return "# MEMORY.md\n\n"
def consolidate(self, days: int = 7):
"""从每日记忆中提炼长期记忆"""
recent_daily = []
for i in range(days):
date = (datetime.now() - timedelta(days=i)).strftime("%Y-%m-%d")
content = self.daily_memory.read_day(date)
if content:
recent_daily.append(content)
if not recent_daily:
return
# 用LLM进行记忆提炼
prompt = f"""以下是过去{days}天的每日记忆记录。请提取值得长期记住的信息:
1. 用户偏好和习惯
2. 重要的架构/技术决策
3. 经验教训
4. 待办事项
每日记忆:
{chr(10).join(recent_daily)}
当前长期记忆:
{self.content}
请输出更新后的完整长期记忆。保留已有内容中仍然相关的部分,添加新发现,删除过时信息。"""
updated = self.llm.complete(prompt)
self.content = updated
self.memory_file.write_text(updated, encoding="utf-8")
Layer 4: 损失无关回忆
这是OpenClaw最独特的记忆层——LCM(Lossless Context Management)。它通过摘要DAG(有向无环图)实现对完整对话历史的无损回溯:
对话消息流:
msg1 → msg2 → msg3 → [压缩] → sum_1 → msg4 → msg5 → [压缩] → sum_2 → msg6
↑ ↑
└── 可展开恢复原始消息 ──────────────┘
class LosslessRecall:
"""损失无关回忆:基于摘要DAG的精确回溯"""
def __init__(self, storage):
self.storage = storage # 持久化存储
def compress(self, messages: list[Message]) -> str:
"""将消息序列压缩为摘要"""
summary_id = f"sum_{uuid.uuid4().hex[:12]}"
# 生成摘要
summary_text = self._generate_summary(messages)
# 存储摘要及其子节点
self.storage.save_summary(
id=summary_id,
content=summary_text,
children=[m.id for m in messages],
metadata={
"timestamp": datetime.now().isoformat(),
"message_count": len(messages),
"token_count": sum(m.token_count for m in messages),
}
)
return summary_id
def expand(self, summary_id: str, query: str = None) -> str:
"""展开摘要,恢复底层细节"""
summary = self.storage.get_summary(summary_id)
# 递归展开子节点
children = []
for child_id in summary.children:
if child_id.startswith("sum_"):
# 子节点也是摘要,递归展开
children.append(self.expand(child_id, query))
else:
# 叶子节点是原始消息
msg = self.storage.get_message(child_id)
children.append(msg.content)
return "\n".join(children)
def grep(self, pattern: str, scope: str = "both") -> list[Match]:
"""在记忆中搜索模式"""
matches = []
# 搜索原始消息
if scope in ("messages", "both"):
matches.extend(self.storage.search_messages(pattern))
# 搜索摘要
if scope in ("summaries", "both"):
matches.extend(self.storage.search_summaries(pattern))
return matches
记忆的检索策略
当Agent需要回忆信息时,OpenClaw采用多路检索 + 语义排序的策略:
class MemoryRetriever:
"""多路记忆检索"""
def __init__(self, working: WorkingMemory, daily: DailyMemory,
long_term: LongTermMemory, lcm: LosslessRecall):
self.working = working
self.daily = daily
self.long_term = long_term
self.lcm = lcm
def recall(self, query: str, context: dict) -> RecallResult:
"""根据查询回忆相关信息"""
results = RecallResult(query=query)
# 1. 工作记忆:当前上下文中搜索
results.working = self._search_working(query)
# 2. 每日记忆:最近7天关键词搜索
results.daily = self.daily.search(query, days=7)
# 3. 长期记忆:语义搜索
results.long_term = self._semantic_search(
self.long_term.content, query
)
# 4. LCM:历史对话精确回溯
results.lcm = self.lcm.grep(query, scope="both")
# 合并去重并排序
return self._merge_and_rank(results, context)
def _merge_and_rank(self, results: RecallResult, ctx: dict) -> RecallResult:
"""合并多路结果并按相关性排序"""
all_items = []
# 工作记忆权重最高(当前上下文最相关)
for item in results.working:
all_items.append((item, 1.0, "working"))
# 长期记忆次之(策略性重要信息)
for item in results.long_term:
all_items.append((item, 0.8, "long_term"))
# LCM精确匹配
for item in results.lcm:
all_items.append((item, 0.7, "lcm"))
# 每日记忆(原始记录,可能有噪音)
for item in results.daily:
all_items.append((item, 0.5, "daily"))
# 按权重排序
all_items.sort(key=lambda x: x[1], reverse=True)
results.ranked = all_items
return results
隐私与安全
记忆系统存储用户的私密信息,安全设计不可忽视:
class MemorySecurity:
"""记忆安全策略"""
# 敏感信息检测模式
SENSITIVE_PATTERNS = [
(r'\b\d{16,19}\b', '信用卡号'),
(r'\b\d{11}\b', '手机号'),
(r'[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\.[A-Z|a-z]{2,}', '邮箱'),
(r'password\s*[:=]\s*\S+', '密码'),
]
def sanitize(self, content: str) -> str:
"""脱敏处理"""
for pattern, label in self.SENSITIVE_PATTERNS:
content = re.sub(pattern, f'[{label}已脱敏]', content)
return content
def access_control(self, memory_type: str, context: dict) -> bool:
"""访问控制:不同场景下的记忆访问权限"""
# 在群聊中不加载长期记忆(防止泄露个人信息)
if context.get('channel') == 'group':
return memory_type in ('working', 'daily')
# 在共享环境中限制访问
if context.get('shared', False):
return memory_type == 'working'
# 私有会话中允许所有记忆
return True
性能优化
| 记忆层 | 查询延迟 | 存储开销 | 检索精度 | 使用场景 |
|---|---|---|---|---|
| 工作记忆 | <1ms | 高(内存) | 100% | 当前对话引用 |
| 每日记忆 | 5-20ms | 低 | 70% | 近期事件回忆 |
| 长期记忆 | 10-50ms | 极低 | 85% | 用户偏好、决策 |
| LCM | 50-200ms | 中 | 95% | 精确历史回溯 |
总结
OpenClaw的记忆架构揭示了一个重要的工程洞见:单一记忆机制无法满足Agent的多样化需求。工作记忆保证即时性,每日记忆保留完整性,长期记忆提炼精华,LCM实现无损回溯——四层各司其职,互相补充。
这种分层设计的深层价值在于:它让Agent像人类一样拥有"遗忘"的能力——不是被动地丢失信息,而是主动地将信息从短期记忆沉淀到长期记忆,丢弃噪音,保留信号。这是从"存储"到"记忆"的本质飞跃。