📱

Get Our Mobile App

Take your business learning on the go!

Download on the App StoreGet it on Google Play

КАК СОЗДАТЬ СВОЙ RAG?! | LangChain + Python

AI RANEZ22:49

Transcription

Greetings. Today we will create our own RAG from scratch in Python. I will show you the process of creating this system from A to Z, including setting up all API keys, virtual environments, all databases, and so on. For those who are not new to the channel, you are already familiar with the fact that I try to explain and show everything as thoroughly as possible so that it is maximally clear to you. The material is super cool, I can say, worth its weight in gold, so watch until the end and delve into it. For those who are not familiar with RAG, I highly recommend watching my previous video. I will leave the link in the description under this video. I explained in detail what RAG is, how it all works. Everything step-by-step, a step at a time. The video turned out to be super cool, everything is super detailed, so I highly recommend you watch it if you are not familiar with RAG before starting this video. And we begin. So, today we will create a RAG system using Langchain. This is a Python library. It is quite popular for creating RAG systems. All the links you will need from this video will be in my Telegram channel. Go there too, the link will be in the description. So, Langchain is a Python library for creating RAG systems. It has a lot of functions that you might need, and it covers all the issues in creating RAG systems. Therefore, today I will be using it. There are many other libraries and services, but, in principle, Langchain is one of the most popular methods for creating all of this. Plus, it's all in Python, excellent support, many developers, everything is very cool. Therefore, today we will use Langchain. In this video, we will create a RAG for this article titled "Prompt Engineering". And yes, I want to clarify right away that the article will be in English today. And I will communicate with the LLM in English, but you can easily do all of this in Russian. It's just more convenient for me. And in principle, it is best to communicate with Large Language Models in English. For those who don't know, this video will feature a relatively simple RAG for understanding, but this approach can easily be scaled for your tasks, including business tasks. For example, if you sell your own software, product, or service online, you can create a chatbot in Telegram using this RAG that I will tell you about and show you how to do today, and upload your service descriptions in Russian to it. This could be a PDF file, a Markdown file, or again, it could all be on your website. Perhaps you already have a website where everything is written, the entire description of your product, and you simply, as I do in this video, create a RAG for your website, and a person, by going to your bot in Telegram, will be able to find out everything about your product, service, or software. For example, the coolest thing is that the LLM, when communicating with a client, will be guided by the description of your product, which, again, you uploaded in the form of a PDF, Markdown, or you do it through a website. The main feature is that if your file, i.e., the database, does not contain information about your client's question, then the chatbot can answer: "I don't know." The LLM will not make things up, it will not invent unreliable information about your product. If you are interested in the topic and want a continuation of these videos with more advanced techniques, such as Graph RAG and so on, then welcome to the comments on YouTube or in Telegram. I will definitely shoot a continuation of these video clips. So, we're done with the introduction. Let's not delay. Let's start building. I will create this in Cursor. You can use any IDE, as always. I will just work in Cursor. It's more convenient for me. If you are also going to do it in Cursor, then you just create a new file, open it through Cursor, and we begin. Let's create a file right away where we will write our API keys. In today's video, I will use the API from OpenAI. Let's create a file, let's call it api.py. Here we will create a variable OpenAI_API_KEY. And, accordingly, you need to enter your API key here. So, where can you get this API key? To do this, you need to go to platform.openai.com. Again, the link will be in the Telegram channel. You simply log into your account, top it up with at least five dollars. There is an API Keys tab. Create a new API key, and that's it, you have your API key ready, which you will use for your RAG system. So, after you have created your API key, you simply paste it here and close this file. So, we have a file with the API key from OpenAI. Here it is, api.py. Next, let's move on to the RAG code itself. For this, we create a new file named, let's call it rag_data.py. A Python file. But before we start creating the RAG, let's enable the virtual environment. This is necessary for the Langchain library, accordingly. To do this, you need to type python3 -m venv venv. Super. Press Enter. We have created a virtual environment. If you are on Windows, it's done a little differently, but the essence is the same. Next, let's activate our virtual environment. Source venv/bin/activate. Everything, we have activated our virtual environment. Super. And now we just need to import these libraries. Press Enter. And we also need to install the Beautiful Soup library. This is a library for working with, in principle, the web. We just need it today to collect information from the URL that we will specify in the document. Let's import it too. Now let's get to the code itself. In this rag_data file, we will set up our database, convert everything, and so on. I will show you everything now. First, let's import the libraries. So, let's just import the libraries. Now, accordingly, we need to load the document via URL using the BS4 library. To do this, we write bs4_strainer = BeautifulSoup. Now we are creating a strainer to load precisely the information we need, such as post titles, headers, and content, from HTML. To do this, we write post_title, post_header, and post_content. Now we need to create a data loader that will load data from the URL, which I will specify now. To do this, we write that loader = WebBaseLoader. Open parentheses. Here we write the path, i.e., the URL. So, paste the URL. Then write args=ParseArgs(chunk_size=1000, chunk_overlap=200, start_index=True). This means we want only the information that we need. Again, these are post titles, post headers, post content. This data loader needs to be saved in docs. To do this, we write docs = loader.load, i.e., load this information into docs, and we can print it. Now, as you may remember from the theoretical video on RAG, we need to split the data into chunks, into small pieces. For this, the Langchain library has special functions. Let's write them. Let's create a variable text_splitter. And there is a special function recursive_character_text_splitter. We will pass chunk_size to it. Chunk_size in this case will be 1000. Try to choose a medium chunk size, not too small and not too large. Then we will use chunk_overlap. Accordingly, we will have something like a sliding window. Our chunks will overlap slightly. This is simply for better, let's say, algorithm performance, so that we don't lose anything. And let's write start_index=True. This is simply so that the start index is remembered. Let's create a variable all_splits. Accordingly, this is text_splitter.split_documents(docs). Print("Total Splits:", len(all_splits)). Now let's move on to creating our database. In this video, I will use Chroma. In principle, it's a simple database. An excellent approach for practice, and in principle, for a normal chatbot for your product specifications, this should be enough. Let's specify our model that we will use for embeddings. The model will take this document, which we saved and split into chunks, and will convert each chunk into a vector form. That is, from each chunk in text form, because chunks consist of text initially, the model will convert them into vectors. Again, I explained this in detail in the theoretical video. Go and watch it if you don't understand, for others it should be super clear. Therefore, let's create OpenAIEmbeddings. So, in this video, I will use a small model called text-embedding-3-small. And we need to enter our OpenAI API key here. So, at the moment, it's not visible. For this, we need from api import openai_api_key. Everything, now the API key is visible. Excellent. Let's proceed to creating the Vector Store, namely our database. To do this, we write Chroma. Let's give it a collection_name, the name, let's say, of your database, roughly speaking. Let's call it "prompt_engineering". We need an embedding_function. In this case, the function will be our OpenAI model called text-embedding-3-small. And we simply give, accordingly, our model here as input. persist_directory. This is again what I talked about, where our database will be saved. It will be stored locally on my laptop. Let's just call it "chroma_db". So, here we put a comma and save everything in ids. VectorStore.from_documents(documents=all_splits, embedding=OpenAIEmbeddings(openai_api_key=openai_api_key), persist_directory="chroma_db"). We've written it. And we can print it to the screen. Confirmation that everything is saved correctly and there are no problems. So, we're done with data preparation. Let's go over what we've done one more time. First, we formatted, let's say, our URL, extracted what we needed, and saved it all into the docs variable. Loaded, used RecursiveCharacterTextSplitter. That is, we created a text splitter, we split our material, our data into chunks with a size of 1000 and a chunk overlap of 200. Saved everything. Next, we chose our model for embeddings. The model that will convert chunks, text chunks into vectors, the model text-embedding-3-small, and then our open API key. Next, we created a vector store using the Chroma database, specified the collection name, embedding function, and the directory where all of this will be stored. Saved everything and printed it. We are done with this RAG, with data preparation. Let's move on to the actual query, to building our chain, our RAG. To do this, we will create a new file, let's call it query_rag.py. Very important. Let's import all the modules we need right away, and also from api import, accordingly, our key right away, so that this doesn't bother us anymore. First, we need to load the existing vector store, i.e., our database, which contains the chunks that have already been formatted into vectors. We can simply copy this from here. vector_store = Chroma(persist_directory="chroma_db", embedding_function=OpenAIEmbeddings(openai_api_key=openai_api_key)). This is simply the specifics of how Chroma works, that the database needs to be loaded in this way. Now we need to start composing the augmented prompt. Now we will give the prompt to our LLM. Those who remember from the theoretical video, this was an instruction, so let's write the prompt. There is a special function in the Langchain library for this. And let's write our prompt. In my case, the prompt looks like this because, accordingly, the blog post is on the topic of prompt engineering. And the most important thing I add is "If you don't know the answer, just say I don't know." This is to prevent the LLM from making up any unreliable information. And if, accordingly, there is no related information, then it simply answers "I don't know." In this prompt, you should describe how the LLM should behave. That is, if you sell a product or service, you should describe it here, that it sells a product or service. Describe what kind of service. Everything should be clear and understandable. In principle, there is nothing complicated with the prompt. Next, let's choose our LLM. In this video, I will use the GPT-3.5-turbo model. It is quite inexpensive and, in principle, handles this type of task very well. And again, our OpenAI API key: OpenAI_API_KEY. Let's create a variable question. The first question will be "What is prompt engineering?" because the article is, accordingly, on prompt engineering. This way, we can check how our RAG system works. Now, to get the context that we will pass to the LLM in the augmented prompt, we need to perform a search. A search for vector comparison. That is, we have a vector from the prompt, from this question. From the question. This will also be transformed into a vector, and we will have a comparison with the vectors in the database. To do this, let's create a variable retrieve_docs. And there is a function. Let's write our database, namely vector_store. VectorStore. And in Langchain, there is a function similarity_search. This function, accordingly, compares vectors. Usually, it's either similarity or using Euclidean distance. We will compare with the question, with our prompt that the user is asking. The parameter k will be equal to three. The parameter k simply returns the most similar chunks from the database. That is, in our case, it's the three most similar chunks from our Chroma database. And let's just concatenate our chunks now. To do this, we simply write docs_content = "\n".join([d.page_content for d in retrieve_docs]). Let's create our augmented prompt. Let's call it simply message. To do this, we will add the question itself, the user's prompt, and our context to the prompt that already exists, i.e., to this prompt, and in this prompt, we have the instruction. For those who watched the theoretical video again, we had, accordingly, in the augmented prompt, the instruction, the user's prompt, and the context that is given to the LLM for a clear answer to the user. Let's save all this in the variable answer = llm.invoke(message). And let's print the answer. So, let's save all the files. So, we're done with our RAG pipeline. Let's go over it one more time. Here we simply open our existing database, give instructions to the LLM on how it should behave, who it is. We create our LLM, choose the model we will use. We give the user's prompt. Well, in our case, it's "What is prompt engineering?". Then we start searching in our database. It compares the vector of the user's prompt, i.e., the question, with the chunks that are similar, that are related to our user's question, and returns the three most suitable chunks. Then we simply concatenate and create an augmented prompt that includes the prompt, i.e., the instruction for the LLM, the question, i.e., the user's prompt, and the context, which, accordingly, we get by comparing vectors using cosine similarity or Euclidean distance. We save all this and invoke. Let's start by creating our database. We need to transform this URL into a database and transform everything into chunks and vectors. To do this, let's run our rag_data.py module. Total characters almost 30,000, Total Splits 43. And we have saved the document to our disk. We can go here to chroma_db. And here, accordingly, is our database. Super, everything works fine, everything is saved. Now we can run our query_rag.py. To do this, type python3 query_rag.py. Let's run it. We wait because the LLM is being called. And we have an answer. Look, here is the answer from the LLM. Read it, memorize it. Let's go back to our document and read this first paragraph. In principle, it's almost the same as what the LLM gave. Let's ask it something else. For example, what is self-consistency sampling? To do this, we copy, go back to Cursor. And here we simply change the question. "What is self-consistency sampling?". Let's run it again. "Self-consistency sampling is a technique to improve multiple multiple outputs with the temperature greater than zero." And so on. Let's go back to Safari. Let's read "to sample multiple outputs with temperature greater than zero. Majority." As you can see, our RAG is working quite well. As you can see, our RAG works just great. Now, to be even more convinced, we will ask a question that is not related to the topic of Prompt Engineering, to this article at all. Let's write "What is Ferrari?". Save the file and run our code, our module again. As you can see, the answer is "I don't know." This is simply because the article on Prompt Engineering does not say what Ferrari is. And again, you can see that our RAG is working great, because there is no related information in our database about what Ferrari is. The LLM answers "I don't know the answer" because it doesn't know the answer to this question, because there is no related information in the database. Again, literally about 30 lines of code here, and about 30 lines of code here, so approximately 60-70 lines of code. You can upload your PDF files, Markdown files here, or create a RAG, as I did in this video, for an entire URL. We have a really cool RAG. I am very happy with the results. I hope you are too. If you liked this video, give it a like, write a comment, and definitely, if you want a continuation with RAG systems, because this topic is really very useful, also very useful for business, then definitely write in the comments on YouTube and Telegram. I will shoot more advanced topics on this subject, we will build cooler systems, we can build a whole chatbot that will be integrated into Telegram. That is, we will have a RAG system directly in Telegram with an LLM. And we can even create a description of some real product and make a real case study. And I thank everyone for watching.