☰
千亿级AI知识库实战:腾讯云ES混合检索与RAG链路优化
2026/9/30 5:32:06 网站建设 项目流程

1. 千亿级AI知识库到底难在哪

第一次听到"千亿级AI知识库"这个量级的时候,我脑子里第一反应不是兴奋,而是"这得烧多少钱"。后来真正参与到类似规模的项目里才发现,钱只是一方面,更麻烦的是数据规模、检索延迟、召回质量这三者之间的三角博弈。ima这个产品做的是AI知识库,底层依托腾讯云ES(Elasticsearch)来承载千亿级的向量和文本混合检索,这个架构选择本身就值得好好拆一拆。

先说清楚这个项目解决的是什么问题。传统的企业知识库,本质上就是"存文档+关键词搜索",用户搜"报销流程",它给你返回一堆包含"报销"两个字的文档,至于哪篇真正回答了问题,得你自己翻。而AI知识库要干的事情是:用户用自然语言提问,系统理解意图,从千亿级的知识片段里精准捞出最相关的那几条,喂给大模型,让大模型生成一个直接可用的答案。这中间涉及**RAG(检索增强生成)**的完整链路,而检索这一环,就是整个链路的瓶颈所在。

为什么说是瓶颈?因为大模型本身的能力再强,如果检索回来的内容是错的、不全的、或者排序不对,那生成的答案就是"一本正经地胡说八道"。行业里有个说法叫"RAG的hit rate决定了天花板",检索命中率上不去,后面所有的优化都是白搭。ima要面对的是千亿级的数据量,这意味着单靠一个向量库或者单靠关键词检索都撑不住,必须做向量检索+全文检索的混合召回,还要在毫秒级完成排序返回。

这套架构适合谁来参考?我觉着有三类人值得细看:一是正在做RAG项目、卡在检索质量上的工程师;二是负责企业知识库建设、需要做技术选型的架构师;三是对AI知识库底层原理好奇、想搞清楚"为什么我的知识库答不准"的产品经理。不管你用的是LangChain4j、Spring AI还是自己手搓的RAG框架,底层的检索逻辑是相通的。

2. 架构选型的核心逻辑拆解

2.1 为什么是腾讯云ES而不是纯向量数据库

很多人一上来就问:做AI知识库,不是应该用专门的向量数据库吗?Milvus、Qdrant、Weaviate这些不香吗?我一开始也这么想,但实际做过几个项目之后,发现事情没那么简单。

纯向量数据库的优势在于向量检索的性能和召回率调优空间大,但它有个致命短板:不支持复杂的标量过滤和全文检索。举个实际场景,用户问"2024年第三季度的销售政策里关于返点的规定",这里面既有语义检索的需求("返点规定"),又有精确过滤的需求("2024年第三季度"),还有全文匹配的需求("销售政策")。如果你只用向量库,那个时间过滤就得在应用层做,数据量一大,性能直接崩。

腾讯云ES的好处在于它是向量检索和全文检索的统一引擎。ES从7.x版本开始支持dense_vector字段类型,到8.x已经支持kNN检索,同时它本身就是一个成熟的全文搜索引擎,倒排索引、BM25打分、聚合分析这些都是看家本领。一个查询请求里,你可以同时做向量相似度匹配和关键词匹配,然后用RRF(Reciprocal Rank Fusion)或者自定义的加权策略把两路结果融合排序。这就省掉了在应用层做多路召回合并的复杂度。

还有一个很现实的原因:运维成本。单独维护一套向量数据库加一套全文搜索引擎,意味着两套集群、两套监控、两套备份策略、两套扩容逻辑。用ES统一承载,至少运维层面少一半工作量。当然,这不是说ES就是万能的,后面我会讲到它在向量检索上的一些坑。

2.2 千亿级数据的分片策略怎么定

千亿级数据量,这个规模下分片策略直接决定了集群能不能稳住。我见过太多项目一开始随便设了个默认的5个分片,数据涨到几十亿就开始各种超时。

ES的分片设计有个经验公式:单个分片的大小控制在30GB到50GB之间。假设千亿级数据,每条记录平均1KB(包含向量、原文、元数据),那就是大约10TB的原始数据。算上副本和索引开销,实际存储可能在20TB到30TB。按每个分片40GB算,大概需要500到750个主分片。这个数量听起来吓人,但分布到几十个数据节点上,每个节点承担十几个分片,是可以接受的。

