之前我们讲解了LangChain的提示工程,以及相关的输出解析,乃至于链路选择,但是有一个问题,就是每次当大模型与用户进行交互的时候,总是从头开始的,导致没法进行多轮持久的对话。

如果我们在页面与OpenAI旗下的Chatgpt对话,却能惊奇的发现,其可以记住之前我们与之沟通的细节,从而进行反馈,他是如何实现的呢?这就是大模型中的记忆功能。

图片

是的,在有了OpenAI金玉在前,我们就可以看看如何将记忆这一项和LangChain进行结合。

对于LangChain中的记忆集成,需要涉及到一个Chain对象,ConversationChain,这个Chain的特点在于可以提供记忆功能。

我们先看下在ConversationChain中的默认模板

from langchain import OpenAI

from langchain.chains import ConversationChain

# 初始化大语言模型

llm = OpenAI(

temperature=0.5,

model_name=”text-davinci-003″

)

# 初始化对话链

conv_chain = ConversationChain(llm=llm)

# 打印对话的模板

print(conv_chain.prompt.template)

得到的模板中,主要包含了两个字段,history和input

当然在第一轮的过程中,这两个字段都是空,不过在未来的多轮对话中,会被逐渐的增加填充。

history是用来存储会话记忆的地方

input 是新输入的地方,可以理解为文本框中的输入。

那么我们看下记忆的基本使用ConversationBufferMemory

这是最基本的记忆使用对象,其会讲返回的所有信息全部记录下来。

# 导入所需的库

from langchain import OpenAI

from langchain.chains import ConversationChain

from langchain.chains.conversation.memory import ConversationBufferMemory

# 初始化大语言模型

llm = OpenAI(

temperature=0.5,

model_name=”text-davinci-003″

)

# 初始化对话链

conversation = ConversationChain(

llm=llm,

memory=ConversationBufferMemory()

)

那么我们进行多轮的对话

conversation(“我姐姐明天要过生日,我需要一束生日花束。”)

print(“第一次对话后的记忆:”, conversation.memory.buffer)

第一次对话后的记忆: Human: 我姐姐明天要过生日,我需要一束生日花束。AI:  哦,你姐姐明天要过生日,那太棒了!我可以帮你推荐一些生日花束,你想要什么样的?我知道有很多种,比如玫瑰、康乃馨、郁金香等等。

conversation(“她喜欢粉色玫瑰,颜色是粉色的。”)

print(“第二次对话后的记忆:”, conversation.memory.buffer)

第二次对话后的记忆: Human: 我姐姐明天要过生日,我需要一束生日花束。AI:  哦,你姐姐明天要过生日,那太棒了!我可以帮你推荐一些生日花束,你想要什么样的?我知道有很多种,比如玫瑰、康乃馨、郁金香等等。Human: 她喜欢粉色玫瑰,颜色是粉色的。AI:  好的,那我可以推荐一束粉色玫瑰的生日花束给你。你想要多少朵?我可以帮你定制一束,比如说十朵、二十朵或者更多?

conversation(“我又来了,还记得我昨天为什么要来买花吗?”)

print(“/n第三次对话后的记忆:/n”, conversation.memory.buffer)

Human: 我姐姐明天要过生日,我需要一束生日花束。AI:  哦,你姐姐明天要过生日,那太棒了!我可以帮你推荐一些生日花束,你想要什么样的?我知道有很多种,比如玫瑰、康乃馨、郁金香等等。Human: 她喜欢粉色玫瑰,颜色是粉色的。AI:  好的,那我可以推荐一束粉色玫瑰的生日花束给你,你想要多少朵?Human: 我又来了,还记得我昨天为什么要来买花吗?AI:  是的,我记得你昨天来买花是因为你姐姐明天要过生日,你想要买一束粉色玫瑰的生日花束给她。

利用直接读取上下文中的对话,LLM从而可以对当下的提问作为最优回答,但是有一个问题,直接存储上下文信息固然好,但是响应时间和处理成本也对应的变高了。

而且很多LLM都对输入的上下文长度有限制。

那么怎么办,为此LangChain提供了两种类型的解决方案,分别是

ConversationBufferWindowMemory和ConversationSummaryMemory.

ConversationBufferWindowMemory走的路线是缓冲窗口,即只保留最近几轮的互动记录,之前的就会被抛弃。

from langchain.chains.conversation.memory import ConversationBufferWindowMemory

conversation = ConversationChain(

llm=llm,

memory=ConversationBufferWindowMemory(k=1)

)

这里我们指定了k=1,k是窗口值,意味着只保留k轮对话的记忆

这可能是面对token长度限制的一种解决方案。

除此外就是ConversationSummaryMemory

这是一种交给Ai模型,让其对对话不断的进行总结

从而更加适合长对话,毕竟能把之前的核心内容提炼出来。

from langchain.chains.conversation.memory import ConversationSummaryMemory

summartMemory = ConversationSummaryMemory(llm=llm)

这里我们进行两轮对话

result = conversation(“我姐姐明天要过生日,我需要一束生日花束。”)

print(result)

# 回合2

