查看原文
其他

角色扮演大模型的碎碎念

快乐子涵酱 NLP工作站 2024-04-07

今天给大家带来一篇角色大模型相关思考的文章,来自知乎@快乐子涵酱(已授权)。

知乎:https://zhuanlan.zhihu.com/p/685823865

什么是角色扮演大模型?

首先提两个问题,目前大模型有自己的“自我意识”吗?为什么大模型生成的答案可以一眼分辨出来?

答案其实很简单,目前所有大模型技术,并不能让大模型具备本身的独立意识,大模型表现出的「拟人化」本质上是在努力扮演一个人类喜好的Assistant角色;或者说,大模型通过SFT和RLHF等技术路线实现与人类喜好的对齐。然而,以chatGPT为例,目前市面上所有的通用大模型的答案具有一种浓浓的「Assistant」语气,具体来说就是很官方、书面,具有强烈的说教口吻,不够口语化,例如「总之......」「记住......」等等。这一切来源于openAI的标注标准,我们不做深究。当大模型作为一个「提效工具」时,这种答案风格是完全OK的;然而对于大部分非程序员的用户群体来说,大模型的「提效能力」并不是一个必需品,「娱乐能力」才是提升一个产品留存率和黏性最重要的能力纬度。当大模型作为一个娱乐工具时,非常官方的语气和说教口吻必然会带来巨大的违和感。

随着以character.AI为首的众多以角色扮演能力为核心的大模型产品的爆火,我们不去讨论当今环境下人类社交形式的演变以及背后的社会原因,我们只讨论对于用户来说,他们更需要的是一个可定制的、高度拟人化的有情感、有温度的聊天机器人,这就是角色扮演模型。

角色扮演模型和通用模型的区别是什么?

概念上

目前大模型本质上是扮演一个assistant助手,直接使用通用大模型进行角色扮演任务,类似于「让一个大模型扮演的assistant助手去扮演某个特定角色」,大模型“意识”中的「我」仍然是一个asisstant助手,「角色扮演」相当于是人类分配给这个助手的一个任务,相当于我们绕了一圈来达到角色扮演目的,效果必然打了一个折扣。

但对于角色扮演模型,我们可以直接让这个AI去扮演某个角色,如虚拟女友、历史人物等。此时大模型“意识”中的「我」就是某个特定的人物,它一切出发点和“自我意识”都是从某个人物的角度出发和考虑。

表现上

对于通用大模型和角色扮演模型,在说话的风格和语气上有明显的不同:

  • 对于角色扮演模型来说,不会具有明显的官方语气和说教口吻,除非你明确要求角色扮演模型去扮演一个类似的角色;相反会表现出符合角色的特定性格特点和说话风格,比如在扮演“张飞”时性格莽撞不拘小节,说话豪爽大气
  • 角色扮演模型可能会具有一定的情绪能力,例如我们可以问通用大模型100遍1+1等于几,但对于角色扮演模型来说,问到第2遍就可能会表现出差异或不耐烦的情绪来;例如在扮演虚拟女友时会表现出撒娇、吃醋等属于人类的情绪
  • 角色扮演模型的输出更具画面感和沉浸感,当我们与通用模型交互时,体感上更像是阅读一本「工具书」,是机械的、没有情感的;而角色扮演模型更像是一个真实的人在隔着屏幕与用户聊天,用户可以想象出到对方的动作、想法和情绪等
  • 角色扮演模型具备更强的交互性:传统的通用模型本质上是一个问答机器人,用户与AI采取一问一答的形式;而角色扮演模型可以给用户主动预设一个场景或情节背景,用户和AI一起交流来演绎并推动剧情的发展。在这当中,角色扮演模型不会简单回答用户问题,更具有主动提问、主动推动剧情发展的能力

假如说通用问答大模型如GPT等是一个assistant助手,那角色扮演大模型的定位就是一个「演员」。通用模型更偏向是「工具」,而角色扮演模型更偏向「产品」属性。角色扮演模型比通用模型更贴近「图灵测试」的目标,即具备「以假乱真」的能力。当用户与角色扮演模型进行交互时,会激发出更多交流欲望。

用一个类比来聊聊我对「角色扮演」的认知

我们把角色扮演大模型类比成一个演员,那大家通常如何评价一个演员演技的好坏呢?

