构建您自己的 RAG 应用程序:使用 Ollama、Python 和 ChromaDB Response 在本地设置 LLM 的分步指南

2025-05-25

构建您自己的 RAG 应用程序:使用 Ollama、Python 和 ChromaDB 在本地设置 LLM 的分步指南

回复

在数据隐私至关重要的时代,建立自己的本地语言模型 (LLM)对公司和个人来说都是至关重要的解决方案。本教程旨在指导您使用OllamaPython 3ChromaDB创建自定义聊天机器人,所有组件均托管在您的本地系统上。以下是您需要本教程的主要原因:

  • 完全自定义:在本地托管您自己的检索增强生成 (RAG) 应用程序意味着您可以完全掌控设置和自定义。您可以根据自己的特定需求对模型进行微调,而无需依赖外部服务。

  • 增强隐私:通过在本地设置 LLM 模型,您可以避免通过互联网发送敏感数据所带来的风险。这对于处理机密信息的公司尤其重要。在本地使用私有数据训练模型,可确保您的数据始终在您的掌控之中。

  • 数据安全:使用第三方 LLM 模型可能会使您的数据面临潜在的泄露和滥用风险。本地部署可将您的训练数据(例如 PDF 文档)保存在安全的环境中,从而降低这些风险。

  • 掌控数据处理:当您托管自己的 LLM 时,您可以按照自己的意愿管理和处理数据。这包括将您的私有数据嵌入到 ChromaDB 向量存储中,确保您的数据处理符合您的标准和要求。

  • 无需网络连接:本地运行聊天机器人意味着您无需依赖网络连接。即使在离线情况下,也能保证聊天机器人的服务和访问不间断。

本教程将帮助您构建一个强大且安全的本地聊天机器人,以满足您的需求,同时又不损害隐私或控制。

微调模型


检索增强生成(RAG)

检索增强生成 (RAG)是一种先进的技术,它结合了信息检索和文本生成的优势,能够创建更准确、更符合语境的响应。以下是 RAG 的工作原理及其优势的详细说明:

什么是 RAG?

RAG 是一种混合模型,它通过整合外部知识库或文档存储来增强语言模型的功能。该过程涉及两个主要部分:

  • 检索:在此阶段,模型根据输入查询从外部源(例如数据库或向量存储)检索相关文档或信息。

  • 生成:然后,生成语言模型使用检索到的信息来产生连贯且适合上下文的响应。

RAG 如何工作?

  • 查询输入:用户输入查询或问题。

  • 文档检索:系统使用查询搜索外部知识库,检索最相关的文档或信息片段。

  • 响应生成:生成模型处理检索到的信息,并将其与自身知识相结合以生成详细而准确的响应。

  • 输出:最终的响应,包含知识库中的具体和相关细节,呈现给用户。

RAG 的优势

  • 增强准确性:通过利用外部数据,RAG 模型可以提供更精确、更详细的答案,尤其是针对特定领域的查询。

  • 上下文相关性:检索组件确保生成的响应基于相关和最新的信息,从而提高响应的整体质量。

  • 可扩展性:RAG 系统可以轻松扩展以包含大量数据,从而使其能够处理各种查询和主题。

  • 灵活性:这些模型只需更新或扩展外部知识库即可适应各个领域,从而具有高度的通用性。

为什么在本地使用 RAG?

  • 隐私和安全:在本地运行 RAG 模型可确保敏感数据保持安全和私密,因为它不需要发送到外部服务器。

  • 定制:您可以定制检索和生成过程以满足您的特定需求,包括集成专有数据源。

  • 独立性:本地设置确保您的系统即使在没有互联网连接的情况下也能保持运行,提供一致可靠的服务。

通过使用 Ollama、Python 和 ChromaDB 等工具设置本地 RAG 应用程序,您可以享受高级语言模型的好处,同时保持对数据和自定义选项的控制。

RAG 应用程序


图形处理器

运行大型语言模型 (LLM),例如检索增强生成 (RAG) 中使用的模型,需要强大的计算能力。图形处理单元 (GPU) 是实现这些模型高效处理和嵌入数据的关键组件之一。以下是 GPU 对这项任务至关重要的原因,以及它们如何影响本地 LLM 设置的性能:

什么是 GPU?

GPU 是一种专用处理器,旨在加速图像和视频的渲染。与针对顺序处理任务进行优化的中央处理器 (CPU) 不同,GPU 擅长并行处理。这使得它们特别适合机器学习和深度学习模型所需的复杂数学计算。

