【2024最全最细Lanchain教程-9】Langchain互联网查询-CSDN博客
上节课我们介绍了如何利用langchain去加载互联网页面内容(中文信息)、向量化和利用大语言模型进行查询,这节课我们讲一下Langchain的记忆模块。
我们利用langchain构造最多的就是聊天机器人,而要进行聊天的业务功能,就必须使得大语言模型能够获得上下文,这样对话才能继续。我们注意一下,这句话非常关键:
记忆组件会将处理过的聊天信息数据注入提示词模板中,将模板传给大语言模型来实现记忆功能。
也就是说,记忆的功能其实是通过prompt模板来实现的,在prompt中要给memory组件预留好一个位置并告诉模板,这个是记忆内容,并在加载模板的时候把上下文注入进去传给大模型,大模型才能够知道你上文说的是啥。
ConversationBufferMemory是一个最简单的记忆组件,他不对数据结构和获取算法做任何讲过,就是简单的原进原出,我们来看他的代码:
from langchain.memory import ConversationBufferMemory
memory = ConversationBufferMemory()
memory.load_memory_variables({})
运行load_memory_variables方法(注意要加载一个空的字典),不出意外可以得到空的一个memory:
我们可以加载一些数据给memory再看一下:
memory.chat_memory.add_user_message("hi!")
memory.chat_memory.add_ai_message("what's up?")
memory.load_memory_variables({})
再加载一下,就可以看到刚才加载的数据了:
我们尝试在LLMChain里,加入memory功能,下面是完整的可直接运行代码:
import os
from langchain_openai import OpenAI
from langchain.prompts import PromptTemplate
from langchain.chains import LLMChain
from langchain.memory import ConversationBufferMemory
llm = OpenAI(
temperature=0,
openai_api_key = os.getenv("OPENAI_API_KEY"),
base_url = os.getenv("OPENAI_BASE_URL")
)
# 注意,在模板里,要给聊天记录留下位置,聊天记录是通过注入给模板来实现的
template = """You are a nice chatbot having a conversation with a human.
Previous conversation:
{chat_history}
New human question: {question}
Response:"""
prompt = PromptTemplate.from_template(template)
# `memory_key`要和模板里的参数保持一致
memory = ConversationBufferMemory(memory_key="chat_history")
conversation = LLMChain(
llm=llm,
prompt=prompt,
verbose=True,
memory=memory
)
conversation.invoke({"question":"hi"})
conversation.invoke({"question":"你最喜欢什么动物?"})
conversation.invoke({"question":"那么它最爱吃什么?"})
memory.load_memory_variables({})
注意几个要点:
1. 模板里要预留好memory参数的位置,且要和构造memory时,设置的memory_key保持一致,如果不一致,会报错。
2. 在LLMChain的设置里,可以选择verbose=True,会把创建链的一些中间过程给体现出来,方便理解业务,我们来看代码的运行结果:
通过运行结果可以看到每次每次prompt模板加载的内容都有不同,就是每次在调用的时候memory的数据注入进了模板导致的。
我们尝试在LCEL语法的chain中加入memory功能,下面是hi代码实现:
import langchain
import os
from operator import itemgetter
from langchain_openai import ChatOpenAI
from langchain_core.prompts import ChatPromptTemplate,MessagesPlaceholder
from langchain_core.runnables import RunnableLambda, RunnablePassthrough
from langchain.memory import ConversationBufferMemory
llm = ChatOpenAI(
temperature=0,
openai_api_key = os.getenv("OPENAI_API_KEY"),
base_url = os.getenv("OPENAI_BASE_URL")
)
这块是引入必要的包、构建好模型,然后继续:
memory = ConversationBufferMemory(return_messages=True)
prompt = ChatPromptTemplate.from_messages([
("system", "你是一个中国历史专家."),
MessagesPlaceholder(variable_name="history"),
("user", "{input}")
])
memory.load_memory_variables({})
这里注意,因为我们用的是ChatOpenAI聊天模型包装器,所以return_messages 要选择True,否则memory的输出会是str。
然后我们在构造提示词的时候,需要用这个占位符来实现memory的插入,注意这里的variable_name是memory默认的history,如果你要改成chat_history,在memory构造的时候就要把key重新声明一下,这里我们就不改了,就用默认的history:
MessagesPlaceholder(variable_name="history"),
我们继续:
chain = (
RunnablePassthrough.assign(
history=RunnableLambda(memory.load_memory_variables) | itemgetter("history")
)
| prompt
| llm
)
input = {"input":"中国改革开放的总设计师是谁?"}
response = chain.invoke(input)
print(response)
memory.save_context(input, {"output": response.content})
memory.load_memory_variables({})
这一行的难点在于:
RunnablePassthrough.assign(
history=RunnableLambda(memory.load_memory_variables) | itemgetter("history")
)
这里用RunnablePassthrough把用户输入的input传入,同时使用RunnableLambda方法将memory做加载(第一轮是空的,不过没关系,第二次调用就有数据里),RunnableLambda把memory加载获得数据(字典)赋值给history,构造了一个字典{“history”:"{}"},然后传给itemgetter,itemgetter把键值对里的值取出来然后再传给 prompt,大体的流程就是这样的。
我们进行一下调用看一下结果:
注意我的第二个问题,“他是什么时候去世的?”如果不联系上文,大模型是不知道如何回答你的,我们做一下对比实验:
我们重新构造一下memory,然后在第一次invoke之后不加载input和output,然后继续:
如果之前你不把聊天记录加载到memory里,大模型就无法回答你的问题。
有更多类型的memory组件,我们就不一一介绍了,大家可以去官网上去看,或者简要看一下这个图就行了:
需要用到更细的memory的时候再去学也来得及。
视频教学:【2024最全最细】LangChain之记忆模块_哔哩哔哩_bilibili
本教学演示代码已上传github: https://github.com/jerry1900/jupyter