如何迁移到 LangGraph 记忆
自 LangChain v0.3 版本发布以来,我们建议 LangChain 用户利用 LangGraph 持久化 将 memory 集成到他们的 LangChain 应用中。
- 依赖
RunnableWithMessageHistory或BaseChatMessageHistory的用户 无需 进行任何更改,但鼓励他们考虑使用 LangGraph 来处理更复杂的用例。 - 依赖 LangChain 0.0.x 中已弃用的记忆抽象的用户应遵循本指南,升级到 LangChain 0.3.x 中的新 LangGraph 持久化功能。
为什么在 LangGraph 中使用记忆?
LangGraph 持久化的主要优势包括:
- 内置支持多用户和多会话,这是真实会话式 AI 应用的典型需求。
- 能够随时保存和恢复复杂的对话。这有助于:
- 错误恢复
- 允许人工干预 AI 工作流
- 探索不同的对话路径(“时间旅行”)
- 与传统的语言模型和现代聊天模型完全兼容。LangChain 中早期的记忆实现并未为新的聊天模型 API 设计,导致了诸如工具调用等功能出现问题。LangGraph 记忆可以持久化任何自定义状态。
- 高度可定制,允许您完全控制记忆的工作方式并使用不同的存储后端。
LangChain 中记忆的演进
自发布以来,LangChain 中的记忆概念已发生重大演变。
LangChain 0.0.x 记忆
总的来说,LangChain 0.0.x 记忆用于处理三个主要用例:
| 用例 | 示例 |
|---|---|
| 管理对话历史 | 只保留用户和 AI 之间对话的最后 n 轮。 |
| 提取结构化信息 | 从对话历史中提取结构化信息,例如关于用户所学知识的列表。 |
| 复合记忆实现 | 组合多个记忆来源,例如,关于用户已知事实的列表以及在给定对话中学习到的事实。 |
虽然 LangChain 0.0.x 记忆抽象很有用,但它们的功能有限,并且不适合真实的会话式 AI 应用。这些记忆抽象缺乏对多用户、多会话场景的原生支持,而这对于实际的会话式 AI 系统至关重要。
其中大部分实现已在 LangChain 0.3.x 中被 LangGraph 持久化正式弃用。
RunnableWithMessageHistory 和 BaseChatMessageHistory
如果您想在 LangGraph 中使用 BaseChatMessageHistory(无论是否使用 RunnableWithMessageHistory),请参阅如何将 BaseChatMessageHistory 用于 LangGraph。
从 LangChain v0.1 开始,我们开始建议用户主要依赖 BaseChatMessageHistory。BaseChatMessageHistory 作为一种简单的持久化机制,用于存储和检索对话中的消息。
当时,编排 LangChain 链的唯一选择是通过 LCEL。要结合使用 LCEL 和记忆,用户必须使用 RunnableWithMessageHistory 接口。虽然这对于基本的聊天应用来说已经足够,但许多用户发现该 API 直观性不足且难以使用。
从 LangChain v0.3 开始,我们建议新代码利用 LangGraph 进行编排和持久化:
- 编排:在 LangGraph 中,用户定义图来指定应用程序的流程。这允许用户在需要时使用
LCEL,同时轻松定义更具可读性和可维护性的复杂编排逻辑。 - 持久化:用户可以依赖 LangGraph 的持久化来存储和检索数据。LangGraph 持久性非常灵活,可以支持比
RunnableWithMessageHistory接口更广泛的用例。
如果您一直在使用 RunnableWithMessageHistory 或 BaseChatMessageHistory,则无需进行任何更改。我们不计划在不久的将来弃用任一功能。此功能对于简单的聊天应用程序已足够,并且任何使用 RunnableWithMessageHistory 的代码将继续按预期工作。
迁移
这些指南假定您对以下概念有所了解:
1. 管理对话历史
管理对话历史的目标是以最适合聊天模型使用的方式存储和检索历史记录。
这通常涉及修剪和/或总结对话历史,以保留对话中最相关的部分,同时使对话适合聊天模型的上下文窗口。
属于此类的记忆类包括:
| 记忆类型 | 如何迁移 | 描述 |
|---|---|---|
ConversationBufferMemory | 迁移指南链接 | 基本记忆实现,仅存储对话历史。 |
ConversationStringBufferMemory | 迁移指南链接 | ConversationBufferMemory 的特例,专为 LLM 设计,现已不再相关。 |
ConversationBufferWindowMemory | 迁移指南链接 | 保留对话的最后 n 轮。当缓冲区已满时,会丢弃最旧的一轮。 |
ConversationTokenBufferMemory | 迁移指南链接 | 保留对话中最近的消息,同时限制对话中的总令牌数不超过特定限制。 |
ConversationSummaryMemory | 迁移指南链接 | 持续总结对话历史。每次对话轮次后都会更新摘要。该抽象返回对话历史的摘要。 |
ConversationSummaryBufferMemory | 迁移指南链接 | 提供对话的运行摘要以及对话中最近的消息,同时限制对话中的总令牌数不超过特定限制。 |
VectorStoreRetrieverMemory | 请参阅相关的长期记忆代理教程 | 将对话历史存储在矢量存储中,并根据输入检索过去对话中最相关的部分。 |
2. 从对话历史中提取结构化信息
请参阅长期记忆代理教程,该教程实现了一个可以从对话历史中提取结构化信息的代理。
属于此类的记忆类包括:
| 记忆类型 | 描述 |
|---|---|
BaseEntityStore | 一个类似于键值存储的抽象接口。它用于存储在对话中学习到的结构化信息。信息必须表示为键值对的字典。 |
ConversationEntityMemory | 结合了总结对话的能力,同时从对话历史中提取结构化信息。 |
以及抽象的特定后端实现:
| 记忆类型 | 描述 |
|---|---|
InMemoryEntityStore | BaseEntityStore 的一个实现,将信息存储在计算机内存(RAM)中。 |
RedisEntityStore | 使用 Redis 作为后端的 BaseEntityStore 的特定实现。 |
SQLiteEntityStore | 使用 SQLite 作为后端的 BaseEntityStore 的特定实现。 |
UpstashRedisEntityStore | 使用 Upstash 作为后端的 BaseEntityStore 的特定实现。 |
这些抽象自发布以来只得到了有限的开发。这是因为它们通常需要针对特定应用程序进行大量定制才能有效,这使得它们的普及程度不及对话历史管理抽象。
因此,没有这些抽象的迁移指南。如果您在迁移依赖这些抽象的应用时遇到困难,请执行以下操作:
- 请查阅此长期记忆代理教程,该教程应能提供提取对话历史结构化信息的良好起点。
- 如果您仍然遇到困难,请在 LangChain GitHub 存储库上打开一个 issue,解释您的用例,我们将 尝试提供有关如何迁移这些抽象的更多指导。
从对话历史中提取结构化信息的通用策略是使用支持工具调用的聊天模型从对话历史中提取结构化信息。 提取的信息可以保存到适当的数据结构(例如,字典)中,然后可以检索其中的信息并根据需要添加到提示中。
3. 在一个或多个记忆实现之上提供复合逻辑的实现
属于此类的记忆类包括:
| 记忆类型 | 描述 |
|---|---|
CombinedMemory | 此抽象接受一个 BaseMemory 列表,并根据输入从每个列表中获取相关的记忆信息。 |
SimpleMemory | 用于添加只读的硬编码上下文。用户可以直接将此信息写入提示。 |
ReadOnlySharedMemory | 为现有的 BaseMemory 实现提供只读视图。 |
这些实现似乎并未被广泛使用或提供显著的价值。用户应该能够非常轻松地在自定义代码中重新实现它们。
相关资源
通过 LangGraph 探索持久化:
使用简单的 LCEL 添加持久化(对于更复杂的用例,请优先使用 langgraph):
处理消息历史: