ARTICLE · INTELLIGENCE

战地情报 · 详情页

来自尧图项目组的一线实战观察与深度解析

AI Agent开发实战(十一)向量数据库与检索基础设施

AI Agent开发实战(十一)向量数据库与检索基础设施 引言上一篇我们讲了RAG 的检索链路:切块→向量化→检索→重排序→作答。但有一块基础设施只点到为止——向量到底存在哪、怎么存才能又快又省、数据量大了怎么办?这一篇深入检索的地基:向量数据库怎么选、元数据过滤与多租户怎么做、GraphRAG 如何用知识图谱补向量的短板,以及从 PoC 到生产之间那条被很多人低估的路——数据管道与增量更新。一、向量数据库是什么:给语义搜索一个家上一篇我们知道了 Embedding 把文本变成向量,然后用 ANN(近似最近邻)索引做毫秒级检索。向量数据库就是专门干这件事的存储引擎:存向量、建索引、做相似度搜索,并且在此之上提供持久化、并发、过滤、扩展等数据库该有的能力。它与传统数据库最大的区别:传统数据库的核心操作是精确匹配(WHERE id 42);向量数据库的核心操作是相似度排序(找和这个向量最像的 K 个)。传统数据库: SELECT * FROM docs WHERE id 42 → 精确匹配 向量数据库: SEARCH docs NEAREST TO [0.12, 0.87, ...] LIMIT 4 → 语义搜索你当然也可以在 PostgreSQL 里装个扩展就做向量搜索(pgvector),而不是引入一个全新的数据库——这正是选型的核心决策之一。二、主流向量库横评:六个选择怎么挑市面上选择很多,这里聚焦六个最常出现在 RAG 项目里的,按部署重量从轻到重排列。Chroma—— 最轻量的起步之选。Python 原生,单文件嵌入式运行(像 SQLite),pip install 就能用,零配置。适合 PoC、个人项目、本地开发。数据量上万之后性能会明显下降,没有生产级的分布式和高可用,所以它的定位就是开发和实验用,不是生产方案。Pgvector(PostgreSQL 扩展)—— 最务实的不加新组件路线。如果你已经在用 PostgreSQL,装个 pgvector 扩展就能存向量、做 ANN 搜索,不用引入新的数据库。向量和业务数据(用户、文档元信息)住在一张表里,JOIN 和事务全部复用 PG 的能力,运维团队不需要学新东西。百万级向量 合理索引完全撑得住。如果你的规模不超过千万级,pgvector 应该是默认首选——少一个组件就少一份运维成本和故障面。Redis Stack(RediSearch 模块)—— 和 pgvector 同样逻辑的已有就复用路线。Redis Stack 内置的 RediSearch 模块支持向量索引(HNSW/FLAT)、相似度搜索和元数据过滤。如果你的系统本来就跑着 Redis,不需要引入新组件就能获得向量搜索能力。最大亮点是延迟极低——向量和索引全在内存,检索是微秒到毫秒级,对实时性要求高的场景(如聊天中的即时检索)很有吸引力。代价也很直白:全内存意味着数据量受内存上限约束,百万级向量就需要可观的内存;持久化靠 RDB/AOF,不如 PG 的事务和 WAL 那么扎实。适合数据量适中、延迟敏感、且已有 Redis 基建的团队。Qdrant—— 专建向量库里的好用代表。Rust 写的,性能好;API 设计干净;元数据过滤做得很完善(下一节会讲为什么这很重要);支持单机和分布式两种模式。从 PoC 到中等规模生产都很顺滑,社区活跃。如果 pgvector 满足不了你(需要更好的过滤性能、更丰富的向量操作),Qdrant 是下一步首选。Weaviate—— 特色是内置向量化。别的库你要自己调 Embedding 模型再存向量,Weaviate 可以配置存原文时自动调模型生成向量,少一步。也内置了混合搜索(BM25 向量)和 GraphQL 查询。适合希望在数据库层就把向量化和混合搜索搞定的团队。代价是概念层多了一些,上手比 Qdrant 稍重。Milvus—— 为大规模而生。分布式架构,支持十亿级向量,存算分离,弹性扩缩。如果你的数据量到了千万甚至亿级,或者需要多集群、高并发、GPU 加速搜索,Milvus 是这个量级的主力选择。代价也很明确:部署运维复杂度最高(依赖 etcd、MinIO/S3、消息队列),中小规模用它纯属自找麻烦。一张表收口:向量库一句话定位适合规模最大优势最大短板Chroma嵌入式,零配置起步开发/实验最快上手不是生产方案PgvectorPG 扩展,不加新组件≤千万级复用现有 PG,运维零成本专项性能不如专建库Redis StackRedis 扩展,全内存极速≤百万级延迟最低,复用现有 Redis受内存限制,持久化偏弱Qdrant专建库,好用均衡百万~千万级API 干净,过滤强大规模需分布式部署Weaviate内置向量化混合搜索百万~千万级自动向量化,GraphQL概念层偏重Milvus分布式,十亿级≥千万级大规模,弹性扩缩部署运维最复杂选型口诀:已有 PG → pgvector;已有 Redis 且延迟敏感 → Redis Stack;没现成基建、中等规模 → Qdrant;数据量奔亿 → Milvus;只是实验 → Chroma。核心思路是能复用已有基建就复用,别为 RAG 引入不必要的新组件。三、元数据过滤与多租户:生产 RAG 绕不开的两件事光靠向量相似度做检索,在生产环境很快就会不够。两个最常见的需求:元数据过滤你的知识库里有产品 A 和产品 B 的文档。用户问的是产品 A 的问题,但向量相似度可能把产品 B 的相似段落也捞上来——因为向量只看语义,不看这段属于哪个产品。解法:存块的时候带上元数据(product、version、date、source 等),检索时先过滤再搜索:// 伪代码:先过滤产品,再在过滤后的范围内做向量搜索 var results vectorStore.search(queryVec, 4, Filter.eq(product, A).and(Filter.gte(date, 2025-01-01)));这就是上一节说 Qdrant元数据过滤做得好的意义——过滤性能直接影响检索速度和准确性。pgvector 的过滤靠 PG 原生的 WHERE,也能用,但大数据量下专建向量库的过滤效率通常更高。设计原则:凡是你觉得应该缩小搜索范围的维度(产品、版本、文档类型、时间范围、语言),都做成元数据字段。不要让向量相似度独自承担所有区分工作。多租户SaaS 场景下,租户 A 绝对不能搜到租户 B 的数据。实现通常有三种粒度:库级隔离:每个租户一个独立的 Collection / Index。隔离最干净、性能互不影响,但租户多了管理成本高。元数据隔离:所有租户共享一个 Collection,通过 tenant_id 元数据过滤。管理简单,但大租户会拖慢小租户,且必须在每条查询里硬加 filter(漏了就是数据泄露)。混合:大客户独立库,中小客户共享。生产里最常见。安全底线:多租户的数据隔离不能只靠应用层代码,要在数据库层或中间件层有兜底(比如 Row-Level Security),否则一个 bug 就是安全事故四、GraphRAG:用知识图谱补向量的短板向量检索有一个结构性弱点:它只看片段级的相似度,不理解实体之间的关系。举个例子:你的文档分散在十几篇里,A 篇提到张三是项目经理,B 篇提到项目经理负责审批预算,C 篇提到预算超过 10 万需要 VP 批准。如果有人问张三能审批多少预算,纯向量检索可能只命中其中一两段,拼不出完整答案——因为答案需要跨文档的推理链。GraphRAG的思路:在向量索引之外,额外构建一张知识图谱(实体 关系),检索时不仅找相似片段,还沿着图谱的关系走出相关上下文。纯向量:问题 ──▶ 找最相似的块(可能不全) GraphRAG:问题 ──▶ 识别实体张三 ├──▶ 图谱:张三 → 项目经理 → 审批预算 → 上限 10 万 └──▶ 向量:找相似块(补充细节) 两路结果合并 ──▶ LLM 综合作答什么时候该用 GraphRAG:知识分散在多个文档,回答需要跨文档串联(关联推理)。数据有天然的实体-关系结构(人物、组织、项目、产品之间的关系)。需要全局摘要型的问题(如这个项目整体进展如何),纯片段检索很难凑出全貌。什么时候不需要:问题和答案都在同一段落里能找到(大部分常见问答),纯向量Rerank 就够了。数据量小到所有内容塞进上下文也不贵——不需要检索。务实建议:GraphRAG 是锦上添花,不是 RAG 的起步标配。先把朴素 RAG 优化做好,评估完召回率仍不够时再考虑引入图谱。构建和维护知识图谱本身有不小的工程成本(实体抽取、关系对齐、图更新),别过早承担。五、检索延迟、成本与规模化的工程权衡RAG 到了生产环境,你会发现跑通和跑好之间有三座山:延迟。一次 RAG 请求的延迟 Embedding 编码 向量检索 (可选)Rerank LLM 生成。向量检索本身通常很快(毫秒级),延迟大头在 Embedding(如果是远程 API)和 LLM 生成。优化方向:用本地或批量 Embedding 减少网络开销;Rerank 只对 Top K 做,不要对全量;缓存高频问题的检索结果(语义缓存,第 20 篇展开)。成本。两个容易被忽略的成本源:一是 Embedding 调用量(每个新块和每个查询都要调一次);二是向量存储本身(维度越高、数据量越大,存储和内存越多)。降本方向:选合适维度的模型(不是越高维越好);用量化(quantization)压缩向量;冷数据归档到更便宜的存储层。规模化。当数据从几千块涨到几千万块:索引构建时间显著增长(离线建索引要提前规划);单机内存可能放不下全量索引(需要分片或换分布式方案);检索精度在极大规模下会轻微下降(ANN 的近似本质)。提前规划好分片策略和索引类型(HNSW 吃内存但快,IVF 省内存但稍慢),不要等到线上吃紧了才想。一张取舍图:延迟低 ▲ │ HNSW(内存索引) │ 在内存里放 │ 成本低 ◀─────────┼─────────▶ 精度高 │ │ IVF/PQ(压缩索引) │ 牺牲一点精度换内存 ▼ 延迟高没有完美方案,只有适合你当前阶段的权衡。起步不要过度设计,但也别等到数据暴涨才开始想分片和压缩——这两件事往往需要重建索引,代价不小。六、从 PoC 到生产:数据管道与增量更新这一节讲的是很多团队 RAG 项目最后一公里翻车的地方。PoC 阶段你可能手动导了几十篇文档就开心地问答了——但生产要面对的是:文档一直在更新。产品文档改了一版、新增了几篇工单、删了一批过期规范。如果知识库还是上线那天的快照,用户问的最新退货政策拿到的是去年的。知识新鲜度是 RAG 系统的生命线,而维护它的就是数据管道。一条典型的生产数据管道长这样:数据源 数据管道 向量库 ┌──────┐ 监听变更 ┌──────────────────┐ ┌──────┐ │ 文档库 │──(webhook/ │ 增量同步服务 │──存/更新──▶│向量库│ │ Wiki │ 定时扫描) │ 1. 新增→切块→向量化→写入 │ └──────┘ │ 工单 │─────────────▶│ 2. 修改→删旧块→重新切块写入│ │ 数据库│ │ 3. 删除→标记删除/物理删除 │ └──────┘ │ 4. 记录同步水位 │ └──────────────────┘几个关键设计:增量而非全量。每次只处理变更的文档,不是每天把全部文档重新跑一遍。靠文档的修改时间、版本号或变更事件来识别增量。全量重建只作为兜底(比如每月一次或索引损坏时)。文档→块的映射要追踪。一篇文档切成了哪些块、每块存在向量库的什么 ID,这层映射必须保留。否则文档更新时,你不知道该删哪些旧块、更新哪些——这是增量更新能跑通的前提。处理删除别偷懒。文档删了,对应的块也得从向量库里去掉,否则用户会检索到过期甚至错误的信息。很多团队的 RAG幻觉其实是旧块没清干净。同步水位与重试。数据管道会失败(网络抖动、Embedding API 限流),需要记录处理到哪了(水位),失败的能自动重试,不能丢数据。这和普通的数据同步工程是一样的——别因为是 AI 项目就忘了数据工程的基本功。监控知识新鲜度。加一个简单的监控:最新同步时间、待同步队列长度、同步失败率。知识库悄悄过期是最隐蔽的质量退化。七、踩坑记录坑一:PoC 用 Chroma 跑得很好,直接上生产。Chroma 是实验工具,不保证持久性和并发。上生产至少换到 pgvector 或 Qdrant,别抱有侥幸。坑二:不加元数据过滤,全靠向量相似度。用户问产品 A,检索到产品 B 的相似段落,答案驴唇不对马嘴。凡是能缩小范围的维度,都做成元数据过滤。坑三:Embedding 模型和检索模型不一致。建索引时用模型 A 的向量,查询时换成模型 B——两个模型的向量空间不同,检索结果会非常差。存和查必须用同一个 Embedding 模型,换模型等于重建索引。坑四:向量维度一味追高。1536 维不一定比 768 维好——维度越高,存储和检索成本越高。先用较低维度模型跑基线,真有需要再升维。坑五:数据管道手动跑。PoC 时手动导一次能接受,上线后还手动,知识库一个月不更新都没人知道。数据管道必须自动化 有监控,这是 RAG 系统的血管,堵了就完。坑六:多租户靠应用层 if 判断。在查询代码里加 if (tenantId ! ...) 过滤——漏一处就是跨租户泄露。数据隔离要在存储层有兜底机制,不能只靠应用代码。八、小结这一篇补完了 RAG 的地基:向量数据库选型(已有 PG → pgvector,中等规模 → Qdrant,奔亿 → Milvus);元数据过滤让检索不只靠语义、多租户隔离不能只靠应用代码;GraphRAG 用知识图谱补向量的不懂关系短板,但先把基础 RAG 做好再上;延迟/成本/规模三座山要提前规划索引策略;而数据管道与增量更新是 PoC 到生产的最后一公里——知识新鲜度是 RAG 的生命线。
RELATED READING

延伸阅读

更多一线实战笔记与深度复盘,助您持续精进