paint-brush
Hướng dẫn về cách xây dựng RAG của riêng bạn và cách chạy nó cục bộ: Langchain + Ollama + Streamlittừ tác giả@vndee
6,983 lượt đọc
6,983 lượt đọc

Hướng dẫn về cách xây dựng RAG của riêng bạn và cách chạy nó cục bộ: Langchain + Ollama + Streamlit

từ tác giả Duy Huynh8m2023/12/15
Read on Terminal Reader

dài quá đọc không nổi

Để làm quen với RAG, tôi khuyên bạn nên xem qua các bài viết này. Tuy nhiên, bài đăng này sẽ bỏ qua những điều cơ bản và hướng dẫn bạn trực tiếp cách xây dựng ứng dụng RAG của riêng bạn có thể chạy cục bộ trên máy tính xách tay của bạn mà không phải lo lắng về quyền riêng tư dữ liệu và chi phí mã thông báo. Chúng tôi sẽ xây dựng một ứng dụng tương tự như ChatPDF nhưng đơn giản hơn. Nơi người dùng có thể tải lên tài liệu PDF và đặt câu hỏi thông qua giao diện người dùng đơn giản. Kho công nghệ của chúng tôi cực kỳ dễ dàng với Langchain, Ollama và Streamlit.
featured image - Hướng dẫn về cách xây dựng RAG của riêng bạn và cách chạy nó cục bộ: Langchain + Ollama + Streamlit
Duy Huynh HackerNoon profile picture

Với sự nổi lên của Mô hình ngôn ngữ lớn và khả năng ấn tượng của chúng, nhiều ứng dụng ưa thích đang được xây dựng dựa trên các nhà cung cấp LLM khổng lồ như OpenAI và Anthropic. Huyền thoại đằng sau những ứng dụng như vậy là khung RAG, đã được giải thích kỹ lưỡng trong các bài viết sau:


Để làm quen với RAG, tôi khuyên bạn nên xem qua các bài viết này. Tuy nhiên, bài đăng này sẽ bỏ qua những điều cơ bản và hướng dẫn bạn trực tiếp cách xây dựng ứng dụng RAG của riêng bạn có thể chạy cục bộ trên máy tính xách tay của bạn mà không phải lo lắng về quyền riêng tư dữ liệu và chi phí mã thông báo.


Chúng tôi sẽ xây dựng một ứng dụng tương tự như ChatPD F nhưng đơn giản hơn. Nơi người dùng có thể tải lên tài liệu PDF và đặt câu hỏi thông qua giao diện người dùng đơn giản. Kho công nghệ của chúng tôi cực kỳ dễ dàng với Langchain, Ollama và Streamlit.

  • Máy chủ LLM : Thành phần quan trọng nhất của ứng dụng này là máy chủ LLM. Nhờ vào Ollama , chúng tôi có Máy chủ LLM mạnh mẽ có thể được thiết lập cục bộ, ngay cả trên máy tính xách tay. Trong khi llama.cpp là một tùy chọn, tôi thấy Ollama, được viết bằng Go, dễ thiết lập và chạy hơn.


  • RAG : Không còn nghi ngờ gì nữa, hai thư viện hàng đầu trong miền LLM là chuỗi lang LlamChỉ số . Đối với dự án này, tôi sẽ sử dụng Langchain do tôi đã quen với nó nhờ kinh nghiệm chuyên môn của mình. Một thành phần thiết yếu của bất kỳ khung RAG nào là lưu trữ vectơ. Chúng tôi sẽ sử dụng sắc độ ở đây vì nó tích hợp tốt với Langchain.


  • Giao diện người dùng trò chuyện : Giao diện người dùng cũng là một thành phần quan trọng. Mặc dù có sẵn nhiều công nghệ nhưng tôi thích sử dụng hơn Tinh giản , một thư viện Python, để bạn yên tâm.


Được rồi, hãy bắt đầu thiết lập nó.

Thiết lập Ollama

Như đã đề cập ở trên, việc thiết lập và chạy Ollama rất đơn giản. Lân đâu tơi thăm ollama.ai và tải xuống ứng dụng phù hợp với hệ điều hành của bạn.


Tiếp theo, mở terminal của bạn và thực hiện lệnh sau để lấy phiên bản mới nhất Mistral-7B . Trong khi có nhiều thứ khác Các mẫu LLM có sẵn , Tôi chọn Mistral-7B vì kích thước nhỏ gọn và chất lượng cạnh tranh.


 ollama pull mistral


Sau đó, chạy ollama list để xác minh xem mô hình có được kéo chính xác hay không. Đầu ra của thiết bị đầu cuối sẽ giống như sau:

