当前位置:   article > 正文

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

lanchain

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

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

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

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

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

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

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

  1. from langchain.memory import ConversationBufferMemory
  2. memory = ConversationBufferMemory()
  3. memory.load_memory_variables({})

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

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

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

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

2. 在LLMChain里加入memory功能

        我们尝试在LLMChain里,加入memory功能,下面是完整的可直接运行代码:

  1. import os
  2. from langchain_openai import OpenAI
  3. from langchain.prompts import PromptTemplate
  4. from langchain.chains import LLMChain
  5. from langchain.memory import ConversationBufferMemory
  6. llm = OpenAI(
  7. temperature=0,
  8. openai_api_key = os.getenv("OPENAI_API_KEY"),
  9. base_url = os.getenv("OPENAI_BASE_URL")
  10. )
  11. # 注意,在模板里,要给聊天记录留下位置,聊天记录是通过注入给模板来实现的
  12. template = """You are a nice chatbot having a conversation with a human.
  13. Previous conversation:
  14. {chat_history}
  15. New human question: {question}
  16. Response:"""
  17. prompt = PromptTemplate.from_template(template)
  18. # `memory_key`要和模板里的参数保持一致
  19. memory = ConversationBufferMemory(memory_key="chat_history")
  20. conversation = LLMChain(
  21. llm=llm,
  22. prompt=prompt,
  23. verbose=True,
  24. memory=memory
  25. )
  26. conversation.invoke({"question":"hi"})
  27. conversation.invoke({"question":"你最喜欢什么动物?"})
  28. conversation.invoke({"question":"那么它最爱吃什么?"})
  29. memory.load_memory_variables({})

        注意几个要点:

1. 模板里要预留好memory参数的位置,且要和构造memory时,设置的memory_key保持一致,如果不一致,会报错。

        

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

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

3. 在LCEL语法中加入memory功能

        我们尝试在LCEL语法的chain中加入memory功能,下面是hi代码实现:

  1. import langchain
  2. import os
  3. from operator import itemgetter
  4. from langchain_openai import ChatOpenAI
  5. from langchain_core.prompts import ChatPromptTemplate,MessagesPlaceholder
  6. from langchain_core.runnables import RunnableLambda, RunnablePassthrough
  7. from langchain.memory import ConversationBufferMemory
  8. llm = ChatOpenAI(
  9. temperature=0,
  10. openai_api_key = os.getenv("OPENAI_API_KEY"),
  11. base_url = os.getenv("OPENAI_BASE_URL")
  12. )

        这块是引入必要的包、构建好模型,然后继续:

  1. memory = ConversationBufferMemory(return_messages=True)
  2. prompt = ChatPromptTemplate.from_messages([
  3. ("system", "你是一个中国历史专家."),
  4. MessagesPlaceholder(variable_name="history"),
  5. ("user", "{input}")
  6. ])
  7. memory.load_memory_variables({})

        这里注意,因为我们用的是ChatOpenAI聊天模型包装器,所以return_messages 要选择True,否则memory的输出会是str。

        然后我们在构造提示词的时候,需要用这个占位符来实现memory的插入,注意这里的variable_name是memory默认的history,如果你要改成chat_history,在memory构造的时候就要把key重新声明一下,这里我们就不改了,就用默认的history:

MessagesPlaceholder(variable_name="history"),

        我们继续:

  1. chain = (
  2. RunnablePassthrough.assign(
  3. history=RunnableLambda(memory.load_memory_variables) | itemgetter("history")
  4. )
  5. | prompt
  6. | llm
  7. )
  8. input = {"input":"中国改革开放的总设计师是谁?"}
  9. response = chain.invoke(input)
  10. print(response)
  11. memory.save_context(input, {"output": response.content})
  12. memory.load_memory_variables({})

        这一行的难点在于:

  1. RunnablePassthrough.assign(
  2. history=RunnableLambda(memory.load_memory_variables) | itemgetter("history")
  3. )

        这里用RunnablePassthrough把用户输入的input传入,同时使用RunnableLambda方法将memory做加载(第一轮是空的,不过没关系,第二次调用就有数据里),RunnableLambda把memory加载获得数据(字典)赋值给history,构造了一个字典{“history”:"{}"},然后传给itemgetter,itemgetter把键值对里的值取出来然后再传给 prompt,大体的流程就是这样的。

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

        注意我的第二个问题,“他是什么时候去世的?”如果不联系上文,大模型是不知道如何回答你的,我们做一下对比实验:

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

        如果之前你不把聊天记录加载到memory里,大模型就无法回答你的问题。

4. 了解更多类型的memory

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

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

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

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

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/繁依Fanyi0/article/detail/287360
推荐阅读
相关标签
  

闽ICP备14008679号