AI-Chain

别让 RAG 卡在检索层:Milvus 如何把向量搜寻做成可扩展的 AI 基础设施

分享:
别让 RAG 卡在检索层:Milvus 如何把向量搜寻做成可扩展的 AI 基础设施

别让 RAG 卡在检索层:Milvus 如何把向量搜寻做成可扩展的 AI 基础设施

我在看 RAG 专案时,最常遇到的误解是:只要把文件切块、呼叫 embedding API,再把结果塞给 LLM,系统就算完成了。原型阶段确实可以很快做到这一步,但当资料量增加、查询变多、租户开始分开、文件需要即时更新,真正先失速的往往不是生成模型,而是检索层。

这也是我认为 Milvus 值得被单独拆解的原因。它不是另一个聊天机器人,也不是帮你包装 prompt 的框架,而是一个专门处理向量资料、相似度搜寻与大规模检索的开源资料库。官方文件把它定位成能从笔电上的 Milvus Lite,一路延伸到单机 Docker 与 Kubernetes 分散式丛集的向量资料库。这个定位很务实:先让开发者把 RAG 跑起来,再在流量、资料规模与可靠性要求出现时,逐步替换部署形态,而不是一开始就被基础设施绑住。

截至 2026 年 8 月 31 日的 GitHub API 查询,milvus-io/milvus 显示 45,901 颗星、4,212 个 forks,且在当日仍有推送活动。星数本身不能证明工具一定适合你的团队,但它至少说明 Milvus 已经不是只存在于概念展示里的实验专案。接下来我不只看它有什么功能,而是从一个 AI 团队真正会遇到的问题来看:它解决了什么、怎么开始、什么时候值得升级,以及哪些限制不能被 marketing 文字掩盖。

先讲结论:Milvus 的价值是把检索层当成一个可以演进的系统

我的判断是,如果你的 AI 应用已经不只做一次性的 demo,而是需要长期保存 embedding、根据 metadata 筛选、支援多种搜寻策略,或预期资料规模会从几千笔成长到更大的集合,Milvus 值得放进候选名单。

它最重要的设计不是「搜寻很快」这句抽象描述,而是把几个常被绑在一起的责任拆开:资料保存、向量索引、查询节点、资料写入与扩展策略。官方架构文件指出,分散式部署可以把 compute 与 storage 分离,并让 query node 与 data node 依读写负载独立扩展。换句话说,读很多的 RAG 服务,不必和写入大量新文件的管线用同一种扩展方式。

对应到开发体验,Milvus 又提供三种部署模式:

1. Milvus Lite:以 Python library 形式嵌入应用,资料可以写入本机档案,适合 notebook、概念验证与边缘装置。

1. Milvus Standalone:以单机伺服器搭配 Docker 执行,适合需要服务端点、多人共用或比本机档案更接近正式服务的场景。

1. Milvus Distributed:部署在 Kubernetes,将 Milvus 的 cloud native 与可水平扩展能力用在更大规模的环境。

这个阶梯式设计比「所有团队都直接上 Kubernetes」更接近实务。原型的目标是验证资料与检索品质,生产环境的目标才是可用性、隔离、监控与成本。

RAG 为什么需要专门的向量资料库?

文字、图片与音讯本身不是资料库很容易比较的栏位。embedding model 会把这些非结构化资料转成高维向量,语义相近的内容在向量空间里通常更接近。RAG 的检索步骤,就是把使用者问题转成 query vector,再从资料集中找出距离较近的内容,最后交给生成模型组合答案。

这个流程看似简单,但至少同时包含四种资料:

  • 向量本身,例如 float、binary 或 sparse vector。
  • 原始内容,例如文件段落、图片描述或切块后的文字。
  • metadata,例如来源、租户、权限、时间与文件类型。
  • 索引与搜寻设定,例如 HNSW、IVF、DiskANN、距离度量与 top K。

