无 GPU 环境下的 RAG 系统搭建实践

最近我在研究如何在没有 GPU 的服务器上部署本地知识库。很多教程都默认你有一块好显卡,但现实是不少人手头只有 CPU 服务器。经过一番折腾,我总结出了这套方案。

一、硬件准备(最低配置)

我先说说硬件要求。没有 GPU 并不意味着配置可以很低,实际上 CPU 推理对内存的依赖更大。

计算设备

  • CPU:Intel i7 12代 / AMD Ryzen 7 5800X 或更高
  • RAM:32GB DDR4(建议64GB+以提升大模型推理效率)
  • 存储:1TB NVMe SSD(存储大模型权重和知识库)
  • 网络:千兆局域网

我踩过的坑

  • 内存一定要够大,我最初用 16GB 跑 7B 模型直接 OOM 了,后来加到 64GB 才稳定
  • SSD 很重要,模型加载时间从机械硬盘的几分钟缩短到 SSD 的十几秒
  • 多线程要配置好,默认配置下 Python 可能只用了一半的 CPU 核心

二、软件环境搭建

我选的是 Ubuntu 22.04 LTS,稳定且社区支持好。

1. 操作系统

# 首先更新系统
sudo apt update && sudo apt upgrade -y
sudo apt install build-essential zlib1g-dev libssl-dev libffi-dev wget curl

2. Python环境

我用 Miniconda 而不是完整版 Anaconda,因为它轻量很多。

# 安装 Miniconda
wget https://repo.anaconda.com/miniconda/Miniconda3-latest-Linux-x86_64.sh
bash Miniconda3-latest-Linux-x86_64.sh

# 创建专用 Python 环境
conda create -n knowledge_base python=3.10
conda activate knowledge_base

3. 安装关键依赖

注意这里用的是 CPU 版本的 PyTorch:

pip install torch torchvision torchaudio --index-url https://download.pytorch.org/whl/cpu
pip install transformers==4.32.0 sentence-transformers faiss-cpu langchain
pip install llama-cpp-python  # 这是 CPU 推理的核心

4. 安装编译工具

这一步很容易漏掉,但 OpenMP 支持对性能影响很大:

# 安装 GCC 编译器和 libgomp 库(用于 OpenMP 支持)
conda install -c anaconda gcc_linux-64 gxx_linux-64
conda install -c conda-forge libgomp

三、模型选择与部署(仅支持CPU)

这是我测试过的几个模型,都能在纯 CPU 环境下运行。

1. 适合CPU运行的模型

模型 适用场景 最低RAM需求
ChatGLM3-6B-CPU 中文问答 32GB
Mistral-7B-Instruct-v0.2-GGUF 轻量级LLM 16GB
Llama-3-8B-Instruct-GGUF 通用智能 64GB
Qwen-1.8B-Chat 超低资源环境 8GB

注意:GGUF 格式是优化后的低资源推理模型格式,CPU 推理必备。

2. 下载并转换模型

首先要编译 llama.cpp,现在必须用 cmake,make 方式已经不支持了:

git clone https://github.com/ggerganov/llama.cpp
cd llama.cpp && make -j$(nproc)

下载模型需要先在 HuggingFace 注册并获取 token:

# 下载并转换模型(以 Mistral 7B 为例)
from huggingface_hub import snapshot_download
snapshot_download(repo_id="mistralai/Mistral-7B-Instruct-v0.2", local_dir="./mistral")

# 转换为 GGUF 格式
python llama.cpp/convert-hf-to-gguf.py mistral/ --outfile mistral.gguf

3. 运行CPU推理

我推荐 4-bit 量化,内存占用能减少一半以上:

# 4-bit 量化(减少RAM占用)
./llama.cpp/quantize mistral.gguf mistral-q4_0.gguf q4_0

# 启动模型服务(启用CPU优化)
./llama.cpp/server -m mistral-q4_0.gguf --port 8000 --threads $(nproc)

四、知识库构建

这部分我用的是 LangChain + FAISS 的组合,简单有效。

1. 数据预处理

from langchain.document_loaders import DirectoryLoader
from langchain.text_splitter import RecursiveCharacterTextSplitter

loader = DirectoryLoader('./docs', glob="**/*.txt")
documents = loader.load()

text_splitter = RecursiveCharacterTextSplitter(
    chunk_size=500, chunk_overlap=50, separators=["\n\n", "\n", "", "", ""]
)
splits = text_splitter.split_documents(documents)

2. 构建向量数据库

from langchain.embeddings import HuggingFaceEmbeddings
from langchain.vectorstores import FAISS

