langChain 基础 03 - 存储

本文介绍使用 LLM 时,利用存储记忆,给予 LLM 感知聊天历史的能力

在提示词内容中,通过传递对话记录给 llm,使得 llm 拥有短期记忆,但是不能每次提问都把以前的对话手动传递给 llm,这太麻烦,本章通过 langchian 的存储组件解决这个问题
Langchain 提供多种模块来管理这些 "短暂记忆",包括:

  • 对话缓存储存 (ConversationBufferMemory)
  • 对话缓存窗口储存 (ConversationBufferWindowMemory)
  • 对话令牌缓存储存 (ConversationTokenBufferMemory)
  • 对话摘要缓存储存 (ConversationSummaryBufferMemory)

对话缓存储存 (ConversationBufferMemory)

1
2
3
4
5
6
7
8
9
10
from langchain.chains import ConversationChain
from langchain.memory import ConversationBufferMemory
# 这里我们将参数temperature设置为0.0,从而减少生成答案的随机性。
# 如果你想要每次得到不一样的有新意的答案,可以尝试增大该参数。
memory = ConversationBufferMemory()
# 新建一个 ConversationChain Class 实例
# verbose参数设置为True时,程序会输出更详细的信息,以提供更多的调试或运行时信息。
# 相反,当将verbose参数设置为False时,程序会以更简洁的方式运行,只输出关键的信息。
conversation = ConversationChain(llm=llm, memory = memory, verbose=True)
conversation.predict(input="你好, 我叫皮皮鲁")
1
2
3
4
5
6
7
8
> 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.
'你好,皮皮鲁!很高兴认识你。我可以称呼你皮皮鲁吗?我听说你是一个非常勇敢的小朋友,有很多奇妙的经历呢。你有什么有趣的故事或者冒险想和我分享的吗?'
1
conversation.predict(input="1+1等于多少?")
1
2
3
4
5
6
7
8
9
10
> 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哦!这是一个基本的加法运算。你在数学方面学得真快呀,皮皮鲁!接下来,我们可以聊聊你的冒险故事了,你最喜欢哪次冒险呢?有没有什么有趣的事情想要分享?'
1
conversation.predict(input="我叫什么名字?")
1
2
3
4
5
6
7
8
9
10
11
12
> 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.
'你叫皮皮鲁哦!看来你已经告诉我你的名字了。你有什么有趣的冒险故事或者想知道的东西想和我一起探索吗?我在这里等着听你的故事呢!'
1
2
# 查看缓存
print(memory.buffer)
1
2
3
4
5
6
Human: 你好, 我叫皮皮鲁
AI: 你好,皮皮鲁!很高兴认识你。我可以称呼你皮皮鲁吗?我听说你是一个非常勇敢的小朋友,有很多奇妙的经历呢。你有什么有趣的故事或者冒险想和我分享的吗?
Human: 1+1等于多少?
AI: 1+1等于2哦!这是一个基本的加法运算。你在数学方面学得真快呀,皮皮鲁!接下来,我们可以聊聊你的冒险故事了,你最喜欢哪次冒险呢?有没有什么有趣的事情想要分享?
Human: 我叫什么名字?
AI: 你叫皮皮鲁哦!看来你已经告诉我你的名字了。你有什么有趣的冒险故事或者想知道的东西想和我一起探索吗?我在这里等着听你的故事呢!

对话缓存窗口储存 (ConversationBufferWindowMemory)

随着对话变得越来越长,所需的内存量也变得非常长,对话缓存窗口储存只保留一个窗口大小的对话。它只使用最近的 n 次交互。这可以用于保持最近交互的滑动窗口,以便缓冲区不会过大

1
2
3
4
5
6
7
8
9
10
11
12
13
from langchain.memory import ConversationBufferWindowMemory
# k=1表明只保留一个对话记忆
memory = ConversationBufferWindowMemory(k=1)
memory.save_context({"input": "你好,我叫皮皮鲁"}, {"output": "你好啊,我叫鲁西西"})
memory.save_context({"input": "很高兴和你成为朋友!"}, {"output": "是的,让我们一起去冒险吧!"})
memory = ConversationBufferWindowMemory(k=1)
conversation = ConversationChain(llm=llm, memory=memory, verbose=False )
print("第一轮对话:")
print(conversation.predict(input="你好, 我叫皮皮鲁"))
print("第二轮对话:")
print(conversation.predict(input="1+1等于多少?"))
print("第三轮对话:")
print(conversation.predict(input="我叫什么名字?"))
1
2
3
4
5
6
第一轮对话:
你好,皮皮鲁,很高兴认识你!我可以叫你皮皮鲁吗?我叫Qwen,是来自阿里云的助手。你喜欢阅读冒险故事吗?我是说,你是否喜欢《皮皮鲁总动员》系列的故事呢?
第二轮对话:
1+1等于2哦!这是一个基本的加法运算。你对数学很有兴趣吗?如果有的问题不懂的话,尽管问我,我会耐心给你解释的。顺便说一句,关于《皮皮鲁总动员》系列的故事,我也很感兴趣呢!里面有很多有趣的冒险故事和角色呢。
第三轮对话:
你没有在对话中告诉我你的名字哦。不过没关系,你可以告诉我你想叫什么名字。如果有关于《皮皮鲁总动员》或其他任何问题,都可以和我分享。我可以帮你解答疑惑或一起探讨有趣的话题!如果你愿意的话,也可以告诉我你的名字是什么。

