Milvus + LangChain + Ollama 搭建生产级 RAG(含 Tag / Metadata 解析)

本文记录一次从 Milvus 容器反复重启、端口拒绝,到最终稳定运行并实现 LangChain RAG 成功检索的完整实战过程。适用于本地 RAG、私有大模型、知识库系统等场景。

一、背景与问题

在本地构建 RAG(Retrieval-Augmented Generation)时,开发者常遇到以下典型问题:

  • telnet 19530 连接被拒绝
  • Milvus 容器反复 Restarting (1)
  • pymilvus 能连上,但 LangChain 查不到数据
  • 不清楚 Milvus 中的「tag / metadata」到底存在哪里

本文基于 Milvus 2.4 + LangChain + Ollama(Qwen + bge-m3),逐步解决上述问题。

二、整体架构

复制代码
LangChain
   │
   ├─ Ollama Embedding (bge-m3)
   │
   ├─ Milvus Vector Store
   │     ├─ etcd
   │     ├─ minio
   │     └─ standalone
   │
   └─ Ollama LLM (qwen2.5)

Python 3.9 / 3.10 / 3.11 均可支持。

bash 复制代码
pip install -U \
  langchain \
  langchain-core \
  langchain-community \
  langchain-text-splitters \
  langchain-ollama \
  pymilvus \
  faiss-cpu

三、Milvus Docker Compose(稳定版)

注意:Milvus standalone 必须依赖 etcd + minio,不能直接使用 docker run milvusdb/milvus,否则 19530 端口不会监听。

docker-compose.yml

yaml 复制代码
version: '3.5'

services:
  rag-etcd:
    container_name: rag-milvus-etcd
    image: quay.io/coreos/etcd:v3.5.5
    volumes:
      - ./rag-volumes/etcd:/etcd
    command: >
      etcd
      -advertise-client-urls=http://127.0.0.1:2379
      -listen-client-urls http://0.0.0.0:2379
      --data-dir /etcd

  rag-minio:
    container_name: rag-milvus-minio
    image: minio/minio:RELEASE.2023-03-20T20-16-18Z
    environment:
      MINIO_ACCESS_KEY: minioadmin
      MINIO_SECRET_KEY: minioadmin
    ports:
      - "19000:9000"
      - "19001:9001"
    volumes:
      - ./rag-volumes/minio:/minio_data
    command: minio server /minio_data --console-address ":9001"

  rag-milvus:
    container_name: rag-milvus-standalone
    image: milvusdb/milvus:v2.4.0
    command: ["milvus", "run", "standalone"]
    environment:
      ETCD_ENDPOINTS: rag-etcd:2379
      MINIO_ADDRESS: rag-minio:9000
    volumes:
      - ./rag-volumes/milvus:/var/lib/milvus
    ports:
      - "19530:19530"
      - "9091:9091"
    depends_on:
      - rag-etcd
      - rag-minio

networks:
  default:
    name: rag-milvus-net

启动命令:

bash 复制代码
docker compose up -d

四、验证 Milvus 是否正常

telnet 验证端口

bash 复制代码
telnet 127.0.0.1 19530

若看到如下输出:

复制代码
Connected to 127.0.0.1.
HTTP/1.1 400 Bad Request

这是正常现象,因为 19530 是 gRPC 端口,并非 HTTP 接口。

Python 连接 Milvus

python 复制代码
from pymilvus import connections, utility, Collection

connections.connect(
    host="127.0.0.1",
    port="19530"
)

print("connected:", connections.has_connection("default"))
print("collections:", utility.list_collections())

五、理解 Milvus 里的 "tag / metadata"

Milvus 没有内置 tag 概念。所谓的 tag,本质是 Collection schema 中的 scalar 字段。

查看 collection schema:

python 复制代码
col = Collection("rag_qwen_prod")
print(col.schema)

典型结构如下:

复制代码
id (INT64, primary)
vector (FLOAT_VECTOR)
text (VARCHAR)
source (VARCHAR)
category (VARCHAR)

其中 source / category 即为 RAG 中的 tag。

六、LangChain + Ollama + Milvus 实战

Embedding(bge-m3)

python 复制代码
from langchain_ollama import OllamaEmbeddings

embeddings = OllamaEmbeddings(
    model="bge-m3",
    base_url="http://192.168.31.161:11434"
)

构造文档

python 复制代码
from langchain_core.documents import Document

docs = [
    Document(page_content="RAG 是检索增强生成"),
    Document(page_content="Milvus 是生产级向量数据库"),
    Document(page_content="Qwen2.5 是高质量中文大模型"),
]

文本切分

python 复制代码
from langchain_text_splitters import RecursiveCharacterTextSplitter

splitter = RecursiveCharacterTextSplitter(
    chunk_size=300,
    chunk_overlap=50
)
docs = splitter.split_documents(docs)

写入 Milvus

python 复制代码
from langchain_community.vectorstores import Milvus