但分片不是越多越好。每个分片本质上是一个Lucene索引,分片太多会导致:

  • 集群状态管理开销增大(master节点压力大)
  • 查询时需要合并的分片结果增多(协调节点压力大)
  • 每个分片的段合并(segment merge)消耗更多资源

所以实际做法是按时间或者按业务维度做索引分层。比如热数据(最近3个月)放在高配节点上,分片数多一些保证查询性能;冷数据(3个月以前)做索引合并,减少分片数,甚至用可搜索快照(searchable snapshot)降到对象存储里。ima这种知识库场景,大部分查询集中在近期文档上,冷热分离能省下大量成本。

2.3 向量维度和索引类型的选择

向量检索的核心参数就两个:维度和索引类型。

维度取决于你用的embedding模型。常见的比如OpenAI的text-embedding-3-large是3072维,BGE-large是1024维,m3e-base是768维。维度越高,语义表达能力越强,但存储和计算成本也线性增长。千亿级数据下,3072维的向量光存储就是一大笔开销。我的建议是:除非你的场景对语义精度要求极高,否则768到1024维足够用了。实测下来,1024维和3072维在大部分知识库问答场景下的召回率差异不到3个百分点,但存储成本差了3倍。

索引类型方面,ES支持两种kNN检索方式:

  • 近似kNN(ANN):基于HNSW算法,查询快,但召回率不是100%
  • 精确kNN(exact):暴力计算,召回率100%,但速度慢

千亿级数据下,精确kNN基本不可用,必须用近似kNN。HNSW的关键参数是m(每个节点的连接数)和ef_construction(构建时的候选队列大小)。m越大,索引越大,召回率越高;ef_construction越大,构建越慢,但索引质量越好。经验值是m=16到m=32,ef_construction=100到200。查询时的ef_search参数可以动态调整,牺牲延迟换召回率。

3. 混合检索与RAG链路的实操细节

3.1 向量检索和全文检索怎么融合

这是整个架构里最核心的部分。ima的做法是双路召回+融合排序,具体流程是这样的:

第一路,向量检索。用户query经过embedding模型转成向量,在ES里做kNN检索,返回top-K个语义最相似的文档片段。这一路擅长处理"意思相近但用词不同"的情况,比如用户问"怎么请假",能召回"休假申请流程"。

第二路,全文检索。用户query经过分词后,在ES里做BM25检索,返回top-K个关键词匹配度最高的文档片段。这一路擅长处理"精确术语"和"专有名词",比如用户问"P0级故障处理流程",向量检索可能召回一堆"故障处理"的文档,但全文检索能精准命中"P0"这个关键词。

两路各返回比如50条结果,然后用RRF算法融合。RRF的公式很简单:score = sum(1 / (k + rank)),其中k是一个常数(通常取60),rank是文档在每一路结果里的排名。这个算法的好处是不需要归一化不同路的分数,直接基于排名融合,工程上很好实现。

但RRF也不是万能的。如果两路召回的质量差异很大,比如向量检索明显更准,那RRF会把两路平等对待,反而拉低了整体效果。这时候可以给两路加权重,比如向量路权重0.7,全文路权重0.3。权重的调参没有理论最优解,只能靠A/B测试和人工评估。

3.2 Chunk策略决定了检索的上限

很多人把精力全花在检索算法上,却忽略了**文档切分(chunking)**这个前置环节。我可以负责任地说:chunk策略没做好,后面怎么调都是白费。

千亿级知识库的文档来源五花八门:PDF、Word、网页、数据库记录、聊天记录。不同来源的文档结构差异巨大,用一套固定的chunk大小(比如512个token)去切所有文档,效果一定好不了。

我的实操经验是分层chunk:

  • 第一层,按文档的自然结构切分。比如Markdown按标题层级切,PDF按段落切,表格单独处理。
  • 第二层,对过长的段落做滑动窗口切分,窗口大小512 token,重叠128 token。重叠是为了避免关键信息被切断。
  • 第三层,对每个chunk生成一个摘要向量和一个原文向量。摘要向量用于粗筛,原文向量用于精排。

为什么要生成摘要向量?因为有些chunk很长,直接embedding会丢失细节。先用摘要做粗筛,把候选范围从千亿级降到百万级,再用原文向量精排,这样兼顾了速度和精度。

