AI智能体内存演进:构建永不遗忘的长期记忆系统

文章深入探讨了AI智能体内存系统的演进,从基础的Python列表到Markdown持久化,再到向量搜索,最终提出结合图、向量和关系存储的Cognee开源框架,解决了多跳查询和长效记忆问题。

Image

关于 Agent 记忆的第一性原理探究:从 Python 列表到 Markdown 文件,再到向量搜索与图-向量混合方案,最后是一个简洁的、开源的整体解决方案。

Image

LLM 在设计上是无状态的。每次 API 调用都是从零开始。你在与 ChatGPT 聊天时感受到的“记忆”,其实是通过在每次请求中重新发送整个对话历史而产生的一种错觉。

这种技巧对于日常聊天很有效。但当你尝试构建一个真正的 Agent 时,它就会分崩离析。

无记忆 Agent 的失效模式

如果你跳过记忆环节,以下 7 种失效模式会立即显现:

  1. 上下文健忘症: Agent 会询问你已经提供过的信息。
  2. 零个性化: 每次交互都感觉很生硬。
  3. 多步任务失败: 中间状态在任务中途会默默丢失。
  4. 重复错误: 没有情节性回溯意味着永远在犯同样的错误。
  5. 无知识积累: 每个会话都从零开始。
  6. 间隙引起的幻觉: 当上下文溢出时,模型会胡编乱造。
  7. 身份崩塌: 缺乏连续性,无法建立信任。

显而易见的反应是“投入更多上下文”。这就是为什么 128K 和 200K 的 Token 窗口让人觉得能解决一切。但事实并非如此。

当相关信息处于长上下文的中间位置时,准确度会下降 30% 以上。这就是有据可查的“迷失在中间 (lost in the middle)”效应。上下文是一个共享预算:系统提示词 (System Prompts)、检索到的文档、对话历史和输出都在争夺相同的 Token。即使在 100K Token 下,如果缺乏持久性、优先级和显著性,单纯的上下文长度也是不够的。

Image

记忆并不是要把更多的文本塞进提示词。它是关于如何组织 Agent 记住的内容,以便它能找到重要的东西。

认知科学框架

Lilian Weng 在 2023 年提出的公式已成为默认框架:Agent = LLM + 记忆 + 规划 + 工具使用。

她的分类借鉴了认知科学,在认知科学中,人类记忆分为三个系统:

  • 感官记忆: 捕捉原始感知输入并保留几分之几秒。只有你注意到的部分才会被传递下去。
  • 工作记忆: 活跃思考发生的地方。它一次大约能容纳 7±2 个项目。一旦失去焦点,内容就会消失。
  • 长期记忆: 具有持久性的存储,没有实际的容量限制。检索是瓶颈:你可以存储数百万件事,但仍可能记不起你需要的那一件。

每一部分都直接对应现代 Agent 架构中的一个组件:

Image

长期记忆本身进一步细分:

  • 情节性 (Episodic): 特定的过去事件(“周二,PostgreSQL 集群宕机了”)。
  • 语义性 (Semantic): 事实和概念(“PostgreSQL 是一个关系型数据库”)。
  • 程序性 (Procedural): 技能和工作流(“当用户要求退款时,首先检查购买日期”)。

情节性记忆和语义性记忆之间的桥梁是记忆整合:重复的具体事件提炼成通用知识。如果一个 Agent 在几十次交互中注意到“用户始终偏好执行摘要”,就应该将其转化为一条可重用的规则。

Image

Agent 记忆的演进

剥离掉框架,Agent 就是一个循环:感知、思考、行动。

class Agent:
    """最小化 AI Agent:感知、思考、行动"""
    def __init__(self):
        self.client = anthropic.Anthropic()
        self.model = "claude-sonnet-4-20250514"

    def run(self, user_input: str) -> str:
        response = self.client.messages.create(
            model=self.model,
            max_tokens=1024,
            messages=[{"role": "user", "content": user_input}],
        )
        return response.content[0].text

告诉它“我有 4 个苹果”,然后问“我吃了一个,还剩几个?”,它完全不知道你在说什么苹果。每次调用都是孤立存在的。

第一层:Python 列表

每个人都会想到的第一个修复方案:

class Agent:
    def __init__(self):
        self.client = anthropic.Anthropic()
        self.messages = []  # 整个“记忆”就是一个列表

    def chat(self, user_input: str) -> str:
        self.messages.append({"role": "user", "content": user_input})
        response = self.client.messages.create(
            model="claude-sonnet-4-20250514",
            max_tokens=1024,
            messages=self.messages,  # 每次都发送完整历史记录
        )
        reply = response.content[0].text
        self.messages.append({"role": "assistant", "content": reply})
        return reply

现在可以进行多轮对话了,但很快就会出现两个问题:

  1. 无限制增长: 你会触及上下文上限,最早的消息会被丢弃。
  2. 易失性存储: 所有内容都存在 RAM 中。重启进程,记忆就消失了。

第二层:实现持久化的 Markdown 文件

下一步是将记忆写入磁盘。Markdown 是人类可读的,且易于 Agent 读取。

class MarkdownMemoryAgent:
    def __init__(self):
        self.client = anthropic.Anthropic()
        self.history_file = Path("memory/conversation_history.md")
        self.facts_file = Path("memory/known_facts.md")

    def save_to_disk(self, role: str, content: str) -> None:
        with open(self.history_file, "a") as f:
            f.write(f"### {role} at {datetime.now().isoformat()}\n{content}\n\n")

    def load_history(self) -> str:
        if self.history_file.exists():
            return self.history_file.read_text()
        return ""

    def chat(self, user_input: str) -> str:
        self.save_to_disk("user", user_input)
        history = self.load_history()
        response = self.client.messages.create(
            model="claude-sonnet-4-20250514",
            max_tokens=1024,
            system=f"Previous conversation:\n{history}",
            messages=[{"role": "user", "content": user_input}],
        )
        reply = response.content[0].text
        self.save_to_disk("assistant", reply)
        return reply

持久化问题解决了,但随着文件增大,你无法再加载所有内容。你需要有选择性的检索。关键词搜索(如 grep)过于脆弱,无法处理同义词或复杂的关联。

第三层:向量搜索及其局限性

加入 Embedding。将你的 Markdown 进行分块,对分块进行向量化,并通过余弦相似度进行搜索。现在“数据库”可以匹配“PostgreSQL”了。

然后你会遇到新的瓶颈。考虑这些事实:

  • “Alice 是 Project Atlas 的技术负责人”
  • “Project Atlas 使用 PostgreSQL 作为其主数据存储”
  • “PostgreSQL 集群在周二发生了故障”

用户询问:“Alice 的项目是否受到了周二故障的影响?”

向量搜索可能会找到第一条和第三条事实,但关键的桥梁(“Project Atlas 使用 PostgreSQL”)可能不会出现,因为它与特定查询词的语义相似度不够。连结组织对向量来说是不可见的。

Image

能力矩阵

每一层都解决了前一个痛点,但又揭示了一个更深层的痛点:

Image

你需要在单个记忆层中实现持久化、语义理解和关系推理。

Cognee:统一的知识引擎

Cognee 是一个专为 Agent 记忆构建的开源知识引擎。它将向量搜索与知识图谱以及关系溯源层结合在一起。

该 API 由四个主要的异步调用组成:

import cognee

await cognee.add("Your document here")   # 摄取任何内容
await cognee.cognify()                    # 构建知识图谱 + Embedding
await cognee.memify()                     # 自我完善记忆
await cognee.search("Your query")         # 通过推理进行检索

三种存储架构

Image

Cognee 使用三种存储来捕捉知识的不同维度:

  • 关系型存储: 跟踪溯源(来源、时间、访问权限)。
  • 向量存储: 处理语义和相似性。
  • 图存储: 映射关系和因果链接。

默认技术栈是 SQLite + LanceDB + Kuzu(嵌入式)。对于生产环境,它可以切换到 Postgres、Qdrant/Pinecone 和 Neo4j。

Cognify 和 Memify

cognee.cognify() 运行一个流水线,将原始文本转换为结构化知识:

  1. 文档分类和权限检查。
  2. 结构感知的分块提取。
  3. 实体和关系提取及去重。
  4. 摘要生成。
  5. 向量存储和图存储的双重索引。

Image

memify() 对图进行优化处理,强化有用的路径,修剪陈旧的节点,并根据使用情况识别隐性关系。

Image

检索模式

Cognee 提供了 14 种搜索模式,包括语义搜索、图遍历和混合补全。

Image

使用 Cognee 构建 Agent

以下是如何将 Cognee 接入 Agent 循环:

import cognee
from cognee import SearchType

class CogneeMemoryAgent:
    """具有图-向量混合持久化记忆的 Agent。"""

    def __init__(self, session_id: str = "default"):
        self.llm_client = OpenAI()
        self.session_id = session_id

    async def ingest(self, text: str, dataset: str = "main"):
        await cognee.add(text, dataset)
        await cognee.cognify([dataset])

    async def recall(self, query: str) -> str:
        results = await cognee.search(
            query_text=query,
            query_type=SearchType.GRAPH_COMPLETION,
            session_id=self.session_id,
        )
        return results[0] if results else ""

    async def chat(self, user_input: str) -> str:
        context = await self.recall(user_input)
        messages = [
            {"role": "system", "content": "You are helpful. Use memory context."},
            {"role": "system", "content": f"Memory context:\n{context}"},
            {"role": "user", "content": user_input},
        ]
        response = self.llm_client.chat.completions.create(
            model="gpt-4o-mini", messages=messages
        )
        reply = response.choices[0].message.content
        await cognee.add(
            f"User: {user_input}\nAssistant: {reply}",
            "conversations"
        )
        await cognee.cognify(["conversations"])
        return reply

结论:切实可行的前进之路

在构建 Agent 时,请考虑它需要记住什么。如果查询很简单,向量记忆就足够了。如果查询跨越实体边界,你就需要图遍历。

智能需要结构,而不仅仅是存储。关系、向量和图范式是完整记忆系统互补的层面。将它们视为整体,才能将无状态的 LLM 变成一个真正具备学习能力的 Agent。

  • 原文链接: x.com/akshay_pachaar/sta...
  • 登链社区 AI 助手,为大家转译优秀英文文章,如有翻译不通的地方,还请包涵~
点赞 0
收藏 0
分享
本文参与登链社区写作激励计划 ,好文好收益,欢迎正在阅读的你也加入。

0 条评论

请先 登录 后评论
akshay_pachaar
akshay_pachaar
江湖只有他的大名,没有他的介绍。