Talk to Your Code | Github Repo | Learn How GitHub Co-Pilot & Others Transform Coding ðŸ§

Build a Q&A system that lets you ask questions about code. The tutorial walks through loading a GitHub repo, splitting it into chunks, storing embeddings in Chroma, and connecting it to GPT-4 so you can have a conversation about how the code works.
Questions this video answers
1398
2000 characters
200 characters
4246
OpenAI embeddings
Chapters
How to chat with a GitHub code repository just like you chat with your own documents using the power of LangChain and large language models. That's exactly what we are going to be exploring. In today's video, I'll show you a step by step process of how to create Q and a system or the code base that you are working with. Okay, so this is the architecture that we are going to be using. It's very similar to what you probably have seen or systems that are used for chatting with your documents, such as PDF files. But there is one major difference when it comes to context aware splitting that is needed when you're working with source code. So in this video we are going to build a system that will let you chat with the LangChain GitHub repo, but you can use the same code example to build a chat system for your own code base. So we will look at a code example and we will also talk about different aspects which are different than when you're building a Q and a system or documents compared to code. If you are not familiar with this topic, I would recommend you to watch my videos on chatting with your own data. So the main difference when it comes to chatting with your code versus your documents is the strategy that you use for document splitting. Now, LangChain has different splitters when it comes to different programming languages. And the reason is that each programming language has a different syntax. But in general, each top level function that is present in a file is going to be separated into its own document. And each top level function that is present in a given code file, e.g. a Python file that is going to be converted into its own document and any remaining top level code outside the already loaded functions and classes is loaded into a separate document. And this happens for each file separately. This will become very clear when we look at the actual code examples. Next we need to install the required packages. But for this specific example we are going to be using OpenAI LLM. But in the subsequent video I'll show you how to do exactly the same thing using Code Llama model. Then we will install Tick token for Vector store. We are using Chroma DB and everything is going to be put together using LangChain. Next we import different packages that we need in order to work with the code. So specifically there is a text splitter which is designed for different programming languages. So we're importing that. Then we are importing a generate generic loader. So that's for loading the files. And there is a language parser we will look at where these different components are being utilized. Now we're also importing the dot ENV package and that is going to be used for loading our OpenAI API key from a dot env file. So next I use the env package to load my API key from the dot in the env file that I have created on my disk. So if you look here, there's a env file, and within that you need to provide your own API key. Next, we need a code example to work with. So I'm using a LangChain repo on GitHub that is going to be our code base. So what I have done is actually went ahead and downloaded the whole repo and actually cloned it on my local system. So you can see it here. And this is what we're going to be using for our Information Retrieval or Q and A system. Next, we need to load all the documents or Python files. So for that we are going to be using the generic loader that we already imported. So what we are doing is we are looking at our file system. So that's basically a hard drive. Then within the repo that we have downloaded, we are specifically looking at this folder. So if I go here, this is my repo that I downloaded. So within the repo there is this libs folder. Within that there's a LangChain folder and again another LangChain folder. So this is the folder that we are actually focusing on. And within that folder we are recursively going through each and every directory. So it will, for example, start here and start going through each directory. And in each directory we are specifically looking for dot PY files. So these are the Python files. So it's going to start reading each and every Python file. And based on the criteria that I already showed you, it will start parsing those. So it's going to use all the principles or syntax related to Python, because we are specifically looking for just Python files. Now, you can also add other file extensions here. So for example, if you are working with a JavaScript or C files, so you can also add those extension here. But in that case you will need to also change the parser that you're using for that specific language. Now, so there are a total of 1398 Python files in this repo that it has loaded and converted into documents. Now, one special characteristic of these loaders for programming languages, that it also stores the metadata along with the actual code. Right? So let's look at how this looks like. So here I'm simply taking each document and printing its metadata. So if you look here to this example, so you'll notice something. For example, this is a single file which is converted into multiple documents. And if you look at the content types, it can, it is either a function or a class. And that's what we talked about, that each top level function or a top level class is divided into its own document, right? And then you see the other information. In terms of language, we're specifically focusing on Python, right? So a single file can be divided into multiple different documents. That is different than what happens when you read a PDF file. So this is very important to keep in mind when we, we are working with Python or any other programming language and we want to do Q and A on top of it. Okay? So once we create these documents, next we need to split them into chunks or sub documents. So for that we're going to be using recursive character text splitter, but we're going to be using recursive character checks specific to Python. So you have this function called form language. Then you need to pass on the language that you are working with. We are working with Python. Then you need to define the chunk size in characters. So we are using a chunk size of 2000 characters and we want all to have an overlap as well. So that's set to 200. And using that character text splitter or recursive character text splitter, we're simply dividing our documents that we created into different chunks. So you will see that there are a total of 4,246 chunks as a result of this splitting process. Now, if you really want to understand how the recursive text splitter works, I have a dedicated video that you can watch. I'm going to put the link to that video in the description of this video. Now we can look at one of these chunks. So for example, here is what's inside this chunk and it also stores the corresponding metadata. So here's the actual file, where it's coming, where it's coming from, and then the corresponding language, which is Python in this case. Next, in order to do a retrieval Q and A on our code base, we first need to compute embeddings. So for embedding computation, we are going to be using the OpenAI's embeddings. Then we need to store those embeddings somewhere. So for that we are going to be using the CHROMA vector store. So here we are creating a vector store object for the Chroma db. We are passing on our text chunks or documents and then the OpenAI's embeddings. So for each of these chunks, it will compute the corresponding embeddings and store those in our vector db. Now, in order to do a vector search on our embeddings using the vector store, we first need to create a retriever object based on our vector db. And then we need to define the type of search that we're going to be doing, as well as the number of documents that are going to be retrieved when we perform that search. Now, there are quite a few options when it comes to the type of search you can do. So for example, some people use similarity based search, but for this specific application we are going to be using something called maximum marginal relevance. The reason for using MMR is that we don't want all the chunks to be retrieved from the same document. So now this will ensure that the retrieved documents or chunks are not from the exactly same Python file. Rather, it will pick eight different Python files and find the most appropriate different chunks based on our query. And then this K defines the number of documents or the number of chunks that are going to be retrieved when we do a query. So that completes our initial basic setup. Next, we need to define the conversational retrieval chain. Now, in this case, the LLM that we are using is GPT4. So we are going to be using chat OpenAI. We are also adding memory to our Q and A chain. That's why we are using the conversation summary memory. So basically it will look at the historical conversation, compute the summary and add that to a subsequent conversation. Right? And for the chain itself, we're using the conversational retrieval chain. We are passing our LLM, passing our retriever, and passing the memory object that we just created. So after this, we are all set to start having conversation with our code base. So let's look at a few examples. So here is an example question, how can I initiate a react agent? Right? So we pass on that query to our Q and A chain that we just created. We get an answer just to format this better, I'm just printing the response. So it says to initialize a react agent you would need the following steps, right? So import the necessary class, this is and method, and it gives us the code on how to do that. Then initialize the LLM, right? So it's basically import the OpenAI LLM now then it asks us to initialize Zapier wrapper and it also provides the corresponding code, right? And then it's telling us to create a toolkit, right? So these are basic steps that you need to perform in order to initialize a react agent. And all the responses are coming from the code base that we provided. It's actually quite amazing to think about it that you are able to chat or communicate with a code base that you have created. Now you can also ask multiple questions and since it has memory component, so it will remember the conversation as well. So for example, here we have three different questions and we ask them sequentially. So for example, the first one is what is the class hierarchy? And it comes up with an answer. So it also gives us different example memories as well. And then it looks at the class hierarchy specifically for chat message history. So here's the answer, then the second question. So it gives us an an answer. And if you follow, if you ask a question which builds on the subsequent question, so it's going to remember the previous conversation. Basically it will compute the summary of all the previous conversations as a part of the context and generate answer on top of that. Now this is a simple example of how you can build Smart Q and a system or your own code base using LangChain and GPT4. In a subsequent video I'm going to show you how to do exactly the same, but using an open source model. And in that case we're going to be looking at the code llama13B model. If you found this video helpful, consider liking this video and subscribe to the channel. If you want to learn more about how to build Q and A chatbots for your own PDF files or your own documents, I would recommend you to watch this video. Thanks for watching and as always, see you in the next one.