对话令牌缓存储存 (ConversationTokenBufferMemory)

以上是限制聊天论次,这里是限制 token 数量,内存将限制保存的 token 数量。如果字符数量超出指定数目,它会切掉这个对话的早期部分以保留与最近的交流相对应的字符数量,但不超过字符限制

1
2
3
4
5
6
from langchain.llms import OpenAI
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: 轻舟已过万重山。’}

对话摘要缓存储存 (ConversationSummaryBufferMemory)

直接保存聊天记录,可能内容太多了,每次保存前使用 LLM 总结一下聊天记录,存储总结内容即可

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
from langchain.chains import ConversationChain
from langchain.chat_models import ChatOpenAI
from langchain.memory import ConversationSummaryBufferMemory
# 创建一个长字符串
schedule = "在八点你和你的产品团队有一个会议。 \
你需要做一个PPT。 \
上午9点到12点你需要忙于LangChain。\
Langchain是一个有用的工具,因此你的项目进展的非常快。\
中午,在意大利餐厅与一位开车来的顾客共进午餐 \
走了一个多小时的路程与你见面,只为了解最新的 AI。 \
确保你带了笔记本电脑可以展示最新的 LLM 样例."
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}"})
conversation = ConversationChain(llm=llm, memory=memory, verbose=True)
conversation.predict(input="展示什么样的样例最好呢?")
1
2
3
4
5
6
7
8
9
10
> 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:
System: Hello, User. You introduced yourself as Pipilu. How can I assist you today? The AI greets the user and introduces itself as Lu Xi Xi. They become friends and decide to go on an adventure together. The user asks about their schedule for the day, which includes a meeting with their product team at 8 AM where they need to prepare a PPT. From 9 AM to 12 PM, they are focused on LangChain, as it is a useful tool that will help progress their project quickly. They have a business lunch at an Italian restaurant with a customer who drove for over an hour just to discuss the latest AI developments and brought a laptop to showcase new LLM examples.
Human: 展示什么样的样例最好呢?
AI:
Token indices sequence length is longer than the specified maximum sequence length for this model (1135 > 1024). Running this sequence through the model will result in indexing errors
> Finished chain.
'展示样例的时候,选择那些能够清晰地体现LangChain如何帮助解决实际问题的案例会很好。可以考虑以下几个方面来挑选和准备样例:\n\n1. **具体业务场景**:选择一个具体的业务场景或者项目,比如自动化的数据处理、实时数据分析等。这样可以让对方更直观地看到LangChain的实际应用价值。\n\n2. **技术亮点**:突出展示LangChain在这些场景中的关键优势和技术特性,例如快速构建复杂的数据流系统、提高数据处理效率等。\n\n3. **对比分析**:如果可能的话,可以准备一些基于传统方法和使用LangChain后的效果对比分析。这样不仅能够直观地展示LangChain的优势,还能增加说服力。\n\n4. **实际案例研究**:如果有现成的客户成功案例或者内部项目案例,可以详细讲述这些案例中的问题、解决方案以及最终结果。这不仅可以提供具体的操作指南,还能增强对方对LangChain的信任感和兴趣。\n\n5. **未来展望**:简要介绍LangChain在未来的潜在应用场景和发展趋势,激发客户的想象空间。\n\n例如,在展示时,你可以先概述一下今天将要讨论的主题,比如“今天的会议我们将探讨如何利用LangChain技术来加速我们的数据分析项目。首先,我将通过一个具体的案例来详细说明该技术的应用方式及其带来的好处。”\n\n这样既能确保内容的全面性和实用性,也能让对方保持兴趣并积极参与到对话中来。希望这些建议对你有所帮助!'

这段脚本展示了如何使用 Langchain 库中的不同记忆管理模块来处理和存储对话历史,以便在与 LLM 交互时保持短期记忆。通过示例代码,分别介绍了 ConversationBufferMemory、ConversationBufferWindowMemory、ConversationTokenBufferMemory 和 ConversationSummaryBufferMemory 四种不同的记忆管理方式,用于应对不同类型的需求和场景