使用GLM-4-Long实现超长记忆

向量数据库大模型机器学习

我们都知道,大模型本身是无状态、无记忆的。默认情况下,我们对大模型的每次提问,在其内部都会被视为一次全新的调用。尽管诸如 ChatGPT 等聊天应用内置了部分记忆功能,可以记录用户最近几轮的聊天信息,但它仍然存在上下文长度限制,对话历史超过一定长度后,就会强制开启新一轮对话。

为了解决这个问题,很多 AIGC 应用都需要独立开发记忆系统,特别是像 AI 聊天陪伴、RAG、智能客服等应用,记忆系统的质量会直接影响到用户体验和产品口碑。目前,业内典型的 Memery 实现方案如下:

  1. 全量缓冲记忆 ======

1.1 实现思路

最基础的记忆模式,将所有 Human/AI 生成的消息全部存储起来,每次需要使用时将保存的所有聊天消息列表全部传递到 Prompt 中,通过往用户的输入中添加历史对话信息/记忆,可以让 LLM 能理解之前的对话内容,而且这种记忆方式在上下文窗口限制内是无损的。

1.2 优点

  1. 在上下文窗口内可以实现无损记忆,可以记忆用户输入的全部内容。
  2. 实现方式简单,兼容性最好,所有大模型都支持。

1.3 缺点

  1. 将全部的历史上下文都传递给 LLM,输入中会包含大量的 Token,会导致响应时间变慢和成本增加。

  2. LLM 的上下文有最大的 token 限制,无法记忆太长的对话。

  3. 记忆内容不是无限的,对于上下文长度较小的模型来说,记忆内容会变得极短。

  4. 缓冲窗口记忆 ======

2.1 实现思路

在缓冲记忆的基础上,增加上下文窗口限制,即只保留固定轮次的历史对话,"遗忘"掉过于久远的记忆。

2.2 优点

  1. 在窗口内可以实现无损记忆。
  2. 对小模型也比较友好,在不提问较为久远的内容时效果最佳。
  3. 实现方式简单,性能优异,所有大模型都支持。

2.3 缺点

  1. 无法保留长期的记忆,会遗忘之前的互动。

  2. 如果窗口内部分对话的内容较长,也容易超过 LLM 的上下文限制。

  3. token 缓冲记忆 ==========

3.1 实现思路

同样是基于缓冲记忆的思想,只保留 max_tokens 长度的历史上下文,超过长度限制的历史记忆会被遗忘。

3.2 优点

  1. 可以基于特定模型的上下文长度限制来分配记忆长度。
  2. 对小模型也比较友好,如果不提问比较远的关联内容,一般效果最佳。
  3. 实现方式简单,性能优异,所有大模型都支持。

3.3 缺点

  1. 无法保留长期的记忆,会遗忘之前的互动。

  2. 摘要总结记忆 ======

4.1 实现思路

将每轮对话的输入输出,生成总结摘要,作为记忆保存起来,并在下一轮对话时传递给 LLM。

4.2 优点

  1. 可以同时支持长期记忆和短期记忆。
  2. 基于摘要功能,可以有效减少长对话中使用的token 数量,能记忆更多轮的对话信息。特别是在长对话时效果更加明显。

4.3 缺点

  1. 因为记忆是基于生成的摘要,因此无论是长期记忆还是短期记忆,都是模糊记忆,会丢失对话的细节。

  2. 对于较短的对话,可能会增加 token 使用量(短对话时,生成的摘要可能会比原始对话更长)。

  3. 记忆功能完全依赖于摘要 LLM 的能力,并且需要为摘要 LLM 额外分配 Token,会增加使用成本。

  4. 摘要+缓冲 混合记忆(缓冲短期记忆+摘要长期记忆) ===============================

5.1 实现思路

摘要+缓冲混合记忆,是目前业内采用较为广泛的记忆方案,它结合了缓冲窗口记忆和摘要总结记忆两种模式:

  • 对于窗口限制内的对话,保留原始内容,作为短期记忆。
  • 对于超过窗口限制的历史对话,生成摘要后保存,作为长期记忆。
  • 将短期记忆与长期记忆合并,作为记忆保存。

例如,针对最大 token 长度为16k 的 LLM,可以设置记忆窗口 max_token = 12k,并将超过 12k 的历史对话生成摘要。

5.2 实现流程

picture.image

5.3 优点

  1. 可以同时实现长期记忆和短期记忆,长期为模糊记忆,短期为精准记忆。
  2. 通过摘要功能,可以有效减少长对话中使用的 token 数量,能记忆更多轮的对话信息。

5.4 缺点

  1. 久远的历史对话为模糊记忆,会丢失部分细节。

  2. 长期记忆部分依赖于摘要 LLM 的能力,需要为摘要 LLM 额外分配 token,会增加使用成本。

  3. 向量数据库记忆 =======

6.1 实现思路

将全量记忆数据存储在向量存储中,每次搜索记忆时,基于向量检索,获取前 K 个最匹配的语料。

6.2 优点

  1. 基于向量数据库的横向扩展能力,理论上可以支持无限长度的记忆。
  2. 在记忆的细节上,可以比摘要总结处理得更好。
  3. token 的消耗相对可控。

6.3 缺点

  1. 需要向量数据库支持,增加使用成本。

  2. 用户的每次对话,都需要经过 Embedding 过程,性能有一定损耗。

  3. 记忆效果受 Embedding 检索结果的影响,效果不稳定。

下面,我们使用智谱AI的GLM-4-Long超长上下文模型,并借助LangChain的Memory模块,快速实现一个具有记忆功能的聊天机器人。

首先,基于LangChain,封装一个带有记忆功能的 chat_memory_chain:

(完整代码参考:https://gitee.com/zhangshenao/llm-ops-backend/blob/master/internal/handler/chat\_memory\_chain.py)

CHAT_HISTORY_FILE_PATH = '../../storage/memory/chat_history.json' # 聊天历史文件路径
HISTORY_KEY = 'history' # 聊天历史Key
CONTEXT_KEY = 'context' # 上下文信息Key
INPUT_KEY = 'input' # 聊天输入Key
OUTPUT_KEY = 'output' # 聊天输出Key
MEMORY_CONFIG_KEY = 'memory' # 记忆配置Key
SAVE_CONVERSATION_ROUNDS = 50# 保存历史对话的轮数

def invoke_chain_with_chat_memory(input: Dict[str, Any],
prompt_template: BaseChatPromptTemplate,
llm: BaseChatModel,
parser: BaseTransformOutputParser[str],
vector_store_service: VectorStoreService) -> Output:
"""
将传入的Runnable组件编排成Chain,并在此基础上封装聊天记忆功能,返回最终调用结果
:param input: 调用输入参数
:param prompt_template: 提示词模板
:param llm: LLM聊天模型
:param parser: 输出解析器
:return: Chain调用结果
"""

使用本地文件保存聊天历史

chat_history = FileChatMessageHistory(

        file\_path=CHAT\_HISTORY\_FILE\_PATH)
创建聊天记忆组件,使用缓冲窗口记忆方式

memory = ConversationBufferWindowMemory(
input_key=INPUT_KEY,
output_key=OUTPUT_KEY,
memory_key=HISTORY_KEY,
k=SAVE_CONVERSATION_ROUNDS,
return_messages=True,
chat_memory=chat_history
)

构建Retriever Chain,执行向量相似度检索

retriever = vector_store_service.as_retriever()

| vector_store_service.join_document_page_contents

构造Chain执行链,用于编排组件的执行流程

chain = RunnablePassthrough.assign(
context=itemgetter(INPUT_KEY) | retriever,
history=RunnableLambda(_load_memory_variables_from_config) | itemgetter(HISTORY_KEY)
) | prompt_template | llm | parser

封装chain,在运行配置中传入记忆信息,并且注册on_end监听回调,在回调函数中保存聊天历史

memory_chain =

(chain.with_config(configurable={MEMORY_CONFIG_KEY: memory})

.with_listeners(on_end=_save_chat_history))

调用memory_chain,返回结果

output = memory_chain.invoke(input)
return output

def _load_memory_variables_from_config(input: Dict[str, Any],

config: RunnableConfig) -> Dict[str, Any]:

"""
从运行配置中,加载记忆变量
:param input: 运行调用输入
:param config: 运行配置
:return: 记忆变量字典
"""

获取运行时配置,从配置读取记忆信息

conf = config.get('configurable', {})
memory = conf.get(MEMORY_CONFIG_KEY, None)
if memory is not None and isinstance(memory, BaseChatMemory):
return memory.load_memory_variables(input)

空记忆信息

return {}

def _save_chat_history(run_obj: Run, config: RunnableConfig)

-> None:

"""
保存聊天历史
:param run_obj: 运行时对象,包含了所有运行时的相关信息
:param config: 运行时配置信息
"""

获取运行时配置,从配置读取记忆信息

conf = config.get('configurable', {})
memory = conf.get(MEMORY_CONFIG_KEY, None)
if memory is not None and isinstance(memory, BaseChatMemory):

将当前聊天的输入输出保存到Memory中

memory.save_context(run_obj.inputs, run_obj.outputs)

启动应用,开启聊天。我们先告诉大模型关于个人的一些信息:

picture.image

接下来,我们让大模型生成一些较长的内容,便于后面测试记忆能力:

picture.image

picture.image

最后,我们来测试一下记忆功能,看看 LLM 是否还记得最开始的聊天信息:

picture.image

可以看到,即使中间经历了多轮对话和长文本生成,GLM-4-Long

仍然能够准确记忆历史的聊天信息。

最后,简单介绍一下智谱AI的 GLM-4-Long 这个大模型。

GLM-4-Long 是支持100万上下文的⻓⽂本模型,它专为处理超⻓⽂本和

记忆型任务设计,支持⼤约相当2本红楼梦或者125篇科研论⽂的⻓度。

GLM-4-Long 极⼤的提⾼了模型的上下⽂理解能⼒,

丰富了⼤模型的应用落地能力。

0
0
0
0
关于作者
关于作者

文章

0

获赞

0

收藏

0

相关资源
IDC 大模型应用落地白皮书
大模型技术已深度融入业务实践,各企业期望其释放更大商业价值。 但大模型落地之路面临许多挑战和顾虑。 如何精准对接业务需求与发展蓝图,制定切实可行的大模型落地策略? IDC发布首个大模型应用策略与行动指南 一为您揭晓一
相关产品
评论
未登录
看完啦,登录分享一下感受吧~
暂无评论