写点什么

Milvus × RAG 助力快看多业务应用

作者:Zilliz
  • 2024-07-26
    上海
  • 本文字数:8069 字

    阅读完需:约 26 分钟

Milvus × RAG助力快看多业务应用

快看漫画介绍


快看漫画创办于 2014 年,集漫画阅读、创作互动、线下漫画沉浸体验、周边衍生品购买等体验于一体,是年轻人的一站式漫画生活方式平台。截止到 2023 年底,快看总用户超过 3.8 亿,在中国漫画市场渗透率超过 50%。经过 9 年的创作者生态建设,快看已汇聚超过 12 万注册创作者,发表漫画作品超 13000 部。目前,快看漫画已有超过 500 部作品登陆全球近 200 个国家和地区,成为中国文化出海的代表。



除了线上平台,快看还经常在线下组织沉浸式漫画乐园、漫画狂欢夜、漫画家见面会等活动,打造漫画粉丝们的嘉年华。


Milvus 在快看基础业务的应用



快看基础业务包括常见的搜索、推荐、广告,此外还包括图像相关的业务,比如图像去重、以图搜图等,为了更好的服务上述场景需求,需要构建向量检索系统,首先要做的一件事,就是确定一款向量检索引擎,我们当时也做了一些技术选型,包括 faiss、milvus、elasticsearch、vearch、proxima 等。最后选定了 Milvus 作为我们的向量检索引擎,因为 milvus 有如下的优点:

  • 开箱即用:几乎不用考虑基础建设,专注于业务侧工作

  • 高性能:在 ANN 向量检索 benchmark 中排名靠前

  • 高可用:Milvus 系统组件相互独立、隔离,能充分确保系统弹性和可靠性。

  • 混合查询:支持向量与结构化数据的混合查询

  • 开发者友好:支持 Java、Python、Go 等 sdk

  • 分布式:Milvus 的分布式架构和高吞吐量特性使其非常适合处理大规模向量数据

  • 监控报警:Milvus 会生成关于系统运行状态的详细时序 metrics。可以通过 PrometheusGrafana等可视化工具进行观察

  • 社区活跃:github star 28.5k+、社区人数 5000+、贡献者 260+



Milvus 的社区非常活跃,这也是我们考量的一个重点因素,在 Github issue 上提一些问题,都能得到及时和耐心的反馈,并且有专门的微信运营服务群,在群里不仅可以反映自己遇到的问题,也能看到别人遇到的各种问题,还能起到相互学习的作用。


有了向量检索引擎之后,就可以根据向量检索的三要素搭建向量检索服务:

  1. Embedding 模型:通常是在自己业务数据上训练 Embedding 模型,如果是文本向量也可以使用开源的 Text Embedding 模型。之后就可以获取到每个物料的 embedding 向量,这里我们会对 embedding 向量先进行 L2 归一化,再考虑入库建索引。

  2. 创建 collection&index:入库在 milvus 中的操作就是创建一个 collection 集合,然后对向量字段构建 index 索引,这些通过 milvus 的 API 可以很方便的完成。

  3. 向量查询:创建好索引后,就可以做向量查询了,向量查询本质上是将 Query 向量和 collection 中的所有向量进行相似度匹配,所以需要确定一个相似度指标,比如欧氏距离、Cosine 相似度等。我们这里使用的 L2 欧式距离。其实最开始是想用 Cosine 相似度,但是当时 Milvus 还不支持,所以我们入库前先将向量进行 L2 归一化,查询的时候再使用欧氏距离,这种方式和直接使用 Cosine 相似度是成反比的,两种方案匹配出的结果都是一样的,只不过一个分数越小越好,一个分数越大越好。



我们最开始使用的索引是 Ivf_Flat,后面切换到了 HNSW 索引,在我们的业务数据上做了一些实验,发现 Hnsw 索引和 Ivf_Flat 相比:

  1. 两者在查询速度上差不多,细究下来,hnsw 要快一点

  2. hnsw 在不同 @k 下的平均召回率都要好于 ivf_flat,这个是业务上更加关心的点,所以后面就切到了 HNSW 索引。