还有一个细节:chunk的元数据要保留完整。每个chunk必须带上来源文档ID、章节路径、创建时间、权限标签。权限标签尤其重要,企业知识库里不同部门的文档访问权限不同,检索时必须做权限过滤,否则会出现"员工搜到了不该看的文档"这种严重问题。

3.3 写入性能优化:怎么判断是磁盘瓶颈还是其他问题

千亿级数据不是一次性灌进去的,而是持续增量写入。写入性能直接决定了知识库的时效性。ES写入慢的原因有很多,我整理了一个排查思路:

现象可能原因排查方法解决方向
写入延迟高但CPU不高磁盘IO瓶颈看iostat的%util和await换SSD或增加节点
写入延迟高且CPU高段合并频繁看thread_pool的merge队列调大refresh_interval
写入延迟周期性飙升GC压力看JVM的GC日志调大堆内存或换G1
写入吞吐上不去分片数不足看每个分片的写入速率增加主分片数
批量写入超时bulk队列满看thread_pool的write队列减小bulk批次或增加节点

判断磁盘是否是瓶颈,最直接的指标是iostat的%util。如果%util持续超过80%,同时await(平均等待时间)超过20ms,那基本可以确定是磁盘扛不住了。这时候要么换NVMe SSD,要么增加数据节点分摊压力。

另一个容易被忽略的指标是ES的refresh_interval。默认是1秒,意味着每秒都会生成一个新的segment,写入量大时会产生大量小segment,段合并压力巨大。对于知识库这种场景,实时性要求没那么高,把refresh_interval调到30秒甚至60秒,写入吞吐能提升好几倍。

3.4 RAG链路中检索结果怎么喂给大模型

检索回来top-N个chunk之后,不能直接一股脑塞给大模型。这里有几个坑:

第一,上下文长度限制。大模型的context window是有限的,比如32K token。如果每个chunk 512 token,那最多塞60个chunk。但实际不能塞满,因为还要留空间给系统prompt和用户query。一般控制在top-10到top-20之间。

第二,chunk排序。检索返回的结果是按相关性排序的,但喂给大模型时,最相关的应该放在最前面还是最后面?实测下来,放在最前面和最后面效果最好,中间的位置容易被大模型忽略。这叫"lost in the middle"现象。所以可以做一个重排,把最相关的几条放在开头和结尾。

第三,去重和压缩。检索回来的chunk之间可能有大量重复内容,直接喂给大模型会浪费context window。可以做一层去重,或者用一个小模型对chunk做压缩,只保留和query最相关的句子。

第四,引用标注。生成答案时,要让大模型标注每个结论来自哪个chunk,这样用户能溯源。实现方式是在prompt里给每个chunk编号,要求大模型在生成时带上编号引用。

4. 常见问题与排查技巧实录

4.1 检索命中率上不去怎么办

这是被问得最多的问题。检索命中率低,原因可能出在链路的任何一个环节。我的排查顺序是:

先看query本身。用户的query是不是太短?比如只输入"报销"两个字,这种query的语义信息太少,embedding出来的向量区分度很低。解决办法是做query改写,用大模型把短query扩展成完整的问句,再做检索。

再看embedding模型。你用的embedding模型是不是适合中文?是不是适合你的领域?通用embedding模型在专业领域(比如医疗、法律)的表现可能很差。解决办法是用领域数据做微调,或者换一个在该领域表现更好的模型。

然后看chunk质量。随机抽几个检索失败的case,看看对应的chunk内容是不是完整、是不是包含了答案。如果chunk本身就不包含答案,那检索算法再牛也没用。

最后看融合策略。向量检索和全文检索的权重是不是合理?RRF的k值是不是合适?这些参数需要根据实际数据调优。

4.2 向量检索的召回率怎么评估

很多人不知道怎么评估向量检索的效果。我的做法是构建一个评测集:人工标注100到200个query,每个query标注哪些文档是相关的。然后计算Recall@K和MRR(Mean Reciprocal Rank)。

Recall@K衡量的是top-K结果里包含多少相关文档,MRR衡量的是第一个相关文档出现的位置。这两个指标结合起来,能比较全面地反映检索质量。

评测集的建设是个体力活,但非常值得。没有评测集,所有的优化都是盲调。我见过团队花了几个月调参数,结果因为没有评测集,根本不知道有没有变好。

4.3 集群稳定性怎么保障

