Vector Store:FAISS、Chroma、Milvus、Qdrant、ES 怎么选?
1、Vector Store 不是普通数据库
普通数据库更擅长精确匹配。你查订单号,它能准。你查用户 ID,它也能准。
但 RAG 场景不是这么问的。用户不会说“我要第 32 页第 5 段”。用户只会问:“合同里违约责任怎么写?”、“三安光电这份公告到底利好还是利空?”、“提前还款怎么操作?”
这时候系统要做的不是关键词匹配,而是语义匹配。意思相近,就应该能找回来。Vector Store 就是为这件事服务的。
把它想成一个仓库:仓库里放的不是原文,而是原文的“语义坐标”。用户问题进来,也先变成坐标,再去找最近的资料。 |
2、LangChain 对 Vector Store 做了什么封装?
LangChain 的价值,不是自己重新造一个向量数据库。它的价值是提供一套统一接口。今天你用 FAISS,明天换 Milvus,后天接 Elasticsearch,业务链路不用整体推倒重写。
官方文档里,Vector Store 的统一接口主要围绕三件事:add_documents 添加文档,delete 删除文档,similarity_search 做语义相似检索。初始化时通常要传入 Embedding 模型,因为入库和查询都离不开向量化。
所以它的抽象非常清楚:文档进来,变成向量,写入仓库;问题进来,变成向量,检索文档。 |
源码层面,核心类是 VectorStore。它是一个抽象基类。基类负责定义标准动作,真正的存储和搜索由不同子类实现。FAISS 有自己的实现,Chroma 有自己的实现,Milvus、Qdrant、Elasticsearch 也都有自己的实现。
3、add_documents() 到底做了什么?
先看入库。很多人以为 add_documents() 就是把 Document 原封不动塞进数据库。不是。
源码逻辑更像这样:先拿到 Document,再拆出 page_content、metadata、id。如果子类实现了 add_texts(),基类就会把文本和元数据转交给 add_texts()。具体怎么写入索引,由子类决定。
源码压缩成伪代码
VectorStore.add_documents(documents)
-> texts = [doc.page_content]
-> metadatas = [doc.metadata]
-> ids = [doc.id]
-> self.add_texts(texts, metadatas, ids)
子类 add_texts / add_documents
-> embedding.embed_documents(texts)
-> 写入 vector + text + metadata + id
-> 返回 ids
这条链路非常关键。因为所有向量库的差异,最后都落在“子类怎么写入”和“子类怎么搜索”。LangChain 只负责统一门面。
用 InMemoryVectorStore 看得最清楚:它内部用一个字典保存数据。每条记录里有 id、vector、text、metadata。入库时先调用 embedding.embed_documents(),再把向量和原文一起保存。
4、similarity_search() 到底怎么搜?
查询时也不是直接拿字符串去搜。第一步仍然是向量化。用户问题先被 embed_query() 转成查询向量。然后向量库拿这个查询向量去索引里找最近的文档。
在 InMemoryVectorStore 的实现里,思路很直接:把所有文档向量取出来,计算查询向量和文档向量的余弦相似度,然后按分数排序,取 TopK。生产级向量库会用更高效的索引结构,但抽象思想一样。
查询链路:query -> embed_query -> vector search -> TopK documents -> List[Document]。 |
5、as_retriever():为什么要把 Vector Store 变成 Retriever?
这是很多人容易混淆的一点。Vector Store 本身不一定是 Runnable。Retriever 才是 LangChain 链路里更标准的“可调用检索组件”。
官方语义搜索教程也强调:VectorStore 对象不继承 Runnable;Retriever 是 Runnable,所以有 invoke、batch 等标准方法。也就是说,在 RAG 链里,常见写法是先 vectorstore.as_retriever(),再 retriever.invoke(query)。
源码层面,as_retriever() 做的事情很直接:用当前 vectorstore 创建一个 VectorStoreRetriever,并把 search_type、search_kwargs 等参数带进去。
6、三种 search_type:别乱用
VectorStoreRetriever 默认支持三类搜索。它们不是装饰参数,而是三种不同的检索策略。
第一种是 similarity。最朴素,直接找最相似的 TopK。适合大部分基础 RAG。
第二种是 similarity_score_threshold。先算相关度,再按分数阈值过滤。适合不想硬凑答案的场景。没有足够相关资料,就应该少答或者不答。
第三种是 mmr。它不只看相似度,也看多样性。适合同质化文档很多的知识库。比如同一份公告被多家媒体转载,如果只用 similarity,很容易召回一堆重复内容;MMR 可以让结果更分散。
similarity 追求相似,threshold 追求可信,MMR 追求不重复。 |
7、FAISS、Chroma、Milvus、Qdrant、ES 怎么选?
向量库选型不要看谁名气大。要看四个问题:数据多大、是否需要复杂过滤、团队会不会运维、是否需要关键词和向量混合检索。
FAISS:最快开始,但不是完整数据库
FAISS 更像一个高性能本地向量索引库。它适合实验、离线索引、小型服务。LangChain 的 FAISS 文档里也提供了保存、加载、合并索引,以及 as_retriever 转成 Retriever 的用法。
它的优点是轻。缺点也明显:权限、多租户、服务化、分布式治理,都不是它最擅长的部分。
Chroma:开发体验好,适合快速迭代
Chroma 适合快速做知识库。它可以本地跑,也可以连接 server 或 cloud。LangChain 的 Chroma 文档里,创建 vectorstore 后,可以直接 add_documents、update_documents、delete,再进行查询。
如果你是做 Demo、个人知识库、中小型 RAG,Chroma 很顺手。大型生产系统要看团队对持久化、备份、权限和运维的要求。
Milvus:大规模生产优先考虑
Milvus 是正经向量数据库。LangChain 的 Milvus 文档明确提到,如果数据量很大,例如超过百万向量,更推荐部署性能更强的 Milvus Server,并利用不同索引提升检索能力。
它更适合企业级、百万级以上向量、需要 Docker/Kubernetes 部署和索引调优的场景。代价是运维复杂度更高。
Qdrant:过滤和工程体验都不错
Qdrant 的特点是 payload / metadata 友好。LangChain 文档里提到 Qdrant 会把文本和 metadata 放在 payload 结构里,也支持 named vectors 和 hybrid retrieval 模式。
如果你的 RAG 经常要按租户、来源、时间、业务类型过滤,Qdrant 是值得重点看的方案。
Elasticsearch:已有 ES 体系,就别急着再上一套
Elasticsearch 的优势不是“纯向量最强”,而是搜索体系成熟。关键词、过滤、聚合、权限、日志、运维经验,很多团队已经有现成基础。
LangChain 的 Elasticsearch 文档里展示了向量相似搜索、metadata filter、score threshold retriever,也说明 Elasticsearch 支持 cosine、euclidean、dot_product 等向量距离算法。
已有 ES 团队,优先考虑 ES + 向量检索 + BM25 混合召回。不要为了追新技术把系统复杂度拉爆。 |
8、统一接口背后的差异在哪里?
LangChain 统一了接口,但没有抹平底层能力差异。
差异主要在四个地方:第一,如何建索引。第二,如何过滤 metadata。第三,如何更新和删除。第四,如何扩展到大数据量和高并发。
所以你看源码时,不要只看 VectorStore 基类。基类只告诉你“应该有什么方法”。真正要看子类:它怎么接客户端、怎么建 collection、怎么把 Document 转成底层 payload、怎么把查询结果还原成 Document。
读源码顺序:VectorStore 基类 -> 目标向量库子类 -> add_documents/add_texts -> similarity_search -> as_retriever。 |
9、企业级落地:Vector Store 只是其中一环
很多 RAG 系统效果不好,不是向量库选错了,而是前后链路都没做好。
切分太烂,入库就是垃圾。metadata 不全,过滤就做不起来。没有重排,召回结果就容易混杂。没有评测,效果好坏只能靠感觉。没有版本管理,文档更新后新旧数据混在一起。
生产环境要补上的能力
• 文档 ID:每个 Chunk 要有稳定 ID,方便更新、删除、回滚。
• 元数据:source、tenant、page、section、time、permission 都要保留。
• 批量入库:Embedding 要做批处理、重试、限流和失败补偿。
• 混合检索:向量召回 + BM25 关键词召回,再做 RRF 融合。
• 重排:TopK 只是粗召回,重要场景要加 Rerank。
• 评测:记录 query、召回文档、分数、最终答案、用户反馈。
10、总结
图 7:本章总结
Vector Store 不负责让模型变聪明。它负责把资料找准。找得准,模型才有机会答得准。找不准,后面的 Prompt 再漂亮,模型也只能胡说。
源码层面,它就是一套统一抽象:Document 入库,Embedding 生成向量,VectorStore 保存索引,Retriever 调用检索,最后返回 List[Document]。
工程层面,它是一套选型问题:小数据用轻量方案,快速迭代用 Chroma,大规模生产看 Milvus/Qdrant,已有 ES 体系就考虑 ES 混合检索。
真正成熟的 RAG,不是“上了向量库”。而是数据、索引、过滤、召回、重排、评测、监控全部闭环。 |
内容来源:Vector Store:FAISS、Chroma、Milvus、Qdrant、ES 怎么选?:功能变化与行业影响解析_热闻岛