以快看搜索场景为例,目前在多个场景应用了向量检索技术,搭建了如下的向量召回全景架构:



并在线上多个业务场景进行了实验,以数据量最大的社区帖子 Feed 流为例,应用了上述架构之后,在消费时长、下滑深度、曝光、点击等指标上均有不同程度的正向提升。


快看 RAG 技术探索和应用


以 ChatGPT 为代表的大语言模型(LLM)在自然语言理解和生成任务上,展现了前所未有的能力,但是大语言模型(LLM)在特定领域任务中,会出现信息延迟和幻觉现象,检索增强生成(RAG)通过引用外部知识可以有效缓解这些问题,是 LLM 在工业领域应用的关键技术。

快看在大语言模型及 RAG 出现之后,迅速切入到以大语言模型为代表的技术领域,开始探索快看内部的应用场景,并在快看 AI 智能问答、IP 角色互动两个场景取得了实质性进展,接下来以这两个场景为例,详细介绍下我们的技术方案。


快看 AI 智能问答


这件事的背景是,大语言模型的对话模式,具有交互性强、沉浸式体验、拟人化等特点,是对传统搜索的一种创新,因此有必要搭建快看基于大语言模型的 AI 智能问答系统,期望提高作品的搜索转化率,为快看搜索带来新的活力。但是要实现这个事并不容易,主要有以下几个挑战:

  • 新目标新挑战:RAG 是一个新的技术方向,当前业界并无成熟的落地方案可以参考,此外部署和训练大模型都需要较大的成本。

  • 数据在哪:构建知识库首先要有数据,尤其是文本类数据,但是企业内部有比较多的结构化数据库表,如何有效的利用这些数据,是值得深思的一个点。

  • 模型多:整个 RAG 系统中,涉及到的模型比较多,比如 Embedding、Rerank、大语言模型,以及意图识别、实体抽取等环节都需要用到模型,需要对这些模型有一个全局的认识。

  • 如何评估:搭建好 RAG 系统后,就需要考虑如何来评估这个事的好坏,以方便进行迭代。

基于以上挑战,我们制定了在 RAG 方向的工作流程,包括知识挖掘、数据索引、检索模块、重排模块、评估模块五个关键阶段。


知识挖掘


我们的文本知识采取【内部数据为主,外部数据为辅】的策略:

  • 内部数据

    社区 UGC 帖子:用户帖子中会包含对某个漫画的评价、剧情讨论、作者讨论、角色关系等,这些内容是对问答有正向帮助的

    快看增长业务问答数据:由标题、答案、背景知识等组成的正文

    结构化数据:MySQL、Mongo、ES 等结构化数据库表,这部分数据我们有两种用法,一是将部分关键字段按照特定的文本模板拼成一个 text 段落,去构建文本知识库。另一种做法是利用 Text2SQL 的技术,直接去查询结构化数据库表进行生成。

  • 外部数据:外部数据主要是对内部数据进行定向的补充,以及爬取一些问答 QA 对。


有了原始数据后,就需要做数据清洗,得到和领域相关的干净的格式,同时保证数据的质量和多样性。为此,我们制定了下面的数据清洗 pipeline,最后会按照不同的用途统一成不同的数据格式。


数据索引



数据清洗之后就可以构建知识库,我们内部知识库所包含的知识信息如上图所示,根据知识库的用途和专业度,我们划分为三种类型:

  1. PGC 作品知识库

  2. UGC 帖子知识库

  3. 问答知识库


构建知识库的过程就是给文本数据构建索引,首先要基于清洗好的数据切分成不同的 chunk 块,每个 chunk 块称作是一个 doc,这是构建向量的最小单位,然后使用 Embedding 模型在 doc 上编码出向量,存储到 Milvus 中并建好向量索引,此时一个知识库就构建好了。



