从0开始搭建AI Agent(三)
为什么需要记忆?
LLM 本身是无状态的:每次 API 调用对模型来说都是全新对话,上一轮说了什么它完全不知道。
记忆系统解决的就是这个问题,核心流程只有三步:
1.对话前 ,从 Memory 中加载历史对话;
2.对话中 ,把历史 + 当前问题一起塞进 Prompt 发给 LLM;
3.对话后,把新一轮对话存回 Memory。
下面我们介绍一下Langchain各种记忆类型的使用方式:
一、ConversationBufferMemory
这个是最简单的应用方法,它会把所有的对话原文都保存下来,无损,但缺点就是随着对话的增加,将消耗大量的Token,容易超出模型上下文窗口限制,这种方式适合比较短、保留完整对话的场景(如律师咨询);
代码示例:
新建一个“memory.ipynb”文件,同样,我们需要把上一章的模型加载部分代码搬过来,如下图:

点击运行;
新建一段代码,如下:
from langchain.memory import ConversationBufferMemory
from langchain import ConversationChain
#创建记忆系统
memory = ConversationBufferMemory()
conversation = ConversationChain(
llm=chat,memory=memory)
conversation.predict(input="你好,我的名字叫小明,我是一名软件工程师,我想和你聊一聊人工智能的发展趋势。")
这里,conversation.predict(input="你好,我的名字叫小明,我是一名软件工程师,我想和你聊一聊人工智能的发展趋势。"),我们先发起了一段会话,点击运行;
然后再新建一段代码,模拟第二次会话:
conversation.predict(input="你是谁?")
点击运行;
再新建一段代码,模拟第三次会话:
conversation.predict(input="我是谁?我是什么职业?")
点击运行后,可以看到,模型记住了你的名字和职业。
二、ConversationBufferWindowMemory
这种存储机制,只会存储最近的K条对话记录(包括模型输出和用户输入的),K指的是窗口的大小,表示保留多少轮会话,当新的对话发生时,最旧的对话被移除窗口,确保内存和Token使用量保持在可控范围内;这种模式需要根据应用场景来权衡K值的大小,过小则导致会话丢失,信息不足,过大则失去了效率优势。
代码示例:
from langchain.memory import ConversationBufferWindowMemory
from langchain.chains import ConversationChain
#创建记忆系统
memory = ConversationBufferWindowMemory(k=1)
#会话
conversation = ConversationChain(llm=chat, memory=memory)
运行,k值你可以自己测试,然后就像ConversationBufferMemory会话那样,多开起几轮会话,如:
conversation.predict(input="你好,我的名字叫小明")
conversation.predict(input="你好,我是一名软件工程师")
conversation.predict(input="你好,我的名字叫什么?")
然后,你观察不同的k值,输出结果有何不同;
补充:
记忆系统的memory,会话完成后,如何查看之前的历史记录呢?或者我能否手动追加会话内容?
如下所示:
print(memory.buffer)
print(memory.load_memory_variables({}))
这两种方式都可以打印出之前的会话记录,再看下面,我们可以重新初始化一个memory,如下:
#增加会话上下文
memory = ConversationBufferWindowMemory(k=2)
memory.save_context({"input": "你好,我的名字叫小明"}, {"output": "你好,小明!很高兴认识你。"})
memory.chat_memory.add_user_message("你好,我是一名软件工程师")
memory.chat_memory.add_ai_message("你好,软件工程师!很高兴认识你。")
memory.save_context({"input": "你好,我的名字叫小明"}, {"output": "你好,小明!很高兴认识你。"})
这个时候调用打印历史记录的话,第一次对话:“你好,我的名字叫小明”,“你好,小明!很高兴认识你。”没有保存,因为我的k值取了2,所以它只保存后两轮对话,k值大于2,即可保存全部会话内容了。
三、ConversationTokenBufferMemory
这种存储机制,会根据Token的数量来限制存储对话历史,用户指定一个Token数,系统会保留不超过该限制的最近对话内容,当新对话的加入导致Token总数超过限制时,最早的对话记录会被自动移除,以保持总Token数在指定的范围内。这种模式依赖LLM的Token化规则,需要合理设置最大Token数。
代码示例:
进入自己的conda环境,执行安装命令:
pip install transformers
from langchain.memory import ConversationTokenBufferMemory
from langchain.chains import ConversationChain
memory = ConversationTokenBufferMemory(llm = chat, max_token_limit=60)
#conversation = ConversationChain(llm=chat, memory=memory)
memory.save_context({"input": "你好,我的名字叫小明"}, {"output": "你好,小明!很高兴认识你。"})
memory.chat_memory.add_user_message("你好,我是一名软件工程师")
memory.chat_memory.add_ai_message("你好,软件工程师!很高兴认识你。")
memory.save_context({"input": "你好,我的名字叫小明"}, {"output": "你好,小明!很高兴认识你。"})
print(memory.buffer)
你可以自己设置max_token_limit的值,来测试打印的会话历史记录。
四、ConversationSummaryBufferMemory
这种存储机制是一种混合模式,结合了ConversationBufferMemory和ConversationSummaryMemory的优点;它通过总结早期对话并保留近期对话,保持上下文在Token限时内,同时尽量保留关键信息,这种机制通过智能压缩历史对话,减少Token消耗,同时仍能够提供长期上下文支持;它的缺点是:一是总结的准确性和完整性依赖于使用的LLM,如果总结遗漏关键信息,可能影响上下文连贯性,二是生成对话总结需要额外的LLM调用,增加计算成本和响应时间,它不适合只需要短会话的场景。
代码示例:
from langchain.memory import ConversationSummaryBufferMemory
from langchain.chains import ConversationChain
memory = ConversationSummaryBufferMemory(llm = chat, max_token_limit=20)
conversation = ConversationChain(llm=chat, memory=memory,verbose=True) #verbose=True表示打印出模型的输出结果
print(conversation.predict(input="你好,我的名字叫小明"))
和之前的示例相同,多开几个代码段执行:print(conversation.predict(input="输入会话内容")),输出的标记System的部分,就是机器总结的。
好的,记忆模型就先介绍到这里,后面继续介绍Langchain的文本嵌入模型 ......
更多推荐
所有评论(0)