RAG为什么需要向量数据库

接入与开发

讲清向量数据库在 RAG 检索里到底干什么活、什么规模可以不上它、什么情况非上不可,给初学者的判断清单。

刚开始搭 RAG 的人常卡在同一个问题上:明明用内存数组算一算余弦相似度就能检索,为什么教程都在推向量数据库?反过来也有人一上来就装 Milvus,结果数据才几千条,维护成本比业务还高。这篇不谈产品优劣,只回答一件事:向量数据库在检索环节承担的是哪部分职责,哪些可以自己写代码顶替,哪些顶不了。

刚开始搭 RAG 的人经常卡在同一个地方:明明在内存里存一个向量数组、每次全量算一遍余弦相似度就能检索,为什么教程一上来就让人装向量数据库?另一头也有人反着来,第一个 demo 就上集群版,结果文档统共几千条,维护索引的时间比写业务还多。这两种做法都不算错,问题在于没想清楚向量数据库在检索环节里到底承担哪几件事。

这篇不讨论具体产品谁好谁坏,只回答一个问题:检索这一段,哪些活可以自己写几十行代码顶替,哪些活绕不过去。看完你应该能给自己手上的项目下一个判断——现在该不该上,什么时候该换。

检索环节里,向量数据库到底替你做了哪几件事

把它当成一个专门存向量、专门找近邻的服务就好。它的价值不在「会算余弦相似度」——这个谁都会——而在于把算相似度这件事从你的应用进程里剥出去,变成一个可以独立扩容、独立重启、多服务共享的组件。

  • 把相似度计算从应用内存挪到独立服务,查询时不必把全量向量读进内存;
  • 负责近似最近邻索引的构建和增量更新,数据写进去之后不用自己维护索引结构;
  • 附带元数据过滤、分页、多条件组合查询,让「先按权限或分类筛、再按语义搜」在一个系统里完成;
  • 承载并发和持久化,进程重启数据还在,多个实例可以同时查同一份向量;
  • 把索引参数、距离度量这些细节封装掉,换索引类型不用改业务代码。

注意最后一条是双刃剑:封装得好省事,封装得太深,出了召回质量问题你反而不知道该调哪里。所以选型时要把「索引参数能不能自己调」当成一个考察点,具体哪些产品暴露了哪些参数,到 工具目录(/tools) 里对照着看。

它不负责什么:三个常见误解

初学者最容易把检索效果差直接归罪于数据库。实际上向量数据库只负责「找得回来、找得快」,找得准不准,大头在它上游。先把这个边界划清楚,排查问题才不会被带偏。

你以为它管的实际归谁管出问题时的表现
把文档变成向量嵌入模型换数据库没用,召回内容就是偏的
文档怎么切块分段策略块太碎语义不完整,块太粗噪声多
召回之后的精排重排逻辑或生成阶段的提示词召回的前几条相关性一般,答案跟着跑偏
答案准不准生成模型加上下文拼装检索结果对,模型照样答错

还有一个更隐蔽的误解:以为近邻就等于相关。向量距离近只说明语义上像,不说明这条内容能回答问题。所以召回的条数和阈值要拿真实问题去试,而不是看数据库给的相似度分数高低就下结论。

什么规模可以先不上:内存与普通数据库顶上来的边界

数据量小、更新不频繁、单进程服务,这三种情况同时成立时,自己写全量比对完全够用,还能少维护一个服务。做法很简单:启动时把向量读进内存数组,查询时和全量算一遍相似度,取前若干条。几千条的量级,这点计算量对现代机器不算什么。

如果已经有关系型数据库,也可以先用它自带的向量能力或扩展列,避免向量和原文双写两份。代价是查询灵活性差一些,但省掉了数据同步的麻烦。

  • 先算三个数并写下来:现有向量条数、每天新增量、峰值查询并发;
  • 单进程加内存能扛住全量比对,就先别引入新服务;
  • 数据已有主库的,优先试主库的向量扩展,别急着拆两套存储;
  • 但要留个心眼:全量比对的耗时随条数线性增长,压测时按预估增长量测,别只测当前数据。

判断门槛不能只看条数。查询很频繁、数据每天增量写入、或者两个以上服务要共享同一份向量,哪怕条数不多,也该考虑独立服务了。这块没有统一标准,可以对照 指南中心(/guides) 里的规模测算方法自己套一遍。

什么时候绕不开:几个必须上的信号

下面这些信号出现任意一个,继续用内存数组硬顶就会开始难受。注意是「开始难受」,不是「立刻崩」——给自己留出改造时间,别等到线上报警才动手。

信号说明先做什么
全量比对延迟影响首字时间条数涨上来后单次查询明显变慢先加缓存顶一阵,同时评估独立服务
数据高频增量写入每次写入都要重建全量索引不现实确认候选方案支持增量更新索引
多服务共享同一份知识库每个服务各存一份,更新不同步统一成一个数据源,其他服务只读
检索要带权限或时间过滤纯向量数组里实现过滤很别扭选支持元数据过滤的方案,先做小验证

还有一类情况容易被忽略:同一份知识库要同时服务测试环境和线上环境。这时候即使条数不多,也需要一个能统一管理数据版本的地方,否则两边召回结果不一致,排查问题会非常痛苦。

动手前的对照清单

不管最后上不上,下面这几步在动手前都值得做一遍。它们不依赖任何具体产品,做完你对项目的规模就有数了,后面选型也不会被人牵着走。

  1. 算清三个数向量条数、每天新增量、峰值查询并发,写成一行记在文档里;后面每次觉得慢,先回头看这三个数变了多少。
  2. 定死嵌入维度确认嵌入模型对应的维度并写进配置;维度一旦要变,是重建整个集合而不是改个字段,所以尽量先用小样本试稳。
  3. 检索和生成分开测先只测召回,拿一批真实问题看前几条对不对;召回没问题再接生成,否则分不清是哪一段出的错。
  4. 留降级路径想清楚数据库连不上时怎么办:退回小规模全量比对、读缓存结果,还是直接提示降级。这条不做,上线后一次抖动就是事故。
  5. 选型后先做压力验证用接近真实规模的数据灌一遍,测召回延迟和写入耗时;别用几百条 demo 数据下最终结论。

如果决定上独立服务,选型阶段可以用 站点导航(/sites) 里的中转站和数据库服务做对照,重点看接入方式、计费和限速,具体数字到 价格追踪(/price-watch) 核对当时的情况,这里不写死。

下一步先把自己项目的三个数算出来,再拿这份清单过一遍。如果已经决定要上,去站点导航看看各家的接入方式和当前计费口径,对照着做初步筛选。

常见问题

我只用几万条文档,直接用 Python 算余弦相似度不行吗?

行,只要单次查询延迟能接受、服务是单进程、重启可以重建。问题通常出在后面:数据涨上来、查询变多、多实例共享时,你会开始自己实现索引和持久化,那时代价已经不划算了。

向量数据库能提高回答准确率吗?

不能直接提高。它影响的是召回的速度和稳定性,准确率主要由切块策略、嵌入模型、检索参数和重排决定。数据库选错只体现在慢和不稳,不会让答案变对或变错。

不用向量数据库,用关系型数据库存向量可以吗?

可以,前提是数据量和并发在你现有数据库扛得住的范围内,并且能接受检索性能随数据增长而下降。要留意的是别把同一份数据双写到两个地方,否则更新时很容易不一致。

本文依据各平台公开文档与官方公告整理,只做中文归纳;具体做法、参数与限制以官方文档为准。