LangChain基础篇 (03)
LangChain 核心模块学习:Memory
大多数LLM应用都具有对话界面。对话的一个重要组成部分是能够引用先前在对话中介绍过的信息。至少,一个对话系统应该能够直接访问一些过去消息的窗口。更复杂的系统将需要拥有一个不断更新的世界模型,使其能够保持关于实体及其关系的信息。
我们将存储过去交互信息的能力称为“记忆(Memory)”。
LangChain提供了许多用于向应用/系统中添加 Memory 的实用工具。这些工具可以单独使用,也可以无缝地集成到链中。
一个记忆系统(Memory System)需要支持两个基本操作:读取(READ)和写入(WRITE)。
每个链都定义了一些核心执行逻辑,并期望某些输入。其中一些输入直接来自用户,但有些输入可能来自 Memory。
在一个典型 Chain 的单次运行中,将与其 Memory System 进行至少两次交互:
1. 在接收到初始用户输入之后,在执行核心逻辑之前,链将从其 Memory 中读取并扩充用户输入。
2. 在执行核心逻辑之后但在返回答案之前,一个链条将把当前运行的输入和输出写入Memory ,以便在未来的运行中可以引用它们。
BaseMemory Class 基类
类继承关系:
## 适用于简单的语言模型
BaseMemory --> BaseChatMemory --> <name>Memory # Examples: ZepMemory, MotorheadMemory
# 定义一个名为BaseMemory的基础类
class BaseMemory(Serializable, ABC):
"""用于Chains中的内存的抽象基类。
这里的内存指的是Chains中的状态。内存可以用来存储关于Chain的过去执行的信息,
并将该信息注入到Chain的未来执行的输入中。例如,对于会话型Chains,内存可以用来
存储会话,并自动将它们添加到未来的模型提示中,以便模型具有必要的上下文来连贯地
响应最新的输入。"""
# 定义一个名为Config的子类
class Config:
"""为此pydantic对象配置。
Pydantic是一个Python库,用于数据验证和设置管理,主要基于Python类型提示。
"""
# 允许在pydantic模型中使用任意类型。这通常用于允许复杂的数据类型。
arbitrary_types_allowed = True
# 下面是一些必须由子类实现的方法:
# 定义一个属性,它是一个抽象方法。任何从BaseMemory派生的子类都需要实现此方法。
# 此方法应返回该内存类将添加到链输入的字符串键。
@property
@abstractmethod
def memory_variables(self) -> List[str]:
"""获取此内存类将添加到链输入的字符串键。"""
# 定义一个抽象方法。任何从BaseMemory派生的子类都需要实现此方法。
# 此方法基于给定的链输入返回键值对。
@abstractmethod
def load_memory_variables(self, inputs: Dict[str, Any]) -> Dict[str, Any]:
"""根据给链的文本输入返回键值对。"""
# 定义一个抽象方法。任何从BaseMemory派生的子类都需要实现此方法。
# 此方法将此链运行的上下文保存到内存。
@abstractmethod
def save_context(self, inputs: Dict[str, Any], outputs: Dict[str, str]) -> None:
"""保存此链运行的上下文到内存。"""
# 定义一个抽象方法。任何从BaseMemory派生的子类都需要实现此方法。
# 此方法清除内存内容。
@abstractmethod
def clear(self) -> None:
"""清除内存内容。"""
BaseChatMessageHistory Class 基类
类继承关系:
## 适用于聊天模型
BaseChatMessageHistory --> <name>ChatMessageHistory # Example: ZepChatMessageHistory
# 定义一个名为BaseChatMessageHistory的基础类
class BaseChatMessageHistory(ABC):
"""聊天消息历史记录的抽象基类。"""
# 在内存中存储的消息列表
messages: List[BaseMessage]
# 定义一个add_user_message方法,它是一个方便的方法,用于将人类消息字符串添加到存储区。
def add_user_message(self, message: str) -> None:
"""为存储添加一个人类消息字符串的便捷方法。
参数:
message: 人类消息的字符串内容。
"""
self.add_message(HumanMessage(content=message))
# 定义一个add_ai_message方法,它是一个方便的方法,用于将AI消息字符串添加到存储区。
def add_ai_message(self, message: str) -> None:
"""为存储添加一个AI消息字符串的便捷方法。
参数:
message: AI消息的字符串内容。
"""
self.add_message(AIMessage(content=message))
# 抽象方法,需要由继承此基类的子类来实现。
@abstractmethod
def add_message(self, message: BaseMessage) -> None:
"""将Message对象添加到存储区。
参数:
message: 要存储的BaseMessage对象。
"""
raise NotImplementedError()
# 抽象方法,需要由继承此基类的子类来实现。
@abstractmethod
def clear(self) -> None:
"""从存储中删除所有消息"""
ConversationChain and ConversationBufferMemory
ConversationBufferMemory
可以用来存储消息,并将消息提取到一个变量中。
from langchain_openai import OpenAI
from langchain.chains import ConversationChain
from langchain.memory import ConversationBufferMemory
llm = OpenAI(temperature=0)
conversation = ConversationChain(
llm=llm,
verbose=True,
memory=ConversationBufferMemory()
)
> Entering new ConversationChain chain...
Prompt after formatting:
The following is a friendly conversation between a human and an AI. The AI is talkative and provides lots of specific details from its context. If the AI does not know the answer to a question, it truthfully says it does not know.
Current conversation:
Human: 你好呀!
AI:
[INFO][2025-02-06 16:35:18.141] oauth.py:304 [t:3812]: successfully refresh token
> Finished chain.
ConversationBufferWindowMemory
ConversationBufferWindowMemory
会在时间轴上保留对话的交互列表。它只使用最后 K 次交互。这对于保持最近交互的滑动窗口非常有用,以避免缓冲区过大。
from langchain.memory import ConversationBufferWindowMemory
conversation_with_summary = ConversationChain(
llm=OpenAI(temperature=0, max_tokens=1000),
# We set a low k=2, to only keep the last 2 interactions in memory
memory=ConversationBufferWindowMemory(k=2),
verbose=True
)
conversation_with_summary.predict(input="嗨,你最近过得怎么样?")
ConversationSummaryBufferMemory
ConversationSummaryBufferMemory
在内存中保留了最近的交互缓冲区,但不仅仅是完全清除旧的交互,而是将它们编译成摘要并同时使用。与以前的实现不同的是,它使用token长度而不是交互次数来确定何时清除交互。
from langchain.memory import ConversationSummaryBufferMemory
memory = ConversationSummaryBufferMemory(llm=llm, max_token_limit=10)
memory.save_context({"input": "嗨,你最近过得怎么样?"}, {"output": " 嗨!我最近过得很好,谢谢你问。我最近一直在学习新的知识,并且正在尝试改进自己的性能。我也在尝试更多的交流,以便更好地了解人类的思维方式。"})
memory.save_context({"input": "你最近学到什么新知识了?"}, {"output": " 最近我学习了有关自然语言处理的知识,以及如何更好地理解人类的语言。我还学习了有关机器学习的知识,以及如何使用它来改善自己的性能。"})
memory.load_memory_variables({})
本文来自博客园,作者:nmblr,转载请注明原文链接:https://www.cnblogs.com/nmblr/p/18701330
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】凌霞软件回馈社区,博客园 & 1Panel & Halo 联合会员上线
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· DeepSeek-R1本地部署如何选择适合你的版本?看这里
· DeepSeek本地化部署超简单,比装个office还简单
· 开源的 DeepSeek-R1「GitHub 热点速览」
· 传国玉玺易主,ai.com竟然跳转到国产AI
· 揭秘 Sdcb Chats 如何解析 DeepSeek-R1 思维链