如果只用一个通用储存层硬塞所有东西,早期可能没有问题;但当你需要把「语义相似」与「只看某个租户、某个产品版本、某个权限范围」放在同一个查询里,检索就不再只是排序,而是资料模型与查询计划的问题。Milvus 把向量栏位与 scalar 栏位放在同一个 collection 里,让向量搜寻能配合 filter expression 使用,这正是它对 RAG 应用最有实际价值的部分。

从官方 Quickstart 开始:先用 Milvus Lite 验证资料流

我建议第一个实验不要直接搭分散式丛集,而是使用官方 quickstart 的 Milvus Lite。前置条件是 Python 3.8 以上,接着安装 pymilvus:

pip install -U pymilvus

建立本机资料库只需要一个档案路径:

from pymilvus import MilvusClient
client = MilvusClient("milvus_demo.db")

接着建立 collection。官方范例使用 768 维向量,并让 SDK 先套用基本预设值:

if client.has_collection(collection_name="demo_collection"):
    client.drop_collection(collection_name="demo_collection")
client.create_collection(
    collection_name="demo_collection",
    dimension=768,
)

这里有一个初学者容易忽略的重点:向量维度不是装饰性设定,而是 collection schema 的契约。你的 embedding model 如果输出 1536 维,collection 就不能照抄 768;模型替换时,也必须确认既有资料是否需要重建。

官方 quickstart 接着使用 pymilvus[model] 的预设 embedding function,把三段文字转成向量,再以每笔 entity 一个 dictionary 的形式插入:

from pymilvus import model
embedding_fn = model.DefaultEmbeddingFunction()
docs = [
    "Artificial intelligence was founded as an academic discipline in 1956.",
    "Alan Turing was the first person to conduct substantial research in AI.",
    "Born in Maida Vale, London, Turing was raised in southern England.",
]
vectors = embedding_fn.encode_documents(docs)
data = [
    {"id": i, "vector": vectors[i], "text": docs[i], "subject": "history"}
    for i in range(len(vectors))
]
client.insert(collection_name="demo_collection", data=data)

然后把查询句子转成 query vector,执行向量搜寻:

query_vectors = embedding_fn.encode_queries(["Who is Alan Turing?"])
res = client.search(
    collection_name="demo_collection",
    data=query_vectors,
    limit=2,
    output_fields=["text", "subject"],
)

这个例子值得保留,因为它完整走过「文字、embedding、collection、insert、search」的最小闭环。不要一开始就追求复杂的 reranker 或 agent;先确认你能从一笔可理解的输入得到合理的检索结果,才有资格讨论扩展。

Milvus 的关键不是只有 ANN,而是向量与条件可以一起查

纯向量搜寻会找距离 query vector 最近的资料,但企业应用通常还有条件。比如同一个问题,客服只能查询自己负责的产品线,法律文件只能在使用者有权限的范围内检索,或回答只能引用某个版本以前的文件。Milvus 将这些非向量栏位视为 scalar data,支援在搜寻时加入 filter:

res = client.search(
    collection_name="demo_collection",
    data=embedding_fn.encode_queries(["tell me AI related information"]),
    filter="subject == 'biology'",
    limit=2,
    output_fields=["text", "subject"],
)

这不是小功能,而是 RAG 是否能真正进入产品的分水岭。没有 metadata filtering,你很容易把错误租户、过期版本或不该曝光的文件送入 LLM;有了 filter,检索流程才有机会和权限、版本及业务条件对齐。不过,filter 也不会自动替你完成 authorization。应用程式仍要验证使用者身份与可用范围,资料库层则要搭配 authentication、TLS 与 RBAC 等安全设定。

Milvus 官方文件列出的搜寻能力也不只一种:ANN search 负责找近似邻居,range search 找距离范围内的向量,hybrid search 可以在多个向量栏位上搜寻,full text search 则提供基于 BM25 的全文检索,另有 reranking 来调整初步结果。这些能力反映一个现实:好的 RAG 往往不是 dense embedding 单独决定一切,而是把语义相似、关键字命中、metadata 条件与 reranking 组合起来。

从向量搜寻走向 RAG:Milvus 放在哪里?

RAG 不是一个单一元件,而是一条管线。最常见的路径是:

