AI 情感聊天机器人之旅 —— 多轮对话存在的问题与数据积累

clvsit 2024-08-13 14:01:02 阅读 56

在 QA、逻辑推理等领域,多跳问答比单跳问答难得多。在聊天机器人场景中亦是如此,模型需要结合历史对话和用户当前的输入内容生成合适的响应。然而,现有的指令数据大都是单轮或者两轮的对话(截止这篇文章落笔的日期 2023-09-10),模型在对话轮数较少时,还能很好地遵循指令、记住历史信息以及输出合适的内容。但对话轮数多了后,模型的输出往往会变得不可控,例如越来越长、格式出现错误、遗忘历史信息、指令遵循能力变弱(人设不符)。一方面是因为上下文变长、加上 Lost in the middle 等 prompt 层面的影响;另一方面是模型在多轮对话下的对齐能力较弱(多轮对话数据的训练数据质量较差,且在 long context 场景下“锻炼”得不够)。

在处理多跳问题和数学推理等较难任务时,除了在模型层面做优化外,往往会使用 CoT 系列的 prompt 工程,例如“Let’s think step by step”的方式。我理解它们能提升 LLM 推理能力的一部分原因在于将任务拆解,输出中间步骤,对于从左到右的生成式模型来说,这些补齐的中间步骤的生成为输入空间带来了更细致的条件约束,而这些条件约束引导模型输出更为准确的结果

Prompt 对于模型的生成有着至关重要的影响,在另外一个将对话内容抽取摘要和标题的项目中,对 prompt 做一些细微的调整,例如仅删除个别词语,先后两次模型的 greedy 输出的相似度相差就非常大。如果将模型的输出过程比作一条长长的道路,前面每一步的偏差都会通往不同的终点。有的道路一帆风顺,而有的道路布满荆棘、高山险阻、沟壑纵横。“Let’s think step by step” 就像路途中的补给站,当你来到这里,补给站中的人给你指向了一条缓慢但平坦的道路,虽然要多走几步路,但更容易通往正确的终点。CoT 等后续发展的一系列思维链相关的 prompt 工程都通过人为添加或者引导模型自行生成中间“道路”的方式,来“安稳”抵达期望的“终点”。

多轮对话存在的问题

我们的 AI 情感聊天机器人在对话轮数多了之后,效果会明显下降。甚至产品反馈,当超过 50 轮对话后,模型会出现百分百的重复回复(大量重复的短语或近似的语义)。我的推测是:

对话到后期,用户与模型都陷入到“无话可说”的地步,用户没有“强烈”地转换话题。同时,模型在几轮雷同回复的条件约束下很难有“新颖”的表达方式。对数据的理解不够透彻、对数据的质量没有把控,尤其在 3000 - 3500 token(超过 3500 token 会被截断)范围内的数据质量没有肉眼审核过,如果这部分的数据大都是雷同的,那么模型学到的或许就不是先后顺序,而是类似 ICL 演示(few-shot)的并列关系,从而去模仿历史对话的表达方式和类比生成,这样就很容易重复。关于这部分的内容,后续会将相关的研究写一篇新的博客。统一数据格式(包括 prompt 的格式)时没有做好规范,导致模型的输出不“规范”,甚至有些“离经叛道”。按照上文中提到的关于 CoT 的描述,模型在行进途中的几步就走偏一步,走着走着就来到了“地图”上没有标识的地区(SFT 阶段没有训练好,不仅损坏了模型原本的知识,还让模型不知道该怎么合理地生成符合用户指令的响应)。

结合上述思考和缓解重复问题时的实践,提出一个猜想:随着聊天的进行,更多的 context 会有更强的 conditional 限制,使得模型的输出空间囿于小而窄的空间(实际上该表述并不准确,还需要加入一些限定,例如自研模型、训练数据质量受限,本质上还是模型训练的问题)。

但在使用 gpt-4-1106-preview 作为聊天模型时,很少出现或几乎不会出现多轮重复的问题。它完全按照我们的设想,在遵循用户当前轮的指令(聊天的话题与内容)的前提下,从历史对话中撷取所需的信息,然后生成满足用户需求的响应。一个很直观的感受是,gpt4 能很好地 get 到我们的意思,甚至很多时候我们都不知道该如何表达自己的问题,它也能给出我们所需的答案。因此,一个理解力强的模型,在情感聊天场景中已经具备足够的下限,我们只需要改写其输出,让其少点“AI 味”,多点“人情味”,除了用改写的方式,通过调整 prompt 也能实现,例如:

论文《Guidling Large Language Models via Directional Stimulus Prompting》提出了一个名为“定向刺激 prompt”(Directional Stimulus Prompting)的新型 prompt 框架,先训练一个经过微调、强化学习后的小型模型,然后使用该小型模型根据用户的查询来生成对应的刺激(文本),将其添加到 prompt 中来引导黑盒大语言模型朝着所需的输出方向前进。论文《EmotionPrompt:Leveraging Psychology for Language Models Enhancement via Emotional Stimulus》的作者从心理学中汲取灵感,提出 EmotionPrompt(情感提示)来探索情商,以提高 LLM 的性能。具体来说,作者为 LLMs 设计了 11 句情感刺激句子,只需将其添加到原始 prompt 中即可。缺陷在于情绪刺激可能并不适用于其他任务,并且对不同 LLM 的效果无法保证。

