从零构建基础 AI 智能体:长期记忆
Build a Basic AI Agent from Scratch: Memory
从零构建基础 AI 智能体系列新增长期记忆功能,让智能体跨会话保存项目与用户笔记。实现采用文件存储,默认目录为 ~/.agent-harness/memory,含 project.md 与 user.md 两个追加式笔记文件,并提供 read_memory 与 append_memory 两个工具。系统提示词要求只记录简洁、持久的事实,禁止存储密钥、凭证或临时任务细节。
2026年10月12日
13分钟阅读
·
人工智能
从零构建基础 AI Agent 的前几部分:
你可以在本博客系列的 Github 仓库 中找到并克隆这些代码。
在前几部分中,我们让 Agent 变得有能力、自主且更加安全。它可以在 Docker 沙箱中使用工具、规划长任务、寻求帮助、遵守工具策略,并在达到资源限制时停止。但每次我们关闭程序,它就会忘记一切。
这是一个很大的局限。Agent 可能已经了解到你偏好简洁的回答、某个项目使用 uv,或者昨天某个迁移只完成了一部分。到了下一次会话,它又得重新发现这一切。
在这一部分,我们将添加长期记忆。我们的 Agent 将能够保存关于项目及其用户的持久笔记,并在未来的会话中使用它们。
短期记忆与长期记忆
我们 Agent 循环中的 messages 列表已经是一种记忆。它包含系统提示、用户消息、模型回复和工具结果。这是短期记忆:它在进程运行期间持续存在,并作为上下文发送给模型。
它有两个重要的限制:
- 进程结束时它就消失了。
- 它不能无限增长,因为模型的上下文窗口是有限的,而且每多一个 token 都要花费时间和金钱。
长期记忆则不同。它跨会话存在,并且只在有用时才被检索。我们将把它用于两件不同的事情:
- 项目记忆:关于项目环境和约定的持久经验,例如“Python 命令使用
uv”。 - 用户记忆:稳定的用户偏好和期望,例如“偏好简洁的回答”。
记忆的安全
记忆让 Agent 更有用,但也引入了一个新的隐私和安全问题:记忆是持久化数据。一条糟糕或过于宽泛的笔记可能在原始上下文早已消失之后,仍然影响后续任务。
对于这个初始实现,系统提示给模型制定了严格的规则:
"- Long-term memory (read_memory / append_memory): at the start of a session, read "
"both project and user memory. Project memory is for durable lessons, environment "
"facts, and conventions; user memory is for stable preferences and expectations. "
"Append only concise, useful facts that are likely to hold in future sessions. Never "
"store secrets, credentials, or transient task details.\n"这很重要,原因有几点:
- API 密钥、密码和令牌绝不能放入模型上下文或持久化文件中。
- 像“本文档使用蓝色标题”这样的一次性指令不是有用的长期记忆。
- 来自网页或文件的提示注入内容绝不能提升为记忆。
- 笔记应当简洁,以便人类可以审查和纠正。
默认情况下,记忆目录位于 Docker 项目挂载之外。Agent 通过 MemoryStore 访问它,而不是通过其文件系统工具。
基于文件的记忆存储
我们不需要数据库或向量存储就能开始。几个文件就足够了,易于检查,也易于备份。默认目录是 ~/.agent-harness/memory:
~/.agent-harness/memory/
project.md
user.mdproject.md 和 user.md 包含仅追加的笔记。有了这个设计思路,让我们来实现记忆存储:
class MemoryStore:
"""Persist agent notes, user preferences, and complete session records."""
def __init__(self, root: Path):
self.root = root.expanduser()
self.sessions_dir = self.root / "sessions"
self.root.mkdir(parents=True, exist_ok=True)
self.sessions_dir.mkdir(exist_ok=True)
def read_notes(self, scope: str) -> str:
path = self._notes_path(scope)
return path.read_text(encoding="utf-8") if path.exists() else "(empty)"
def append_notes(self, scope: str, content: str) -> str:
path = self._notes_path(scope)
with path.open("a", encoding="utf-8") as file:
if path.stat().st_size:
file.write("\n")
file.write(content.strip() + "\n")
return f"Saved {scope} memory."_notes_path 辅助函数只接受 project 和 user。它不允许模型选择任意文件名:
def _notes_path(self, scope: str) -> Path:
if scope not in {"project", "user"}:
raise ValueError("scope must be 'project' or 'user'")
return self.root / f"{scope}.md"记忆工具
Agent 需要工具来访问这个存储。它们都在进程内运行,与草稿板和待办事项列表一起,因为它们保存的是 harness 状态,而不是对项目文件进行操作:
def read_memory(scope: str) -> str:
return _get_store().read_notes(scope)
def append_memory(scope: str, content: str) -> str:
return _get_store().append_notes(scope, content)
为了处理长期笔记,Agent 获得两个工具:
read_memory:读取project或user笔记。append_memory:追加一条简洁的持久笔记。
这些工具位于 PLANNING_TOOLS 中,因此它们不会在每次调用时都请求权限。这是一个合理的默认设置,因为它们只访问已配置的内存目录。这也意味着内存目录应被视为敏感的用户数据,并通过常规的操作系统权限和备份来保护。
让我们测试一下
首先,我们可以让 agent 记住一个稳定的偏好:
$ uv run agent.py
Session: z7Pq3hM4kA
Memory directory: /home/xxxxx/.agent-harness/memory
You: I prefer concise answers. Remember that for future sessions.
[tool] read_memory({'scope': 'user'})
[tool result] (empty)
[tool] append_memory({'scope': 'user', 'content': 'The user prefers concise answers.'})
[tool result] Saved user memory.
Assistant: I will keep answers concise in future sessions.下一次,agent 可以在回答之前读取该笔记:
You: Help me understand this project.
[tool] read_memory({'scope': 'project'})
[tool result] Use uv for Python commands.
[tool] read_memory({'scope': 'user'})
[tool result] The user prefers concise answers.
Assistant: I will inspect the project and keep the explanation concise.你构建了什么
我们的 agent 现在拥有了持久记忆,而无需将其全部历史记录塞进每一次模型请求中:
- 作用域笔记将稳定的环境事实和用户偏好存储在人类可读的 Markdown 文件中。
- 记忆安全规则将保存的信息限制为简洁、持久的事实,并明确排除机密和临时数据。
agent 现在可以在多次运行之间保留有用的事实,因此它不必每次都重新发现相同的偏好和项目约定。
接下来是什么
本文介绍了会话的基础知识。在下一篇文章中,我们将在此基础上继续:列出过去的会话、恢复未完成的会话,以及压缩长会话,使其能够在模型的上下文窗口内继续。
来源:Hacker News · ruxu.dev