ZMonster's Blog 巧者劳而智者忧,无能者无所求,饱食而遨游,泛若不系之舟

LLM Prompt Engineering 实践:记忆(1)

本文是《LLM Prompt Engineering 实践》系列的第三篇文章,系列文章如下:

  1. LLM Prompt Engineering 实践:序 · ZMonster's Blog
  2. LLM Prompt Engineering 实践:原型 · ZMonster's Blog
  3. LLM Prompt Engineering 实践:记忆(1) · ZMonster's Blog

之前我提出了一些问题:

  1. ChatMessageHistory 是基于内存的历史消息记录方法,一旦退出历史对话消息将全部丢失
  2. 当讨论的话题更早之前聊过时,选择最近历史消息的做法无法利用之前的讨论
  3. 固定设置输出最大 token 数量的做法为了照顾长输出的情况,会导致短输出情况下无法利用更多的历史消息
  4. 一个全局设置的温度参数会影响机器人处理不同任务的表现,比如说像翻译、分类、事实性问答这些任务并不需要随机性,而写作、创意生成则有一定的随机性会更好一些
  5. 在当前这种模式下,将机器人属性设置放在最开始的做法无法保证设定的一致性和连续性,用户总是能通过有意构造的输入来突破这种设置

其中 1/2/3 涉及到记忆机制的问题,对这几个问题都可以独立地去思考和尝试解决,但在此之前,还是有必要再对这几个问题做更多的探讨。

我在之前 xorius 的开发日志里第一次提出使用历史对话记录时是这么说的:这段代码不是对话的模式,没有考虑聊天历史,如果要做聊天的话,需要维护一个聊天历史。

那么问题来了,为什么在响应当前用户输入的时候,要去考虑聊天历史呢?这种做法其实就是假设聊天历史对响应当前的用户输入有帮助,那么:

  1. 这个假设会一直成立吗?
  2. 什么情况下这个假设会成立?此时历史记忆和当前用户输入有哪些可能的相关关系?
  3. 假设成立的情况下,使用最近 K 轮历史记忆的做法,K 会有一个模型计算力能承受的上限吗?
  4. 假设成立的情况下,使用最近 K 轮历史记忆的做法,相关的内容在这 K 轮历史记忆中的占比会有多大?
  5. 假设成立的情况下,使用最近 K 轮历史记忆的做法,其中的无关内容会带来负面影响吗?如果会的话可能带来的负面影响有哪些?

对第 1 个问题,既然是假设,那么它当然不会一直成立,否则它就是真理而不是假设了,而之前 xorius 的实现里是在这一假设下实现了回答时对历史记忆的利用 —— 即无论何时都会尝试把历史记忆用上,因而也会自然而然地带来一定的副作用: 在响应不需要历史记忆的用户输入时,可能因为强制使用历史记忆而造成错误的回答。

对第 2 个问题,个人认为可能有以下几种情况:

  1. 当前输入提及了历史对话中的某些内容,比如
    • 使用代词提及历史对话中聊过的某个或某几个对象,这种情况称之为指代

      「它」指代「语言模型」

      You: 语言模型是什么
      
      Xorius:
      语言模型是一种计算机程序,用于预测自然语言文本中下一个单词或字符的概率分布。它是自然语言处理中的一个重要组成部分,可以用于许多任务,如语音识别、机器翻译、文本生成和自动摘要等。语言模型通常基于统计学方法或神经网络方法,通过学习大量的文本数据来建立模型,并使用该模型来预测下一个单词或字符的概率分布。在实际应用中,语言模型可以帮助计算机更好地理解和生成自然语言,从而提高自然语言处理的效果和质量。
      
      ------------------- 上方为历史对话 -------------------
      
      You: 它有智能吗
      
      Xorius:
      语言模型本身并没有智能,它只是一个程序,能够根据已有的文本数据预测下一个单词或字符的概率分布。然而,通过不断地训练和优化,语言模型可以逐渐提高其预测的准确性和效率,从而更好地模拟人类的语言习惯。此外,语言模型也可以与其他人工智能技术结合使用,如机器学习、深度学习、自然语言处理等,从而实现更加智能化的应用。因此,虽然语言模型本身没有智能,但它可以为人工智能的发展提供重要的支持和基础。
      
    • 提及历史对话中聊过的某个或某几个对象,但以省略的形式,这种情况称之为零指代

      「语言模型在语音识别中怎么用」省略了「语言模型」

      You: 语言模型是什么
      
      Xorius:
      语言模型是一种用于自然语言处理的技术,它可以对一段文本的语言结构进行建模,从而计算出该文本的概率。语可以用于很多应用,例如语音识别、机器翻译、自然语言生成等。在语音识别中,语言模型可以帮助识别出最有可能的语音转录结果;在机器翻译中,语言模型可以帮助翻译系统选择最合适的翻译结果;在自然语言生成中,语言模型可以帮助生成自然流畅的语言表达。常见的语言模型包括n-gram模型、神经网络语言模型等。
      
      ------------------- 上方为历史对话 -------------------
      
      You: 在语音识别中怎么用
      
      Xorius:
      在语音识别中,语言模型主要用于解决识别歧义的问题。当语音识别系统对一段语音进行转录时,可能会遇到多个候选结果,这些结果在音频信号上看起来很相似,但在语言表达上却有很大差异。这时,语言模型可以帮助系统选择最有可能的结果。
      
      具体来说,语言模型会对每个候选结果进行打分,计算出其在语言表达上的概率。然后,系统会选择得分最高的结果作为最终的转录结果。这样,语言模型可以帮助系统更准确地识别语音,提高识别准确率。
      
      在语音识别中,常用的语言模型包括n-gram模型和神经网络语言模型。n-gram模型是一种基于统计的模型,它通过计算文本中相邻的n个词出现的概率来建模。神经网络语言模型则是一种基于神经网络的模型,它通训练神经网络来预测下一个词的概率。这些模型都可以用于语音识别中的语言模型建模。
      
    • 使用代词提及历史对话中的比词语粒度更大的对象,比如说事件、观点、句子甚至更大段的话

      「最后一段」指代对历史对话回答中结尾部分的「他们成功地激活了这个装置……也激励了更多人类探索宇宙的冒险精神。」这段话

      You: 写一个木卫二上的冒险故事
      
      Xorius:
      在木卫二的表面,有一个被称为“红海”的巨大火山口。这个火山口的深度超过了地球上最深的海洋,被认为是太阳系中最深的地方之一。有一天,一组勇敢的宇航员决定探索这个神秘的地方。
      
      他们穿上了特制的宇航服,搭乘着一艘小型的探测器,开始了他们的冒险之旅。他们在探测器上看到了一些奇怪的能量信号,这些信号似乎来自深处的地下洞穴。
      
      他们决定跟随这些信号,进入了一个巨大的洞穴系统。在洞穴里,他们发现了一些奇怪的生物,这些生物似乎是在这个深处的环境中生存了很长时间。
      
      随着他们深入洞穴,他们发现了一些神秘的符号和图案,这些符号似乎是来自一个古老的文明。他们开始研究这些符号,试图理解这个文明的历史和目的。
      
      在他们的探险中,他们遇到了一些危险,包括地震和洪水。但他们始终坚持不懈,终于到达了洞穴的深处。在那里,他们发现了一个神秘的装置,这个装置似乎是一个能量生成器,可以为整个木卫二提供能源。
      
      他们成功地激活了这个装置,并将它带回了地球。这个发现改变了人类对木卫二的认识,也为人类提供了一种新的能源来源。这个冒险故事成为了人类历史上的一个重要事件,也激励了更多人类探索宇宙的冒险精神。
      
      ------------------- 上方为历史对话 -------------------
      
      You: 把最后一段翻译成英文
      
      Xorius: "They successfully activated the device and brought it back to Earth. This discovery changed humanity's understanding of Europa and provided a new source of energy for humanity. This adventure story became an important event in human history and inspired more people to explore the adventure spirit of the universe."
      
    • 提及历史对话中的比词语粒度更大的对象,比如说事件、观点、句子甚至更大段的话,但以省略的形式

      「压缩一下」省略了宾语,指的是历史对话里的整段回答「在遥远的未来……寻找未知的世界和可能性」

      You: 写一个火星流浪的故事
      
      Xorius:
      在遥远的未来,人类已经开始探索太空,其中包括火星。一名名叫艾米的宇航员在一次任务中不幸与同事失联,最终被遗弃在了火星上。
      
      艾米意识到自己已经被遗弃在了这个荒凉的星球上,没有任何人类的生命迹象。她开始寻找食物和水源,但很快发现火星上的环境非常恶劣,几乎没有任何生命存在的可能。
      
      在接下来的几个月里,艾米不断地寻找食物和水源,同时也努力修复她的通讯设备,希望能够联系到地球上的人类。但是,她的努力都没有任何回应。
      
      在孤独和绝望的日子里,艾米开始思考自己的人生和存在的意义。她开始重新审视自己的价值观和信仰,并逐渐接受了自己可能会永远孤独地生活在这个星球上的现实。
      
      然而,就在艾米准备放弃的时候,她收到了一条来自地球的信号。原来,地球上的科学家们一直在寻找她,并且已经派出了一支救援队伍来到火星上救援她。
      
      在救援队伍的帮助下,艾米最终成功返回地球,并成为了一名备受尊敬的宇航员。她的经历也激励了更多的人类探索太空,寻找未知的世界和可能性。
      
      ------------------- 上方为历史对话 -------------------
      
      You: 压缩一下,用更短的文字
      
      Xorius:
      一名宇航员在火星上被遗弃,孤独地寻找食物和水源,修复通讯设备,思考人生意义。最终收到地球救援信号,成功返回地球,成为备受尊敬的宇航员,激励更多人类探索太空。
      
  2. 历史记忆中的内容可以作为回答当前输入的知识,比如说
    • 历史记忆中提供了当前输入的某些知识的定义或详细说明,回答当前输入时正确使用历史记忆中提供的知识可以避免 AI 胡编乱造
    • 历史记忆中描述了用户(或 AI)的喜好、三观或其他个性化(或者说人格化?)的属性描述,并且当前输入是以这些个性化信息为背景的,那么正确地使用相关的历史记忆可以使得回答时表现出来的个性与历史记忆中的保持一致性、连续性
    • ……
  3. 上述两种情况的混合

