【LangChain】2 储存
LangChain 的储存模块(Memory)旨在解决语言模型(LLM)在多轮对话中无法保留历史上下文的问题。通过外部储存机制,这些模块帮助 LLM 实现短期记忆的持久化,从而提升对话连贯性和智能性。
储存模块保存用户与模型的交互记录,避免上下文丢失。支持动态更新和检索对话内容。
不同储存类型可单独或组合使用,适应多样化场景需求。与其他 LangChain 组件(如链、代理)无缝集成。
LLM 本身仅保留当前会话的临时记忆,外部储存扩展了记忆保留时间。
四种主要储存类型
对话缓存储存(ConversationBufferMemory)
- 保存完整的对话历史,适用于需要全局上下文的场景。
- 示例代码:
对话缓存窗口储存(ConversationBufferWindowMemory)
- 仅保留最近 k 轮对话,避免历史过长导致资源浪费。
- 参数
k
控制窗口大小。
对话令牌缓存储存(ConversationTokenBufferMemory)
- 基于令牌数限制历史内容,适用于模型有输入长度限制的场景(如 GPT-3)。
- 参数
max_token_limit
设定最大令牌数。
对话摘要缓存储存(ConversationSummaryBufferMemory)
- 对历史对话生成摘要,平衡信息压缩与上下文保留。
- 需配合摘要生成模型(如
OpenAI
)使用。
一、设置Key
import osfrom zhipuai import ZhipuAI
from dotenv import find_dotenv, load_dotenv# 读取本地/项目的环境变量。# find_dotenv()寻找并定位.env文件的路径
# load_dotenv()读取该.env文件,并将其中的环境变量加载到当前的运行环境中
# 如果你设置的是全局的环境变量,这行代码则没有任何作用。
_ = load_dotenv(find_dotenv())# 获取环境变量 OPENAI_API_KEY
key = "f5cd91f2528fed334b9dfd75015791c3.GuLdvM9tXWrGQnAg"
client = ZhipuAI(api_key = key)
二、对话缓存储存
初始化对话模型
from langchain.chains.conversation.base import ConversationChain
from langchain_community.chat_models.zhipuai import ChatZhipuAI
from langchain.memory import ConversationBufferMemory
llm = ChatZhipuAI(temperature=0.0,zhipuai_api_key=key)
memory = ConversationBufferMemory()conversation = ConversationChain(llm=llm, memory = memory, verbose=True )
第一轮对话
conversation.predict(input="你好, 我叫皮皮鲁")
> Entering new ConversationChain chain... Prompt after formatting: The following is a friendly conversation between a human and an AI. The AI is talkative and provides lots of specific details from its context. If the AI does not know the answer to a question, it truthfully says it does not know. Current conversation: Human: 你好, 我叫皮皮鲁 AI: > Finished chain. '你好,皮皮鲁,很高兴认识你!有什么我可以帮助你的吗?无论是生活中的小事,还是你感兴趣的知识点,都可以和我聊聊。😊'
第二轮对话
conversation.predict(input="1+1等于多少?")
> Entering new ConversationChain chain... Prompt after formatting: The following is a friendly conversation between a human and an AI. The AI is talkative and provides lots of specific details from its context. If the AI does not know the answer to a question, it truthfully says it does not know.Current conversation: Human: 你好, 我叫皮皮鲁 AI: 你好,皮皮鲁,很高兴认识你!有什么我可以帮助你的吗?无论是生活中的小事,还是你感兴趣的知识点,都可以和我聊聊。😊 Human: 1+1等于多少? AI:> Finished chain.'1+1等于2。这是一个基础的数学问题。如果你有更复杂的问题,也可以问我哦!😉'
第三轮对话
conversation.predict(input="我叫什么名字?")
> Entering new ConversationChain chain... Prompt after formatting: The following is a friendly conversation between a human and an AI. The AI is talkative and provides lots of specific details from its context. If the AI does not know the answer to a question, it truthfully says it does not know.Current conversation: Human: 你好, 我叫皮皮鲁 AI: 你好,皮皮鲁,很高兴认识你!有什么我可以帮助你的吗?无论是生活中的小事,还是你感兴趣的知识点,都可以和我聊聊。😊 Human: 1+1等于多少? AI: 1+1等于2。这是一个基础的数学问题。如果你有更复杂的问题,也可以问我哦!😉 Human: 我叫什么名字? AI:> Finished chain.'你叫皮皮鲁。如果你需要我帮你回忆我们的对话中的其他内容,也可以告诉我。😊'
查看储存缓存
print(memory.buffer)
Human: 你好, 我叫皮皮鲁 AI: 你好,皮皮鲁,很高兴认识你!有什么我可以帮助你的吗?无论是生活中的小事,还是你感兴趣的知识点,都可以和我聊聊。😊 Human: 1+1等于多少? AI: 1+1等于2。这是一个基础的数学问题。如果你有更复杂的问题,也可以问我哦!😉 Human: 我叫什么名字? AI: 你叫皮皮鲁。如果你需要我帮你回忆我们的对话中的其他内容,也可以告诉我。😊
print(memory.load_memory_variables({}))
{'history': 'Human: 你好, 我叫皮皮鲁\nAI: 你好,皮皮鲁,很高兴认识你!有什么我可以帮助你的吗?无论是生活中的小事,还是你感兴趣的知识点,都可以和我聊聊。😊\nHuman: 1+1等于多少?\nAI: 1+1等于2。这是一个基础的数学问题。如果你有更复杂的问题,也可以问我哦!😉\nHuman: 我叫什么名字?\nAI: 你叫皮皮鲁。如果你需要我帮你回忆我们的对话中的其他内容,也可以告诉我。😊'}
直接添加内容到储存缓存
memory = ConversationBufferMemory()
memory.save_context({"input": "你好,我叫皮皮鲁"}, {"output": "你好啊,我叫鲁西西"})
memory.load_memory_variables({})
memory.save_context({"input": "Not much, just hanging"}, {"output": "Cool"})
memory.save_context({"input": "很高兴和你成为朋友!"}, {"output": "是的,让我们一起去冒险吧!"})
memory.load_memory_variables({})
{'history': 'Human: 你好,我叫皮皮鲁\nAI: 你好啊,我叫鲁西西\nHuman: Not much, just hanging\nAI: Cool\nHuman: 很高兴和你成为朋友!\nAI: 是的,让我们一起去冒险吧!'}
当我们在使用大型语言模型进行聊天对话时,大型语言模型本身实际上是无状态的。语言模型本身并不记得到目前为止的历史对话。每次调用API结点都是独立的。储存(Memory)可以储存到目前为止的所有术语或对话,并将其输入或附加上下文到LLM中用于生成输出。如此看起来就好像它在进行下一轮对话的时候,记得之前说过什么。
三、对话缓存窗口储存
随着对话变得越来越长,所需的内存量也变得非常长。将大量的tokens发送到LLM的成本,也会变得更加昂贵,这也就是为什么API的调用费用,通常是基于它需要处理的tokens数量而收费的。
针对以上问题,LangChain也提供了几种方便的储存方式来保存历史对话。其中,对话缓存窗口储存只保留一个窗口大小的对话。它只使用最近的n次交互。这可以用于保持最近交互的滑动窗口,以便缓冲区不会过大
添加两轮对话到窗口储存
from langchain.memory import ConversationBufferWindowMemory# k=1表明只保留一个对话记忆
memory = ConversationBufferWindowMemory(k=1)
memory.save_context({"input": "你好,我叫皮皮鲁"}, {"output": "你好啊,我叫鲁西西"})
memory.save_context({"input": "很高兴和你成为朋友!"}, {"output": "是的,让我们一起去冒险吧!"})
memory.load_memory_variables({})
{'history': 'Human: 很高兴和你成为朋友!\nAI: 是的,让我们一起去冒险吧!'}
在对话链中应用窗口储存
llm = ChatZhipuAI(temperature=0,zhipuai_api_key=key)
memory = ConversationBufferWindowMemory(k=1)
conversation = ConversationChain(llm=llm, memory=memory, verbose=False )
print(conversation.predict(input="你好, 我叫皮皮鲁"))
print(conversation.predict(input="1+1等于多少?"))
print(conversation.predict(input="我叫什么名字?"))
你好,皮皮鲁,很高兴认识你!有什么我可以帮助你的吗?无论是生活中的小事,还是你感兴趣的知识点,都可以和我聊聊。😊 1+1等于2。这是一个基础的数学问题。如果你有更复杂的问题,也可以问我哦!😉 对不起,我还不知道你的名字。如果你愿意告诉我,我们可以继续进行更个性化的对话。😊
四、对话token缓存储存
使用对话token缓存记忆,内存将限制保存的token数量。如果token数量超出指定数目,它会切掉这个对话的早期部分 以保留与最近的交流相对应的token数量,但不超过token限制。
from langchain.memory import ConversationTokenBufferMemory
memory = ConversationTokenBufferMemory(llm=llm, max_token_limit=30)
memory.save_context({"input": "朝辞白帝彩云间,"}, {"output": "千里江陵一日还。"})
memory.save_context({"input": "两岸猿声啼不住,"}, {"output": "轻舟已过万重山。"})
memory.load_memory_variables({})
{'history': 'AI: 轻舟已过万重山。'}
五、对话摘要缓存储存
对话摘要缓存储存,使用LLM编写到目前为止历史对话的摘要,并将其保存
from langchain.memory import ConversationSummaryBufferMemory
使用对话摘要缓存储存
创建一个长字符串,其中包含某人的日程安排
# 创建一个长字符串
schedule = "在八点你和你的产品团队有一个会议。 \
你需要做一个PPT。 \
上午9点到12点你需要忙于LangChain。\
Langchain是一个有用的工具,因此你的项目进展的非常快。\
中午,在意大利餐厅与一位开车来的顾客共进午餐 \
走了一个多小时的路程与你见面,只为了解最新的 AI。 \
确保你带了笔记本电脑可以展示最新的 LLM 样例."llm = ChatZhipuAI(temperature=0,zhipuai_api_key=key)
memory = ConversationSummaryBufferMemory(llm=llm, max_token_limit=100)
memory.save_context({"input": "你好,我叫皮皮鲁"}, {"output": "你好啊,我叫鲁西西"})
memory.save_context({"input": "很高兴和你成为朋友!"}, {"output": "是的,让我们一起去冒险吧!"})
memory.save_context({"input": "今天的日程安排是什么?"}, {"output": f"{schedule}"})
print(memory.load_memory_variables({})['history'])
基于对话摘要缓存储存的对话链
基于上面的对话摘要缓存储存,新建一个对话链
conversation = ConversationChain(llm=llm, memory=memory, verbose=True)
conversation.predict(input="展示什么样的样例最好呢?")
memory.load_memory_variables({}) # 摘要记录更新了