数据积累

综其根本,还是模型能力的问题:模型的理解能力以及抗干扰能力(在存在冗余、干扰信息且较长的历史对话(context)中找寻能够帮助回答当前轮用户的内容)。

增强模型的指令遵循能力,寻找并清洗得到质量更好的多轮对话数据集,充分对齐模型(SFT + RLHF 的标准道路)。除此之外,也可以考虑扬长避短,将多轮对话“拍平”成单轮对话,发挥模型单轮对话的优势。那么该如何“拍平”成单轮对话呢?

最先想到的方法是减少送入模型的对话轮数,仅保留最近的 5 轮对话,将 context 控制在 2500 token 左右,与收集到的高质量对话数据集的平均 token 保持一致。缺点在于送入的历史信息较少,模型没有“记忆”。但在当时,即便送入 10 轮对话(20 句),历史对话中较为久远的信息,模型也大概率 get 不到,反而会因为大量重复的历史信息(闲聊场景中,大多数的历史对话并没有意义,甚至用户输入的指令也大都没有信息)干扰当前输出。如果 context 中干扰、冗余的信息越少,模型输出的效果越好,那么我们是可以减少送入模型的对话轮数,提升模型输出的质量,并以此积累多轮对话。

在使用 LLM 清洗数据时,发现 vicuna-v1.5 等指令遵循能力较强的模型(当然,现在可以选择能力更强的模型)可以对历史对话进行总结和评分,于是尝试提取历史对话中的核心内容,去除其中的“杂质”与“噪声”,从而规范“过去的道路”,避免其误入“藕花深处”。

将历史对话全部进行摘要:将当前轮前面的所有历史对话转变成摘要,结合 Rethinking Historical Messages(后续有时间会写一篇博客,重点讲述历史对话对当前轮模型输出的影响)的研究结果,该做法可以减少历史几轮对话对当前轮模型输出的影响,《Calibrate Before Use:Improving Few-Shot Performance of Language Models》论文提到的三个偏见。其核心是可以缓解模型输出的重复问题,并且减少 ICL 对模型输出的影响。在多轮重复问题测试集上进行测试,发现该方式的确可以很好地解决模型输出重复的问题。

但该方式的缺点在于摘要会丢失细节信息,而这些细节信息恰好是未来几轮对话的重点部分,这就会导致对话的不连贯和剧情发展的磕磕绊绊。

当时对老板提出的一种解释是,原始的历史对话是人与模型的对话,而生成的摘要是模型的摘要,模型更容易理解自己的“语言”,而非人的“语言”,尤其在与人类对齐这方面有所欠缺的模型。此外,模型的摘要抽取能力仍然是模型自身的能力,没有受到 SFT 的影响,输出的摘要内容仍然是模型“语言”。没过多久,微软提出了 LLMLingua 方法,可以对 prompt 进行压缩,压缩后的 prompt 虽然人类不可读,但模型仍然能够识别并输出正确的结果,且可以反向还原。这说明,在对齐还没有达到一定程度(2024-02 使用 LLMLingua 测试 GPT4 时,GPT4 会在生成的响应中说明用户提供的文本存在格式错误的问题,这说明 GPT-4 已经能够很好地理解人类的语言)时,模型更容易理解自身的“语言”。

将每一轮对话都进行摘要:每一轮对话并不一定有足够的信息,尤其在闲聊场景下,这会导致前后两轮的摘要内容几乎没有变化,那么模型的输出很大程度上取决于当前轮用户的输入内容,如果用户输入内容也没有太多变化,模型的输出很容易雷同,仍然存在重复问题。

将久远历史对话进行摘要:不再将“多余”的历史对话删除,而是用 LLM(vicuna-13B-v1.5)从中抽取信息,以前情提要的形式添加到 system prompt 中,拼接成 system prompt + 前情提要 + 最近 5 轮历史对话的形式。上线后,平均对话轮数得到了提升。

将历史对话全部进行摘要类似 MQA、将每一轮对话都进行摘要类似 MHA,将两者折衷,每 N 轮进行一次摘要,或者当有较大变化时,进行一次摘要(类似 GQA,关于 GQA 可以参见我的另一篇博客《论文阅读:GQA: Training Generalized Multi-Query Transformer Models from Multi-Head Checkpoints》)。

核心思想是提供更好、冗余干扰信息越少的 context,提升模型每一轮输出的质量,从而积累多轮对话的训练数据

后续(23 年 12 月份)尝试对历史对话进行压缩(使用 LLMLingua),从表象上来看,对 prompt 进行压缩与抽取摘要相同,都是输入较长的 prompt,得到简短的、新的 prompt,但本质上是不同的。抽取摘要的核心还是将 prompt 进行精细加工,输出成人类可读的文本内容,而 prompt 压缩并不为人类可读而服务,压缩后的文本内容对于人类不一定可读,但模型能够正确识别,甚至可以还原回原先的 prompt,更像是压缩软件的压缩过程。该方法也可以缓解重复问题,但对模型的输出效果会有一定的影响。



声明

本文内容仅代表作者观点,或转载于其他网站,本站不以此文作为商业用途
如有涉及侵权,请联系本站进行删除
转载本站原创文章,请注明来源及作者。