在多轮对话的研究里,对历史记忆和当前输入的相关关系应该还会有更全面、更细致的分类,暂时不想去翻相关的研究资料了,等需要做更精细的处理的时候可能会去看看,现在主要是做一个大致的梳理,知道模型在利用聊天历史时存在不同情况即可。

在第 2 个问题的回答的基础上,可以对第 3 个问题做一定的回答

  • 如果当前输入和历史记忆的关系是第 1 种情况(当前输入提及了历史对话中的某些内容),可以认为这种情况下要用到的历史记忆都会是比较近的,也就是 K 不会太大,我个人认为是可以让模型直接处理的
  • 如果当前输入和历史记忆的关系是第 2 种情况(历史记忆中的内容可以作为回答当前输入的知识),那么相关的历史记忆未必是在最近,它完全可以是长期记忆里的内容,比如说我让它推荐书籍的时候希望它可以记起来一年前我说过我喜欢看科幻小说进而推荐一些最新的科幻小说,这种情况下这个 K 可能会非常非常大,个人认为这种情况下使用最近 K 轮历史记忆的做法将会超出模型的计算能力上限
  • 如果当前输入和历史记忆的关系是第 3 种情况(第 1 种情况和第 2 种情况的混合),那么同第 2 种情况

对于第 4 个问题,如果精力允许,或许可以去分析一下一些公开的多轮对话数据集来给出一个相对量化的结果,不过目前我并不想去做这个事情,提出这个问题,其实只是想说明一点 —— 即使在聊天历史对响应当前用户输入有帮助这个假设成立,并且有帮助的信息就在最近 K 轮历史记忆中的时候,也可能不是所有 K 轮历史记忆都是有帮助的。

第 5 个问题则是在第 4 个问题上更进一步思考,如果最近 K 轮历史记忆中有无关内容,那么它们一定是会带来负面影响的,它们可能会摊薄当前输入中 token 和历史记忆中有用内容的 attention 权重,进而导致回可能偏离预期。这种负面影响的大小一定程度上取决于模型本身的能力,很强的模型(比如 GPT-4)可能不会表现得很明显。

综上,使用最近 K 轮历史记忆的做法其实是会有一些问题的,但是这种方法是最容易实现的、最直观可理解的,并且在模型较强的时候效果也不错,加上现在也没有公认的更好的方案,所以大家普遍都这么做。

方法有缺陷是正常的,事实上也不存在哪个方法是完美的、没有任何问题的,但这个方法最大的问题不在于其假设,而在于它没有设计对应的错误应对或者说优化迭代的措施,一旦这个机制工作不正常,就只能期待模型自身的改进或者用户自己能够掌握所谓的 Prompt 编写技巧来再次尝试了。如果能对这些问题心知肚明并抱有适当的预期,那么使用这个方法倒也没什么问题,但如果使用了这个方法出了问题后就只会调侃 AI 弱智,那就没什么意思了。