除了 Embedding 的 dense 索引,我们还会基于 ES 在每个知识库上构建倒排索引。


检索模块


所以检索的时候就包括 ES 索引和 Milvus 向量索引的混合检索,目前的混合策略是先进行 ES 前置检索,返回父层级的索引,然后在这些父索引范围内,进行更精确的 doc 层级的向量索引。



  1. ES 检索:通过 paddle 的实体抽取模型,从 Query 中抽取实体信息的关键字段,在 ES 检索的时候进行不同的加权,ES 返回匹配的 source 文档集合,source 可以认为是 doc 向量索引的 parent_id。

  2. milvus 向量检索:对 source 集合内的每个子 doc 进行更精确的向量检索匹配,我们选取了 3 个异质化的 Embedding 模型,构建了三个 collection 集合,在这三个 collection 上并行检索 topk,最后再通过 RRF 算法进行融合截断。

重排模块



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,丢到大语言模型中进行生成。


评估模块


我们从三个维度来评估 RAG 系统,分别是召回、重排和端到端评估

5.1 评估召回


召回阶段关注的是,在不同 @k 下捞出真实相关 doc 的能力,所以我们主要看 recall 指标,这里我们关注的是整个召回模块,这个模块的输入就是给定一个 Query,输出 topk 个 docs。这里给出一些我们的实验结果,供大家参考。



  • 左边的图是最初只使用开源的 m3e-base 模型做召回的评测结果,这个结果作为 baseline

  • 中间的图是对 m3e-base 模型进行微调后的评测结果,提升还是很明显的,Recall 大概有 20%的提升

  • 右边的图是使用微调后的 m3e-base 模型,加上 ES 索引前置检索的混合检索,相比 baseline 大概有 32%的提升

5.2 评估重排


重排的目标是把真实相关的 doc 排在前面,所以谁能把这个事干的越好,谁就是好的模型/策略。

我们的做法是先把一批召回结果保存下来,然后让不同的重排模型/策略基于这份结果进行排序,为了方便对比,我们的 baseline 就是不使用任何排序模型,直接对召回后的结果进行 topk 截断。下面是我们的一些实验结果:



  • 左边的图是 baseline 结果,直接对召回结果进行 topk 截断

  • 中间的图是使用开源的 bge-rerank-base 模型,在排序指标上反而是有下降的

  • 右边的图是对 bge-rerank-base 模型进行微调后的结果,相比于 baseline,map 有 5%的提升,相比于不微调,map 有 8%左右的提升

5.3 端到端评估



端到端评估,就是把 RAG 系统看作黑盒子,这个黑盒子的输入是一个 query,输出是一个 answer 和引用 docs,根据系统的输入和最终的输出进行评估。这种端到端评估我们认为有两种方式,一是从生成角度评估<真实答案,生成答案>的相似性,二是从<query,context,answer>三元组的角度进行评估。


  1. 评估 <真实答案,生成答案>:这种方式本质上是在看两个字符串的相似度,前提是需要准备一批带 ground truth 答案的 QA 对作为测试集,然后逐一评测真实的 A 和 RAG 系统生成的 A' 之间的相似度,这里我列举了几个相似度评价指标,比如 Rouge、EM、BLEU、embedding sim 等,但是具体要以哪一个指标为准,这个也没有一个共识,倒是有一些研究会把这几个指标进行加权融合,算出一个融合分数,以最后的融合分数为主。

  2. 评估 <query, context, answer>:目前一些开源的 RAG 评估框架,是从这个三元组的角度来评测的,比如 ragas,如果是评 retrieval 侧的指标,同样需要先准备一批带 ground truth 的 QA 对,评 generation 侧的指标则不需要。不过 ragas 中使用了 LLM 作为打分器,由于 LLM 输出结果的不稳定性,会导致算出来的指标值有差异,这就需要考虑稳定性和置信度的问题了。