result = conversation(“她喜欢粉色玫瑰,颜色是粉色的。”)

print(result)

在第二轮的result中,得到的结果

{‘input’: ‘她喜欢粉色玫瑰,颜色是粉色的。’, ‘history’: “nThe human asked what the AI thinks of artificial intelligence. The AI thinks artificial intelligence is a force for good because it will help humans reach their full potential. The human then asked the AI for advice on what type of flower bouquet to get for their sister’s birthday, to which the AI provided a variety of suggestions.”, ‘response’: ‘ 为了为你的姐姐的生日准备一束花,我建议你搭配粉色玫瑰和白色康乃馨。你可以在玫瑰花束中添加一些紫色的满天星,或者添加一些绿叶以增加颜色对比。这将是一束可爱的花束,让你姐姐的生日更加特别。’}

这里的history并不是原本的用户和LLM的对话,而是一个提炼的结果。

在这里用来总结的LLM,不仅可以是同一个大模型,也可以是不同的大模型。

需要注意的是,因为需要调用LLM,所以可能会多一轮的调用。

但上面的SummaryMemory仍然存在一个多轮使用后Token过大的问题。

那么LangChain还存在一个Memory,可以进行多总结

就是ConversationSummaryBufferMemory,对话总缓冲记忆,是一种混合记忆

可以总结的同时只保留最近互动的内容。

这是利用了max_token_limit这个参数做到的

比如我设置为300的时候,超过300的内容就会导致其进行总结,来节省Token长度

这里我们依旧进行一次多轮对话,并查看其history

# 导入所需的库

from langchain import OpenAI

from langchain.chains import ConversationChain

from langchain.chains.conversation.memory import ConversationSummaryBufferMemory

# 初始化大语言模型

llm = OpenAI(

temperature=0.5,

model_name=”text-davinci-003″

)

# 初始化对话链

conversation = ConversationChain(

llm=llm,

memory=ConversationSummaryBufferMemory(

llm=llm,

max_token_limit=300

)

)

# 第一天的对话

# 回合1

result = conversation(“我姐姐明天要过生日,我需要一束生日花束。”)

print(result)

# 回合2

result = conversation(“她喜欢粉色玫瑰,颜色是粉色的。”)

print(result)

# 第二天的对话

# 回合3

result = conversation(“我又来了,还记得我昨天为什么要来买花吗?”)

print(result)

对应的输出分别为

{‘input’: ‘我姐姐明天要过生日,我需要一束生日花束。’, ‘history’: ”, ‘response’: ‘ 哇,你姐姐要过生日啊!那太棒了!我建议你去买一束色彩鲜艳的花束,因为这样可以代表你给她的祝福和祝愿。你可以去你家附近的花店,或者也可以从网上订购,你可以看看有没有特别的花束,比如彩色玫瑰或者百合花,它们会更有特色。’}
{‘input’: ‘她喜欢粉色玫瑰,颜色是粉色的。’, ‘history’: ‘Human: 我姐姐明天要过生日,我需要一束生日花束。nAI:  哇,你姐姐要过生日啊!那太棒了!我建议你去买一束色彩鲜艳的花束,因为这样可以代表你给她的祝福和祝愿。你可以去你家附近的花店,或者也可以从网上订购,你可以看看有没有特别的花束,比如彩色玫瑰或者百合花,它们会更有特色。’, ‘response’: ‘ 好的,那粉色玫瑰就是一个很好的选择!你可以买一束粉色玫瑰花束,这样你姐姐会很开心的!你可以在花店里找到粉色玫瑰,也可以从网上订购,你可以根据你的预算,选择合适的数量。另外,你可以考虑添加一些装饰,比如细绳、彩带或者小礼品’}
{‘input’: ‘我又来了,还记得我昨天为什么要来买花吗?’, ‘history’: “System: nThe human asked the AI for advice on buying a bouquet for their sister’s birthday. The AI suggested buying a vibrant bouquet as a representation of their wishes and blessings, and recommended looking for special bouquets like colorful roses or lilies for something more unique.nHuman: 她喜欢粉色玫瑰,颜色是粉色的。nAI:  好的,那粉色玫瑰就是一个很好的选择!你可以买一束粉色玫瑰花束,这样你姐姐会很开心的!你可以在花店里找到粉色玫瑰,也可以从网上订购,你可以根据你的预算,选择合适的数量。另外,你可以考虑添加一些装饰,比如细绳、彩带或者小礼品”, ‘response’: ‘ 是的,我记得你昨天来买花是为了给你姐姐的生日。你想买一束粉色玫瑰花束来表达你的祝福和祝愿,你可以在花店里找到粉色玫瑰,也可以从网上订购,你可以根据你的预算,选择合适的数量。另外,你可以考虑添加一些装饰,比如细绳、彩带或者小礼品}

其内部机制可以查看,不过可以看出,其本身是对早期的对话进行了总结,从而避免了Token过长的问题。

但是其触发和整体的过程,还可以后续调研查看。

那么总结一下,我们今天介绍了四种记忆机制,分别如下

图片

发表评论

邮箱地址不会被公开。 必填项已用*标注