快看漫画创办于2014年,集漫画阅读、创作互动、线下漫画沉浸体验、周边衍生品购买等体验于一体,是年轻人的一站式漫画生活方式平台。截止到2023年底,快看总用户超过3.8亿,在中国漫画市场渗透率超过50%。经过9年的创作者生态建设,快看已汇聚超过12万注册创作者,发表漫画作品超13000部。目前,快看漫画已有超过500部作品登陆全球近200个国家和地区,成为中国文化出海的代表。
除了线上平台,快看还经常在线下组织沉浸式漫画乐园、漫画狂欢夜、漫画家见面会等活动,打造漫画粉丝们的嘉年华。
02.Milvus在快看基础业务的应用
快看基础业务包括常见的搜索、推荐、广告,此外还包括图像相关的业务,比如图像去重、以图搜图等,为了更好的服务上述场景需求,需要构建向量检索系统,首先要做的一件事,就是确定一款向量检索引擎,我们当时也做了一些技术选型,包括 faiss、milvus、elasticsearch、vearch、proxima等。最后选定了 Milvus作为我们的向量检索引擎,因为milvus有如下的优点:
Milvus的社区非常活跃,这也是我们考量的一个重点因素,在 Github issue上提一些问题,都能得到及时和耐心的反馈,并且有专门的微信运营服务群,在群里不仅可以反映自己遇到的问题,也能看到别人遇到的各种问题,还能起到相互学习的作用。
有了向量检索引擎之后,就可以根据向量检索的三要素搭建向量检索服务:
Embedding模型:通常是在自己业务数据上训练Embedding模型,如果是文本向量也可以使用开源的Text Embedding模型。之后就可以获取到每个物料的embedding向量,这里我们会对embedding向量先进行 L2归一化,再考虑入库建索引。
创建collection&index:入库在 milvus中的操作就是创建一个collection集合,然后对向量字段构建index索引,这些通过milvus的API可以很方便的完成。
向量查询:创建好索引后,就可以做向量查询了,向量查询本质上是将Query向量和collection中的所有向量进行相似度匹配,所以需要确定一个相似度指标,比如欧氏距离、Cosine相似度等。我们这里使用的L2欧式距离。其实最开始是想用Cosine相似度,但是当时Milvus还不支持,所以我们入库前先将向量进行L2归一化,查询的时候再使用欧氏距离,这种方式和直接使用Cosine相似度是成反比的,两种方案匹配出的结果都是一样的,只不过一个分数越小越好,一个分数越大越好。
我们最开始使用的索引是 Ivf_Flat,后面切换到了 HNSW索引,在我们的业务数据上做了一些实验,发现 Hnsw索引和 Ivf_Flat相比:
以快看搜索场景为例,目前在多个场景应用了向量检索技术,搭建了如下的向量召回全景架构:
并在线上多个业务场景进行了实验,以数据量最大的社区帖子Feed流为例,应用了上述架构之后,在消费时长、下滑深度、曝光、点击等指标上均有不同程度的正向提升。
03.快看RAG技术探索和应用
以ChatGPT为代表的大语言模型(LLM)在自然语言理解和生成任务上,展现了前所未有的能力,但是大语言模型(LLM)在特定领域任务中,会出现信息延迟和幻觉现象,检索增强生成(RAG)通过引用外部知识可以有效缓解这些问题,是LLM在工业领域应用的关键技术。
快看在大语言模型及RAG出现之后,迅速切入到以大语言模型为代表的技术领域,开始探索快看内部的应用场景,并在快看AI智能问答、IP角色互动两个场景取得了实质性进展,接下来以这两个场景为例,详细介绍下我们的技术方案。
这件事的背景是,大语言模型的对话模式,具有交互性强、沉浸式体验、拟人化等特点,是对传统搜索的一种创新,因此有必要搭建快看基于大语言模型的AI智能问答系统,期望提高作品的搜索转化率,为快看搜索带来新的活力。但是要实现这个事并不容易,主要有以下几个挑战:
基于以上挑战,我们制定了在RAG方向的工作流程,包括知识挖掘、数据索引、检索模块、重排模块、评估模块五个关键阶段。
1.知识挖掘
我们的文本知识采取【内部数据为主,外部数据为辅】的策略:
外部数据主要是对内部数据进行定向的补充,以及爬取一些问答QA对。
有了原始数据后,就需要做数据清洗,得到和领域相关的干净的格式,同时保证数据的质量和多样性。为此,我们制定了下面的数据清洗pipeline,最后会按照不同的用途统一成不同的数据格式。
2.数据索引
数据清洗之后就可以构建知识库,我们内部知识库所包含的知识信息如上图所示,根据知识库的用途和专业度,我们划分为三种类型:
构建知识库的过程就是给文本数据构建索引,首先要基于清洗好的数据切分成不同的chunk块,每个chunk块称作是一个doc,这是构建向量的最小单位,然后使用Embedding模型在doc上编码出向量,存储到Milvus中并建好向量索引,此时一个知识库就构建好了。
除了Embedding的 dense索引,我们还会基于ES在每个知识库上构建倒排索引。
3.检索模块
所以检索的时候就包括ES索引和Milvus向量索引的混合检索,目前的混合策略是先进行ES前置检索,返回父层级的索引,然后在这些父索引范围内,进行更精确的doc层级的向量索引。
4.重排模块
Rerank重排模块还是很有必要的,重排和召回所关注的目标不一样,召回重点是在topk中能把真实相关的doc给捞出来,而重排则需要把真实相关的doc排在前面,同时减少topk的数量。
rerank模型一般是Cross-Encoder架构,就是把query和每个候选doc组成一个pair对,对每个pair进行相似性打分,所以rerank模型会有一点性能上的开销,因为要把query和每个候选doc进行逐一的打分,但是匹配结果会更精准。
Rerank的排序结果,一般会取一个小的topk进行截断,比如top3,因为后面要丢到大语言模型中进行生成,doc数量比较多会对大模型推理造成干扰,并且会有token的开销。其实这里的终极目标应该是只包括真实相关doc不包含噪声doc,但是这个目标任重而道远,我们所做的模型和策略都要向这个终极目标靠拢,只要能向这个终极目标更近一步,那就是一个更好的优化。
我们在重排之后,并不会把top3 doc丢到大语言模型里进行生成,因为这top3 doc,我们看作是3个定位锚点,接下来会以每个锚点为中心进行上下文扩展,增强背景信息,但是在扩展的过程中要注意几个细节,比如docId对齐、doc去重、扩展边界、doc还原顺序等等。扩展后的内容会合并成一个context,丢到大语言模型中进行生成。
5.评估模块
我们从三个维度来评估RAG系统,分别是召回、重排和端到端评估。
5.1 评估召回
召回阶段关注的是,在不同@k下捞出真实相关doc的能力,所以我们主要看 recall指标,这里我们关注的是整个召回模块,这个模块的输入就是给定一个Query,输出topk 个docs。这里给出一些我们的实验结果,供大家参考。
5.2 评估重排
重排的目标是把真实相关的doc排在前面,所以谁能把这个事干的越好,谁就是好的模型/策略。
我们的做法是先把一批召回结果保存下来,然后让不同的重排模型/策略基于这份结果进行排序,为了方便对比,我们的baseline就是不使用任何排序模型,直接对召回后的结果进行topk截断。下面是我们的一些实验结果:
5.3 端到端评估
端到端评估,就是把RAG系统看作黑盒子,这个黑盒子的输入是一个query,输出是一个answer和引用docs,根据系统的输入和最终的输出进行评估。这种端到端评估我们认为有两种方式,一是从生成角度评估<真实答案,生成答案>的相似性,二是从三元组的角度进行评估。
总体上,我个人不太建议使用端到端的方式进行评估,看似比较省事,实则有很多麻烦需要考虑,比如:
所以我个人更建议从召回和重排的结果上去评测,因为这个结果输出是稳定的,评测指标也是稳定的,而且RAG的核心是检索,检索对了模型才有可能回答对,至于生成端的问题,就和检索无关了,可以去调prompt或者换更好的生成模型来解决。
6.高级RAG
上面所说的算是一个比较标准的RAG流程,但是企业应用中的数据和用户query都是多种多样的,为了解决更复杂的业务case,我们做了一些改造,包括query转换、检索时机意图识别、Text2SQL等。
6.1 query转换
用户的query实际是多种多样的,有简单的query,也有复杂的query,我举几个例子:
其中Q1类型的问题,我们称之为简单的单点问题,目前在这类问题上,我们的RAG已经可以很好的回答了。比较难处理的是复杂类型的问题,比如Q2和Q3,我们称之为多跳类问题,针对问题Q2,实际上需要先做query分解,分解为两个子问题,即【偷偷藏不住的作者是谁】和【难哄的作者是谁】,然后这两个子问题并行去做检索,最后将各自检索到的docs汇总在一起,丢给大语言模型进行生成。针对问题Q3,则需要做串行分解,因为有依赖关系,先根据【偷偷藏不住的作者是谁】去做检索和生成,根据答案再组成第二个子问题【XX还写过哪些作品】,再去做一次检索和生成。
所以加了query转换模块后,我们的流程是这样的,用户输入一个query,首先会并行的做几个转换:
如果query不能分解,则以前面两个转换为主,继续后面的RAG流程,如果能分解,则以分解的结果为主,同时还要看是并行的分解,还是串行的分解:
6.2 检索时机
有的query是不需要在私域知识库上进行检索的,比如【中国的首都是哪】这种常识类问题,或者用户输入【嗯嗯】这种语气句,因此有必要做检索时机的判断,在需要检索的问题上执行RAG,不需要检索的问题则直接调用大语言模型进行生成,这样也可以减少后端不必要的调用,提高前端响应速度。但是在这个问题上没有很好的解决方案,我们做了一些探索,可以分享下我们的方案,供大家参考。
我们目前的做法是先用大语言模型进行判断,会在 prompt中写清楚知识库的范围,这个prompt会写的比较严格,尽量让判断为检索的问题确实是需要检索的。判定为不需要检索的问题,则进行第二关句型维度的判断,我们做了一个假设,就是用户的输入如果是疑问句和祈使句大概率是需要检索的,其它句型如陈述句、感叹句、语气句等,则不需要检索,直接调用大语言模型进行生成即可,为此我们专门训练了一个Bert的句型分类模型。当然,这种做法仅供参考,大家如果有更好的意图识别方案也欢迎交流分享。
6.3 Text2SQL
此外在RAG方向上,我们还结合了Text2SQL的技术,因为企业通常会有很多结构化的数据表,这些表是企业非常重要的数据资产,但是生产环境的数据表之间有非常复杂的关联,目前LLM还不能很好的处理这些关联关系。而快看有自建的 Elasticsearch引擎,相当于是聚合了很多业务表的大宽表,因此我们探索了通过大语言模型生成标准SQL语句,继而来查询ES引擎关键字段进行生成的方案,期望通过这种方式来回答用户实时性和客观性的问题,增强模型回答的准确度和事实性。比如【某某作品更新到第几话了】、【现在最流行的漫画是哪个】这种实时性和客观性的问题,其实在ES中是有特定的字段可以回答的,查出来后再结合字段的物理意义,组装成prompt让大语言模型进行生成。
但实际在执行的时候就遇到了不少问题,比如 ES需要用DSL语法来查询,而大语言模型生成SQL语句还勉强可以,生成DSL就完全不能用了,所以需要做SQL到DSL的翻译,好在ES官方提供了翻译的API,但是这个API又有些限制,不能翻译带select嵌套的SQL,所以我们又做了一层SQL语句的select分解,分解成多个子sql,每个子sql会先转成 dsl再去查es,将查询到的结果回填到下个子sql,重复这个过程直到最后一个子sql的结果,将查询结果和用户query组装成prompt,让大语言模型进行推理生成。
6.4 整体方案
所以结合了query转换、检索时机、Text2SQL三个改造,我们的整体方案是这样的:
7.大模型微调
快看作为二次元领域的龙头,积累了非常多的领域知识,因此也在尝试基于开源大模型进行微调,训练快看在二次元领域的垂直大模型。此外快看还基于自身的数据优势,制作了一份二次元领域的基准评估数据集,并开放到了 Huggingface平台
(https://huggingface.co/datasets/gctian/comic-eval-benchmark),欢迎贡献更多二次元领域语料及二次元大模型,如需评测请联系作者获取评测脚本。
以下是我们基于 Baichuan2-13b大模型微调后的评测结果,分别在zero-shot和3-shot下进行了评估,相比于不微调,均有不同程度的提升。
快看作为国内最大的漫画平台,拥有超过1.3万部漫画作品,聚集了国内80%的头部优质IP,这种IP优势是独一无二的。我们希望通过这些IP衍生出IP角色互动类的应用,用户可以跟IP中的角色进行沉浸式聊天,而不是纯虚拟角色的聊天,这是我们IP角色互动和市场上常见的虚拟角色扮演类应用不同的地方。
而这背后的实现方案就是角色扮演大模型+知识库RAG,知识库又分为原创剧情知识库和用户个性化记忆知识库,原创剧情知识库是AI角色在IP剧情中的记忆,包括角色的成长经历、故事线、社交关系等,这个知识库也是快看最大的优势,用户个性化知识库是由每个用户和AI角色的聊天历史组成的。
1.构建知识库
整体RAG方案和上面讲的类似,这里说一下两个知识库的构建策略。首先是剧情知识库,我们会将剧本做三级切分,即chapter-session-chunk,在每个chunk块上利用LLM抽取summary、question以及一些结构化字段,将这些信息构建向量索引存储到 Milvus中作为剧情知识库,但有很多细节要注意,比如脏数据过滤、故事线划分、业务字段过滤、chunk长度、大模型抽取准确性等。
用户和AI角色的聊天历史,首先会切分成对话session,每个session作为一个chunk,利用LLM在session上抽取对话摘要,然后构建摘要的向量索引存储到 Milvus中。
当用户输入一个query后,会同时检索这两个知识库,将query、检索到的剧情块、对话列表组装成prompt,调用角色扮演大模型进行生成,相当于模型既能知道角色的剧情记忆又知道和用户短期内的聊天记忆,如果聊天历史比较短,也可以不检索,直接带上最近N条聊天历史即可。
2.知识库评测
在原创剧情知识库方案上,我们也使用了头部厂商的知识库方案进行构建,并和我们自建的知识库进行对比,使用原创剧情上提取出的5000个问题作为测试集,评测不同知识库方案的剧情召回能力。评测结果显示,我们自建知识库在各个指标上均超过了头部厂商的知识库方案。
此外在角色扮演模型评测方向,快看也做了很多工作,包括人工的主观评估和定量的自动化评估:
04.RAG经验分享
这里分享下RAG的一些经验吧,其中有的是我实践过程中踩过的坑,有的是个人思考,不一定对,仅供参考。
作者介绍
田贵成
快看资深算法工程师,
目前负责大语言模型方向的探索和落地。