1. 读取文件并切成适当大小的 chunks。

1. 用 embedding model 将 chunks 转成向量。

1. 将向量、原文与 metadata 写入 Milvus。

1. 将使用者问题转成 query embedding。

1. 用 Milvus 找回 top K 文件,必要时加 filter 或 hybrid search。

1. 将检索片段组成 context,交给 LLM 产生答案。

1. 保留来源、距离与版本资讯,让回答可以被追溯。

官方的「Build RAG with Milvus」教学就是按照这个方向示范:使用 pymilvus、openai、requests 与 tqdm,以 embedding model 建立向量,再用 MilvusClient 建 collection、插入资料、搜寻相关内容,最后把 retrieved context 组给 LLM。这个示范也清楚区分了两个 URI 层级:本机档案路径会使用 Milvus Lite;资料量较大时,则连线到 Docker 或 Kubernetes 的 Milvus server,例如 http://localhost:19530。

我会特别建议团队把「检索品质」与「生成品质」分开量测。LLM 回答不好,可能是模型没有理解 context,也可能是 Milvus 根本没有找对文件。至少要记录 query、命中的 chunk、distance、filter、embedding model 与最终答案,否则你只看到错误结果,却不知道问题发生在哪一层。

什么时候需要从 Lite 升级到 Docker?

Milvus Lite 的优点是快,但它不是所有场景的终点。以下情况出现时,我会考虑升级到 Standalone:

  • 多个服务需要透过网路共用同一个向量资料库。
  • 需要独立处理资料写入与查询,而不是让资料库嵌在单一 Python 程式中。
  • 想把资料持久化、监控、备份与部署生命周期从应用程式分开。
  • 需要更接近正式环境的 authentication、TLS 或 RBAC 配置。

官方 Docker Compose 文件要求先安装 Docker,下载 Milvus repository 提供的 compose configuration,再启动服务:

wget https://github.com/milvus-io/milvus/releases/download/v2.6.0/milvus-standalone-docker-compose.yml -O docker-compose.yml
sudo docker compose up -d
docker compose ps

上面的版本号应以官方文件或最新 release 为准,不要长期固定在范例版本。官方文件指出,Standalone 预设会启动 milvus-etcd、milvus-minio 与 milvus-standalone,主服务通常在本机的 19530 提供连线,并可以透过 9091 的 WebUI 观察系统。启动后先执行 docker compose ps,确认容器状态是 healthy,再让应用程式连线,这比看到容器存在就直接开始压测可靠得多。

如果资料量、查询流量或可用性要求再往上走,才进一步评估 Kubernetes 的 Distributed deployment。这一步不只是把 YAML 换成 Helm,而是连同 object storage、metadata、message queue、节点配置、监控、备份、升级与故障复原一起管理。没有运维能力的团队,不应只因为「分散式」听起来更专业就直接采用。

索引与效能:不要把 benchmark 当成你的结果

Milvus 支援 HNSW、IVF、FLAT、SCANN、DiskANN 等向量索引,也提供量化变体与 GPU 加速选项。这些选择背后都是同一组取舍:查询延迟、召回率、记忆体、建索引时间与更新成本。

例如,追求低延迟不代表可以无限降低候选数;索引参数如果让召回率下降,RAG 可能会因为拿不到关键段落而产生看似流畅、实际错误的回答。反过来,追求最高召回率也可能把太多噪音送入 context,增加 token 成本与模型混淆。

所以我不会把官方文件提到的「效能优势」直接改写成你的系统保证。正确做法是用自己的 embedding model、资料分布、filter 条件、top K、硬体与并发量做基准测试,并同时看 recall、p95 latency、写入吞吐量、索引重建时间与成本。Milvus 提供的是可调整的检索引擎,不是免除测试的魔法。

这个方案的限制与常见坑

1. Milvus 不会替你选 embedding model

向量资料库只能依照向量与距离搜寻。若 embedding model 不适合你的语言、领域或文件型态,资料库再快也只会更快地找到不相关内容。模型、chunk size、overlap、query rewrite 与 reranker 都必须一起评估。