Bây giờ, nếu máy chủ LLM chưa chạy, hãy khởi chạy nó bằng ollama serve . Nếu bạn gặp thông báo lỗi như "Error: listen tcp 127.0.0.1:11434: bind: address already in use" , điều đó cho biết máy chủ đã chạy theo mặc định và bạn có thể tiến hành bước tiếp theo.

Xây dựng đường ống RAG

Bước thứ hai trong quy trình của chúng tôi là xây dựng đường dẫn RAG. Do ứng dụng của chúng tôi đơn giản nên chúng tôi chủ yếu cần hai phương thức: ingestask .


Phương thức ingest vào chấp nhận đường dẫn tệp và tải nó vào bộ lưu trữ vectơ theo hai bước: đầu tiên, nó chia tài liệu thành các phần nhỏ hơn để đáp ứng giới hạn mã thông báo của LLM; thứ hai, nó vector hóa các khối này bằng cách sử dụng Qdrant FastEmbeddings và lưu trữ chúng vào Chroma.


Phương thức ask xử lý các truy vấn của người dùng. Người dùng có thể đặt câu hỏi và sau đó RetrievalQAChain truy xuất các ngữ cảnh có liên quan (các đoạn tài liệu) bằng cách sử dụng các kỹ thuật tìm kiếm tương tự vectơ.


Với câu hỏi của người dùng và bối cảnh được truy xuất, chúng tôi có thể soạn lời nhắc và yêu cầu dự đoán từ máy chủ LLM.

 from langchain.vectorstores import Chroma from langchain.chat_models import ChatOllama from langchain.embeddings import FastEmbedEmbeddings from langchain.schema.output_parser import StrOutputParser from langchain.document_loaders import PyPDFLoader from langchain.text_splitter import RecursiveCharacterTextSplitter from langchain.schema.runnable import RunnablePassthrough from langchain.prompts import PromptTemplate from langchain.vectorstores.utils import filter_complex_metadata class ChatPDF: vector_store = None retriever = None chain = None def __init__(self): self.model = ChatOllama(model="mistral") self.text_splitter = RecursiveCharacterTextSplitter(chunk_size=1024, chunk_overlap=100) self.prompt = PromptTemplate.from_template( """ <s> [INST] You are an assistant for question-answering tasks. Use the following pieces of retrieved context to answer the question. If you don't know the answer, just say that you don't know. Use three sentences maximum and keep the answer concise. [/INST] </s> [INST] Question: {question} Context: {context} Answer: [/INST] """ ) def ingest(self, pdf_file_path: str): docs = PyPDFLoader(file_path=pdf_file_path).load() chunks = self.text_splitter.split_documents(docs) chunks = filter_complex_metadata(chunks) vector_store = Chroma.from_documents(documents=chunks, embedding=FastEmbedEmbeddings()) self.retriever = vector_store.as_retriever( search_type="similarity_score_threshold", search_kwargs={ "k": 3, "score_threshold": 0.5, }, ) self.chain = ({"context": self.retriever, "question": RunnablePassthrough()} | self.prompt | self.model | StrOutputParser()) def ask(self, query: str): if not self.chain: return "Please, add a PDF document first." return self.chain.invoke(query) def clear(self): self.vector_store = None self.retriever = None self.chain = None

Lời nhắc có nguồn gốc từ trung tâm Langchain: Lời nhắc của Langchain RAG cho Mistral . Lời nhắc này đã được thử nghiệm và tải xuống hàng nghìn lần, đóng vai trò là nguồn tài nguyên đáng tin cậy để tìm hiểu về các kỹ thuật nhắc nhở LLM.


Bạn có thể tìm hiểu thêm về kỹ thuật nhắc LLM đây .


Thêm chi tiết về việc thực hiện:


  • ingest : Chúng tôi sử dụng PyPDFLoader để tải tệp PDF do người dùng tải lên. RecursiveCharacterSplitter, do Langchain cung cấp, sau đó chia tệp PDF này thành các phần nhỏ hơn. Điều quan trọng là phải lọc ra siêu dữ liệu phức tạp không được ChromaDB hỗ trợ bằng cách sử dụng hàm filter_complex_metadata từ Langchain.


    Để lưu trữ vector, Chroma được sử dụng kết hợp với Qdrant FastNhúng như mô hình nhúng của chúng tôi. Sau đó, mô hình nhẹ này được biến thành một chú chó tha mồi có ngưỡng điểm là 0,5 và k=3, nghĩa là nó trả về 3 khối hàng đầu có điểm cao nhất trên 0,5. Cuối cùng, chúng ta xây dựng một chuỗi hội thoại đơn giản bằng cách sử dụng LECL .


  • ask : Phương thức này chỉ đơn giản chuyển câu hỏi của người dùng vào chuỗi được xác định trước của chúng tôi và sau đó trả về kết quả.


  • clear : Phương pháp này được sử dụng để xóa phiên trò chuyện và bộ nhớ trước đó khi tệp PDF mới được tải lên.