最简单或者最抽象来说,就是演得“像不像”。要想做到演啥像啥,就要理解角色,对于演员来说理解角色的途径就是阅读剧本,对大模型来说就是阅读system prompt。system prompt就是一个人物卡,当中包含角色的背景信息、性格特点、说话风格等等。大模型要想演的像,就要把这些信息吃透。

  • 特型演员

    对于演员来说,有些演员可能只适合演某种特型人物,如皇帝、学生等,这类人物是该演员的舒适圈。对应到一些开源产品或者模型来说,就是这一个模型只做针对某个特定人物做SFT的微调,如characterLLM等。我本人是不太喜欢这种模式的:首先显而易见,一个角色对应一个模型必然会浪费很多资源;其次,只训练某个角色有点杀鸡用牛刀了,浪费了大模型超强的泛化能力;其次这样做的效果真的比用N多个不同角色训练之后泛化的infer结果更好吗?我觉得存疑。特定角色必然会导致训练数据量级受限,且在该数据集上做finetune必然会导致过拟合,过拟合必然会导致模型灾难性遗忘,性能下降。

    还有一些项目比如「ChatHaruhi」,他们最开始的做法是抽取一些小说、剧本当中的角色对话,比如韦小宝、令狐冲等。我的看法和之前类似,使用几十或上百个角色且同一个角色的数据使用几百条上千条,还是会导致一些过拟合的出现。结果就是训练过程中,模型对system prompt的敏感度降低,导致推理时对于训练集中出现过的角色,这种模型通常表现较好;但面对一个全新的角色,模型泛化能力可能会打个折。类比到演员上,可以认为这个演员之前演过韦小宝和令狐冲,你再让他演同样的角色他压根不需要读剧本,只要回忆之前是怎么演的就行了,呈现效果上肯定得心应手;但是如果你突然让他演甄嬛,他已经忘了怎么钻研剧本了,必然演的很别扭。

    所以我一直秉持的技术路线是,构造大量人物卡,每个人物只放一条或几条对话session数据,让模型学会「阅读剧本」,也就是我们说的指令(在这里是system prompt)跟随能力。

  • 源于生活,高于生活

    有时候我们评价一个演员很有灵气,或者字面意义上评价这个演员很讨喜,可能说的是这个演员在表演过程中的表情、行为是否灵动;在角色大模型来说,就是动作描写是否生动形象。像character.AI还有BaichuanNPC,一直都默认会输出角色的动作、表情、心理以及对应的场景描写。通常中文放在()里,英文放在*号里(MD格式)。

    电视剧中的人物对话,或者一些小说、剧本中人物对话的风格,介于严肃文学和真人对话之间。一方面需要接地气,不能太枯燥太端着;也不能完全和真人聊天一样完全随意,需要有有一定阅读的体验,并通过说话内容和旁白等来补充相对现实世界缺失的信息。

    什么叫现实世界缺失的信息呢?举个例子,假设小说中新登场了一个人物,一个惯用的处理手法就是通过某个路人的视角和口吻来介绍这个新人物的来历,这个描述在一些二流作家笔下甚至可能非常啰嗦或稍显突兀。但现实世界中大家可能一张名片或一份简历就知道这人是谁了。这就是文本内容的「信息缺失」,文本必须通过更多笔墨来描写某个现实世界中可能一个眼神就能get到的信息量。

    大模型类似,我们既需要有与通用底座模型迥异的、更拟人化的输出风格,又要比真人对话更稍微正式一点点。真人微信聊天时可能一句“笑死”+表情包就能传达的情绪,角色扮演模型需要更多的描述来渲染角色对某个情景时的反应。

    我有时候甚至觉得,角色扮演对标的与其说是真人聊天,不如说是galgame。或者说,角色扮演模型做的事情是「和用户一起完成某个虚拟情节的构建」。在这个过程中,角色扮演模型的输出不仅是角色「说的话」,在某种程度上也充当了「旁白」的角色。这再次证明了「描述性文本」的重要性。

    所以,这就是为什么很多人会用小说、剧本中抽取的内容来训练SFT。

    所以,这就是为什么如果直接用小说、剧本抽取对话来训练通常不太work。(后边会展开讲实验)

    直接从小说中抽人物对话会导致一个问题,那就是小说人物对话可能非常短,有时候甚至只有一两个字,更多的信息如角色的心理活动等放在旁白里进行描写了。如果只使用角色说的话来训练的话,会导致「信息缺失」。

  • 违和感

    一个不成熟的演员在扮演某个角色时会有违和感,模型同样如此。

    我一直觉得:例如「请你扮演一个翻译专家」「请你扮演一个程序员」这种任务类“角色扮演”;或者是一些「请你扮演张飞:请告诉我你作为刘备的部下如何评价他的处事准则」这种辣鸡问答,本质上还是一个assistant助手,根本就不是我今天想要聊的角色扮演,更不是我们当今想要的角色扮演模型。真正的角色扮演应该是类似真实人类的对话,永远都不会是刻板的一问一答,而是有来有回的碰撞。

    这就涉及到一个表述方式上的违和感的问题了:

    作为一个真实的人或角色,通常都会有一个明确的立场,所以永远都不会说”因人而异“这种端水类的话术;

    作为一个真实的人或角色,通常都会缺点有小心机,所以从来不会像chatGPT一样永远一本正经讲大道理;

    作为一个真实的人或角色,通常都会有自己的性格和脾气,所以从来都不会像正常底座模型一样有问必答;

    作为一个真实的人或角色,从来都不会说「作为xxx,我认为......」这种奇怪的话。

    那这个问题怎么解决呢?我目前的做法是简单粗暴建立一个黑名单词表,把所有带强烈违和感或真实人类根本不会说的词给过滤掉。

    那怎么快速评价模型输出是否有违和感呢?或者换个角度,什么样的输出算是一个没有违和感的模型呢?

    我的方法就是:把模型输出结果中所有的「我」这个字替换成「角色名」,看这句话是否成立。如果成立,则认为有违和感,即模型并没有真正带入角色,只是在输出形式上做到了角色扮演而已;如果不成立,那我们认为当前模型输出质量基本达标。