总体上,我个人不太建议使用端到端的方式进行评估,看似比较省事,实则有很多麻烦需要考虑,比如:

  • 要事先准备一批带 ground truth 答案的 QA 对作为测试集,这个就比较消耗人工成本, 而且标准答案不好制定,比如”中国的首都是哪“ 这个问题,可以把”北京“两个字作为答案,也可以把”北京是中国的首都“作为答案,但是答案字符串的长短、字数、表达方式等,都会影响到评测指标的变化。

  • 大语言模型的生成有一个特点,就是同一个输入 Prompt,模型每次生成的答案字符串是不一致的,具体表现在答案的长短、字数、表达方式等,那就导致同一份测试集,第一轮评测和第二轮评测的指标值是会变化的,需要考虑指标稳定性和置信度的问题。当然如果像 ragas 中那样,借助 LLM 来打分,那就需要考虑双重稳定性和置信度的问题了。


所以我个人更建议从召回和重排的结果上去评测,因为这个结果输出是稳定的,评测指标也是稳定的,而且 RAG 的核心是检索,检索对了模型才有可能回答对,至于生成端的问题,就和检索无关了,可以去调 prompt 或者换更好的生成模型来解决。

高级 RAG


上面所说的算是一个比较标准的 RAG 流程,但是企业应用中的数据和用户 query 都是多种多样的,为了解决更复杂的业务 case,我们做了一些改造,包括 query 转换、检索时机意图识别、Text2SQL 等。

6.1 query 转换


用户的 query 实际是多种多样的,有简单的 query,也有复杂的 query,我举几个例子:

  1. Q1:偷偷藏不住的作者是谁?

  2. Q2:偷偷藏不住和难哄是一个作者吗?

  3. Q3:偷偷藏不住的作者还写过哪些作品?


其中 Q1 类型的问题,我们称之为简单的单点问题,目前在这类问题上,我们的 RAG 已经可以很好的回答了。比较难处理的是复杂类型的问题,比如 Q2 和 Q3,我们称之为多跳类问题,针对问题 Q2,实际上需要先做 query 分解,分解为两个子问题,即【偷偷藏不住的作者是谁】和【难哄的作者是谁】,然后这两个子问题并行去做检索,最后将各自检索到的 docs 汇总在一起,丢给大语言模型进行生成。针对问题 Q3,则需要做串行分解,因为有依赖关系,先根据【偷偷藏不住的作者是谁】去做检索和生成,根据答案再组成第二个子问题【XX 还写过哪些作品】,再去做一次检索和生成。


所以加了 query 转换模块后,我们的流程是这样的,用户输入一个 query,首先会并行的做几个转换:

  • 普通的 query 改写

  • hyde 生成假设答案

  • query 分解


如果 query 不能分解,则以前面两个转换为主,继续后面的 RAG 流程,如果能分解,则以分解的结果为主,同时还要看是并行的分解,还是串行的分解:

  • 并行分解:并行执行多个子问题的检索,最后将检索结果汇总成 context 进行生成

  • 串行分解:进行迭代式的检索生成


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 三个改造,我们的整体方案是这样的:

  1. 用户 query 先进行检索时机的判断,如果不需要检索,则直接调用大语言模型进行生成,如果需要检索,则并行的执行 RAG 和 Text2SQL 两个分支

  2. 如果 Text2SQL 分支有返回结果,则以这个分支的 prompt 为主进行生成,有返回结果大概率是置信的,否则在中间过程就会出错了,比如生成 sql 有问题、转换 dsl 有问题、查询 es 有问题等等。

  3. 如果 Text2SQL 分支没有返回结果,则以 RAG 分支的 prompt 为主进行生成,这个分支就包括了刚才提到的 query 转换模块,转换之后就是标准的检索、重排等等。

大模型微调



快看作为二次元领域的龙头,积累了非常多的领域知识,因此也在尝试基于开源大模型进行微调,训练快看在二次元领域的垂直大模型。此外快看还基于自身的数据优势,制作了一份二次元领域的基准评估数据集,并开放到了 Huggingface 平台 https://huggingface.co/datasets/gctian/comic-eval-benchmark,欢迎贡献更多二次元领域语料及二次元大模型,如需评测请联系作者获取评测脚本。


