00:00
大家好,我是泽辉啊,今天我跟大家分享一下Doris在字节跳动啊这个AI方向上的一些探索跟实践。呃,首先是去年的时候,去年年终的时候,我们在思考一个问题,就是。呃,能不能做一款AI+data这样一站式的数据引擎,它既能做现在这种文本啊,音视频的非结构化处理啊,也能很好的做这个。传统的这种结构化处理的数据能力啊,并且方便算法工程师去开发,同时数据跟这个模型啊,可以非常方便的去打通,然后处理后的数据呢,也能啊快速的去上线去服务我们在线的这个AI应用,并且整个过程这个数据处理跟这个在线的这个。服务的负载啊,是完全可以隔离开的。
01:01
啊,有没有这样的一个产品啊,于是我们开始去做一些选型的调研,那当时市面上在开源这个产品上实际上并没有。啊,完全符合我们需求的这样的一个产品存在,那相对来讲我们看到了Doris的一些优势,啊,Doris比较完善的这个功能。呃,吸引了我们,一个是它本身数据库的能力比较完善,然后O方向的这个性能啊跟功能也都比较完善,然后产品的生态以及应用场景啊都比较成熟,社区的口碑跟活跃度也都不错啊。所以我们就考虑。基于这个。Doris去二次开发,去设计date mind的这样的一个啊,Date+AI一站式的一这么一个产品,那我们需要给Doris去补齐的能力啊,主要有以下几点啊,一个是搜索场景,就AI这种向量索引的能力。
02:02
啊,第二个是这种混合搜索的能力,因为Doris的全文索引还不支持这个。夜猫5的打分啊,如果在混合搜索的话,是会有一些这个功能上的不足。呃,第三个是说把这些非结构化的数据送去这个AI进行处理,跟AI进行一个打通。那第四个就是说在这些基础能力之上啊,去建设一些。嗯,更贴近这个AI应用层这样的一些能力的建设啊,大概上我们的,呃,初步的想法主要是这些啊,需要在do瑞上去补齐的一个能力,以及做这个性能优化的一些方向。那基于这些思路呢,我们大概呃,规划了一些功能啊,主要是这个混合搜索啊,AI函数,还有graph fg, 还有企业级的这个AI问述场景的一些实践啊,那首先讲的是这个。
03:00
混合搜索,那在这个AI场景比较典型的这种混合搜索的架构可以。看成是这张图啊,首先是基于这个文本相似性的全文匹配的这种搜索啊,比较传统,然后第二个呢,是基于这个向量的搜索啊,基于这个语义的这个相似性的一个匹配,第三个就是这种t base的啊,基于规则的这种业务特定规则去啊召回的一些内容。那一般这三路召回的信息呢,会在经过这个。啊,一定规则去排序啊,可能是业务自己训练的模型啊,然后一般的话呢,啊,可能会先进一个出牌模型,然后再进一个金牌的模型,然后去。平衡一下这个性能跟红排序的一个。啊,效果这样的一个开销啊,那基于这三个能力呢,我们希望这三种搜索能力啊,它能融合进Doris啊,也就是data mind这个产品这样一个引擎里面啊,用户只需要把数据导入进来一份啊经过处理之后呢。
04:08
他通过建一些索引,那就能上线服务了啊,所以我们给这个Doris补充了两个能力,一个是。啊,向量索引啊,向量索引,我们主要是既支持了这个。HNSW啊,IVIVIPQ两种算法啊,前者的话是效果比较好啊,但是可能大规模数据集。啊,性能还有资源开销比较大,那后者的话,在大规模的数据集上,它的这个成本会性能效果都会相对好一点。然后呢,第二个是支持了这个BMO的这个打分的这个函数啊,我们是支持了在。Tablet level去做这样的一个分数的计算。那它的这个用法,就像这底下这个circle口L这两条circle口写的这样啊,当然这两条circle口的所有内容都是可以啊自由的组合的,比如说把这两个搜索结果再union起来,再去做一个啊,这些都是没有问题的。
05:12
那整个混合搜索的这个框架,首先要解决的一个问题是因为这两个。啊,函数它的计算并不是普通的函数,它不是在计算层去直接根据这个函数的输入啊进行一个计算,它是需要在这个。索引搜索的这个过程中啊,去算出来,所以呢,整个下推的这个。这种特殊的函数的投影的下推流程呢?啊,大概是这样,就是会在执行的计划上做一定改造,把相对应的函数退换成替换成这个虚拟列。啊,虚拟列会在下推到skin算子。最终由SC算子把这个虚拟列上具体的信息带到实际做索引。跟这个。
06:07
查询block的这个存储的这个代码的这个附近。啊,在计算索引的过程中,算出这些啊距离的这个分数,算出这些BM和相似性的这些分数。然后再填充回这个block啊,通过这个虚拟列,最终并从SC算子上输出出来,然后带到这个下游的算子上啊呃,下游算子就能在。很自然的去完成整个啊,执行计划的一个执行的这样的一个过程。啊,那关于向量索引呢,我们是做了这种,也是做了这种一些设计。啊,他是可以跟这个。倒排索引去混合使用的,也就是说你的这个circle里的围绕条件啊,可以带一些这些关键词的匹配,同时在做这个。
07:00
向量的检索,那它大体上的原理是说,呃,这个倒排索引搜出的这个行号的bit map.啊,我们会传递到这个face库上啊,Face库在搜索的时候。啊,它会限制在这样的一个范围,然后最终输出这个top n的这个。行号啊,那这个行号就是相当于是一个merge后的这样一个最终的一个行号。然后这里还有一些小的优化点啊,比如说如果在第一步。倒排索引的过程中啊,过滤后的数据就已经比较少了,那这个时候我们会去跳过这个向量索引的搜索过程。因为这个时候少量的数据可能暴力计算,暴力计算这个向量的距离,再去排序。啊,它不仅这个耗时更低,而且它的这个效果也更精准啊。然后还有一个就是小数据集啊,小数据集可能就是说bucket的数量少一点,它的这个搜索性能也会提升的,这个非常明显。
08:05
这是向量索引这一块,我们大致上的一个原理跟经验。然后再说一下这个文本相似性,B5的这个打分,它在DOS上是怎么实现的。呃,首先可以看到它这个公式大概是有。三部分组成啊,一个是这个视频啊,第二个是说这个逆文档频率啊,就是这个IDF啊,第三部分就是这个啊。文档权重这一块啊,文档长度的这个权重。那首先持平,呃,持平的话。在这个公司的设计中,它主要是它的分子分母,可以看到都引入了持平这个变量,那它主要是为了做一个这个饱和度的控制。打个比方,比如说一篇文章中啊,某个关键词,比如说AI啊,他提到了100次,另一篇文章提到200次,那并不一定说这个。
09:04
另一篇文章,它的这个。他对AI的相关性就一不一定是说是前面这篇文章的两倍啊,所以说这里有个饱和度的快概念,去快速收敛这一部分的得分,然后第二个是文档的这个长度的这样的一个权重,那这这个这公司中这部分主要是为了控制他在。啊,相对相同的词令下,那更短的这个文本。更短的文本。它会被认为更相关啊,因为他在更有限的内容里更多的提及了你的这个,你需要搜索这个词啊,啊第3个就是逆文档频率,那逆文档频率主要是为了限制这些常见词的这个。得分啊。当然本身像了,呃,你我他这种常见词,可能在这个analy啊,这个切词分析的阶段,它就已经被过滤掉。
10:03
然后这个公司中,大家重点关注的就是。啊,这些大N,还有这个DF文档频率这些。统计信息,因为这些统计信息是全局相关的,这个是会影响到啊后续工程实践中的。一些难度,那它具体的问题在哪呢?因为呃,在整个DOS的设计中。我们可以简单的认为一个segment啊,比如说它就对应一个solution。那如果我们做一个segment level的这个BMO打分的话是比较简单的,那直接拿这个segment对应的solution的统计信息,也就是那些大N啊BF。对吧,我们就可以算出这个赛格面的每一行,它的一个得分。但这里有个问题,就是segment。它是会发生合并的。也就是说在用户没有新增导入数据的情况下,有可能出现一种情况啊,两个小的segment合成一个大的之后,那这个大的segment它的统计信息,也就是他的这个大N跟这个DNF是有变化的。
11:11
那这个数字的变化就会导致他打分的变化。所以在用户的视角会比较奇怪啊啊,他可能没有新增数据,但是呢,莫名其妙,分数可能就有一个很大幅度的变化。那这这个是在生产上是不太能接受的一个设计啊,所以我们想办法把这个公式啊,设计在了tablet level啊。也就是说我们的所有统计信息用到这些大N跟这个DF,它必须是在整个。的这个级别去做一个啊聚合统计,那以这个magic right这条链路为例,那我们右边也画了一张图啊,它大概的过程是这样,首先在这个SC算子。最开始的这个初始化阶段。
12:02
我们会进行一个提前的搜索,因为正常的DOS的读的流程,它是每个segment轮流去。啊拉数据整整体是一个流失的往外突block的一这样的一个过程。那当你处理某个segment的时候。呃,这个时候如果你没有全集的信息,你是算不出这个tablet level的。分数的啊,所以说在处理每个segment之前,我们就已经要把。已经要把这个。啊,Tablet level这样的一个统计信息给算出来,所以在算子初始化阶段,我们会进行一个提前搜索,相当于每个segment的这些solution啊,我们会用对应的搜索条件去访问一遍。当然访问完之后,这个对应的这个搜索过程中产生的一些。这个啊,文件的打开,或者一些数据啊,在c solution中捞到了这个内存,一些seek的一些操作啊,这些产生的一些结果,也就可以认为是一个搜索的上下文,或者说搜索的一些对象。
13:10
啊,我们都会缓存下来,那以便就是说实际真的开始。啊,搜索拉数据的时候,这一部分不会产生重复的这个IO的开销啊。等到真正进入到这个具体的某个,呃,索引啊,就某个inverted index的时候啊,他在这个。搜索的这个索引的过程中,会根据。啊,之前已经收集好的这个。呃,Tablet level的统计信息,去计算这个命中的每一行的这个分数。然后最终再通过这个一个虚拟列的这个啊迭代器,相当于作为一个桥接的数据结构,把索引啊,索引搜索过程中计算的这个分数再带回到segment,最终通过这个。
14:03
然后输出出来啊。大致上的流程啊,是这样的一个形式。然后说完了这个混合搜索,然后我们再讲一下这个。Airi function airi function我们主要是支持了两种啊,一种是这个a query a query就是调用大模型的这样的一个函数啊。它会比较好的处理这种非结构化的文本之类的数据。把他们转化成结构化的数据之后,再做这种传统的这个分析需求啊,比如说你有一张。这个客户评价表,那么你可以让这个大模型对表中的每一条客户评价进行一个打分啊,进行一个分类啊,比如说这个好评输出1,差评输出0,那你通过统计之后,你就能知道大致上啊有多少好评,有多少差评。
15:00
然后第二个是这个taxi inding函数,呃,Taxi in bedding函数,我们。主要用在两个场景。一个是本身数据这个。在AI这个清洗的过程中,它去生成。啊,对应的向量,然后再构建向量索引啊。第二个是说数据查询阶段,查询阶段呃,用户有两种选择,一种是说他自己在自己的应用层的代码里去生成这个查询的向量,然后。把这个向量作为一个参数传到这个circle口中去进行搜索,第二个是直接调这个text inding函数啊,把它的query传进来进行搜索,那这两种方式主要的区别,一个是啊,使用text in bedding会更方便。第二个是。它的性能也会更好一些,因为传一个比较长的这个向量的,呃,Float速度进来,那优化器整体的解析开销会更高,它的整体的这个吞吐的上限也会更低。
16:03
啊,这个大概是这两个函数的一些。啊用力啊,写在这个右边的这个代码里。那除了这两个标准的函数,我们也做了这个Python的udf啊,Python udf主要是为了满足用户自己部署的模型啊,这些re rank模型,Inbing模型啊,甚至是这种大模型。啊,他们的访问的这个需求,以及他本身有一些。呃,非结构化数据处理的一些,呃,用Python的一些库去做处理的一些需求。那。可以看右边这个代码的例子啊。右边这个例子我们,嗯。混合搜索了一个是向量,还有一个是全文,那么这两个结果呢,再通过用户自眼的这个。Python udf的这样的一个打分的一个从排序的一个模型啊进行排序,最终输出结果可以看到还不摄取加这个AI函数,再加上Python这个udf。
17:12
基本上你只需要啊,用一条比较简单的circle口就能把整个。呃,业务的搜索流程,以及他数据处理的这个流程啊,全部串起来,那么它在使用上。啊,还是非常方便的。那Python udf, 我们的核心设计主要有几个点啊?一个是说啊多进程,多进程主要为了解决几个问题,一个是不同udf之间的隔离的问题。啊,第二个是避免Python的这个GL锁的问题啊。然后同时我们的每个Python udf也做了这个依赖的隔离啊,利用Python的这个VMV的这个机制去做了一些隔离。然后啊,我们设计上整个。
18:01
这个。执行Python的这个进程啊,子进程是跟这个do瑞pipeline task的生命周期去绑定的,也就是说当一个pipeline生成的时候,那也会有对应的一个。呃,紫禁城生成,然后它结束的时候也会有相应的这个清理的动作。这样的好处是整个并发模型是跟啊DOS的这个计算引擎绑定的,你只需要正常调整Doris的这些并发参数啊,就能调整这个Python udf执行的这样的一个并发。然后并且呢,我们没没有维护这个长度的这样的一个。外部的额外部署的这样的一个进程,那它整体的维护啊也会更简单。然后主进程跟子进程之间的这个数据传输啊,是通过这个管道。然后序列化的话呢,因为我们这个版本啊,支持的是Python原生的这个。
19:04
对象的输入输出来编程啊,所以是用的这个Python,这个master去做这个序列化啊。啊,这个是Python的一些设计上的一些东西。然后像hi设取跟这个AI函数的结合使用呢,我们在内部也是啊,落地了一些比较典型的场景啊,比如说简历啊,简历也是一个比较常见的这种非结构化的这种啊信息对吧,那我们会对简历调这个AI函数去做这个达标以及生成摘要啊,对摘要也会调这个embedding这个函数去生成向量,在构建索引去检索啊,基于标签以及基于这个。Summary的这个销量检索啊,还有像better rag这种啊,比较标准的做rag的平台啊,也是基于我们这个。
20:02
Date mind的引擎,一站式的去构建,然后还有一些像内容治理,内容治理方向上的啊,应用场景啊,基于这个大模型,对这些内容做一些打标,然后再基于这个。向量去召回一些历史达标的一些case,做一些综合性的一些这个判断啊。然后说完了混合搜索跟AI函数,呃,接下来讲一下graph。呃,首先是我们为什么要做graph fg啊,因为我们在实际推广这些AI功能的时候,我们发现一个问题就是。大部分有这个AI诉求。或者说有AI想法的这个业务团队。他们本身。呃,离这个数据数据库啊,这些还是比较远,就可能没有那么熟这些啊,大数据啊,数据库产品的使用啊,但是实际上需求是来源于这些。
21:08
实际做业务应用层的这些啊,研发同学。然后再加上,嗯。他们如果想去自己做一些落地啊,可能这个周期会有点长啊,所以我们就在想像这些能不能做一些更更贴近应用层的一些呃东西出来。然后避免用户去基于比较基础的这些啊,混合搜索啊,AI方可选这些比较基础的这个AI功能,去从从0~1去搭建这样的一个一些场景啊,所以我们当时就。啊,做了graph fg这个事情啊,因为graph fg相对实现会更复杂一些,它不像奶1fg可能比较好啊,建一个表,建个向量索引可能就搭出来,那graph fg啊,它要基于这些基本的AI功能去构建,相对过程比较复杂,然后当时的呃,微软开源之后,它的这个漏度也比较高,也有很多啊用户想在上面去试效果啊,所以啊,我们就做了这样的一个事情。
22:16
啊,先说一下graph fg的整体的一个流程啊,分为构建跟查询,呃,首先是构建,构建的话,它的输入是文档,或者是文档切成了这个。那首先会用大模型,也就是。呃,AI函数去做一个实体抽取,就从文档中抽出,可以理解为是知识点或者说关键信息啊,就是在这个graph fg的术语里面,叫做实体,然后实体呢。实体跟实实体之间是有这个关系的,这个关系可以认为就是图中的边,那这个边也是有一定权重的啊,那这些权重也都是大模型自己识别出来的。然后呢啊,这些实体以及实体的描述都会经过这个向量化之后啊,存下来去构建这个索引啊,包括这个图也会用这个一张表去。
23:10
存下来啊,包括这些边啊,这边的描述都会存下来。然后呢,同时会在基于这个图去做一个啊聚类啊,相当于是用这个。来等这个社区发现算法会去做一个社区的识别啊,相当于是把不同的实体可能归类在一个社区里,他们可能是有一些相似的东西啊,然后会再去生成这个社区报告,通过大模型。然后检索的过程呢,啊,我们首先会。这个把这个query变成向量,然后这个向量去搜什么呢?搜的是这个实体的向量啊,相当于是搜出top k相关的这个实体。得到top k相关的实体之后呢,这些实体又会继续去这个召回他们相关的这些。
24:04
边啊,他们关联着的边,因为边上有。跟这些实体再关联的这个实体的一些关系上的一些描述,以及一些信息,然后以及这些实体的这个关联的这个社区报告啊,以及这些实体关联的原始的这个文档的创。然后呢,在这个有限的上下文内啊,会按一定优先级啊去拼接这些内容。凭借这些内容之后,会形成一个呃,最终输送给AI的这个上下文,然后再去生成答案,大致的这个流程基本上是这样。那我们在这个Doris上啊,也就是我们mind这款产品上,我们怎么建设这个。嗯,Graph fg呢,我们分为几层啊,最底层是这个表的设计啊,比如说这个实体的表。这些社区的表啊,还有一些客户制定的这个原数据啊,这些七七八八的信息。
25:05
啊,这些表呢,上面会跑这个。AI函数还包括我们写的这个切分文档的这个函数啊,以及这个lighten这个。聚类的这个聚合函数啊,那这些函数再加上这个。E tr的circle啊,跟credit circle啊。综合的去实现这个graph的构建跟查询的流程。当然这些搜狗比较复杂啊,所以在这些搜狗之上呢,我们又分装了购物Python以及Java这样的SDK啊,去方便用户使用啊,用户只需要可能调进啊,调用一个比如说build的接口啊,或者说import的接口,就可以把数据导进来构建,嗯,再调一个快递接口啊,就能去检索数据。然后方便这个应用层的同学去啊,快速的接入这样的一些。
26:00
呃,比较啊,新的这样的一些AI的一些能力啊,他只需要购买这样的一个啊,Do瑞这样的一个数据库啊,再用上我们的SDK,那他就能立马把它的这个业务跑起来去验证效果。啊,那古FG上线之后,我们也是跟很多客户合作啊,落地了一些效果,比如说这个广告场景啊,还有这个代码搜索的这个场景啊,以及最近比较流行的这种。呃,PRD啊,生成扣的这种研发提效的场景也是做了一些,呃,落地。然后最后来讲讲这个。AI问述啊,AI问述也是比较这个。嗯。比较这个经典或者说比较呃流行的,在这个大家在尝试的一个方向就是啊n to circle对吧,然后直接去查这个。
27:03
啊,像Doris这样的一些数据库。那。我们之所以叫企业级呢,是因为我们在字节的这个内部的啊,集团信息系统去落地的时候呢,也遇到了一些问题啊,有一些这个各方面的一些考虑啊,所以也跟大家分享一下这里面的一些困难。啊,首先现代的一个企业的收藏架构,可以基本上认为是以这个数据湖为中心啊,外部的这种业务的系统啊,企业内部的这些信息系统啊,像RDS啊,或者是通过API。啊取数,然后再通过这个。这个DTS类似的产品,它可能最终沉淀在这个云存储上啊,以数据湖的格式,或者是像这种比较传统的have的这种,原生的这个qui的这种格式啊,然后再经过一些Spark或者弗Li克的ETL的倾斜啊,这种比较标准的这种。啊,拉姆达架构那产生了一些最终可以被应用成消费的数据,啊,这类数据通常会在加速到这个ola引擎内,比如说do瑞斯这种产品。
28:10
啊,最终去服务这个在线的这些应用啊,实时的报表啊之类的这些产品。那如果AI要来消费对吧,想做一个,呃,比如说类似企业的这种。类似智能体对吧,企业的大脑,那它需要消费企业所有信息系统的数据,那这些数据大部分是沉淀在这个。啊,数据湖上的,那直接来消费所要面临的就是啊延迟之类的问题,当然还有一些安全上的问题,那理想的一个架构。是这样的,就是说。嗯,我们用Doris,也就是data mind去加速这个数据湖上的数据啊,可以把数据同步到这个Doris内去进行加速。然后呢,那应用层,应用层一般它会通过啊一个data agent data agent, 它可能会调这个图circle口这样的外部的tool。
29:08
啊,它内部可能是用这个plan或者react这样的模型去这个啊,规划它的这个执行路径,然后以及它执行过程中啊,他规划过程中需要这种原数据。还有业务自己定义的这个语音模型。啊,语音模型可以简单理解为是对表的字段的描述,以及像一些字段的条件的使用啊,比如说这个filter是什么含义啊的一些增强的一些信息,那基于这些信息data最终能生成啊去取数的这样的一个circle。然后这个circle口直接发给这个啊do去加速执行,然后最终能把这个数据取回到这个AI问数这样的一个应用层,这是一个比较理想的架构,但这个架构要面临的几个问题,一个是。
30:02
数据库上的数据很多,你并不可能啊,全部都同步到这个DOS内啊,一个是量的问题,第二个是一些数据比较敏感啊,可能也。不可能直接给你这么就全部弄进去。啊,第2个问题是啊,你数据加速到。Mind内啊。在do瑞s do瑞斯的它的这个内表跟外表会有一些区别,如果说你你不加速的情况下呢,虽然它的这个延迟大概可能啊,数据量不大的话,也是秒级别的去访问外表啊,加速可能会到这个样,秒级别就是可能一两百毫秒。但这个加速跟不加速会产生一个区别,就是它的circle的这个catalog写写法上是有一个变化的,因为那个外表的catalog,比如说叫have,那内表它是叫internal,这个对AI的生成是否是有一定影响的?相当于AI在。
31:01
去生成circle,去查这个Doris的时候,他得感知这个数据有没有被加速过。这个就会对AI产生一定不必要的干扰,生存上会有一些麻烦啊,理论上他是不应该感知的,就是在他看来,他去查一个数据啊,这个数据如果。不是很热对吧,那到时就自动调外表的能力去直接去查这个HDSS上的数据。啊,如果说这个数据很了,那当瑞S本身可能自动已经加速进来,那直接就查得出列表,那这个过程理论上是要对上层进行一个啊屏蔽的啊,所以基于这些实际场景中我们遇到的。一些问题。啊,我们做了一些改进啊,做了一些改进啊。第一个是说,呃。Did agent来查这个Doris的时候。
32:01
他的搜口只需要写库,表明他不需要关心这张表,现在是在数据库上,还是说他已经加速了一份到这个do内。啊,这个他不需要关心,我们会自动在优化期阶段去给他做一个判断,做一个路由,把完整的这个。表明给补齐啊,对于data agent来来讲,它的使用体面,使用体验是透明的,它只需要理解这个数据弧上的这个数据的这个S码。然后通过这个DOS去加速查询就可以了。啊,第二个是权限啊,权限在。我们打通了这个字节的这个数据库的一个权限系统,因为字节大部分包括大部分企业本身数据库上。嗯,它是有一套权限系统去管控这个数据上权限的这个读写这些访问的。那如果你把数据加速一份到Doris内,也就相当于拷贝一份出来,那这份数据其实是失去了它原先的这个安全管控的这个范范围。
33:07
啊,所以我们做了一个事情,就是这张表同步到到20内之后呢,这张表的权限。他仍然是要受这个,呃。字节的这个传,这个数据库的权限系统来管控。是跟Doris本身的这个账号密码,以及do瑞斯本身的这个权限系统是无关的。那这样的好处是,呃,应用层他以前在数据库上他申请过这些权限,他加速之后,他不需要做额外的。啊,权限申请动作对他来讲会更方便啊,权限这个事情是透明的,第二个是并不会因为数据被同步到Doris内啊,那持有Doris账号密码的DBA这些同学,他就能看到这些数据,他本身没有申请过权限。他没有在这个数据库上申请过去权限他是看不到的啊,这个安全性上也是做了一个保证。
34:04
然后核心的设计大概是这样来保证啊,Doris能作为这个。这种企业级的AI问述的场景,它的一个,呃,作为一个安全的这样的一个数据加速访问的这么一个角色的存在。嗯,然后今天啊,我要分享的差不多就这么多,主要是三个模块啊,一个是啊混合搜索跟AI函数,第二个是graph啊,第三个是这个企业级的这个AI问述的一些实践啊。大家如果有什么问题,也欢迎后续线下在社区里面进行交流啊,谢谢。
我来说两句