如何迁移到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,如果您想在LangGraph中使用BaseChatMessageHistory
(无论是否使用RunnableWithMessageHistory
)。
自LangChain v0.1起,我们开始建议用户主要依赖BaseChatMessageHistory。BaseChatMessageHistory
作为一个简单的持久化工具,用于存储和检索对话中的消息。
当时,编排LangChain链的唯一选择是通过LCEL。要将内存与LCEL
结合使用,用户必须使用RunnableWithMessageHistory接口。虽然这对于基本的聊天应用程序来说已经足够,但许多用户发现该API不直观且难以使用。
截至LangChain v0.3,我们建议新代码利用LangGraph进行编排和持久化:
- 编排:在LangGraph中,用户定义图表来指定应用程序的流程。这使得用户在需要
LCEL
时,可以在单个节点内继续使用LCEL
,同时轻松定义更易读和可维护的复杂编排逻辑。 - 持久性:用户可以依赖LangGraph的持久性来存储和检索数据。LangGraph的持久性非常灵活,可以支持比
RunnableWithMessageHistory
接口更广泛的使用场景。
如果您一直在使用RunnableWithMessageHistory
或BaseChatMessageHistory
,您不需要做任何更改。我们不计划在不久的将来弃用这些功能。这些功能对于简单的聊天应用程序已经足够,任何使用RunnableWithMessageHistory
的代码将继续按预期工作。
迁移
这些指南假设您对以下概念有一定的了解:
1. 管理对话历史
管理对话历史的目标是以一种对聊天模型使用最优的方式存储和检索历史。
通常这涉及修剪和/或总结对话历史,以保留对话中最相关的部分,同时使对话适应聊天模型的上下文窗口。
属于此类的内存类包括:
内存类型 | 如何迁移 | 描述 |
---|---|---|
ConversationBufferMemory | Link to Migration Guide | 一个基本的内存实现,仅存储对话历史。 |
ConversationStringBufferMemory | Link to Migration Guide | ConversationBufferMemory 的一个特殊案例,专为LLMs设计,现已不再相关。 |
ConversationBufferWindowMemory | Link to Migration Guide | 保留对话的最后n 轮。当缓冲区满时,丢弃最旧的一轮。 |
ConversationTokenBufferMemory | Link to Migration Guide | 仅在对话中的总令牌数不超过某个限制的情况下,保留对话中最新的消息。 |
ConversationSummaryMemory | Link to Migration Guide | 持续总结对话历史。每次对话轮次后更新摘要。该抽象返回对话历史的摘要。 |
ConversationSummaryBufferMemory | Link to Migration Guide | 提供对话的运行摘要以及对话中的最新消息,前提是对话中的总令牌数不超过某个限制。 |
VectorStoreRetrieverMemory | 参见相关的长期记忆代理教程 | 将对话历史存储在向量存储中,并根据输入检索过去对话中最相关的部分。 |
2. 从对话历史中提取结构化信息
请参阅长期记忆代理教程,该教程实现了一个可以从对话历史中提取结构化信息的代理。
属于此类的内存类包括:
内存类型 | 描述 |
---|---|
BaseEntityStore | 一个类似于键值存储的抽象接口。它用于存储在对话过程中学习到的结构化信息。这些信息必须表示为键值对的字典。 |
ConversationEntityMemory | 结合了总结对话的能力,同时从对话历史中提取结构化信息。 |
以及抽象的具体后端实现:
内存类型 | 描述 |
---|---|
InMemoryEntityStore | BaseEntityStore 的一个实现,它将信息存储在计算机的内存(RAM)中。 |
RedisEntityStore | BaseEntityStore 的一个特定实现,使用 Redis 作为后端。 |
SQLiteEntityStore | BaseEntityStore 的一个特定实现,使用 SQLite 作为后端。 |
UpstashRedisEntityStore | BaseEntityStore 的一个特定实现,使用 Upstash 作为后端。 |
这些抽象自首次发布以来发展有限。这是因为它们通常需要对特定应用进行大量定制才能有效,这使得它们不如对话历史管理抽象那样广泛使用。
因此,没有针对这些抽象的迁移指南。如果您在迁移依赖这些抽象的应用程序时遇到困难,请:
- 请查看这个长期记忆代理教程,它应该为如何从对话历史中提取结构化信息提供一个良好的起点。
- 如果您仍然遇到困难,请在LangChain GitHub仓库上提交一个问题,解释您的使用案例,我们将尽力提供更多关于如何迁移这些抽象概念的指导。
从对话历史中提取结构化信息的通用策略是使用具有工具调用功能的聊天模型来从对话历史中提取结构化信息。 提取的信息随后可以保存到适当的数据结构中(例如,字典),并且可以根据需要从中检索信息并将其添加到提示中。
3. 在一个或多个内存实现之上提供复合逻辑的实现
属于此类的内存类包括:
内存类型 | 描述 |
---|---|
CombinedMemory | 此抽象接受一个BaseMemory 列表,并根据输入从每个列表中获取相关的内存信息。 |
SimpleMemory | 用于添加只读的硬编码上下文。用户可以简单地将此信息写入提示中。 |
ReadOnlySharedMemory | 提供了现有BaseMemory 实现的只读视图。 |
这些实现似乎没有被广泛使用或提供显著的价值。用户应该能够在自定义代码中重新实现这些功能,而不会遇到太多困难。
相关资源
探索LangGraph的持久性:
使用简单的LCEL添加持久性(对于更复杂的用例,推荐使用langgraph):
处理消息历史记录: