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

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

LLM 在设计上是无状态的。每次 API 调用都是从零开始。你在与 ChatGPT 聊天时感受到的“记忆”,其实是通过在每次请求中重新发送整个对话历史而产生的一种错觉。
这种技巧对于日常聊天很有效。但当你尝试构建一个真正的 Agent 时,它就会分崩离析。
如果你跳过记忆环节,以下 7 种失效模式会立即显现:
显而易见的反应是“投入更多上下文”。这就是为什么 128K 和 200K 的 Token 窗口让人觉得能解决一切。但事实并非如此。
当相关信息处于长上下文的中间位置时,准确度会下降 30% 以上。这就是有据可查的“迷失在中间 (lost in the middle)”效应。上下文是一个共享预算:系统提示词 (System Prompts)、检索到的文档、对话历史和输出都在争夺相同的 Token。即使在 100K Token 下,如果缺乏持久性、优先级和显著性,单纯的上下文长度也是不够的。

记忆并不是要把更多的文本塞进提示词。它是关于如何组织 Agent 记住的内容,以便它能找到重要的东西。
Lilian Weng 在 2023 年提出的公式已成为默认框架:Agent = LLM + 记忆 + 规划 + 工具使用。
她的分类借鉴了认知科学,在认知科学中,人类记忆分为三个系统:
每一部分都直接对应现代 Agent 架构中的一个组件:

长期记忆本身进一步细分:
情节性记忆和语义性记忆之间的桥梁是记忆整合:重复的具体事件提炼成通用知识。如果一个 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 个苹果”,然后问“我吃了一个,还剩几个?”,它完全不知道你在说什么苹果。每次调用都是孤立存在的。
每个人都会想到的第一个修复方案:
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
现在可以进行多轮对话了,但很快就会出现两个问题:
下一步是将记忆写入磁盘。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 使用 PostgreSQL”)可能不会出现,因为它与特定查询词的语义相似度不够。连结组织对向量来说是不可见的。

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

你需要在单个记忆层中实现持久化、语义理解和关系推理。
Cognee 是一个专为 Agent 记忆构建的开源知识引擎。它将向量搜索与知识图谱以及关系溯源层结合在一起。
该 API 由四个主要的异步调用组成:
import cognee
await cognee.add("Your document here") # 摄取任何内容
await cognee.cognify() # 构建知识图谱 + Embedding
await cognee.memify() # 自我完善记忆
await cognee.search("Your query") # 通过推理进行检索

Cognee 使用三种存储来捕捉知识的不同维度:
默认技术栈是 SQLite + LanceDB + Kuzu(嵌入式)。对于生产环境,它可以切换到 Postgres、Qdrant/Pinecone 和 Neo4j。
cognee.cognify() 运行一个流水线,将原始文本转换为结构化知识:

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

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

以下是如何将 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 助手,为大家转译优秀英文文章,如有翻译不通的地方,还请包涵~
如果觉得我的文章对您有用,请随意打赏。你的支持将鼓励我继续创作!