前言
- 上一章讲解了如何构建一个简单的 LangChain 应用,但此时的应用是没有记忆的,不知道以前我们说了什么,现在我们使用的大模型应用都是有记忆的,虽然这个记忆有一定长度。本章将讲解如何使用LangChain 构建一个有上下文记忆简单聊天机器人。
准备工作
- 需要了解 LangChain 的基础用法,可以阅读上一篇文章pip安装LangChain:
pip install langchain
调用大模型key,我们主要是学习为主,能白嫖自然白嫖,不需要多么快速的响应,下面是对应的申请方式,都是免费的,其他模型都是需要对应token花费钱的。注意:我们只要申请openai的key,openai更加通用以上两个模型都是免费的,可以放心使用,注意申请 openai 访问方式的key建议使用 Jupyter Notebook,更加方便,安装教程1. 没有记忆的示例
我们先看一个体现 LangChain 调用大模型没有记忆的示例
from langchain_openai import ChatOpenAIfrom langchain_core.messages import HumanMessage, SystemMessage, AIMessagefrom langchain_core.output_parsers import StrOutputParsermodel = ChatOpenAI(model="GLM-4-Flash-250414", api_key="申请的key", base_url="https://open.bigmodel.cn/api/paas/v4/")parser = StrOutputParser()chain = model | parser# 大模型没有记忆print(chain.invoke([HumanMessage(content="你好!我是小明")]))print(chain.invoke([HumanMessage(content="我叫什么名字?")]))
模型给的回答,可以看出现在是没有记忆的
你好,小明!很高兴见到你。请问有什么我可以帮助你的吗?抱歉,我无法回答这个问题。作为一个人工智能助手,我没有访问您的个人信息的权限,因此无法得知您的名字。如果您需要帮助或有其他问题,请随时告诉我。
1.1. 手动增加记忆
为了解决这个问题,我们需要将整个对话历史传递给模型。
from langchain_openai import ChatOpenAIfrom langchain_core.messages import HumanMessage, SystemMessage, AIMessagefrom langchain_core.output_parsers import StrOutputParsermodel = ChatOpenAI(model="GLM-4-Flash-250414", api_key="申请的key", base_url="https://open.bigmodel.cn/api/paas/v4/")parser = StrOutputParser()chain = model | parser# 需要把上下文全部发送print(chain.invoke( [ HumanMessage(content="你好!我是小明"), AIMessage(content="你好,小明!很高兴见到你。请问有什么我可以帮助你的吗?"), HumanMessage(content="我叫什么名字?"), ]))
模型现在知道我们刚才问的什么了,但是这种方式很繁琐需要我们手动维护对话
你的名字是“小明”。
2. 增加消息历史
首先,让我们确保安装 langchain-community,因为我们将使用其中的集成来存储消息历史pip install langchain_community
导入相关类并设置我们的链,该链包装模型并添加此消息历史。这里的一个关键部分是我们作为 get_session_history 传入的函数。这个函数预计接受一个 session_id 并返回一个消息历史对象。这个 session_id 用于区分不同的对话,并应作为配置的一部分在调用新链时传入
from langchain_openai import ChatOpenAIfrom langchain_core.messages import HumanMessagefrom langchain_core.output_parsers import StrOutputParserfrom langchain_core.chat_history import BaseChatMessageHistory, InMemoryChatMessageHistoryfrom langchain_core.runnables.history import RunnableWithMessageHistorymodel = ChatOpenAI(model="GLM-4-Flash-250414", api_key="申请的key", base_url="https://open.bigmodel.cn/api/paas/v4/")store = {}def get_session_history(session_id: str) -> BaseChatMessageHistory: if session_id not in store: store[session_id] = InMemoryChatMessageHistory() # print(store, "store[session_id]") return store[session_id]parser = StrOutputParser()chain = model | parserwith_message_history = RunnableWithMessageHistory(chain, get_session_history)# 创建一个 config,每次都传递给可运行的部分config = {"configurable": {"session_id": "aaaaaa"}}response = with_message_history.invoke( [HumanMessage(content="你好!我是小明")], config=config,)print(response)response = with_message_history.invoke( [HumanMessage(content="我叫什么名字?")], config=config,)print(response)
现在通过定义的 session_id 已经实现了记忆本次对话,可以修改 session_id 来创建不同的对话,也可以随时切换回来(需要将会话内容储存起来,比如说数据库)
你好,小明!很高兴见到你。有什么我可以帮助你的吗?你叫小明。
3. 提示词模板
调用大模型得到完整的答案需要大量特定的提示词,为了方便用户尽可能少的输入提示词,方便用户操作,我们需要提前预设提示词,提示词模板帮助将原始用户信息转换为大型语言模型可以处理的格式。
添加一个提示词模板。为此,我们将创建一个 ChatPromptTemplate。利用 MessagesPlaceholder 来传递所有消息。
from langchain_core.prompts import ChatPromptTemplate, MessagesPlaceholderprompt = ChatPromptTemplate.from_messages( [ ( "system", "你是个乐于助人的助手。尽你所能回答所有问题。", ), MessagesPlaceholder(variable_name="messages"), ])chain = prompt | model
融合入刚才的上下文代码中
from langchain_openai import ChatOpenAIfrom langchain_core.prompts import ChatPromptTemplate, MessagesPlaceholderfrom langchain_core.chat_history import BaseChatMessageHistory, InMemoryChatMessageHistoryfrom langchain_core.runnables.history import RunnableWithMessageHistoryfrom langchain_core.messages import HumanMessagemodel = ChatOpenAI(model="GLM-4-Flash-250414", api_key="申请的key", base_url="https://open.bigmodel.cn/api/paas/v4/")prompt = ChatPromptTemplate.from_messages( [ ( "system", "你是个乐于助人的助手。尽你所能用{language}回答所有问题", ), MessagesPlaceholder(variable_name="messages"), ])chain = prompt | modelstore = {}def get_session_history(session_id: str) -> BaseChatMessageHistory: if session_id not in store: store[session_id] = InMemoryChatMessageHistory() return store[session_id]with_message_history = RunnableWithMessageHistory(chain, get_session_history, input_messages_key="messages")config = {"configurable": {"session_id": "aaaaaa"}}response = with_message_history.invoke( {"messages": [HumanMessage(content="你好!我是小明")], "language": "英语"}, config=config,)print(response.content)response = with_message_history.invoke( {"messages": [HumanMessage(content="我叫什么名字?")], "language": "英语"}, config=config,)print(response.content)
模型的回答,已经按照预设的提示词模版进行了回答注意:各个模型参数回答等有差异,本示例中不能百分百确定正确返回
Hello, Xiao Ming! How can I assist you today?Your name is Xiao Ming.
本章讲解了如何使用 LangChain 构建一个有上下文记忆简单聊天程序,并且增加了提示词模版,但是我们还是没有很好的体现和管理对话历史,控制上下文长度等。下篇我们将讲解如何管理对话历史