记忆系统

记忆是智能体的核心基础设施之一。没有记忆的Agent就像每次见面都是第一次的人——无法积累经验、无法维持上下文、无法从过去的交互中学习。一个完善的记忆系统让Agent能够记住过去的对话、积累领域知识、追踪任务进展,从而表现出真正的智能行为。

一、短期记忆(Short-term Memory)

短期记忆是Agent在单次任务执行过程中维持的工作上下文。它通常对应于大语言模型的上下文窗口,包含了当前对话历史、中间推理结果和临时数据。短期记忆的特点是访问速度快、容量有限、会话结束后即消失。

短期记忆的管理策略包括:

  • 滑动窗口:只保留最近N轮对话,丢弃更早的内容。简单但可能丢失重要信息。
  • 摘要压缩:当上下文接近限制时,对较早的对话进行摘要,保留关键信息。
  • 重要性标记:为每条记忆标记重要性分数,优先保留高分内容。
  • 分块管理:将长对话分成多个块,按需加载相关块到上下文中。
class ShortTermMemory:
    """短期记忆管理器"""

    def __init__(self, max_tokens=8000):
        self.max_tokens = max_tokens
        self.messages = []
        self.token_count = 0

    def add(self, role, content):
        """添加一条记忆"""
        tokens = self._count_tokens(content)
        self.messages.append({
            "role": role,
            "content": content,
            "tokens": tokens,
            "timestamp": datetime.now()
        })
        self.token_count += tokens

        # 如果超出限制,进行压缩
        if self.token_count > self.max_tokens:
            self._compress()

    def get_context(self):
        """获取当前上下文"""
        return self.messages.copy()

    def _compress(self):
        """压缩记忆:摘要旧消息"""
        # 保留最近的消息
        keep_recent = max(3, len(self.messages) // 3)
        old_messages = self.messages[:-keep_recent]
        recent_messages = self.messages[-keep_recent:]

        if len(old_messages) > 2:
            # 将旧消息生成摘要
            summary = self._summarize(old_messages)
            self.messages = [
                {"role": "system", "content": f"历史摘要: {summary}",
                 "tokens": self._count_tokens(summary)}
            ] + recent_messages
        else:
            # 直接丢弃最早的
            self.messages = self.messages[1:]

        self.token_count = sum(m["tokens"] for m in self.messages)

    def _summarize(self, messages):
        """生成对话摘要"""
        text = "\n".join(
            f"{m['role']}: {m['content'][:200]}"
            for m in messages
        )
        return f"[{len(messages)}条对话的摘要] {text[:500]}..."

    def _count_tokens(self, text):
        """估算token数"""
        return len(text) // 3  # 粗略估算

二、长期记忆(Long-term Memory)

长期记忆是Agent跨会话持久化存储的知识库。它允许Agent记住用户的偏好、过去任务的解决方案、积累的领域知识等。长期记忆的核心挑战在于如何高效地存储、检索和更新信息。

长期记忆的主要实现方式:

  • 键值存储:使用简单的键值对存储事实性知识,如用户偏好、配置信息等。
  • 向量数据库:将知识编码为向量嵌入,通过语义相似度检索相关信息。
  • 知识图谱:以图结构存储实体和关系,支持复杂的推理查询。
  • 文档库:存储完整的文档和参考资料,支持全文检索。
class LongTermMemory:
    """长期记忆系统"""

    def __init__(self, vector_store, kv_store=None):
        self.vector_store = vector_store  # 向量数据库
        self.kv_store = kv_store or {}    # 键值存储

    def store_fact(self, key, value, metadata=None):
        """存储事实性知识"""
        self.kv_store[key] = {
            "value": value,
            "metadata": metadata or {},
            "created_at": datetime.now(),
            "access_count": 0
        }

    def store_experience(self, text, embedding, metadata=None):
        """存储经验性知识到向量数据库"""
        self.vector_store.upsert(
            id=uuid4().hex,
            embedding=embedding,
            text=text,
            metadata=metadata or {
                "type": "experience",
                "created_at": datetime.now().isoformat()
            }
        )

    def recall_fact(self, key):
        """回忆事实性知识"""
        if key in self.kv_store:
            self.kv_store[key]["access_count"] += 1
            return self.kv_store[key]["value"]
        return None

    def recall_similar(self, query_embedding, top_k=5):
        """通过语义相似度回忆相关知识"""
        results = self.vector_store.query(
            embedding=query_embedding,
            top_k=top_k,
            filter={"type": {"$in": ["experience", "knowledge"]}}
        )
        return [r["text"] for r in results]

    def consolidate(self):
        """记忆整合:合并重复信息,清理过期记忆"""
        # 清理长期未访问的键值记忆
        cutoff = datetime.now() - timedelta(days=90)
        expired = [
            k for k, v in self.kv_store.items()
            if v["created_at"] < cutoff and v["access_count"] == 0
        ]
        for key in expired:
            del self.kv_store[key]

三、情景记忆(Episodic Memory)

情景记忆是Agent对过去具体经历的记忆,包括时间、地点、参与者和事件细节。与语义记忆(事实和概念)不同,情景记忆保留了事件的时间顺序和上下文信息。

情景记忆对Agent的价值在于:

  • 经验学习:Agent可以回忆过去的成功和失败案例,指导当前决策。
  • 个性化服务:记住与特定用户的历史交互,提供更个性化的响应。
  • 因果推理:通过回顾事件序列,理解因果关系。
  • 自我反思:Agent可以回顾自己的行为,评估和改进策略。

记忆类型的协作

三种记忆类型不是孤立的,而是协同工作。短期记忆提供当前上下文,长期记忆提供持久知识,情景记忆提供历史经验。当Agent处理新任务时,短期记忆维持当前状态,同时从长期记忆中检索相关知识,从情景记忆中检索类似案例。这种协作使得Agent能够像人类一样"触类旁通"。

四、向量存储与嵌入

向量存储是现代Agent记忆系统的核心技术。通过将文本、图像等信息编码为高维向量(嵌入),Agent可以在语义空间中检索相关信息,而不仅仅依赖关键词匹配。

向量存储的关键概念:

  • 嵌入模型:将文本转化为固定维度的向量表示。常用的嵌入模型包括OpenAI的text-embedding-3、BGE、GTE等。
  • 向量数据库:专门存储和检索向量的数据库。常用方案包括Pinecone、Milvus、Chroma、Qdrant等。
  • 相似度搜索:通过计算向量间的距离(余弦相似度、欧氏距离等)找到语义最相近的内容。
  • 索引策略:如HNSW、IVF等近似最近邻算法,平衡检索速度和精度。
class VectorMemoryStore:
    """基于向量的记忆存储"""

    def __init__(self, embedding_model, db_client):
        self.embedding_model = embedding_model
        self.db = db_client

    def embed_text(self, text):
        """将文本编码为向量"""
        return self.embedding_model.encode(text)

    def store(self, text, metadata=None):
        """存储文本及其向量"""
        embedding = self.embed_text(text)
        doc_id = uuid4().hex

        self.db.upsert(
            id=doc_id,
            values=embedding,
            metadata={
                "text": text,
                "created_at": datetime.now().isoformat(),
                **(metadata or {})
            }
        )
        return doc_id

    def search(self, query, top_k=5, threshold=0.7):
        """语义搜索"""
        query_embedding = self.embed_text(query)
        results = self.db.query(
            vector=query_embedding,
            top_k=top_k,
            include_metadata=True
        )

        # 过滤低相似度结果
        filtered = [
            r for r in results["matches"]
            if r["score"] >= threshold
        ]

        return [
            {
                "text": r["metadata"]["text"],
                "score": r["score"],
                "metadata": r["metadata"]
            }
            for r in filtered
        ]

    def store_with_chunking(self, long_text, chunk_size=500):
        """长文本分块存储"""
        chunks = self._chunk_text(long_text, chunk_size)
        ids = []
        for i, chunk in enumerate(chunks):
            doc_id = self.store(
                chunk,
                metadata={
                    "chunk_index": i,
                    "total_chunks": len(chunks),
                    "source": "long_document"
                }
            )
            ids.append(doc_id)
        return ids

    def _chunk_text(self, text, size):
        """文本分块"""
        words = text.split()
        return [
            " ".join(words[i:i+size])
            for i in range(0, len(words), size)
        ]

五、RAG:检索增强生成

RAG(Retrieval-Augmented Generation)是将记忆系统与生成模型结合的核心技术。Agent在生成回答之前,先从记忆库中检索相关信息,然后将检索到的内容作为上下文提供给LLM,从而生成更准确、更有依据的回答。

RAG的工作流程:

  • 索引阶段:将文档库切分为块,生成嵌入向量,存入向量数据库。
  • 检索阶段:用户提问时,将问题编码为向量,在向量数据库中搜索最相关的文档块。
  • 增强阶段:将检索到的文档块与用户问题组合,构建增强提示。
  • 生成阶段:LLM基于增强提示生成回答,引用检索到的信息。

RAG 的优势与局限

RAG让Agent能够利用外部知识库回答问题,无需将所有知识编码到模型参数中。它的优势包括:知识可更新、回答可溯源、减少幻觉。但RAG也有局限:检索质量直接影响生成质量;对于需要深度推理的问题,简单的检索增强可能不够;分块策略不当会丢失上下文关联。

六、记忆系统的工程实践

在OpenClaw等框架中构建生产级记忆系统,需要考虑以下工程问题:

  • 记忆容量规划:根据使用场景估算所需的存储容量和检索性能。
  • 数据一致性:多个Agent共享记忆时,需要处理并发更新和一致性问题。
  • 隐私保护:敏感信息需要加密存储,遵循数据保护法规。
  • 记忆淘汰:定期清理过时或低价值的记忆,保持记忆库的质量。
  • 备份与恢复:建立记忆的定期备份机制,防止数据丢失。

记忆系统是Agent从"无状态工具"进化为"有经验的智能体"的关键。通过合理设计短期记忆、长期记忆和情景记忆的协作机制,结合向量存储和RAG技术,我们可以构建出具有强大学习和适应能力的Agent系统。