为什么 GPU 对 LLM 如此重要

  • 并行处理能力:GPU 可以同时处理数千个运算,显著加快 LLM 中的训练和推理等任务的速度。这种并行性对于处理大型数据集并实时生成响应所需的繁重计算负载至关重要。

  • 高效处理大型模型:类似 RAG 中使用的 LLM 需要大量内存和计算资源。GPU 配备高带宽内存 (HBM) 和多个核心,使其能够管理这些模型所需的大规模矩阵乘法和张量运算。

  • 更快的数据嵌入和检索:在本地 RAG 设置中,将数据嵌入到 ChromaDB 等向量存储中并快速检索相关文档对于性能至关重要。高性能 GPU 可以加速这些过程,确保您的聊天机器人能够快速准确地响应。

  • 缩短训练时间:训练 LLM 需要调整数百万(甚至数十亿)个参数。与 CPU 相比,GPU 可以大幅缩短此训练阶段所需的时间,从而能够更频繁地更新和优化模型。

选择合适的GPU

设置本地 LLM 时,GPU 的选择会显著影响性能。以下是一些需要考虑的因素:

  • 内存容量:更大的模型需要更大的 GPU 内存。请寻找具有更高 VRAM(视频 RAM)的 GPU,以容纳大量的数据集和模型参数。

  • 计算能力:GPU 拥有的 CUDA 核心越多,其处理并行处理任务的能力就越强。计算能力越强的 GPU 执行深度学习任务的效率就越高。

  • 带宽:更高的内存带宽允许 GPU 与其内存之间更快地传输数据,从而提高整体处理速度。

适用于 LLM 的高性能 GPU 示例

  • NVIDIA RTX 3090:以其高 VRAM(24 GB)和强大的 CUDA 核心而闻名,它是深度学习任务的热门选择。

  • NVIDIA A100:专为人工智能和机器学习而设计,具有大内存容量和高计算能力,性能卓越。

  • AMD Radeon Pro VII:另一个强有力的竞争者,具有高内存带宽和高效的处理能力。

投资高性能 GPU 对于在本地运行 LLM 模型至关重要。它能够确保更快的数据处理、高效的模型训练和快速的响应生成,从而使您的本地 RAG 应用程序更加健壮可靠。通过利用 GPU 的强大功能,您可以充分享受托管自定义聊天机器人的优势,这些聊天机器人可根据您的特定需求和数据隐私要求进行定制。


先决条件

在进行设置之前,请确保您已满足以下先决条件:

  • Python 3:Python 是一种多功能编程语言,您可以使用它来编写 RAG 应用程序的代码。

  • ChromaDB:一个用于存储和管理我们数据嵌入的矢量数据库。

  • Ollama:在我们的本地机器上下载并提供定制的 LLM。

步骤 1:安装 Python 3 并设置环境

要安装并设置我们的 Python 3 环境,请按照以下步骤操作:在你的机器上
下载并设置 Python 3。
然后确保你的 Python 3 已安装并成功运行:



$ python3 --version
# Python 3.11.7


Enter fullscreen mode Exit fullscreen mode

为您的项目创建一个文件夹,例如local-rag



$ mkdir local-rag
$ cd local-rag


Enter fullscreen mode Exit fullscreen mode

创建一个名为的虚拟环境venv



$ python3 -m venv venv


Enter fullscreen mode Exit fullscreen mode

激活虚拟环境:



$ source venv/bin/activate
# Windows
# venv\Scripts\activate


Enter fullscreen mode Exit fullscreen mode

第 2 步:安装 ChromaDB 和其他依赖项

使用 pip 安装 ChromaDB:



$ pip install --q chromadb


Enter fullscreen mode Exit fullscreen mode

安装 Langchain 工具以与您的模型无缝协作:



$ pip install --q unstructured langchain langchain-text-splitters
$ pip install --q "unstructured[all-docs]"


Enter fullscreen mode Exit fullscreen mode

安装 Flask 以将您的应用作为 HTTP 服务提供:



$ pip install --q flask


Enter fullscreen mode Exit fullscreen mode

步骤3:安装Ollama

要安装 Ollama,请按照以下步骤操作:
前往Ollama 下载页面,下载适用于您操作系统的安装程序。
运行以下命令验证您的 Ollama 安装:



$ ollama --version
# ollama version is 0.1.47


Enter fullscreen mode Exit fullscreen mode

提取你需要的 LLM 模型。例如,要使用 Mistral 模型:



$ ollama pull mistral


Enter fullscreen mode Exit fullscreen mode

拉取文本嵌入模型。例如,要使用 Nomic Embed Text 模型:



