在人工智能(AI)的黎明时代,我们创造出的“智能体”大多像是一个个记忆只有七秒的“数字金鱼”。每一次对话都是一次全新的开始,它们无法记住你的名字、你的偏好,更不用说你上周跟它聊过的那个宏伟的旅行计划了。这种“失忆症”极大地限制了 AI 的潜能,使其难以在需要连续性、个性化和强韧性的复杂任务中大展拳。
然而,科学的魅力就在于不断突破看似不可能的界限。今天,我们将一起踏上一段激动人心的旅程,亲手为一位 AI 旅行社特工进行一次“记忆移植手术”。我们将借助强大的内存数据库 Redis 和灵活的智能体框架 LangGraph,为其构建一个兼具短期记忆和长期记忆的复杂大脑。
这次手术的目标,不仅仅是让 AI “记住”东西,而是要教会它如何学习、如何推理、如何利用过去的经验来提供真正个性化的服务。我们将深入探索以下核心技术,揭开 AI 记忆的神秘面纱:
准备好了吗?让我们拿起手术刀,开始这场赋予 AI 持久记忆的革命性手术吧!
人类的大脑之所以强大,在于我们拥有一个精妙绝伦的记忆系统。我们可以记住几秒钟前朋友说的话(短期记忆),也能回忆起童年的夏日午后(长期记忆)。为了让我们的 AI 特工拥有类似的智能,我们必须为其设计一个类似的双重记忆系统。
短期记忆(Short-term Memory):这就像我们脑海中正在进行的“内心独白”。它负责管理当前对话的上下文,确保对话的流畅和连贯。比如,当用户说“我喜欢那个”,AI 需要知道“那个”指的是上一句话里提到的“新加坡金沙酒店”。
长期记忆(Long-term Memory):这是 AI 的知识宝库,存储着可以跨越多次对话、长期保持不变的持久化知识。
在我们的设计中,短期记忆通过 LangGraph 的检查点(Checkpointer)机制 实现。LangGraph 是一个用于构建有状态、多智能体应用的框架。它的工作方式就像一个流程图,数据(或称“状态”)在不同的处理节点之间流动。每当状态流经一个节点(例如,AI 做出回应、调用工具等),检查点机制就会自动将当前对话的所有信息,包括聊天记录和线程元数据,快照并保存到 Redis 中。这确保了即使对话中断,下次也能无缝衔接。
而长期记忆则更为复杂和精妙。我们利用 RedisVL(一个强大的 Redis 客户端库,专为向量相似性搜索设计)来存储和索引两种核心类型的长期记忆:
注解:这种记忆分类与学术界著名的 CoALA(Cognitive Architecture for Language Agents) 论文中的概念不谋而合。CoALA 框架提出,一个完整的认知智能体应包含多种记忆系统。在我们的旅行特工中,它的“程序性记忆”(即如何完成任务的知识,如怎么订票)被编码在了它的 Python 工作流和工具定义中。
在建造宏伟的记忆宫殿之前,我们首先需要一张精确的蓝图。在软件工程中,这张蓝图就是我们的数据模型。通过使用 Pydantic
,一个强大的 Python 数据验证库,我们为 AI 的记忆定义了清晰、严谨的结构。这确保了从记忆的产生、存储到检索的整个生命周期中,数据的格式都是正确和一致的。
让我们来看看构成记忆DNA的四个关键部分:
MemoryType
:记忆类型的枚举
这就像给记忆打上一个分类标签,告诉我们这是关于个人经历的“情景记忆”,还是关于一般事实的“语义记忆”。
class MemoryType(str, Enum):
"""
定义长期记忆的类型,用于分类和检索。
EPISODIC: 个人经历和用户特定偏好
(例如, "用户偏好达美航空", "用户去年去过巴黎")
SEMANTIC: 通用领域知识和事实
(例如, "新加坡需要护照", "东京有出色的公共交通")
"""
EPISODIC = "episodic"
SEMANTIC = "semantic"
Memory
:核心记忆模型
这是代表一条独立记忆的基本单元,包含了记忆的内容(content
)和类型(memory_type
)。
class Memory(BaseModel):
"""代表一个单一的长期记忆。"""
content: str
memory_type: MemoryType
metadata: str
Memories
:记忆容器
大型语言模型(LLM)在分析一段对话后,可能会一次性提取出多条记忆。这个模型就是一个容器,用来存放这些记忆的集合。
class Memories(BaseModel):
"""由LLM从对话中提取的记忆列表。"""
memories: List[Memory]
StoredMemory
:已存储的记忆模型
当一条记忆被正式存入 Redis 后,它就拥有了更多的“身份信息”。这个模型继承自 Memory
,并增加了诸如唯一ID(id
)、创建时间(created_at
)、用户ID(user_id
)等关键元数据。这些信息对于后续的管理和精细化检索至关重要。
class StoredMemory(Memory):
"""一个已存储的长期记忆"""
id: str # Redis中的键
memory_id: ulid.ULID = Field(default_factory=lambda: ulid.ULID())
created_at: datetime = Field(default_factory=datetime.now)
user_id: Optional[str] = None
thread_id: Optional[str] = None
memory_type: Optional[MemoryType]