2. 维度与距离度量必须一致

collection 的 dimension、插入向量与 query vector 必须相容。换模型时不能只改一个环节;如果新模型使用不同维度或不同的语义分布,通常需要建立新 collection 并重新产生 embedding。

3. Metadata filter 不是完整的权限系统

tenant_id 或 user_id filter 可以降低资料串租,但不能取代身份验证、授权逻辑与安全审计。官方文件也把 authentication、TLS 与 RBAC 列为安全能力;实际部署仍要检查预设设定、网路暴露范围、密钥管理与备份权限。

4. 分散式部署带来新的运维负担

Kubernetes 可以提供水平扩展与故障复原,但同时需要处理 storage、metadata、message queue、版本升级与监控。若你的资料只有几万笔、流量也低,Standalone 甚至 Lite 可能更划算。

5. 文件范例不等于生产设定

Quickstart 的目的是在几分钟内跑通闭环,因此会使用预设 schema、简单资料与示范模型。进入生产前,仍要补上 schema versioning、资料删除策略、重嵌入流程、索引生命周期、可观测性与灾难复原演练。

我会怎么安排一个实务导入计划?

我会把导入拆成四个阶段,而不是一次把整套平台搬进来。

第一阶段,验证检索是否有用。 用 Milvus Lite 与一小批真实文件,固定 embedding model 与 chunk 规则,建立一组带有标准答案的 query。先测 top K 是否包含正确来源,不要急着接上复杂 agent。

第二阶段,验证 metadata 与安全边界。 加入 tenant、产品版本、语言、权限等栏位,测试 filter 是否能排除不该出现的内容。这时就要把错误案例列出来,而不是只展示成功案例。

第三阶段,验证混合搜寻与成本。 对专有名词、产品代码与长句问题分别测试 dense search、full text search 与 hybrid search,观察哪种策略能提高召回率,再估算 embedding、储存、查询与 reranking 成本。

第四阶段,才决定部署形态。 如果应用需要多人共用,切到 Standalone;如果查询与写入已经有不同的扩展需求,或可用性与资料规模真的需要,再规划 Distributed。每一次升级都要有可量测的理由。

谁适合先试 Milvus?

我认为以下团队最适合先试:

  • 正在做企业知识库、客服问答、文件搜寻或推荐系统。
  • 已经有 embedding 与 LLM 流程,但检索资料仍散落在档案、cache 或不适合的储存层。
  • 需要 metadata filtering、hybrid search 或多种向量栏位。
  • 希望从本机原型逐步走向自架服务,并保留 Python、Go、Java、Node.js 等 SDK 选择。
  • 有能力管理至少 Docker 与基本监控,或愿意使用托管服务降低维运负担。

反过来说,如果你的应用只需要对十几笔资料做一次性相似度比较,或团队完全不想管理资料库,那么 Milvus 可能太重。Lite 可以降低门槛,但「能嵌入」不代表每个小需求都需要采用完整的向量资料库。

结语:RAG 的下一个瓶颈,通常是资料与检索工程

我对 Milvus 的总结不是「它一定是最好的向量资料库」,而是它把 RAG 最容易被低估的那一层,做成了一个可以逐步演进的工程元件。你可以从一个本机档案开始,先验证 embedding 与搜寻,再依服务化需求切到 Docker,最后才在真正需要时使用 Kubernetes 的分散式架构。

这条路线的价值,在于它让团队把注意力放回正确问题:哪些资料应该被找回来、结果是否符合权限与版本条件、查询品质如何量测,以及系统在成长后能不能维持可观测与可维护。LLM 只负责生成不代表它能修正错误检索;如果 context 一开始就错了,回答再流畅也只是把错误包装得更好看。

所以,如果你下一个 RAG 专案已经开始遇到资料规模、租户隔离、混合搜寻或部署演进的问题,我会建议先用 Milvus Lite 跑通一条可测量的检索基线,再决定是否升级。不要从「我要不要用 Milvus」开始,而要从「我的检索层接下来需要承担什么责任」开始。


参考资料