很多人第一次搭 RAG,会卡在同一个地方:文档切好了、嵌入模型也调通了,但不知道向量库这层到底该存哪些字段、检索时又是被谁按什么顺序调用的。结果要么把向量库当成全文搜索引擎用,要么把所有元数据一股脑塞进去,后面过滤和更新都别扭。这篇按「存什么—怎么检索—怎么接进链路」三段讲清楚,并给出对比表和排查顺序。
检索时它是怎么被调用的
很多人一上手就想改模型参数,其实检索链路是一根绳上的几节,哪节松了都拉不动。用户问题进来,先由嵌入模型转成查询向量,再交给向量库做近邻搜索,中间可以按元数据过滤,取回若干候选片段,必要时过一层重排,最后拼进提示词交给模型。顺序不乱,问题才好定位。
| 环节 | 干什么 | 常见坑 |
|---|---|---|
| 查询向量化 | 用嵌入模型把用户问题转成向量 | 和入库用的不是同一个模型 |
| 近邻搜索 | 向量库找最相似的若干条 | 候选数给太少,重排没素材 |
| 元数据过滤 | 按来源、时间、类型等缩小范围 | 条件写太死,召回直接为空 |
| 重排 | 对候选再过一层相关性排序 | 没候选可排,等于白搭 |
| 拼提示词 | 把片段塞进上下文交给模型 | 塞太满,反而挤掉有效信息 |
最容易被忽略的硬约束是:查询和入库必须用同一个嵌入模型、同一套归一化方式。换模型通常意味着整库重算,不能只在调用端换个名字就完事,否则两边的向量压根不在一个空间里,搜索出来的东西看着像在排序,其实没有可比性。什么情况下这条约束可以放松?只有当你明确知道两边模型语义空间基本对齐,并且做过小样本验证——否则别赌。
三个旋钮互相牵制
- 过滤条件:写太死会召回为空,尤其多条件叠加时;先放宽,确认有结果再加约束。
- 候选数量:取太少,重排无从下手;取太多,拖慢链路还引入噪声。
- 相似度阈值:动它之前先把前两个稳住,不然你分不清是阈值卡掉了,还是本来就没写进去。
所以调参有个顺序:先放宽过滤,确认能召回;再调候选数,给重排留出足够的素材;最后才动相似度阈值。反过来做,基本是在黑暗里拧螺丝,改完也不知道是哪一步起的作用。每次只动一个旋钮,记下改前改后的召回条数,才是能复现的做法。
召回为空,先别怪库
召回为空未必是库的问题。先确认写入是否成功、维度是否一致,再去怀疑查询侧。把「库连不上」和「连上了但查不到」分开看,排查路径完全不同:前者是网络或权限,后者多半是模型、维度或过滤条件的问题。这个探针思路,站内 /tools/verify 里有对应的检查项,可以照着把两类故障拆开。
- 确认写入查一下目标集合里到底有没有数据,条数是否为 0;为 0 就别查查询侧了。
- 核对维度对比写入向量和查询向量的维度是否一致,不一致通常是模型没对齐。
- 放宽过滤把元数据过滤条件先全部去掉,看是否能召回;能召回说明是过滤写太死。
- 调候选数逐步加大候选数量,观察重排后结果是否变好,找到收益拐点。
- 再动阈值前三步都稳了,最后才调相似度阈值,每次只动一点并记录召回变化。
接进链路时的工程检查项
向量库接进 RAG 链路,出问题的地方八成不在库本身,而在接口两侧的约定。下面这几项检查,建议在做完原型、准备接真实文档之前跑一遍,每一项都能在半小时内确认完,但漏掉任何一项,后面排查都得花上成倍的时间。
口径检查:三件事必须在写入端和查询端对齐
- 嵌入模型版本
- 写入时用的模型和查询时用的模型必须是同一个,换了模型就等于换了坐标系,旧向量基本废掉
- 向量维度
- 维度不一致时,多数库会直接拒绝写入或返回空结果,少数会静默截断,后者更危险
- 距离度量
- 余弦、内积、欧氏距离算出来的排序不同,建索引时选的和查询时用的要一致
这三项最常见的踩坑方式是:写入脚本用的是一套配置,线上查询服务用的是另一套,中间没人对过。表现就是「库里明明有几千条数据,检索出来却总是空或者全是无关内容」。验证方法很简单,拿一条你确定在库里的原文去查,看能否召回它自己;召不回就说明口径没对齐。各模型对应的维度和推荐度量方式,可以到 模型资料库(/models) 核对当时的记录。
更新检查:文档改了,库里怎么变
| 更新策略 | 库里的表现 | 风险 |
|---|---|---|
| 覆盖旧切片 | 同一文档只保留最新一版 | 需要能稳定定位到旧切片,删漏了就会新旧混召 |
| 软删除 | 旧切片打标记不再返回 | 过滤条件写错时,旧内容照样被召回 |
| 追加新版本 | 新旧切片共存 | 必须靠版本号或时间戳在检索后做筛选,否则答出过期内容 |
选哪种都行,关键是要显式定下来并写进文档。追加策略看起来最安全,实际最容易出问题——因为检索这一层默认不知道谁新谁旧,你得在查询里带上过滤条件。判断标准是问自己一句:如果同一条规定改了三次,用户问起时,系统有没有把握只答最新那次。
降级检查:向量库挂了会怎样
- 直接报错:用户看到失败提示,体验差但不会答错,适合对准确性要求极高的场景
- 退化为关键词检索:还能给出结果,但要接受召回质量明显下降,且要提前验证关键词通道本身可用
- 跳过检索让模型裸答:最容易出事的一种,模型会用训练时的旧知识自信地编,用户完全看不出区别
- 排队重试后仍失败:要设超时上限和重试次数,否则请求会长时间挂住
这三种策略没有默认正确答案,但必须有一个人拍板选一个,并且在日志里能看出来当时走的是哪条路。很多线上事故不是库挂了,而是库挂了之后系统悄悄换了一种回答方式,没人发现。经验做法是在检索结果里带一个来源标记,前端或者下游能据此决定要不要给用户加一句提示。
日志检查:检索这一步至少要留下什么
- 记命中的片段标识每次检索把返回的切片 ID 或文档位置写下来,出问题时能直接定位到是哪段原文被用了
- 记相似度分值分值能帮你判断是召回质量差还是排序逻辑有问题,也能用来定阈值
- 记是否被用于生成检索到了不等于用上了,要区分「召回了但被过滤」和「召回了并进了提示词」两种情况
- 按请求串联同一次问答的检索日志和生成日志用同一个请求 ID 关联,否则两边的记录对不上
缺了这几项,回答错了只能靠猜:是没检索到,还是检索到了但模型没采纳。前者要改嵌入和切分,后者要改提示词或排序,方向完全相反。日志字段的设计可以参考 指南中心(/guides) 里检索链路相关的整理。
常见问题
向量数据库和普通数据库的区别是不是就是存向量?
不只是数据类型差别。普通数据库按条件精确匹配,向量库按相似度排序返回;前者要你写清楚查什么,后者你给一个查询向量它自己算远近。所以它适合模糊语义召回,不适合替代订单、账户这类要求事务和唯一性的存储,两者在 RAG 里通常是并存关系。
RAG 必须用专门的向量数据库吗?
不一定。数据量小、并发低时,很多通用数据库或搜索组件自带的向量能力就够用,省掉一套独立运维。只有当切片量级上去、需要多路过滤加高并发查询时,专用向量库在索引类型和扩展性上的优势才明显。判断标准是量级和查询模式,不是产品名气。
检索结果不准,先查库里还是先查模型?
先查检索链路。把命中的片段和相似度分打出来看:如果正确片段根本没被召回,问题在切片或嵌入,换生成模型没用;如果召回了但排在后面,才轮到重排或候选数量的事。生成阶段只能用好或坏的材料,它不负责找材料。