$ ollama pull nomic-embed-text


Enter fullscreen mode Exit fullscreen mode

然后运行你的 Ollama 模型:



$ ollama serve


Enter fullscreen mode Exit fullscreen mode

构建 RAG 应用

现在您已经使用 Python、Ollama、ChromaDB 和其他依赖项设置了环境,接下来就可以构建自定义的本地 RAG 应用了。在本节中,我们将逐步讲解 Python 代码,并概述如何构建您的应用程序。

app.py

这是 Flask 应用程序的主文件。它定义了将文件嵌入到矢量数据库以及从模型中检索响应的路由。



import os
from dotenv import load_dotenv

load_dotenv()

from flask import Flask, request, jsonify
from embed import embed
from query import query
from get_vector_db import get_vector_db

TEMP_FOLDER = os.getenv('TEMP_FOLDER', './_temp')
os.makedirs(TEMP_FOLDER, exist_ok=True)

app = Flask(__name__)

@app.route('/embed', methods=['POST'])
def route_embed():
    if 'file' not in request.files:
        return jsonify({"error": "No file part"}), 400

    file = request.files['file']

    if file.filename == '':
        return jsonify({"error": "No selected file"}), 400

    embedded = embed(file)

    if embedded:
        return jsonify({"message": "File embedded successfully"}), 200

    return jsonify({"error": "File embedded unsuccessfully"}), 400

@app.route('/query', methods=['POST'])
def route_query():
    data = request.get_json()
    response = query(data.get('query'))

    if response:
        return jsonify({"message": response}), 200

    return jsonify({"error": "Something went wrong"}), 400

if __name__ == '__main__':
    app.run(host="0.0.0.0", port=8080, debug=True)




Enter fullscreen mode Exit fullscreen mode

embed.py

该模块处理嵌入过程,包括保存上传的文件、加载和拆分数据以及将文档添加到矢量数据库。



import os
from datetime import datetime
from werkzeug.utils import secure_filename
from langchain_community.document_loaders import UnstructuredPDFLoader
from langchain_text_splitters import RecursiveCharacterTextSplitter
from get_vector_db import get_vector_db

TEMP_FOLDER = os.getenv('TEMP_FOLDER', './_temp')

# Function to check if the uploaded file is allowed (only PDF files)
def allowed_file(filename):
    return '.' in filename and filename.rsplit('.', 1)[1].lower() in {'pdf'}

# Function to save the uploaded file to the temporary folder
def save_file(file):
    # Save the uploaded file with a secure filename and return the file path
    ct = datetime.now()
    ts = ct.timestamp()
    filename = str(ts) + "_" + secure_filename(file.filename)
    file_path = os.path.join(TEMP_FOLDER, filename)
    file.save(file_path)

    return file_path

# Function to load and split the data from the PDF file
def load_and_split_data(file_path):
    # Load the PDF file and split the data into chunks
    loader = UnstructuredPDFLoader(file_path=file_path)
    data = loader.load()
    text_splitter = RecursiveCharacterTextSplitter(chunk_size=7500, chunk_overlap=100)
    chunks = text_splitter.split_documents(data)

    return chunks

# Main function to handle the embedding process
def embed(file):
    # Check if the file is valid, save it, load and split the data, add to the database, and remove the temporary file
    if file.filename != '' and file and allowed_file(file.filename):
        file_path = save_file(file)
        chunks = load_and_split_data(file_path)
        db = get_vector_db()
        db.add_documents(chunks)
        db.persist()
        os.remove(file_path)

        return True

    return False


Enter fullscreen mode Exit fullscreen mode

query.py

该模块通过生成查询的多个版本、检索相关文档并根据上下文提供答案来处理用户查询。



import os
from langchain_community.chat_models import ChatOllama
from langchain.prompts import ChatPromptTemplate, PromptTemplate
from langchain_core.output_parsers import StrOutputParser
from langchain_core.runnables import RunnablePassthrough
from langchain.retrievers.multi_query import MultiQueryRetriever
from get_vector_db import get_vector_db

LLM_MODEL = os.getenv('LLM_MODEL', 'mistral')

# Function to get the prompt templates for generating alternative questions and answering based on context
def get_prompt():
    QUERY_PROMPT = PromptTemplate(
        input_variables=["question"],
        template="""You are an AI language model assistant. Your task is to generate five
        different versions of the given user question to retrieve relevant documents from
        a vector database. By generating multiple perspectives on the user question, your
        goal is to help the user overcome some of the limitations of the distance-based
        similarity search. Provide these alternative questions separated by newlines.
        Original question: {question}""",
    )

    template = """Answer the question based ONLY on the following context:
    {context}
    Question: {question}
    """

    prompt = ChatPromptTemplate.from_template(template)

    return QUERY_PROMPT, prompt