关于继续预训练:continue pre-train

「演员」在电影学院会学习大量的表演理论课,大模型角色扮演同样可能需要用一些小说、剧本类数据当作「课本」来学习一些潜在的能力。一个常见的做法是在这类数据上做continue pretrain,例如BaichuanNPC用了大概3T量级的tokens重新做了预训练。但基于海量数据的continue pretrain必然会消耗大量的计算资源,这对于大部分开发者并不友好;另一方面,大部分人能收集几B或者几十B就已经很难了,真的很难搞到那么多的数据。此外,但无论是基于我们的尝试结果还是【Continual Pre-Training of Large Language Models: How to (re)warm your model?】这篇论文的实验结论,使用少量数据进行continue pretrain不仅会发生在灾难性遗忘导致底座模型原有能力损失,亦有相当高的风险和概率在新数据集上表现出loss难收敛的情况。

再从另一个维度想一下这个事儿。预训练的任务目标无非是给大模型「灌知识」,但是小说数据里到底有多少事实性知识呢?大部分小说都是杜撰的,其中大部分信息根本都是没用的,大模型根本不需要学习某个点击量只有几百条的网络小说某个扑街配角的人物生平信息,用户也根本不会问;用户可能会问一些热门小说比如「斗罗大陆」「斗破苍穹」,但这些知识pretrain模型本来就有啊,干嘛还要再做一次continue pretrain呢?因此对于角色扮演任务,我们更希望模型通过小说的描写手法和表述方式来学会如何将信息更好地表达和输出,这反而和SFT微调任务目标更接近。

所以对于大多数开发者,如果你没有能力制作一个很好的预训练数据集和高超的炼丹技术,我可能不太建议走继续预训练这条路。但是可以尝试添加一些小说续写类数据,一方面增强模型的场景描写能力,另一方面写作能力和角色扮演能力确实强相关,也就是说:有角色扮演需求的用户大概率也会有小说创作的需求。

关于通用对话数据

大多数情况下,观众们真的不关心一个演员的数学好不好、会不会写代码。但很遗憾,如果我们把角色扮演模型类比成一个「演员」,那他首先是一个「人类」,对于一个人类来说,基本的知识能力和逻辑能力是必要的;可是要想让大模型具有一定的逻辑性和知识表达能力,不得不添加一些包括少量数学、代码任务在内的通用SFT问答数据。