vectorstore = Milvus.from_documents(
    docs,
    embedding=embeddings,
    collection_name="rag_qwen_prod",
    connection_args={
        "host": "localhost",
        "port": "19530"
    }
)

Retriever

python 复制代码
retriever = vectorstore.as_retriever(
    search_kwargs={"k": 3}
)

LLM(Qwen2.5)

python 复制代码
from langchain_ollama import ChatOllama

llm = ChatOllama(
    model="qwen2.5:7b",
    temperature=0
)

Prompt & LCEL RAG Chain

python 复制代码
from langchain_core.prompts import ChatPromptTemplate
from langchain_core.runnables import RunnablePassthrough

prompt = ChatPromptTemplate.from_messages([
    ("system", "你只能基于上下文回答问题,不允许编造"),
    ("human", "上下文:\n{context}\n\n问题:{question}")
])

rag_chain = (
    {
        "context": retriever,
        "question": RunnablePassthrough()
    }
    | prompt
    | llm
)

查询验证

python 复制代码
result = rag_chain.invoke("什么是 Milvus?")
print(result.content)

输出示例:

复制代码
Milvus 是一个生产级向量数据库,用于高效存储和检索向量数据。

RAG 生效。

七、完整代码与常见问题总结

python 复制代码
from langchain_ollama import ChatOllama, OllamaEmbeddings
from langchain_community.vectorstores import Milvus
from langchain_text_splitters import RecursiveCharacterTextSplitter
from langchain_core.documents import Document
from langchain_core.prompts import ChatPromptTemplate
from langchain_core.runnables import RunnablePassthrough

# 1. Embedding
embeddings = OllamaEmbeddings(
    model="bge-m3",
    base_url="http://192.168.31.161:11434"
)

# 2. 文档
docs = [
    Document(page_content="RAG 是检索增强生成"),
    Document(page_content="Milvus 是生产级向量数据库"),
    Document(page_content="Qwen2.5 是高质量中文大模型"),
]

# 3. 切分
splitter = RecursiveCharacterTextSplitter(
    chunk_size=300,
    chunk_overlap=50
)
docs = splitter.split_documents(docs)

# 4. Milvus Vector Store
vectorstore = Milvus.from_documents(
    docs,
    embedding=embeddings,
    collection_name="rag_qwen_prod",
    connection_args={
        "host": "localhost",
        "port": "19530"
    }
)

retriever = vectorstore.as_retriever(search_kwargs={"k": 3})

# 5. LLM
llm = ChatOllama(
    model="qwen2.5:7b",
    temperature=0
)

# 6. Prompt
prompt = ChatPromptTemplate.from_messages([
    ("system", "你只能基于上下文回答问题,不允许编造"),
    ("human", "上下文:\n{context}\n\n问题:{question}")
])

# 7. LCEL RAG Chain
rag_chain = (
    {
        "context": retriever,
        "question": RunnablePassthrough()
    }
    | prompt
    | llm
)

# 8. Query
result = rag_chain.invoke("什么是 Milvus?")
print(result.content)
问题 原因
19530 连接被拒绝 直接 docker run Milvus
容器重启 缺少 etcd / minio
telnet 返回 400 正常(gRPC)
查不到 tag schema 没定义 metadata
LangChain 无结果 embedding 不一致

八、下一步可以做什么?

  • 多 tag / 多租户 RAG
  • expr 过滤(category == 'ops'
  • Milvus IVF / HNSW 调优
  • Streaming RAG
  • Web UI + API 服务化

九、结语

Milvus + LangChain + Ollama 是目前本地 RAG 的黄金组合:

  • Milvus:性能与扩展性
  • Ollama:本地模型自由
  • LangChain:链路清晰、可组合

如果你已经走到这一步,说明你已经不是"入门玩家"了。

相关推荐
花千树_0105 小时前
多工具调用只是开始:用 Regnexe 构建真正会反思的 Java Agent
langchain·agent
匹诺曹i36721 小时前
memory_search 对了、7B 总结错了:OpenClaw D4 来源引用与 8 个坑
ollama
匹诺曹i3672 天前
docx 报表进 OpenClaw 本地 RAG:memory 索引实践与 6 个坑
ollama
大模型真好玩4 天前
LangChain DeepAgents 速通指南(九)—— 生产级智能体框架 DeepAgents Code 源码导读
人工智能·langchain·agent
早点睡啊6 天前
精读 LangChain 官方文档(二)Model 篇:把模型调用升级成工程化推理接口
人工智能·langchain
星始流年8 天前
从 Tool 到 Skill——基于 LangChain 的服务端Skill实现
前端·langchain·agent
codedx8 天前
LangChain 和 LangGraph 构建的 Agent 项目模版
后端·langchain·agent
颜酱9 天前
LangGraph 入门指南
langchain
武子康10 天前
调查研究-186 LangChain 和 LangGraph 的区别:从快速构建 Agent 到生产级工作流编排
人工智能·langchain·llm
葫芦和十三13 天前
渐进发现|代码库不是文档库
langchain·agent·ai编程