Büyük Dil Modellerinin yükselişi ve etkileyici yetenekleriyle birlikte, OpenAI ve Anthropic gibi dev LLM sağlayıcılarının üzerine birçok süslü uygulama inşa ediliyor. Bu tür uygulamaların arkasındaki efsane, aşağıdaki makalelerde ayrıntılı olarak açıklanan RAG çerçevesidir:
RAG'a aşina olmak için bu makalelere göz atmanızı öneririm. Ancak bu yazı, temel bilgileri atlayacak ve veri gizliliği ve belirteç maliyeti konusunda herhangi bir endişe duymadan dizüstü bilgisayarınızda yerel olarak çalışabilen kendi RAG uygulamanızı oluşturma konusunda size doğrudan rehberlik edecektir.
ChatPD F'ye benzer fakat daha basit bir uygulama geliştireceğiz. Kullanıcıların basit bir kullanıcı arayüzü aracılığıyla bir PDF belgesi yükleyebileceği ve soru sorabileceği yer. Langchain, Ollama ve Streamlit ile teknoloji yığınımız son derece kolaydır.
Tamam, ayarlamaya başlayalım.
Yukarıda belirtildiği gibi Ollama'yı kurmak ve çalıştırmak basittir. İlk ziyaret
Daha sonra terminalinizi açın ve en son sürümü almak için aşağıdaki komutu uygulayın.
ollama pull mistral
Daha sonra modelin doğru şekilde çekilip çekilmediğini doğrulamak için ollama list
çalıştırın. Terminal çıkışı aşağıdakine benzemelidir:
Şimdi, eğer LLM sunucusu halihazırda çalışmıyorsa, onu ollama serve
ile başlatın. "Error: listen tcp 127.0.0.1:11434: bind: address already in use"
gibi bir hata mesajıyla karşılaşırsanız bu, sunucunun zaten varsayılan olarak çalıştığını gösterir ve bir sonraki adıma geçebilirsiniz.
Sürecimizdeki ikinci adım RAG boru hattını inşa etmektir. Uygulamamızın basitliği göz önüne alındığında öncelikle iki yönteme ihtiyacımız var: ingest
ve ask
.
ingest
yöntemi bir dosya yolunu kabul eder ve bunu iki adımda vektör depolama alanına yükler: ilk olarak, LLM'nin belirteç sınırına uyum sağlamak için belgeyi daha küçük parçalara böler; ikincisi, Qdrant FastEmbeddings'i kullanarak bu parçaları vektörleştirir ve Chroma'da saklar.
ask
yöntemi kullanıcı sorgularını yönetir. Kullanıcılar bir soru sorabilir ve ardından RetrievalQAChain, vektör benzerliği arama tekniklerini kullanarak ilgili bağlamları (belge parçaları) alır.
Kullanıcının sorusu ve alınan bağlamlarla bir istem oluşturabilir ve LLM sunucusundan bir tahmin talep edebiliriz.
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
Bilgi istemi Langchain merkezinden alınmıştır:
Yüksek Lisans yönlendirme teknikleri hakkında daha fazla bilgi edinebilirsiniz
Uygulamaya ilişkin daha fazla ayrıntı:
ingest
: Kullanıcı tarafından yüklenen PDF dosyasını yüklemek için PyPDFLoader kullanıyoruz. Langchain tarafından sağlanan RecursiveCharacterSplitter daha sonra bu PDF'yi daha küçük parçalara böler. Langchain'in filter_complex_metadata
işlevini kullanarak ChromaDB tarafından desteklenmeyen karmaşık meta verileri filtrelemek önemlidir.
Vektör depolama için Chroma ile birlikte kullanılır
ask
: Bu yöntem kullanıcının sorusunu önceden tanımlanmış zincirimize iletir ve ardından sonucu döndürür.
clear
: Bu yöntem, yeni bir PDF dosyası yüklendiğinde önceki sohbet oturumunu ve depolama alanını temizlemek için kullanılır. Basit bir kullanıcı arayüzü için kullanacağız
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()
Nasıl göründüğünü görmek için bu kodu streamlit run app.py
komutuyla çalıştırın.
Tamam, işte bu! Artık tamamen dizüstü bilgisayarınızda çalışan bir ChatPDF uygulamamız var. Bu yazı esas olarak kendi RAG uygulamanızı nasıl oluşturacağınıza dair üst düzey bir genel bakış sağlamaya odaklandığından, ince ayar yapılması gereken çeşitli yönler vardır. Uygulamanızı geliştirmek ve becerilerinizi daha da geliştirmek için aşağıdaki önerileri dikkate alabilirsiniz:
Son olarak okuduğunuz için teşekkür ederim. Bu bilgiyi yararlı bulursanız, lütfen abone olmayı düşünün.
Tam kaynak kodu: