AI-Chain

別讓 RAG 卡在檢索層:Milvus 如何把向量搜尋做成可擴展的 AI 基礎設施

RAG 的瓶頸常常不在模型,而在檢索層是否能從本機原型一路長到生產規模。本文用 Milvus 的官方架構與 quickstart 拆解向量搜尋、metadata filtering、hybrid search,以及從 Milvus Lite 走向 Docker 與 Kubernetes 的實務路線。

分享:
別讓 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、概念驗證與邊緣裝置。
  2. Milvus Standalone:以單機伺服器搭配 Docker 執行,適合需要服務端點、多人共用或比本機檔案更接近正式服務的場景。
  3. 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。
  2. 用 embedding model 將 chunks 轉成向量。
  3. 將向量、原文與 metadata 寫入 Milvus。
  4. 將使用者問題轉成 query embedding。
  5. 用 Milvus 找回 top K 文件,必要時加 filter 或 hybrid search。
  6. 將檢索片段組成 context,交給 LLM 產生答案。
  7. 保留來源、距離與版本資訊,讓回答可以被追溯。

官方的「Build RAG with Milvus」教學就是按照這個方向示範:使用 pymilvusopenairequeststqdm,以 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-etcdmilvus-miniomilvus-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_iduser_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」開始,而要從「我的檢索層接下來需要承擔什麼責任」開始。


參考資料