Trong thời đại mà quyền riêng tư dữ liệu được đặt lên hàng đầu, việc thiết lập mô hình ngôn ngữ địa phương (LLM) của riêng bạn sẽ cung cấp một giải pháp quan trọng cho cả các công ty và cá nhân. Hướng dẫn này được thiết kế để hướng dẫn bạn trong quá trình tạo chatbot tùy chỉnh bằng Ollama , Python 3 và ChromaDB , tất cả đều được lưu trữ cục bộ trên hệ thống của bạn. Dưới đây là những lý do chính tại sao bạn cần hướng dẫn này:
Hướng dẫn này sẽ giúp bạn xây dựng một chatbot cục bộ mạnh mẽ và an toàn, phù hợp với nhu cầu của bạn mà không ảnh hưởng đến quyền riêng tư hoặc quyền kiểm soát.
Tạo tăng cường truy xuất (RAG) là một kỹ thuật tiên tiến kết hợp các điểm mạnh của truy xuất thông tin và tạo văn bản để tạo ra các phản hồi chính xác hơn và phù hợp với ngữ cảnh hơn. Dưới đây là bảng phân tích cách thức hoạt động của RAG và lý do nó mang lại lợi ích:
RAG là một mô hình lai giúp nâng cao khả năng của các mô hình ngôn ngữ bằng cách kết hợp cơ sở tri thức bên ngoài hoặc kho tài liệu. Quá trình này bao gồm hai thành phần chính:
Bằng cách thiết lập ứng dụng RAG cục bộ bằng các công cụ như Ollama, Python và ChromaDB, bạn có thể tận hưởng lợi ích của các mô hình ngôn ngữ nâng cao trong khi vẫn duy trì quyền kiểm soát dữ liệu và các tùy chọn tùy chỉnh của mình.
Việc chạy các mô hình ngôn ngữ lớn (LLM) giống như các mô hình được sử dụng trong Thế hệ tăng cường truy xuất (RAG) đòi hỏi sức mạnh tính toán đáng kể. Một trong những thành phần chính cho phép xử lý và nhúng dữ liệu hiệu quả trong các mô hình này là Bộ xử lý đồ họa (GPU). Đây là lý do tại sao GPU lại cần thiết cho nhiệm vụ này và cách chúng tác động đến hiệu suất thiết lập LLM cục bộ của bạn:
GPU là bộ xử lý chuyên dụng được thiết kế để tăng tốc độ hiển thị hình ảnh và video. Không giống như Bộ xử lý trung tâm (CPU), được tối ưu hóa cho các tác vụ xử lý tuần tự, GPU vượt trội ở khả năng xử lý song song. Điều này làm cho chúng đặc biệt phù hợp với các tính toán toán học phức tạp được yêu cầu bởi các mô hình học máy và học sâu.
Khi thiết lập LLM cục bộ, việc lựa chọn GPU có thể ảnh hưởng đáng kể đến hiệu suất. Dưới đây là một số yếu tố cần xem xét:
Đầu tư vào GPU hiệu suất cao là rất quan trọng để chạy các mô hình LLM cục bộ. Nó đảm bảo xử lý dữ liệu nhanh hơn, đào tạo mô hình hiệu quả và tạo phản hồi nhanh, giúp ứng dụng RAG cục bộ của bạn trở nên mạnh mẽ và đáng tin cậy hơn. Bằng cách tận dụng sức mạnh của GPU, bạn hoàn toàn có thể nhận ra lợi ích của việc lưu trữ chatbot tùy chỉnh của riêng mình, phù hợp với nhu cầu cụ thể và yêu cầu về quyền riêng tư dữ liệu của bạn.
Trước khi đi sâu vào thiết lập, hãy đảm bảo bạn có sẵn các điều kiện tiên quyết sau:
Để cài đặt và thiết lập môi trường Python 3 của chúng tôi, hãy làm theo các bước sau: Tải xuống và thiết lập Python 3 trên máy của bạn. Sau đó, hãy đảm bảo Python 3 của bạn đã được cài đặt và chạy thành công:
$ python3 --version # Python 3.11.7
Tạo một thư mục cho dự án của bạn, ví dụ: local-rag
:
$ mkdir local-rag $ cd local-rag
Tạo một môi trường ảo có tên venv
:
$ python3 -m venv venv
Kích hoạt môi trường ảo:
$ source venv/bin/activate # Windows # venv\Scripts\activate
Cài đặt ChromaDB bằng pip:
$ pip install --q chromadb
Cài đặt các công cụ Langchain để hoạt động liền mạch với mô hình của bạn:
$ pip install --q unstructured langchain langchain-text-splitters $ pip install --q "unstructured[all-docs]"
Cài đặt Flask để phân phát ứng dụng của bạn dưới dạng dịch vụ HTTP:
$ pip install --q flask
Để cài đặt Ollama, hãy làm theo các bước sau: Đi tới trang tải xuống Ollama và tải xuống trình cài đặt cho hệ điều hành của bạn. Xác minh cài đặt Ollama của bạn bằng cách chạy:
$ ollama --version # ollama version is 0.1.47
Kéo mô hình LLM bạn cần. Ví dụ: để sử dụng mô hình Mistral:
$ ollama pull mistral
Kéo mô hình nhúng văn bản. Ví dụ: để sử dụng mô hình Văn bản nhúng Nomic:
$ ollama pull nomic-embed-text
Sau đó chạy mô hình Ollama của bạn:
$ ollama serve
Bây giờ bạn đã thiết lập môi trường của mình bằng Python, Ollama, ChromaDB và các phần phụ thuộc khác, đã đến lúc xây dựng ứng dụng RAG cục bộ tùy chỉnh của bạn. Trong phần này, chúng ta sẽ tìm hiểu mã Python thực hành và cung cấp cái nhìn tổng quan về cách cấu trúc ứng dụng của bạn.
app.py
Đây là tệp ứng dụng Flask chính. Nó xác định các tuyến để nhúng tệp vào cơ sở dữ liệu vectơ và truy xuất phản hồi từ mô hình.
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)
embed.py
Mô-đun này xử lý quá trình nhúng, bao gồm lưu các tệp đã tải lên, tải và chia tách dữ liệu cũng như thêm tài liệu vào cơ sở dữ liệu vectơ.
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
query.py
Mô-đun này xử lý các truy vấn của người dùng bằng cách tạo ra nhiều phiên bản của truy vấn, truy xuất các tài liệu liên quan và cung cấp câu trả lời dựa trên ngữ cảnh.
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
get_vector_db.py
Mô-đun này khởi tạo và trả về phiên bản cơ sở dữ liệu vectơ được sử dụng để lưu trữ và truy xuất các phần nhúng tài liệu.
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
Tạo tệp .env
để lưu trữ các biến môi trường của bạn:
TEMP_FOLDER = './_temp' CHROMA_PATH = 'chroma' COLLECTION_NAME = 'local-rag' LLM_MODEL = 'mistral' TEXT_EMBEDDING_MODEL = 'nomic-embed-text'
Chạy tệp app.py
để khởi động máy chủ ứng dụng của bạn:
$ python3 app.py
Khi máy chủ đang chạy, bạn có thể bắt đầu thực hiện yêu cầu tới các điểm cuối sau:
$ curl --request POST \ --url http://localhost:8080/embed \ --header 'Content-Type: multipart/form-data' \ --form file=@/Users/nassermaronie/Documents/Nasser-resume.pdf # Response { "message": "File embedded successfully" }
$ 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." }
Bằng cách làm theo các hướng dẫn này, bạn có thể chạy và tương tác một cách hiệu quả với ứng dụng RAG cục bộ tùy chỉnh của mình bằng Python, Ollama và ChromaDB, phù hợp với nhu cầu của bạn. Điều chỉnh và mở rộng chức năng khi cần thiết để nâng cao khả năng của ứng dụng của bạn.
Bằng cách khai thác khả năng triển khai cục bộ, bạn không chỉ bảo vệ thông tin nhạy cảm mà còn tối ưu hóa hiệu suất và khả năng phản hồi. Cho dù bạn đang tăng cường tương tác với khách hàng hay hợp lý hóa các quy trình nội bộ, ứng dụng RAG được triển khai cục bộ sẽ mang lại sự linh hoạt và mạnh mẽ để thích ứng và phát triển theo yêu cầu của bạn.
https://github.com/firstpersoncode/local-rag
Chúc mừng mã hóa!