千亿级集群,稳定性是生命线。几个关键措施:

监控要全。除了ES自带的监控指标,还要监控JVM的GC、磁盘IO、网络延迟。特别是GC,长时间的Full GC会导致节点短暂失联,触发分片重新分配,引发雪崩。

熔断要配。ES有circuit breaker机制,当内存使用超过阈值时会拒绝请求。这个阈值要合理设置,太小会导致正常请求被拒,太大会导致OOM。

降级要有。当向量检索超时或者不可用时,能不能自动降级到纯全文检索?这个降级逻辑要在应用层实现,保证核心功能可用。

压测要定期做。不要等到大促或者流量高峰才发现集群扛不住。定期做全链路压测,找到瓶颈点。

4.4 成本怎么控制

千亿级数据,成本是个绕不开的话题。几个省钱的方向:

冷热分离。前面提过,冷数据用可搜索快照降到对象存储,成本能降70%以上。

向量维度压缩。用PCA或者量化技术把向量维度从1024降到256,存储成本降75%,召回率损失控制在5%以内。

副本数调整。不是所有索引都需要多副本。冷数据索引可以设0副本,靠快照恢复。

实例类型选择。计算密集型的节点用高主频CPU,存储密集型的节点用大容量SSD,不要一刀切。

5. 一些踩过的坑和实操心得

5.1 关于ES版本选择

ES 8.x对向量检索的支持比7.x好很多,特别是kNN的性能优化。如果新项目,直接上8.x。但要注意8.x默认开启了安全认证,配置起来比7.x麻烦一些。另外,8.x的Java API Client和7.x的RestHighLevelClient差异很大,迁移成本不低。

5.2 关于embedding模型的部署

embedding模型推理是CPU密集型的,千亿级数据下,如果每次查询都实时推理,延迟会很高。我的做法是query embedding实时做,doc embedding离线做。离线做的时候可以用GPU批量推理,速度快很多。另外,embedding模型最好和ES集群部署在同一个内网,减少网络延迟。

5.3 关于权限过滤的性能

权限过滤是在检索时做的,如果权限规则很复杂,会严重影响检索性能。优化方式是把权限规则预处理成位图(bitmap),检索时用位运算做过滤,比逐条判断快几个数量级。

5.4 关于RAG的评估

RAG系统的评估不能只看检索指标,还要看最终生成的答案质量。我一般用两个维度:忠实度(faithfulness)和相关性(relevance)。忠实度衡量答案是不是基于检索到的内容生成的,有没有胡编;相关性衡量答案是不是回答了用户的问题。这两个维度可以用大模型做自动评估,也可以人工抽检。

5.5 关于Agentic RAG的演进

传统的RAG是"一次检索+一次生成",但复杂问题往往需要多轮检索。Agentic RAG的思路是让大模型自己决定什么时候检索、检索什么、要不要追问。这对检索层提出了更高要求:不仅要快,还要支持复杂的查询计划。ES的DSL本身就很灵活,可以支持这种多轮检索的需求,但需要在应用层做好编排。

6. 从千亿级实践中提炼的几条硬经验

做千亿级AI知识库,技术选型只是起点,真正的功夫在细节里。我总结几条我认为最重要的经验:

第一,检索质量是RAG的生命线。不要指望大模型能"化腐朽为神奇",检索回来的内容不对,大模型只会错得更离谱。把70%的精力花在检索优化上,不过分。

第二,评测集是优化的指南针。没有评测集,所有的调参都是玄学。哪怕只有100条标注数据,也比没有强。

第三,chunk策略比检索算法更重要。我见过太多团队在检索算法上死磕,却忽略了chunk切分这个上游环节。chunk切得好,简单的BM25都能有不错的效果。

第四,成本控制要从架构设计阶段就开始。冷热分离、向量压缩、副本策略,这些如果等到账单爆炸了再想,就来不及了。

第五,稳定性是1,其他都是0。千亿级集群,任何一个小故障都可能被放大。监控、熔断、降级、压测,一个都不能少。

最后分享一个我个人的小技巧:在做检索调优的时候,我会把每次查询的召回结果和最终答案都记录下来,定期做bad case分析。很多时候,问题不是出在检索算法上,而是出在数据质量上——比如某个文档的chunk切分错了,导致关键信息丢失。这种问题,只有通过持续的bad case分析才能发现。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询