【2024最全最细Langchain教程-10】Langchain记忆模块

【2024最全最细Lanchain教程-9】Langchain互联网查询-CSDN博客

        上节课我们介绍了如何利用langchain去加载互联网页面内容(中文信息)、向量化和利用大语言模型进行查询,这节课我们讲一下Langchain的记忆模块。

        我们利用langchain构造最多的就是聊天机器人,而要进行聊天的业务功能,就必须使得大语言模型能够获得上下文,这样对话才能继续。我们注意一下,这句话非常关键:

        记忆组件会将处理过的聊天信息数据注入提示词模板中,将模板传给大语言模型来实现记忆功能

        也就是说,记忆的功能其实是通过prompt模板来实现的,在prompt中要给memory组件预留好一个位置并告诉模板,这个是记忆内容,并在加载模板的时候把上下文注入进去传给大模型,大模型才能够知道你上文说的是啥。

1. 了解和使用一个最简单的记忆组件ConversationBufferMemory

        ConversationBufferMemory是一个最简单的记忆组件,他不对数据结构和获取算法做任何讲过,就是简单的原进原出,我们来看他的代码:

from langchain.memory import ConversationBufferMemory

memory = ConversationBufferMemory()
memory.load_memory_variables({})

        运行load_memory_variables方法(注意要加载一个空的字典),不出意外可以得到空的一个memory:

【2024最全最细Langchain教程-10】Langchain记忆模块_第1张图片

        我们可以加载一些数据给memory再看一下:

memory.chat_memory.add_user_message("hi!")
memory.chat_memory.add_ai_message("what's up?")
memory.load_memory_variables({})

        再加载一下,就可以看到刚才加载的数据了:

【2024最全最细Langchain教程-10】Langchain记忆模块_第2张图片

2. 在LLMChain里加入memory功能

        我们尝试在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保持一致,如果不一致,会报错。

        【2024最全最细Langchain教程-10】Langchain记忆模块_第3张图片

2. 在LLMChain的设置里,可以选择verbose=True,会把创建链的一些中间过程给体现出来,方便理解业务,我们来看代码的运行结果:

【2024最全最细Langchain教程-10】Langchain记忆模块_第4张图片

【2024最全最细Langchain教程-10】Langchain记忆模块_第5张图片

        通过运行结果可以看到每次每次prompt模板加载的内容都有不同,就是每次在调用的时候memory的数据注入进了模板导致的。

3. 在LCEL语法中加入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,大体的流程就是这样的。

        我们进行一下调用看一下结果:

【2024最全最细Langchain教程-10】Langchain记忆模块_第6张图片

        注意我的第二个问题,“他是什么时候去世的?”如果不联系上文,大模型是不知道如何回答你的,我们做一下对比实验:【2024最全最细Langchain教程-10】Langchain记忆模块_第7张图片

        我们重新构造一下memory,然后在第一次invoke之后不加载input和output,然后继续:

【2024最全最细Langchain教程-10】Langchain记忆模块_第8张图片        如果之前你不把聊天记录加载到memory里,大模型就无法回答你的问题。

4. 了解更多类型的memory

        有更多类型的memory组件,我们就不一一介绍了,大家可以去官网上去看,或者简要看一下这个图就行了:

【2024最全最细Langchain教程-10】Langchain记忆模块_第9张图片

        需要用到更细的memory的时候再去学也来得及。

视频教学:【2024最全最细】LangChain之记忆模块_哔哩哔哩_bilibili

本教学演示代码已上传github: https://github.com/jerry1900/jupyter

你可能感兴趣的:(langchain,人工智能,ai,python)