# Main function to handle the query process
def query(input):
    if input:
        # Initialize the language model with the specified model name
        llm = ChatOllama(model=LLM_MODEL)
        # Get the vector database instance
        db = get_vector_db()
        # Get the prompt templates
        QUERY_PROMPT, prompt = get_prompt()

        # Set up the retriever to generate multiple queries using the language model and the query prompt
        retriever = MultiQueryRetriever.from_llm(
            db.as_retriever(), 
            llm,
            prompt=QUERY_PROMPT
        )

        # Define the processing chain to retrieve context, generate the answer, and parse the output
        chain = (
            {"context": retriever, "question": RunnablePassthrough()}
            | prompt
            | llm
            | StrOutputParser()
        )

        response = chain.invoke(input)

        return response

    return None



Enter fullscreen mode Exit fullscreen mode

get_vector_db.py

该模块初始化并返回用于存储和检索文档嵌入的向量数据库实例。



import os
from langchain_community.embeddings import OllamaEmbeddings
from langchain_community.vectorstores.chroma import Chroma

CHROMA_PATH = os.getenv('CHROMA_PATH', 'chroma')
COLLECTION_NAME = os.getenv('COLLECTION_NAME', 'local-rag')
TEXT_EMBEDDING_MODEL = os.getenv('TEXT_EMBEDDING_MODEL', 'nomic-embed-text')

def get_vector_db():
    embedding = OllamaEmbeddings(model=TEXT_EMBEDDING_MODEL,show_progress=True)

    db = Chroma(
        collection_name=COLLECTION_NAME,
        persist_directory=CHROMA_PATH,
        embedding_function=embedding
    )

    return db


Enter fullscreen mode Exit fullscreen mode

运行你的应用程序!

创建.env文件来存储您的环境变量:



TEMP_FOLDER = './_temp'
CHROMA_PATH = 'chroma'
COLLECTION_NAME = 'local-rag'
LLM_MODEL = 'mistral'
TEXT_EMBEDDING_MODEL = 'nomic-embed-text'


Enter fullscreen mode Exit fullscreen mode

运行该app.py文件来启动您的应用服务器:



$ python3 app.py


Enter fullscreen mode Exit fullscreen mode

服务器运行后,您可以开始向以下端点发出请求:

  • 嵌入 PDF 文件的示例命令(例如 resume.pdf):```bash

$ curl --request POST \
--url http://localhost:8080/embed \
--header 'Content-Type: multipart/form-data' \
--form file=@/Users/nassermaronie/Documents/Nasser-resume.pdf

回复

{
"message": "文件嵌入成功"
}

- Example command to ask a question to your model:
```bash


$ curl --request POST \
  --url http://localhost:8080/query \
  --header 'Content-Type: application/json' \
  --data '{ "query": "Who is Nasser?" }'

# Response
{
  "message": "Nasser Maronie is a Full Stack Developer with experience in web and mobile app development. He has worked as a Lead Full Stack Engineer at Ulventech, a Senior Full Stack Engineer at Speedoc, a Senior Frontend Engineer at Irvins, and a Software Engineer at Tokopedia. His tech stacks include Typescript, ReactJS, VueJS, React Native, NodeJS, PHP, Golang, Python, MySQL, PostgresQL, MongoDB, Redis, AWS, Firebase, and Supabase. He has a Bachelor's degree in Information System from Universitas Amikom Yogyakarta."
}


Enter fullscreen mode Exit fullscreen mode

结论

按照这些说明,您可以根据自己的需求,使用 Python、Ollama 和 ChromaDB 高效地运行自定义本地 RAG 应用并与之交互。您可以根据需要调整和扩展功能,以增强应用程序的性能。

利用本地部署的功能,您不仅可以保护敏感信息,还可以优化性能和响应速度。无论您是要增强客户互动还是简化内部流程,本地部署的 RAG 应用程序都能提供灵活性和稳健性,以适应并满足您的需求。

检查此 repo 中的源代码:

https://github.com/firstpersoncode/local-rag

编码愉快!

文章来源:https://dev.to/nassermaronie/build-your-own-rag-app-a-step-by-step-guide-to-setup-llm-locally-using-ollama-python-and-chromadb-b12
PREV
俄罗斯黑客攻击我的网站的六种方式 俄罗斯黑客攻击我的网站的六种方式
NEXT
每个软件开发人员都应该写博客