上节课,我我为您介绍了LangChain中最基本的链式结构,以及基于这个链式结构演化出来的ReAct对话链模型。没有看过的小伙伴可以点击链接查看: AI课程合集
今天我将由简入繁,为大家拆解LangChain内置的多种记忆机制。本教程将详细介绍这些记忆组件的工作原理、特性以及使用方法。
历史对话全带上,记忆居然如此低级
随着大模型的发展,语言模型已经能够进行逻辑自洽的对话。但是与人类智能相比,机器对话仍然存在短板,其中一个重要因素就是"记忆力"的缺失。何为记忆力?简单来说,就是机器需要能够记住之前的上下文和知识,并运用这些"记忆",使对话更加流畅合理。
ConversationBufferMemory是LangChain中最基础的记忆组件。它的工作原理非常简单:将对话历史缓存到一个队列中,并提供接口获取历史对话。
这种缓存机制实现了最基本的对话"记忆"功能。当用户询问之前提到的问题时,ConversationBufferMemory可以查找相关记忆,从而使机器人的回答更加连贯合理。
python
# 导入所需的库
from langchain.llms import OpenAI
from langchain.chains import ConversationChain
from langchain.chains.conversation.memory import ConversationBufferMemory
# 初始化大语言模型
# 大模型定义
api_key = ""
api_url = ""
modal= "baichuan"
llm = OpenAI(model_name=modal,openai_api_key=api_key,openai_api_base=api_url,temperature=0.0)
# 初始化对话链
conversation = ConversationChain(
llm=llm,
memory=ConversationBufferMemory()
)
# 第一天的对话
# 回合1
conversation("我姐姐明天要过生日,我需要一束生日花束。")
print("第一次对话后的记忆:", conversation.memory.buffer)
# 回合2
conversation("她喜欢粉色玫瑰,颜色是粉色的。")
print("第二次对话后的记忆:", conversation.memory.buffer)
# 回合3 (第二天的对话)
conversation("我又来了,还记得我昨天为什么要来买花吗?")
print("/n第三次对话后时提示:/n",conversation.prompt.template)
print("/n第三次对话后的记忆:/n", conversation.memory.buffer)
如以上代码和执行结果所示,ConversationBufferMemory会将所有的对话历史存储在buffer中,开发者可以通过'conversation.memory.buffer',访问最近的对话历史。然后基于这些历史信息进行后续处理,从而实现机器人的"记忆"功能,执行结果截图如下:
这种Remember Everything的全历史记忆策略非常简单直接,但是同时也存在一些问题:
- 记忆容量有限,长对话下容易撑爆内存
- 对话噪声也全部记住,降低有效信息密度
所以这只是一个低级的记忆实现,我们还需要更智能的记忆机制,为了解决容量有限及,token耗费过高的问题,Langchain提供了时间窗口记忆组件。
容量有限?试试窗口记忆
既然全历史记忆有容量限制问题,那么可以试试只记住部分重要的对话片段。
ConversationBufferWindowMemory实现了基于时间窗口的记忆策略。
它与全历史缓存的差别在于,只维护一个滑动时间窗口,例如最近5轮对话。超出这个窗口的历史对话将被移出缓存。
ini
# 导入所需的库
from langchain.llms import OpenAI
from langchain.chains import ConversationChain
from langchain.chains.conversation.memory import ConversationBufferWindowMemory
# 初始化大语言模型
# 大模型定义
api_key = ""
api_url = ""
modal= "baichuan"
llm = OpenAI(model_name=modal,openai_api_key=api_key,openai_api_base=api_url,temperature=0.0)
# 初始化对话链
conversation = ConversationChain(
llm=llm,
memory=ConversationBufferWindowMemory(k=1)
)
# 第一天的对话
# 回合1
result = conversation("我姐姐明天要过生日,我需要一束生日花束。")
print(result)
# 回合2
result = conversation("她喜欢粉色玫瑰,颜色是粉色的。")
print("\n第二次对话后的记忆:\n", conversation.memory.buffer)
print(result)
# 第二天的对话
# 回合3
result = conversation("我又来了,还记得我昨天为什么要来买花吗?")
print(result)
如以上代码所示,buffer中只保留了最近一次对话的记忆。这种窗口机制实现了"遗忘"功能,有效控制了记忆容量,防止内存泄漏,执行结果截图如下:
与此同时,通过窗口大小调整,开发者可以平衡记忆容量和内容质量:
- 窗口越大,记住的内容越多
- 窗口越小,记忆更加重点和精炼
但是,本节的截断式遗忘依然是一个相对简单的解决方案。后续我们将探索有选择性地生成"记忆",这才更符合人类智能的特点。
既要还要,这才算是AI记忆
之前的两种记忆机制要么占用过多容量,要么丢失太多重要信息。我们需要一种折中方案------保留关键信息,移除冗余Noise。
ConversationSummary系列组件通过生成语义摘要的方式实现这一目标。
ini
# 导入所需的库
from langchain.llms import OpenAI
from langchain.chains import ConversationChain
from langchain.chains.conversation.memory import ConversationSummaryMemory
# 初始化大语言模型
# 大模型定义
api_key = ""
api_url = ""
modal= "baichuan"
llm = OpenAI(model_name=modal,openai_api_key=api_key,openai_api_base=api_url,temperature=0.0)
# 初始化对话链
conversation = ConversationChain(
llm=llm,
memory=ConversationSummaryMemory(llm=llm)
)
# 第一天的对话
# 回合1
result = conversation("我姐姐明天要过生日,我需要一束生日花束。")
print(result)
# 回合2
result = conversation("她喜欢粉色玫瑰,颜色是粉色的。")
print("\n第二次对话后的记忆:\n", conversation.memory.buffer)
print(result)
# 第二天的对话
# 回合3
result = conversation("我又来了,还记得我昨天为什么要来买花吗?")
print(result)
如以上代码所示,buffer中只保留的记忆并非历史的对话,而是历史对话的摘要,执行结果截图如下:
其工作流程是:
- 对对话历史进行语义分析,提取关键词、实体等语义信息
- 基于这些语义信息,生成文本摘要
- 将生成的摘要作为记忆,而不是完整的对话历史
这种策略融合了记忆质量和容量的考量。摘要只保留了最核心的语义信息,有效减少了冗余,同时质量也更高。
ConversationSummaryMemory会在每轮对话后更新一次摘要。而ConversationSummaryBufferMemory支持配置生成摘要的间隔,从而进一步降低计算消耗。
这里是推荐文章的第四部分内容:
图谱化,记忆向知识进化
前面讨论的几种记忆机制,都是在自然语言的水平上进行对话历史的记录和重用。那么如果能直接建模并记忆更抽象的知识和关系,将是更高一层的进化。
ConversationKGMemory实现了这一目标。它将对话中的实体和事件抽取出来,构建知识图谱;并在回答问题时,探索知识图谱寻找相关记忆。
ini
from langchain.chains.conversation.memory import ConversationKGMemory
from langchain.llms import OpenAI
from langchain.chains import ConversationChain
from langchain.prompts.prompt import PromptTemplate
api_key = ""
api_url = ""
modal= "baichuan"
llm = OpenAI(model_name=modal,openai_api_key=api_key,openai_api_base=api_url,temperature=0.0)
template = """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. The AI ONLY uses information contained in the "Relevant Information" section and does not hallucinate.
Relevant Information:
{history}
Conversation:
Human: {input}
AI:"""
prompt = PromptTemplate(
input_variables=["history", "input"], template=template)
conversation_with_kg = ConversationChain(
llm=llm,
verbose=True,
prompt=prompt,
memory=ConversationKGMemory(llm=llm)
)
conversation_with_kg("我姐姐明天要过生日,我需要一束生日花束。")
conversation_with_kg("她喜欢粉色玫瑰,颜色是粉色的。")
conversation_with_kg("我又来了,还记得我昨天为什么要来买花吗?")
print(conversation_with_kg.memory.kg)
print(conversation_with_kg.memory.kg.get_triples())
如以上代码所示,多次对话过后,模型进行了多个概念的关系组合,形成了一个小型的知识网络,执行结果截图如下:
这样,机器人的记忆获得了概念化的升华,从低级的语言序列,上升为关系网络的知识模型。这也使得记忆的应用更加灵活:
- 可以进行知识推理,呈现更多潜在关联
- 记忆容量也得到扩展
用好实体,AI也会联想
除了建模知识,大模型记忆的另一个途径是通过实体链接链接到大脑知识。ConversationEntityMemory通过实体链接、消歧实现这一目标。
例如用户提到"苹果",实体识别组件会判断其为"苹果公司",从Wikipedia等知识源关联大量相关背景常识。这样当用户询问"蒂姆库克"时,机器人也能很自然地联想到他是苹果公司的CEO这一事实。
python
from langchain.llms import OpenAI
from langchain.chains import ConversationChain
from langchain.chains.conversation.memory import ConversationEntityMemory
from langchain.chains.conversation.prompt import ENTITY_MEMORY_CONVERSATION_TEMPLATE
from pydantic import BaseModel
from typing import List, Dict, Any
api_key = ""
api_url = ""
modal= "baichuan"
llm = OpenAI(model_name=modal,openai_api_key=api_key,openai_api_base=api_url,temperature=0.0)
conversation = ConversationChain(
llm=llm,
verbose=True,
prompt=ENTITY_MEMORY_CONVERSATION_TEMPLATE,
memory=ConversationEntityMemory(llm=llm))
conversation("我姐姐明天要过生日,我需要一束生日花束。")
conversation("她喜欢粉色玫瑰,颜色是粉色的。")
print("\n记忆1:\n",conversation.memory.entity_cache)
conversation("你能帮我联系花店送货上门吗?")
print("\n记忆2:\n",conversation.memory.entity_cache)
如以上代码所示,在不同的对话阶段,模型提炼出了不同的对话实体,对对话内容的理解也更具关联性,执行结果截图如下:
实体和知识图谱可以有效地帮助机器人记住和扩展背景知识,从而支持更丰富、连贯的对话交互。与此同时,相比纯文本的对话历史,基于结构化知识的记忆也更加可解释。
这就是LangChain平台中几种主要的记忆组件。通过它们,开发者可以打造兼具智能对话和知识应用的AI助手。
总结
LangChain作为业内领先的大模型应用平台,提供了多种实用的记忆组件帮助开发者构建有"记忆力"的AI系统。
这些记忆组件从不同角度试图解决之前机器对话固有的遗忘问题:
- ConversationBufferMemory:基于对话历史缓存实现简单的全记忆
- ConversationBufferWindowMemory:利用时间窗口机制控制记忆容量
- ConversationSummaryMemory:通过提取语义摘要,记住关键信息并舍弃Noise
- ConversationKGMemory:将对话实体和事件图谱化,实现知识级记忆
- ConversationEntityMemory:连接外部实体知识,辅助机器人记忆和联想
开发者可以根据实际需求选择使用不同的记忆组件,使AI对话内容更加深层次。此外,这些组件也可以进行定制与扩展,以开发出基于LangChain的创新型应用。
希望本教程能让更多开发者了解并掌握大模型强大的记忆功能,构建出与日俱进、知识渊博的AI助手。