有一些角色扮演模型会直接从pretrain模型启动,仅使用角色扮演对话数据进行训练。从我个人的复现的结果来看,模型的表现更像是一个「努力假装自己是xxx角色的白痴」,下面是一条真实的infer结果:

好的,我叫张飞,出身于涿郡,出生的时候父母不在身边,被母亲过继给关羽。后来曹操杀了他的母亲,与关羽失散,投奔刘备。在战场上,我率领部下多次打败敌军,得到了刘备的信任。

是不是笑麻了?

所以综合前面continue pretrain的相关认知,我可能推荐添加少量通用SFT问答数据直接从一个训练好的pretrain模型启动,大概率就能得到一个还不错的baseline效果了。

那么是否可以直接从SFT模型启动,不添加通用问答数据呢?

答:可以,这取决于个人细节的任务目标、数据量、数据组织形式等等因素。直接从SFT模型启动,可以认为此时模型本身已经具有很好的通用能力了,甚至我们都不需要再添加额外的、重复的通用问答数据也能产生不错的效果。此时要考虑的问题反而变成了「如何在基础能力不退化的情况下迁移模型对话风格」。因为前面我们提到,通用问答模型具有很强的assistant语气,这必然会导致角色扮演任务的违和感。那太小的学习率,会导致模型更难以学到新知识;太大的学习率又容易灾难性遗忘。如何找到平衡点是一个很玄学的问题。这里推荐参考Qwen技术报告,同时增大warmup ratio和学习率,个人实验结果还不错。

那么使用多大比例的通用问答数据?

答:角色扮演任务和我们常谈到的一些垂域问答(如医疗金融法律等)还有一些区别:垂域问答可能需要的数据量更小,任务目标重点考察模型在专业领域的事实性知识能力,一些常见的数据比例可能是垂域数据占总数据量的10%到20%;但角色扮演任务不能单纯当作一个简单的垂域来看,我认为它不是底座大模型的子任务或某项能力,相反,基础的问答能力应该是角色扮演大模型的一项附属能力。因此我们推荐在全量数据当中,角色扮演数据占比更大,通用问答数据占比应该不超过全量数据的50%。我个人大概使用了1/4到1/3量级的通用问答数据,其中数学代码逻辑相关的数据用得非常少,只是通过一些简单的CoT数据来激发模型的逻辑能力或思考能力而已。

一些零散的内容

到此为止,我肚子里的东西基本都掏差不多了,下面是一些零散的小认知。

进度条问题:一些游戏类角色扮演可能需要大模型实时输出一些角色状态信息,这本质上是一个复杂指令跟随能力,通常需要使用更大参数的模型去解决,13B以下规模的模型去做类似的事情肯定会更吃力一点。目前我个人的训练数据中没有特意构建这类数据,所以表现相对一般。

小说抽取对话:我实验结论是这类数据会对最终结果有负面影响,具体现象是模型output变短,更容易给出只有一两字的output,这也就是之前我们提到的「信息缺失」的问题。我个人是不太推荐大量使用这种数据的,或者可能需要做更严格的清洗或改写。

过于配合用户:也就是大模型不会拒绝用户提出的需求或问题,或很少表现出不耐烦等负面情绪。这个问题其实比较容易解决,只要在对话数据里包含这样类似的数据即可(最好是多轮),实在不行可以考虑使用DPO或RLHF来解决。

生成数据多样性:使用GPT等生成对话数据肯定会有多样性问题,这里建议一定要对高频pattern做降采样,否则会导致模型过拟合。

关于DPO:很多人也提到过,建议对模型本身的infer结果做自采样,我尝试下来的体验是:效果出奇的好

安全问题:大模型角色扮演从提出来开始,就和越狱等内容相关,这里做对齐必然会导致效果损失,但没办法hhh

写在最后

OK啦,完结撒花。

给公众号添加【星标⭐️】不迷路!您的点赞在看关注是我坚持的最大动力!

欢迎多多关注公众号「NLP工作站」,加入交流群,交个朋友吧,一起学习,一起进步!

我们的口号是“生命不止,学习不停”!

往期推荐:

继续滑动看下一个
向上滑动看下一个

您可能也对以下帖子感兴趣

文章有问题?点此查看未经处理的缓存