Dự thảo một giao diện người dùng đơn giản

Để có giao diện người dùng đơn giản, chúng tôi sẽ sử dụng Tinh giản , một khung giao diện người dùng được thiết kế để tạo nguyên mẫu nhanh các ứng dụng AI/ML.

 import os import tempfile import streamlit as st from streamlit_chat import message from rag import ChatPDF st.set_page_config(page_title="ChatPDF") def display_messages(): st.subheader("Chat") for i, (msg, is_user) in enumerate(st.session_state["messages"]): message(msg, is_user=is_user, key=str(i)) st.session_state["thinking_spinner"] = st.empty() def process_input(): if st.session_state["user_input"] and len(st.session_state["user_input"].strip()) > 0: user_text = st.session_state["user_input"].strip() with st.session_state["thinking_spinner"], st.spinner(f"Thinking"): agent_text = st.session_state["assistant"].ask(user_text) st.session_state["messages"].append((user_text, True)) st.session_state["messages"].append((agent_text, False)) def read_and_save_file(): st.session_state["assistant"].clear() st.session_state["messages"] = [] st.session_state["user_input"] = "" for file in st.session_state["file_uploader"]: with tempfile.NamedTemporaryFile(delete=False) as tf: tf.write(file.getbuffer()) file_path = tf.name with st.session_state["ingestion_spinner"], st.spinner(f"Ingesting {file.name}"): st.session_state["assistant"].ingest(file_path) os.remove(file_path) def page(): if len(st.session_state) == 0: st.session_state["messages"] = [] st.session_state["assistant"] = ChatPDF() st.header("ChatPDF") st.subheader("Upload a document") st.file_uploader( "Upload document", type=["pdf"], key="file_uploader", on_change=read_and_save_file, label_visibility="collapsed", accept_multiple_files=True, ) st.session_state["ingestion_spinner"] = st.empty() display_messages() st.text_input("Message", key="user_input", on_change=process_input) if __name__ == "__main__": page()


Chạy mã này bằng lệnh streamlit run app.py để xem nó trông như thế nào.

Được rồi, thế thôi! Hiện chúng tôi có ứng dụng ChatPDF chạy hoàn toàn trên máy tính xách tay của bạn. Vì bài đăng này chủ yếu tập trung vào việc cung cấp cái nhìn tổng quan cấp cao về cách xây dựng ứng dụng RAG của riêng bạn nên có một số khía cạnh cần tinh chỉnh. Bạn có thể xem xét các đề xuất sau để nâng cao ứng dụng của mình và phát triển hơn nữa các kỹ năng của mình:


  • Thêm bộ nhớ vào chuỗi hội thoại : Hiện tại, nó không ghi nhớ luồng hội thoại. Việc thêm bộ nhớ tạm thời sẽ giúp trợ lý của bạn nhận biết được ngữ cảnh.


  • Cho phép tải lên nhiều tệp : bạn có thể trò chuyện về một tài liệu cùng một lúc. Nhưng hãy tưởng tượng nếu chúng ta có thể trò chuyện về nhiều tài liệu - bạn có thể đặt toàn bộ giá sách của mình vào đó. Điều đó sẽ cực kỳ tuyệt vời!


  • Sử dụng các Mô hình LLM khác : Mặc dù Mistral có hiệu quả nhưng vẫn có nhiều lựa chọn thay thế khác. Bạn có thể tìm thấy một mô hình phù hợp hơn với nhu cầu của mình, chẳng hạn như LlamaCode dành cho nhà phát triển. Tuy nhiên, hãy nhớ rằng việc lựa chọn model phụ thuộc vào phần cứng của bạn, đặc biệt là dung lượng RAM bạn có 💵


  • Tăng cường Đường ống RAG : Có chỗ để thử nghiệm trong RAG. Bạn có thể muốn thay đổi số liệu truy xuất, mô hình nhúng,.. hoặc thêm các lớp như trình xếp hạng lại để cải thiện kết quả.


Cuối cùng, cảm ơn bạn đã đọc. Nếu bạn thấy thông tin này hữu ích, vui lòng cân nhắc đăng ký kênh của tôi Ngăn xếp phụ hoặc cá nhân của tôi Blog . Tôi dự định viết thêm về các ứng dụng RAG và LLM và bạn có thể đề xuất chủ đề bằng cách để lại nhận xét bên dưới. Chúc mừng!


Mã nguồn đầy đủ: https://github.com/vndee/local-rag-example