今日关注:AIGC 利器 Ray 云原生探索之路-分布式构建本地知识库
在 ChatGPT 火爆全网之后,各行各业都在围绕它来进行构建自己场景的应用。这里以本地知识库为场景来聊聊怎么结合 Ray Core、Ray Serve、KubeRay、LangChain、Embeddings、向量数据库、LLM、Kubernetes 和 GPU 方案来构建属于自己的本地的知识库。对整体方案和 Ray 相关感兴趣的可以阅读前面发布的一些文章,《AIGC 利器-Ray 云原生探索之路--总览篇》,《AIGC 利器 Ray 云原生探索之路--Ray Core 篇 (上)》,《AIGC 利器 Ray 云原生探索之路--Ray Core 篇 (下)》。
01 基本概念
Embeddings:在自然语言处理中,Embeddings 通常指的是将单词或短语映射到连续向量空间中的向量表示。
向量索引:向量索引(Vector Indexing)是一种用于快速检索相似向量的技术。它是基于向量空间模型(Vector Space Model)的思想,通过构建索引结构来加速相似向量的查询。在向量索引中,每个向量都被映射到一个高效的数据结构中,使得可以根据向量之间的相似度进行快速检索。如 FAISS,LlamaIndex 等。
(资料图片仅供参考)
向量数据库:支持向量数据的存储和查询的数据库就可以理解成是向量数据库,目前也有很多基于原有的数据库实现了向量插件的数据库,比如 Postgresql,ElasticSearch 等等。
LLM:Large Language Model 大语言模型。LLM 是一种基于深度学习的人工智能模型,具备强大的自然语言处理能力。它通过大规模的预训练过程,学习了广泛的语言知识和语言模式,并可以根据输入的文本生成连贯、合理的回复。
Prompt:在自然语言处理中,Prompt 是指用户给出的一段文字或指令,用于引导或提示语言模型生成特定的回复或完成特定的任务。Prompt 可以是一个问题、一个描述性的语句、一句指令,甚至是一个完整的上下文对话。它作为输入提供给语言模型,以指导模型生成相关的回答或执行相应的任务。Prompt 的设计因为直接影响语言模型的输出,所以非常重要。一个设计合理的 Prompt 可以引导模型生成更准确、更有针对性的回答。通过在 Prompt 中提供所需的背景信息、明确的要求或限制条件,可以控制模型的回答风格、内容的方向性,或者针对特定任务的执行。
LangChain:提高了一个基于 LLM 构建应用的框架。支持 6 个主要的场景支持,包括 LLM/Prompt(和大语言模型对接,提高大语言模型生成内容的质量),Chains(提供链式的方式运行各种任务),Data Augmented Generation(数据增强的生成能力),Agents(通过大语言模型结合外部工具,完成定制化能力的任务),Memory(提供大语言模型聊天的历史上下文能力),Evaluation(生成式模型很难用传统指标来评估。评估它们的一种新方法是使用语言模型本身。LangChain 提供了一些 prompts/chains 来帮助实现这一点)。
Ray Core:是 Ray 框架的底层框架,提供了一整套的分布式计算的框架,可以将普通的应用转化成分布式的系统。这里主要以 Python 语言的程序为主,具体可以参看前面的文章。
Ray Serve:是一个可扩展的模型服务库,用于构建在线推理 API。Serve 是框架无关的,所以可以使用一个工具包来服务所有的东西,从使用 PyTorch、Tensorflow 和 Keras 等框架构建的深度学习模型,到 Scikit-Learn 模型,再到任意的 Python 业务逻辑。Serve 特别适合于模型组合,使您能够构建由多个 ML 模型和业务逻辑组成的复杂推理服务(全部使用 Python 代码)。Ray Serve 是建立在 RayCore 之上的,所以它很容易扩展到许多机器上,并提供灵活的调度支持。
Fine-Tune:基于数据对模型进行微调。这个过程也是涉及到对 LLM 的训练。目前,社区也有不少开放出来的模型都是基于这种方式的。至于是不要对模型进行调整,可以根据你的需求,如果你的任务和 LLM 本身是有不同的,是想基于 LLM 构建自己任务的大模型,那就需要微调模型。如果 LLM 本身和你的任务是一致的,比如只是为了让 LLM 知道更多知识,那也不一定要调整模型本身,用原来的基础模型就可以。
Search-Ask 方法:是一种用于问答系统的策略,结合了基于检索和基于生成的方法。它旨在充分利用检索和生成两种不同的技术,以提供更全面和准确的答案。在 Search-Ask 方法中,首先进行搜索(Search)阶段。用户的查询被发送到一个检索系统,该系统在预先建立的知识库或文档集合中执行搜索,并返回与查询相关的文档或候选答案。然后是询问(Ask)阶段。在此阶段,通过使用基于生成的方法,从检索到的文档或候选答案中提取或生成最终的答案。这可能涉及文本摘要、实体识别、关系抽取等技术来提取关键信息,或者使用生成模型(如语言模型)来生成具有上下文和语义连贯性的答案。通过结合搜索和生成两个阶段,Search-Ask 方法旨在通过检索提供初始的答案候选集,并通过生成进行下一步的筛选和精炼。这种方法的优势在于,检索阶段可以快速找到相关的文档或信息,而生成阶段可以通过理解上下文和语义生成更准确和丰富的答案。需要注意的是,具体实施 Search-Ask 方法的细节可以因应用场景和具体需求而有所不同。这种方法可以根据实际情况进行调整和定制,以达到最佳的问答效果。
02 本地向量处理
在 OpenAI 的 API 服务中提供了 embeddings 的 API,就是用于根据提供的文本输入,生成向量。但是这种是需要 OpenAI 的账号以及可以连接到 OpenAI 的 API 访问地址,而且还是收费的 API。所以,在内网或者国内的环境,如果有离线的方式也可以完成类似工作,那就是更好的选择。答案是肯定的。
在线的 API:
离线的方式:
以下 code sample 中使用了 HuggingFace 的 Embeddings 的模型 “text2vec-large-chinese” 来完成这个能力。其中 lHuggingFaceEmbeddings 有两个方法。一个是 embed_documents 方法,用于在构建 embeddings 的时候被使用。还有一个是 embed_query 方法,是在提问的整个环境中,以及在和 LLM 通信前,需要被使用到的方法,来完成对提问的文本的向量化处理。
使用 embeddings 对文档进行向量化处理:
基于 pgvector 完成向量处理和向量数据的保存:基于 elasticsearch 完成向量处理和向量数据的保存:03 串行向量化
串行指的是在处理的过程中没有并发多任务处理能力,有一个 worker 顺序执行的方式去处理整个过程,包括数据文件的读取、文本的拆分以及文本的向量处理,到写入向量数据库。如果在数据量很大的情况下,整个效果会很慢,不能充分地利用好整个集群的可用资源去处理相关的任务。
以上的 sample code 主要分为两个阶段:
第一个阶段:主要是读取数据文件,并进行文本的拆分。第二个阶段:使用拆分出来的文本,使用 Embeddings 模型进行向量化处理,这里使用的是 “text2vec-large-chinese” 模型,可以根据需要替换不同的 Embeddings 模型, 然后持久化到 pg 这个类型的向量数据库中。04 并行向量化
并行指的是在处理的过程中有并发多任务处理能力,有 n 个 worker 并行的方式去运行各种任务。如果在数据量很大的情况下,整个数据的向量化处理能力,会随着可用资源的增多,有很明显的提升。能充分的利用好整个集群的可用资源去处理相关的任务。
以上的 sample code 主要分为三个阶段:
第一个阶段:主要是读取数据文件,并进行文本的拆分,为后续的并行处理提供分组数据。这里将数据分成了 8 个分组,这里是根据 db_shards 设置的数值来决定的。第二个阶段:使用拆分出来的文本,将拆分出来的数据进行分组,每组数据进行并行的向量化的处理。这里关键方法是@ray.remote(num_gpus=1) def process_shard(shard),这里使用到了 Ray Core 的 Task 的能力,Task 是可以充分利用好集群的资源,分布式的调度和运行。由于每一个负责分组处理的 Task 需要完成 Embeddings,而 Embeddings 是需要模型参与的,这里使用的是“text2vec-large-chinese”模型,可以根据需要替换不同的 Embeddings 模型, 这里是给每一个 Task 都分配一个 GPU 去独立的处理。这样的并行效率是很高的。虽然有一些模型是可以用 CPU 去运行的,但是效率还是非常低的。第三个阶段:最后,将每组向量化后的数据进行合并后,再写入向量数据库,这样完成了整个并行化向量处理的能力。05 串行知识问答
在问答的过程中,首先需要根据问题进行向量化的处理,然后根据处理后的向量数据去向量数据库中去检索,来找到和问题相似度很高的一些上下文信息,再结合 Prompt 来得到最终需要输入给 LLM 的内容。
06 并行知识问答
在基于基本的流程之外。这里使用了 Ray Serve 的在线并发推理能力,具体的并发能力还是和 GPU 的设备数量相关,可以根据实际情况设置对应的 Ray Serve 的副本数来提升并发推理的能力,这里就是 Ray Serve Deployment 的 num_replicas 配置,这里设置了 1,会使用一张 GPU 设备提供 Serve,可根据实际情况去调整副本的数量。这里使用的是“text2vec-large-chinese”模型作为 Embeddings;使用 “chatglm2-6b-int4” 模型作为 LLM 模型。
以上的 sample code 主要分为五个阶段:
第一个阶段:首先定义了 QADeployment 类,这个类中完成整体的代码的封装和逻辑。这里将这个类标记成 Ray 的 Serve,只要将类使用相关的标注 “@serve.deployment(ray_actor_options={"num_gpus": 1})”。这里使用到了 Ray Core 的 Actor,以及使用 GPU 的资源来提供推理服务。同时在处理请求的时候,使用了 Ray Core 的 async 能力,让其可以支持异步方式处理请求。第二个阶段:在__init__过程中,首先会从向量数据库中加载向量数据,这里使用了支持 pgvector 的 postgresql 数据库作为向量数据库;其次会设置用于对问题进行向量化处理的 embeddings 的模型,这里使用的是 “text2vec-large-chinese” 模型;然后指定 LLM,这里使用的是 “chatglm2-6b-int4” 模型;最后,使用 LangChain 定义 chain 对象,将 LLM,Prompt 等关联起来。至此,Serve 的初始化环节就结束了。第三个阶段:在接收提问的过程中,首先会使用问题进行向量化处理后,再使用向量的相似度查询去获取问题相关的上下文,使用问题以及问题相关的上下文结合 PromptTemplate 完成 LLM 的输入内容的封装,最后去传递给 LLM 去做最后的问题的回答,得到 LLM 的回答。第四个阶段:最后使用 deployment = QADeployment.bind()的方法定义 Ray Serve 应用,然后通过 serve run serve:deployment 的方式启动 serve 应用,对外提供推理服务。第五个阶段:server 应用在本地启动的默认的监听的 port 是 8000。接下来就可以去 call 这个地址去完成问答了。07 离线模型
在企业内部建议下载离线的模型,使用本地的方式加载模型,因为一般模型都很大,在运行的时候在线下载模型不是很稳定,耗时也很久。所以建议下载到本地。可以到https://huggingface.co/上去 search 到自己需要的模型,然后下载所有的相关文件到本地就可以。在构建 Dockerfile 的时候,将这些文件 COPY 到指定的容器的文件夹下,然后程序在加载 model 的时候,用包含模型文件的文件夹即可,包括 Embeddings 和 LLM 模型等。
下载 text2vec-large-chinese 模型:
下载 chatglm2-6b-int4 模型:
08 镜像准备
向量构建相关:
CPU 类型的镜像,用于启动 Ray Cluster 的 Head 节点。
GPU 类型的镜像,用于启动 Ray Cluster 的 Worker 节点。
问答系统相关:
CPU 类型的镜像,用于启动 Ray Cluster 的 Head 节点。
GPU 类型的镜像,用于启动 Ray Cluster 的 Worker 节点。
09 实践--向量构建
构建向量索引(1 张 GPU):这里实用 kuberay 项目的 RayJob CRD 来完成向量的构建,它会负责创建一个 Ray Cluster,同时在 Ray Cluster 启动成功之后,将 configmap 中挂载的 Job 提交给 Ray Cluster,当 Job 中的所有任务运行结束之后,向量构建就算完成了。同时支持多个 GPU 并行文件的向量化处理, 这里 db_shards=1 ,这里是为了对比单卡和多卡的区别,使用了一张 GPU 设备,所以设置成了 1,这样运行下的并行的增效并不明显。可以根据本地的可用的 GPU 设备来调整并行的 tasks 数量,这样就可以完全并行起来了。head group 使用 CPU 类型的镜像,worker group 使用 GPU 类型的镜像。
查看 Ray Cluster 中的 Ray Job 的运行情况(使用 1 张 GPU 卡):从运行的日志看的出,在一个 GPU 的情况下使用了 43s 左右的时间处理了所有的数据。
构建向量索引(2 张 GPU):这里实用 kuberay 项目的 RayJob CRD 来完成向量的构建,它会负责创建一个 Ray Cluster,同时在 Ray Cluster 启动成功之后,将 configmap 中挂载的 Job 提交给 Ray Cluster,当 Job 中的所有任务运行结束之后,向量构建就算完成了。同时支持多个 GPU 并行进行文件的向量化处理, 这里 db_shards=2,是因为这里测试的是两张 GPU 卡的Serve 能力,所以设置成了 2,这样就可以完全并行起来了。
查看 Ray Cluster 中的 Ray Job 的运行情况(使用 2 张 GPU 卡):分析运行时间:这里还是相同的数据,但是使用的时间为,一个 task 用了 15s,一个 task 用了 25s,因为这里的两张 GPU 卡型号不同,性能不同。
查看内容向量化处理之后,在向量数据库中的数据保存情况:
10 实践--问答服务
问答服务(一张 GPU 卡)。这里使用了 RayService CRD 来完成 serve 环节。其中 RayService 也是会启动一个 Ray Cluster 集群,同时根据设置的 runtimeEnv 的 working_dir 的 code 所在路径作为工作路径,基于 importPath 的设置启动 Ray Serve。启动成功之后,会对外提供一个 NodePort 类型的 Kubernetes 的 Service,通过这个 Service 可以访问部署出来的基于 Embeddings 和 LLM 的 serve 了。访问的方式就是基于 http 的方式请求就可以。head group 使用 CPU 类型的镜像,worker group 使用 GPU 类型的镜像。这里测试使用一张 GPU 卡的情况,所以 Serve 的副本数只有 1 个,在 cr 的 numReplicas 中设置为 1。
查看 Ray Cluster 的运行情况和资源使用情况:一个 head 节点,一个 GPU 的 worker 节点。
查看 Ray Cluster 中的 Ray Serve 的运行情况:这里启动了一个副本进行提供服务。
问答服务(两张 GPU 卡)。这里使用了 RayService CRD 来完成 serve 环节。其中 RayService 也是会启动一个 Ray Cluster 集群,同时根据设置的 runtimeEnv 的 working_dir 的 code 所在路径作为工作路径,基于 importPath 的设置启动 Ray Serve。启动成功之后,会对外提供一个 NodePort 类型的 Kubernetes 的 Service,通过这个 Service 可以访问部署出来的基于 Embeddings 和 LLM 的 serve 了。访问的方式就是基于 http 的方式请求。head group 使用 CPU 类型的镜像,worker group 使用 GPU 类型的镜像。这里测试使用两张 GPU 设备,并提供 Serve 的情况,所以 Serve 的副本数有 2 个,在 cr 的 numReplicas 中设置为 2。
查看 Ray Cluster 的运行情况和资源使用情况:一个 head 节点,两个 worker 节点,每个 worker 节点占用一个 GPU。
查看 Ray Cluster 中的 Ray Serve 的运行情况 : 这里启动了两个副本进行提供服务。
测试问答系统:以下脚本是打包在镜像中的,可以在容器里/home/ray/query 路径下使用 query.py 去测试,如果是外部测试的话,需要根据 RayService 派生出来的 serve 的 Kubernetes Service 对应的 NodePort 去修改 localhost:8000 这个地址就可以。
先找到 xxx-serve-svc 的 Kubernetes Service, 这里就是“qallmpg-serve-svc ” ,找到 8000 端口对应的 NodePort 端口,这里 31223 端口就是可以外部访问的模型服务的端口。因为 Ray Serve 默认启动的服务的监听的 Port 就是 8000。
vi query-external.py
提问:
1.一张 GPU 卡(性能较差的卡)
1.1 每次只问一个问题:
问题 1: karmada 包含哪些组件?
耗时:86.1 s。
问题 2: cilium service mesh 是什么?
耗时:85.9 s。
1.2. 每次同时问两个问题:
问题 1: karmada 包含哪些组件?
耗时:173.1 s。
问题 2: cilium service mesh 是什么?
耗时:147.7 s。
2. 两张 GPU 卡(一张性能较差的卡,一张性能较好的卡)
2.1. 每次只问同一个问题,但是请求被 LB 到不同的卡上的测试效果:
问题: karmada 包含哪些组件?
第一次 耗时:69.1 s。
第二次 耗时:14.5 s。
2.2. 每次同时问两个问题,每个问题被同时 LB 到不同卡上的效果:
问题 1: karmada 包含哪些组件?
耗时:85.2 s。
问题 2: cilium service mesh 是什么?
耗时:9.2 s。
11 总结
结合 Ray Core、Ray Serve、KubeRay、LangChain、Embeddings、向量数据库、LLM、Kubernetes 和 GPU 方案来构建知识库可以更大程度的充分利用资源,也可以更大程度的提升整体的灵活性和效率。
参考链接:
https://docs.ray.io/en/latest/
https://github.com/ray-project/kuberay
https://github.com/ray-project/langchain-ray
本文作者:熊中祥
现任「DaoCloud 道客」技术合伙人兼云原生技术专家
关键词:
推荐阅读
月壤形成的主要原因 月壤与土壤有什么区别
月壤形成的主要原因月壤形成过程没有生物活动参与,没有有机质,还极度缺水干燥;组成月壤的矿物粉末基本是由陨石撞击破砰形成,因此,粉末 【详细】
域名抢注是是什么意思?投资角度来看什么域名好?
域名抢注是是什么意思域名抢注是通过抢先注册的方式获得互联网删除的域名的使用权。域名是由点分隔的一串数字,用于标记一台计算机或一组计 【详细】
捷达保养费用是多少?捷达是哪个国家的品牌?
捷达保养费用是多少?全新捷达的保修期为2年或6万公里,以先到者为准,新车可享受一次免费保养,首次免费保养在5000-7500km或1年内进行。如 【详细】
天然气泄露会造成爆炸吗?天然气泄漏怎么办?
天然气泄露会造成爆炸吗?家里用的天然气如果泄露是会发生爆炸的。当空气中含有混合天然气时,在与火源接触的一系列爆炸危险中,就会发生爆 【详细】
四部门明确App收集个人信息范围 个人信息保护范围判断标准
四部门明确App收集个人信息范围近日,国家互联网信息办公室、工业和信息化部、公安部、国家市场监督管理总局联合印发《常见类型移动互联网 【详细】
相关新闻
- 今日关注:AIGC 利器 Ray 云原生探索之路-分布式构建本地知识库
- 选新赛道走自己的路我国第一条量子芯片流水线投产的意义重大
- realme GT Neo 6手机高清渲染图曝光,搭载骁龙8 Gen 2 SoC
- 环球快看点丨地精在哪个图(地精的坐骑在哪买)
- 环球微速讯:突发地震 广州等多地有震感!
- 横琴新区板块7月3日涨0.79%,广东鸿图领涨,主力资金净流入8460.68万元
- 滔搏(06110.HK):7月3日南向资金增持2.7万股
- 每日动态!上半年券商跟投科创板新股浮盈7.82亿元 “投行+投资”业务协同效应逐步凸显
- 被病娇仙子抓住的话,那么修仙生涯也就结束了吧?(5)|全球视点
- 要闻:2014款奥迪RS7 Sportback怎么样及东风英菲尼迪Q50L多少钱
- 最优化估计模型(关于最优化估计模型介绍) 世界播报
- 英国伦敦股市《金融时报》100种股票平均价格指数3日下跌 环球精选
- 每经热评|银行理财费率竞相打折 实力留客才是长久之计 天天讯息
- 每日速讯:数据驱动的人类表型组研究,带来疾病诊疗新曙光
- 深度长文·光模块产业链解读
- 山姆巨型泡面遭疯抢,代购价翻一番!“泡面桶现象”背后是什么?
- 早资道 - 华为回应AITO问界成立销服联合工作组;支付宝升级平台租赁行业治理政策
- 设计“黑科技”AR眼镜 宁波大三学生获国际红点设计大奖
- 【天天播资讯】花海新增3成就,最快4天全达成!原神3.6深罪浸礼者一图流攻略
- 天天动态:有钱花逾期两个月什么后果?几天上信用?