LangChain系列文章
大多数LLM应用程序都有对话界面。对话的一个重要组成部分是能够引用先前在对话中介绍的信息。最基本的是,对话系统应该能够直接访问某些过去的信息窗口。更复杂的系统将需要具有一个世界模型,它不断更新,这使它能够维护有关实体及其关系的信息。
我们称这种存储关于过去交互的信息的能力为“记忆”。LangChain为系统添加记忆提供了许多实用工具。这些实用工具可以单独使用,也可以无缝地整合到链中。
记忆系统需要支持两个基本操作:读取和写入。请记住,每个链定义了一些核心执行逻辑,期望某些输入。其中一些输入直接来自用户,但一些输入可以来自记忆。链将在给定运行中两次与其记忆系统交互。
在任何内存系统中的两个核心设计决策是:
任何记忆的基础都是所有聊天互动的历史。即使这些并非全部直接使用,也需要以某种形式存储。LangChain记忆模块的关键部分之一是一系列用于存储这些聊天消息的集成,从内存列表到持久性数据库。
保留聊天消息列表相当简单。不太简单的是建立在聊天消息之上的数据结构和算法,以便提供最有用的消息视图。
一个非常简单的记忆系统可能只返回每次运行最近的消息。一个稍微复杂一点的记忆系统可能会返回过去K条消息的简明总结。一个更复杂的系统可能会从存储的消息中提取实体,并且只返回当前运行中涉及的实体信息。
每个应用程序对于如何查询记忆都可能有不同的要求。记忆模块应该让简单的记忆系统易于入门,并且如果需要,也能够编写自定义系统。
让我们来看看LangChain
中Memory
实际上是什么样子。在这里,我们将介绍与任意记忆类互动的基础知识。
让我们来看看如何在链中使用ConversationBufferMemory
。ConversationBufferMemory
是记忆的一种极其简单的形式,它只是在缓冲区中保留聊天消息的列表,并将其传递到提示模板中。
from langchain.memory import ConversationBufferMemory
memory = ConversationBufferMemory()
memory.chat_memory.add_user_message("hi!")
memory.chat_memory.add_ai_message("what's up?")
在使用链式内存时,有一些关键概念需要理解。请注意,这里我们涵盖了对大多数类型的内存都有用的一般概念。每种个别的内存类型可能都有自己必须理解的参数和概念。
在进入链之前,会从内存中读取各种变量。这些变量有特定的名称,需要与链期望的变量相匹配。您可以通过调用memory.load_memory_variables({})
来查看这些变量是什么。请注意,我们传入的空字典只是真实变量的占位符。如果您使用的内存类型依赖于输入变量,您可能需要传入一些变量。
print(memory.load_memory_variables({}))
输出结果
{'history': "Human: hi!\nAI: what's up?"}
在这种情况下,您可以看到load_memory_variables
返回一个名为history
的key。这意味着您的链条(很可能是您的提示)应该期望一个名为history
的输入。通常您可以通过内存类的参数来控制这个变量。例如,如果您希望将内存变量返回到键chat_history
中,您可以这样做:
from langchain.memory import ConversationBufferMemory
memory = ConversationBufferMemory(memory_key="chat_history")
memory.chat_memory.add_user_message("hi!")
memory.chat_memory.add_ai_message("what's up?")
print(memory.load_memory_variables({}))
输出结果
{'chat_history': "Human: hi!\nAI: what's up?"}
这些键的控制参数名称可能因内存类型而异,但重要的是要明白:(1)这是可控的,(2)如何控制它。
最常见的记忆类型之一涉及返回聊天消息列表。这些可以作为单个字符串返回,全部连接在一起(当它们将被传递到LLMs时很有用),或者作为ChatMessages
列表返回(当它们被传递到ChatModels
时很有用)。
默认情况下,它们作为单个字符串返回。为了返回消息列表,您可以设置return_messages=True
from langchain.memory import ConversationBufferMemory
memory = ConversationBufferMemory(memory_key="chat_history", return_messages=True)
memory.chat_memory.add_user_message("hi!")
memory.chat_memory.add_ai_message("what's up?")
print(memory.load_memory_variables({}))
输出结果
{'chat_history': [HumanMessage(content='hi!', additional_kwargs={}, example=False),
AIMessage(content='what's up?', additional_kwargs={}, example=False)]}
通常情况下,链条会接收或返回多个输入/输出键。在这种情况下,我们如何知道要保存哪些键到聊天消息历史记录中?这通常可以通过内存类型的input_key
和output_key
参数来控制。这些参数默认为None
-如果只有一个输入/输出键,则可以直接使用它。但是,如果有多个输入/输出键,则必须指定要使用哪一个的名称。
最后,让我们来看看如何在一个链中使用这个。我们将使用LLMChain,并展示如何同时使用LLM和ChatModel。
# 导入 Langchain 库的 ChatOpenAI 类,用于与 OpenAI 聊天模型进行交互。
from langchain.chat_models import ChatOpenAI
# 导入 Langchain 库的不同提示模板类,用于构建会话提示。
from langchain.prompts import (
ChatPromptTemplate,
MessagesPlaceholder,
SystemMessagePromptTemplate,
HumanMessagePromptTemplate,
)
# 导入 Langchain 的 LLMChain 类,用于创建语言模型链。
from langchain.chains import LLMChain
# 导入 Langchain 的 ConversationBufferMemory 类,用于存储和管理会话记忆。
from langchain.memory import ConversationBufferMemory
# 导入 dotenv 库,用于从 .env 文件加载环境变量,管理敏感数据,如 API 密钥。
from dotenv import load_dotenv
# 调用 load_dotenv 函数来加载 .env 文件中的环境变量。
load_dotenv()
# 创建 ChatOpenAI 的实例。
llm = ChatOpenAI()
# 创建聊天提示模板,包含一个系统消息、一个聊天历史占位符和一个人类消息模板。
prompt = ChatPromptTemplate(
messages=[
SystemMessagePromptTemplate.from_template(
"You are a nice chatbot having a conversation with a human."
),
MessagesPlaceholder(variable_name="chat_history"),
HumanMessagePromptTemplate.from_template("{question}")
]
)
# 创建一个会话记忆,用于存储和返回会话中的消息。
memory = ConversationBufferMemory(memory_key="chat_history", return_messages=True)
# 创建一个 LLMChain 实例,包括语言模型、提示、详细模式和会话记忆。
conversation = LLMChain(
llm=llm,
prompt=prompt,
verbose=True,
memory=memory
)
# 使用会话链处理第一个问题,并打印回应。
response = conversation({"question": "hi"})
print(response)
# 使用相同的会话链处理第二个问题,并打印回应。
response = conversation({"question": "how are you?"})
print(response)
输出
zgpeace at zgpeaces-MBP in ~/Workspace/LLM/langchain-llm-app (develop●) (.venv)
$ python Memory/memory_theory.py
> Entering new LLMChain chain...
Prompt after formatting:
System: You are a nice chatbot having a conversation with a human.
Human: hi
> Finished chain.
{'question': 'hi', 'chat_history': [HumanMessage(content='hi'), AIMessage(content='Hello! How can I assist you today?')], 'text': 'Hello! How can I assist you today?'}
> Entering new LLMChain chain...
Prompt after formatting:
System: You are a nice chatbot having a conversation with a human.
Human: hi
AI: Hello! How can I assist you today?
Human: how are you?
> Finished chain.
{'question': 'how are you?', 'chat_history': [HumanMessage(content='hi'), AIMessage(content='Hello! How can I assist you today?'), HumanMessage(content='how are you?'), AIMessage(content="Thank you for asking! As an AI, I don't have feelings, but I'm here to help you. How can I assist you today?")], 'text': "Thank you for asking! As an AI, I don't have feelings, but I'm here to help you. How can I assist you today?"}
代码
https://github.com/zgpeace/pets-name-langchain/tree/develop
https://python.langchain.com/docs/modules/memory/