以下是我们基于 Baichuan2-13b 大模型微调后的评测结果,分别在 zero-shot 和 3-shot 下进行了评估,相比于不微调,均有不同程度的提升。


IP 角色互动


快看作为国内最大的漫画平台,拥有超过 1.3 万部漫画作品,聚集了国内 80%的头部优质 IP,这种 IP 优势是独一无二的。我们希望通过这些 IP 衍生出 IP 角色互动类的应用,用户可以跟 IP 中的角色进行沉浸式聊天,而不是纯虚拟角色的聊天,这是我们 IP 角色互动和市场上常见的虚拟角色扮演类应用不同的地方。

而这背后的实现方案就是角色扮演大模型+知识库 RAG,知识库又分为原创剧情知识库和用户个性化记忆知识库,原创剧情知识库是 AI 角色在 IP 剧情中的记忆,包括角色的成长经历、故事线、社交关系等,这个知识库也是快看最大的优势,用户个性化知识库是由每个用户和 AI 角色的聊天历史组成的。



构建知识库


整体 RAG 方案和上面讲的类似,这里说一下两个知识库的构建策略。首先是剧情知识库,我们会将剧本做三级切分,即 chapter-session-chunk,在每个 chunk 块上利用 LLM 抽取 summary、question 以及一些结构化字段,将这些信息构建向量索引存储到 Milvus 中作为剧情知识库,但有很多细节要注意,比如脏数据过滤、故事线划分、业务字段过滤、chunk 长度、大模型抽取准确性等。



用户和 AI 角色的聊天历史,首先会切分成对话 session,每个 session 作为一个 chunk,利用 LLM 在 session 上抽取对话摘要,然后构建摘要的向量索引存储到 Milvus 中。



当用户输入一个 query 后,会同时检索这两个知识库,将 query、检索到的剧情块、对话列表组装成 prompt,调用角色扮演大模型进行生成,相当于模型既能知道角色的剧情记忆又知道和用户短期内的聊天记忆,如果聊天历史比较短,也可以不检索,直接带上最近 N 条聊天历史即可。

知识库评测

在原创剧情知识库方案上,我们也使用了头部厂商的知识库方案进行构建,并和我们自建的知识库进行对比,使用原创剧情上提取出的 5000 个问题作为测试集,评测不同知识库方案的剧情召回能力。评测结果显示,我们自建知识库在各个指标上均超过了头部厂商的知识库方案。



此外在角色扮演模型评测方向,快看也做了很多工作,包括人工的主观评估和定量的自动化评估:

  • 人工主观评估:快看内部开发了用于人工 pk 的匿名 pk 平台,可以来评估不同模型的角色扮演能力



  • 自动化评估:虽然目前有一些角色模型的评测指标,但是这些指标在置信度和稳定性上都还不够完善,因此快看选择自训 Reward 打分模型,基于打分模型开发了自动化单轮 pk 评估和自动化多轮 pk 评估体系,假设总共收集 300 轮票数,自动单轮 pk 就是两个模型分别和某个角色聊一轮,总共聊 300 个角色。自动多轮 pk 就是两个模型分别和角色深度聊 N 轮,N 是随机的,聊完就换下一个角色,直到收集到 300 轮票数。经过验证,这套自动评测体系和人工 pk 结果是一致的。


RAG 经验分享


这里分享下 RAG 的一些经验吧,其中有的是我实践过程中踩过的坑,有的是个人思考,不一定对,仅供参考。



作者介绍


田贵成,快看资深算法工程师,目前负责大语言模型方向的探索和落地。

发布于: 刚刚阅读数: 6
用户头像

Zilliz

关注

Data Infrastructure for AI Made Easy 2021-10-09 加入

还未添加个人简介

评论

发布
暂无评论
Milvus × RAG助力快看多业务应用_人工智能_Zilliz_InfoQ写作社区