完整教程:本地部署Milvus向量库+Ollama本地模型+LangChain串联,零API key实现私有知识库问答。
每往云端 LLM API 发送一份文档、工单或内部 Wiki 页面,下个月的账单上就多一笔费用——同时,公司的数据又有一份副本躺在别人的基础设施上。
对于处理专有文档、客户记录或受监管数据的团队来说,这种交换越来越难自圆其说。
自托管 RAG(检索增强生成)管道同时解决这两个问题。RAG 是一种让语言模型利用自有文档作为源材料来回答问题的技术,而非仅依赖训练期间学到的知识。它首先检索相关内容块,然后将检索到的上下文提供给模型生成答案。
本教程将带你搭建一套完整的私有 RAG 技术栈:使用 Milvus 作为向量数据库,Ollama 在本地运行语言模型,二者通过 LangChain 连接,全部运行在你控制的一台裸金属服务器上。
零 API 密钥、无按 token 计费、文档不离你的硬件。🔒
🏗️ 私有 AI 的架构
在写任何代码之前,先看看各个组件如何串联起来。该管道分为两个阶段:
索引(一次性完成,或文档变更时执行):文档 → 分块 → 转换为向量(Nomic)→ 存入 Milvus。
查询(每个用户问题时执行):用户问题 → Milvus 相似性搜索检索相关文档块 → 文档块 + 问题发送给 Ollama(Llama 3)→ 生成答案。
这条链路中的每个组件都作为本地进程运行。整个流程中无需任何 outbound API 调用。
前置条件与服务器要求
对于小型文档集来说,这个管道对资源的需求并不算高,但同时运行两个模型服务进程(嵌入和生成)外加 Milvus,还是留些余量更好。合理的裸金属基准配置如下:
存储:NVMe SSD(用于快速的向量索引读写)
操作系统:Ubuntu 22.04 LTS 或更高版本
注意:本指南假设 Milvus 已运行在服务器上,监听 localhost:19530。
步骤 1:在专用服务器上安装 Ollama
Ollama 负责 LLM 和嵌入模型的模型服务,通过 11434 端口暴露简洁的本地 API。用官方脚本安装:
curl -fsSL https://ollama.com/install.sh | sh
systemctl status ollama
裸金属为何重要:模型推理是 CPU/GPU 和内存带宽密集型操作。在共享 VPS 上,"吵闹的邻居"工作负载可能导致吞吐量不可预测地受限。而在专用裸金属服务器上,每个核心都专属于你的模型,转化为更快的 token 生成速度。
步骤 2:拉取 LLM 和嵌入模型
Ollama 安装完成后,拉取本管道需要的两个模型。
生成模型(Llama 3):
ollama pull llama3
嵌入模型(Nomic):
ollama pull nomic-embed-text
注意:nomic-embed-text 是专为嵌入任务打造的,比用通用 LLM 做向量化要小得多、快得多。
步骤 3:搭建 Python 环境
创建项目目录并安装所需依赖库:
mkdir rag-pipeline && cd rag-pipeline
python3 -m venv venv
source venv/bin/activate
pip install pymilvus langchain langchain-community langchain-milvus bs4
步骤 4:编写 RAG 管道脚本
创建名为 rag_app.py 的单个文件,添加以下 Python 代码来处理文档加载和分块:
from langchain_community.document_loaders import WebBaseLoader
from langchain.text_splitter import RecursiveCharacterTextSplitter
# Load a source document
loader = WebBaseLoader("https://example.com/your-internal-doc")
documents = loader.load()
# Split into overlapping chunks so context isn't lost
text_splitter = RecursiveCharacterTextSplitter(
chunk_size=1000,
chunk_overlap=150
)
chunks = text_splitter.split_documents(documents)
print(f"Document split into {len(chunks)} chunks")
使用本地 nomic 模型将文档块转换为向量,然后写入 Milvus。
from langchain_community.embeddings import OllamaEmbeddings
from langchain_milvus import Milvus
# Local embedding model — no external API call
embeddings = OllamaEmbeddings(model="nomic-embed-text")
vector_store = Milvus.from_documents(
documents=chunks,
embedding=embeddings,
connection_args={"host": "localhost", "port": "19530"},
collection_name="rag_documents"
)
print("Chunks embedded and stored in Milvus")
将检索器和生成模型串联起来。
from langchain_community.llms import Ollama
from langchain_core.prompts import ChatPromptTemplate
from langchain.chains.combine_documents import create_stuff_documents_chain
from langchain.chains import create_retrieval_chain
# Local generation model
llm = Ollama(model="llama3")
# Retriever pulls the most relevant chunks
retriever = vector_store.as_retriever(search_kwargs={"k": 4})
# Prompt template
prompt = ChatPromptTemplate.from_messages([
("system", "Answer the question using only the following context. "
"If the answer isn't in the context, say you don't know.\n\n"
"Context: {context}"),
("human", "{input}")
])
combine_docs_chain = create_stuff_documents_chain(llm, prompt)
rag_chain = create_retrieval_chain(retriever, combine_docs_chain)
question = "What does this document say about deployment requirements?"
result = rag_chain.invoke({"input": question})
print("\nAnswer:", result["answer"])
步骤 5:测试你的自托管 RAG 系统
在终端运行脚本:
python3 rag_app.py
如果所有连接都正确,你会看到控制台输出确认分块数量,随后是基于源文档严格生成的答案。
🚀 为什么要在裸金属上运行 RAG 而不是云端?
零 API 成本:嵌入和生成均不按 1K token 计费。
绝对数据隐私:文档、嵌入向量和生成的答案永不离开服务器。
零网络延迟:Milvus 和 Ollama 通过 localhost 通信,消除了往返互联网的延迟。
你现在已经搭建了一个可扩展的私有基础架构,可以在此之上扩展更多文档源或更大规模的模型,完全处于你的掌控之中。
立即在高性能裸金属服务器上部署你的私有 AI:BytesRack。