embeddings = HuggingFaceEmbeddings(model_name="BAAI/bge-small-zh-v1.5")  # 适合CPU
vectorstore = FAISS.from_documents(splits, embeddings)
vectorstore.save_local("faiss_index")

五、RAG增强实现

RAG(检索增强生成)是知识库问答的核心,我的配置如下:

from langchain.chains import RetrievalQA
from langchain.prompts import PromptTemplate

prompt_template = """基于以下上下文和你的知识,用中文回答:
上下文:{context}
问题:{question}
答案:"""

QA_CHAIN_PROMPT = PromptTemplate.from_template(prompt_template)

qa_chain = RetrievalQA.from_chain_type(
    llm, retriever=vectorstore.as_retriever(), chain_type_kwargs={"prompt": QA_CHAIN_PROMPT}
)

六、API系统部署

知识库跑起来后,还需要对外提供服务。我用 FastAPI 做接口,Nginx 做反向代理。

1. API接口(FastAPI)

from fastapi import FastAPI
from pydantic import BaseModel

app = FastAPI()

class Query(BaseModel):
    question: str
    user_id: str

@app.post("/ask")
async def ask(query: Query):
    result = qa_chain({"query": query.question})
    return {"answer": result["result"], "sources": result["source_documents"]}

# 启动命令
# uvicorn main:app --host 0.0.0.0 --port 7860 --workers 2

2. 反向代理(Nginx)

我用 Nginx 做 HTTPS 和负载均衡:

server {
    listen 443 ssl;
    server_name knowledge.example.com;
    
    ssl_certificate /etc/ssl/certs/knowledge.pem;
    ssl_certificate_key /etc/ssl/private/knowledge.key;
    
    location / {
        proxy_pass http://localhost:7860;
        proxy_set_header X-Real-IP $remote_addr;
    }
}

七、优化与监控

纯 CPU 推理性能有限,优化很重要。

1. 推理性能优化

OpenBLAS 对矩阵运算加速明显:

# 安装 CPU 计算库
sudo apt install libopenblas-dev libomp-dev

# 启用 Pytorch 线程优化
export OMP_NUM_THREADS=$(nproc)
export MKL_NUM_THREADS=$(nproc)

2. 监控系统(Prometheus + Grafana)

我用 Docker 快速部署监控:

docker run -d --name prometheus -p 9090:9090 -v ./prometheus.yml:/etc/prometheus/prometheus.yml prom/prometheus
docker run -d --name grafana -p 3000:3000 grafana/grafana-enterprise

八、增量知识库更新

知识库不是一次性的,需要支持增量更新:

def update_knowledge(file_path):
    new_docs = loader.load(file_path)
    new_splits = text_splitter.split_documents(new_docs)
    vectorstore.add_documents(new_splits)
    vectorstore.save_local("faiss_index")

九、扩展方案

后续我还计划做的事情。

1. 分布式部署

如果单机性能不够,可以用 Ray 做分布式:

# Ray CPU 集群优化
ray start --head --port=6379 --dashboard-port=8265
ray start --address='192.168.1.100:6379'

2. 浏览器插件

为了方便使用,我还写了个简单的浏览器插件:

chrome.runtime.onMessage.addListener((request, sender, sendResponse) => {
    if (request.action === "query") {
        fetch('https://knowledge-base/api/ask', {
            method: 'POST',
            headers: {'Authorization': 'Bearer ' + token},
            body: JSON.stringify({question: request.question})
        }).then(response => sendResponse(response.json()))
    }
});

总结

这套方案的核心是:

  • GGUF 格式 + llama.cpp:让大模型能在 CPU 上跑起来
  • 4-bit 量化:大幅减少内存占用
  • LangChain + FAISS:构建高效的向量检索
  • FastAPI + Nginx:提供生产级 API 服务

实测下来,7B 模型在 64GB 内存的服务器上推理速度大约 2-3 tokens/s,虽然比 GPU 慢很多,但对于内部知识库场景完全够用了。

版权声明: 如无特别声明,本文版权归 sshipanoo 所有,转载请注明本文链接。

(采用 CC BY-NC-SA 4.0 许可协议进行授权)

本文标题:《 Python 本地知识库部署(仅 CPU) 》

本文链接:http://localhost:3015/ai/Python%E6%9C%AC%E5%9C%B0%E9%83%A8%E7%BD%B2%E7%9F%A5%E8%AF%86%E5%BA%93.html

本文最后一次更新为 天前,文章中的某些内容可能已过时!