做 RAG 的人常卡在同一处:资料已经切好、embedding 也调通了,但向量库这一层不知道挑哪个、怎么接、检索出来的结果又为什么不对。这篇不堆概念,按「先定需求、再挑库、再接入、最后调检索」的顺序给一份速查大纲,每一节都落到能动手的动作上。
做 RAG 卡在向量库这一层的人特别多:资料切好了、embedding 调用也通了,但一到「挑哪个库、怎么写第一段代码、检索出来为啥不对」就停住。这篇不讲概念史,按先定需求、再挑库、再接入、最后调检索的顺序走一遍,每节都落到能动手的动作上。
先记住一个前提:向量库不是万能钥匙,它只干一件事——把向量存进去、按相似度找回来。选型选错和检索不准是两码事,前者看需求,后者八成是切分和 embedding 的问题。分清楚这两类问题,后面每一步都不会白折腾。
向量库在 RAG 里到底管哪一段
把链路拆开看就清楚了:切分 → 向量化 → 写入索引 → 查询召回 → 交给模型。向量库只负责「写入」和「召回」两段,前面的切分和 embedding 完全不归它管。很多人检索效果差就想着换库,结果换了三四个还是老样子,因为问题根本不在这一层。
- 切分
- 把长文档切成小段文本,按段落、标题或固定长度切,影响召回粒度
- 向量化
- 调 embedding 模型把文本转成向量,同一批数据必须用同一个模型
- 写入与召回
- 向量库的活,存进去、按相似度找出来,顺带带上元数据
- 重排
- 对召回结果二次排序,可选,不是向量库的必备功能
什么情况下根本不需要独立向量库:数据量小、更新很少的时候,内存里的本地索引、甚至现成框架自带的检索就能跑完。上独立服务是为了规模、并发和过滤条件,不是为了「显得专业」。什么时候不适用这套判断——如果你已经确定数据会天天增量写入、还要按字段改删,那就直接跳过本地方案,别在内存索引上浪费时间。
选型看四件事,不看宣传词
挑向量库别看谁的功能列表长,看四件事就够:落在哪、规模与更新方式、过滤与混合检索、谁来维护。第一件定下来,其余选项会立刻收窄一大半。
| 判断维度 | 要问自己的问题 | 收窄后的方向 |
|---|---|---|
| 落在哪 | 纯本地跑、用托管服务、还是接在已有数据库上 | 先定这条,其余选项直接砍掉一半 |
| 规模与更新 | 一次性灌完不动,还是每天增量写入加改删 | 增量多的优先看支持实时写入的 |
| 过滤与混合 | 要不要按字段过滤、要不要和关键词一起排序 | 要求高的提前验证这两项 |
| 谁来维护 | 团队有人愿意维护独立服务吗 | 没人维护就优先托管或数据库扩展 |
- 过滤条件是实际项目里最常踩的坑:能不能在向量召回的同时按来源、时间、章节过滤,先拿真实数据测一遍再定
- 混合检索同理:关键词排序和向量排序能不能一起用,不能的话关键词那一半就得自己在应用层补
- 什么情况下不适用上面的偏好——团队没人愿意维护独立服务、又没有运维预算时,别自建,优先看托管或已经在用的数据库扩展
- 别用「大家都用这个」当理由,用你现在这批数据的规模和更新频率去对,对不上就是不对
- 选完先跑一版最小验证:几百条数据写进去、查十条问题看召回,比读十篇评测有用
接入的最小步骤:从零到一次能用的检索
接入前先把三样东西备齐:embedding 模型的调用方式、切分好的文本块、每条块对应的元数据字段,至少要带来源、时间、章节。元数据不是可选项,没有它后面答错了你都不知道是哪段资料的问题。
- 统一 embedding 来源写入和查询必须用同一个 embedding 调用。默认用同模型同配置生成向量,别让不同批次来自不同模型,否则相似度没有可比性。验证方式:随便挑一条已写入的文本,重新编码一次,跟库里的向量算相似度,应该接近满分。
- 写入时带上元数据每条记录存三部分:向量、原始文本块、元数据字段。元数据跟着向量一起写,别存在另一个地方再关联,查询时要能直接返回。
- 查询侧编码问题用与写入完全相同的 embedding 调用去编码用户问题,传给向量库做近邻检索。返回的是文本块加元数据,不是答案,别指望库直接给你回复。
- 拼进提示词把召回结果按条数和总长度限制后拼进提示词,模型只看得到你塞进去的那几段。条数太多会稀释重点,太少又漏信息,先从召回几条看效果再定。
一个小提醒:检索接口返回的是候选,不是结论。把「召回」和「生成」当成两段独立调试的对象,出问题时才好定位到底是哪一段没做好。
检索不准时,按这个顺序调
检索不准先别动库。把用户问题和命中的文本块打出来人工看一遍,判断是「压根没搜到」还是「搜到了但模型没用」。这两种情况的修法完全不同,混在一起调只会越调越乱。
| 现象 | 先查什么 | 再调什么 |
|---|---|---|
| 没搜到相关块 | 切分粒度、召回条数 | 换 embedding 或补关键词召回 |
| 搜到了但答偏 | 提示词组织、上下文条数 | 调整拼接顺序与长度 |
| 过滤没生效 | 元数据字段有没有写进去 | 检查写入时的字段名与查询条件 |
| 结果时好时坏 | 同一批问题重复跑对比 | 看是否有不同批次向量来源不一致 |
- 先看召回本身:人工判断没搜到还是搜到没用,这是排查的第一步也是分水岭
- 没搜到就调切分和条数,再考虑换 embedding;搜到没用就调提示词和上下文组织方式,别动库
- 加不加重排看候选数量:候选多、要求精的时候才值得上,候选本来就少加了也白加
- 每条都要能溯源,返回的块必须带来源标识,不然答错了没法定位是哪段资料的问题
- 拿一组固定问题当回归集,每次改切分或换模型都跑一遍,比单次效果更有参考价值
上线前后的基本维护清单
上线不等于结束,向量库这层最容易在数据更新后悄悄退化。维护清单不用复杂,但几条关键的得定死。
- 更新机制定死:新资料怎么进、旧资料怎么删、删的时候向量和元数据要不要一起清,别只删文本留下孤儿向量
- 留一层对照:定期用一组固定问题跑一遍检索,看命中的块有没有变,用来发现切分改动或数据源变化带来的退化
- 监控召回条数和响应耗时,这两个指标掉了通常比答案变差更早出现,是更灵敏的预警
- 容量和成本按当时的量算,去站内 /stacks/vector-dbs 和 /embeddings 核对可选范围与口径,别用几年前的印象拍板
- 元数据字段一旦定下来尽量别改,改字段名要同步改查询条件和历史数据,代价比想象中大
这套清单对增量多、更新频繁的项目收益最大;如果是一次性灌完再也不动的小数据集,维护部分可以大幅简化,重点放在切分和召回质量上就够了。
向量库只负责存和找,找不准的时候,先回头看切分和 embedding,而不是急着换库。下一步选型前先去核对当时的可用方案与成本口径,再拿自己的真实数据跑一版最小检索验证,比对着宣传页纠结靠谱得多。→
常见问题
已经有普通数据库了,还需要单独上个向量库吗?
看两件事:数据量和过滤需求。数据量小、又不要求复杂条件过滤,用现成数据库的向量扩展或本地索引就够了,多养一套服务是负担。只有当写入量大、要频繁改删、或者要按字段过滤加混合排序时,独立向量库的优势才明显。先从最简单的方案跑通,再按实际瓶颈换。
检索出来的内容不相关,是向量库选错了吗?
多数不是。先按顺序排:把命中的块打印出来看是压根没召回到,还是召回了但模型没引用。没召回到,问题多半在切分粒度和 embedding 的匹配度;召回到了没用上,多半在提示词和上下文拼接方式。库本身只在规模、过滤、性能上出问题,排序质量很少是它决定的。
向量库和 embedding 模型哪个更影响效果?
embedding 的影响通常更大,因为它直接决定「语义相近」这件事算得准不准,而库负责的是把这个结果快速找出来。换库能换的是速度、容量和过滤能力,换 embedding 才可能换召回质量。所以预算和调试精力如果只够投一边,先投 embedding 和切分。