Introduction to LangChain
If you write code in Python and you're at all interested in AI, then you need to check out LangChain. Now this is a relatively new framework that allows you to build AI-powered applications in both Python and JavaScript. Now we'll be looking at Python here, but the main benefit of LangChain is that you can actually connect to external data sources, databases, APIs, and really any data that you'd like. And you can very easily build applications that are context-aware and that can reason using popular language models like Chat GPT.
Now in this video, I'll give you a high-speed overview of LangChain, show you some of the simple features and capabilities, and give you enough so that you can get started today building AI applications in Python. In my opinion, this is a must-learn, really cool module and surprisingly simple. Stick around for the whole video to see exactly how you can use this in your next Python app.
Installation and Environment Setup
So the first thing we need to do to work with LangChain is install it. Now they have fantastic documentation that I'll link down below that will show you all of these steps, but of course you can just follow along with me. So since we're going to be installing this for Python, we can see on this page here we have a few options: pip install langchain, pip install langchain[llms], or pip install langchain[all]. Now I'm going to recommend that you go with the second option here. You do not need to install all the dependencies, but we do want to install the dependencies related to the language models so that we can connect with those immediately. So let's go ahead and copy that command and paste that in our terminal. I am running on Windows, if you're on Mac or Linux you're likely going to want to adjust this command to be pip3.
So I've gone ahead and installed that and we're just going to install a few modules that we're going to use for these specific examples. So I'm going to do pip install and then OpenAI. We're going to use this to connect with OpenAI. Again, if you're on Mac or Linux you're going to want to change that to pip3. Now once we install OpenAI, I am also going to install the dotenv library. So pip install python-dotenv. Now this is going to allow me to load in an environment variable file so I can store my API keys in a specific file that's kind of hidden from the code. You'll see what I mean in one second. Those are all the modules that we need: LangChain with LLMs, we need OpenAI, and then we need python-dotenv.
Understanding LLMs (and a Word from HubSpot)
Now in the name of saving us a little bit of time, I've already written a few examples and I'll just walk through the code with you so you can see exactly how this works. Now the first thing I want to mention is that before you start using LangChain in any of the LLMs, you want to have a decent idea of how they work. Specifically, you want to understand what they're good at, how you can use them properly, and when you should be cautious of their replies. Now I imagine most of you are going to be using Chat GPT, at least that's what I'll be doing for this tutorial. And fortunately for you, our video sponsor HubSpot actually has a free guide that shows you how to use Chat GPT at work.
Now this free guide gives you a comprehensive overview of exactly how Chat GPT works, it shares some best practices, and it gives you some expert insights so you really know how to use this and get the full power out of it. Now I've left a link in the description so you can check it out completely for free. Now this resource provides a ton of knowledge and even has 100 actionable prompts that you can try today to really leverage Chat GPT. Knowing this, especially as a programmer, is an absolute game-changer and I want to give a big thank you to HubSpot for providing this resource and a ton of others completely for free. Make sure to check it out from the link in the description. And a massive shout out to HubSpot.
Your First LLM Interaction
So now that you're an expert at Chat GPT after clicking on that resource, we can dive into some of the code. So the first thing I want to show you is just a very simple example of interacting with an OpenAI model, in this case Chat GPT, and using it to make a prediction. Now you you can use all kinds of LLMs, but obviously this is the one most of you know, so it's the one I'll use in this video.
Now first what I've done is I've created a .env file here and I've placed my OpenAI API key. I'll show you how to retrieve that in one second if you don't have it, but this way I can actually put the key inside of here and then you guys can't see it while I'm going through the tutorial. So I've just put my actual key inside of there and you can see that the way I'm loading in this API key is I'm importing from the dotenv module the load_dotenv. What this does is look for a .env file in the same directory as our Python script and loads in any of the variables. Then what I do is access the OpenAI API key variable here, so I have it, and I pass that to my ChatOpenAI kind of interface component, whatever you want to call it. Now this will actually create a connection to OpenAI, into Chat GPT. And I can simply use this by just running chat_model.predict and then passing inside of here a string. So if I go to my terminal and I run python simple_example.py, you can see that we're able to interact with GPT here. It just takes a second and it responds to us. It says, 'Hello, how can I assist you today?' Very simple. You can see how easy it is to actually use the module from Python.
Getting Your OpenAI API Key
Now let's dive into some more complex examples. And before I forget, if you need an OpenAI API key, then you can go to platform.openai.com/account/api-keys. If you're not using it very much, you're not going to have to pay for it. I've used it a ton, and I think I've paid 10 cents over the past few months. Anyways, let's move on to the next example.
Providing Context with Multiple Messages
All right, so moving on to the next example, I just want to show you that there's actually a way to pass multiple messages and get a single reply or response based on all of those messages combined. This can be useful because sometimes you have some pieces of context that you want to provide to the model. You don't necessarily want it to give you a prediction or a reply based on that. You want to actually feed some other text or some other information and get one kind of aggregated reply.
So in this case, what I've done is just create an array of messages here. I've specified that these are human messages. Now we can also have system messages, assistant messages, agent messages; there's a bunch of different types, they're all in the documentation, I won't go over them here. And you can see that what I'm doing is saying, 'From now on 1 + 1 = 3. Use this in your replies.' And then I'm asking it some questions based on the context I just provided. So what is 1 + 1? And what is 1 + 1 + 1? So here I go, chat_model.predict_messages, pass in the messages, and if I go ahead and run the code here we should see that it's actually going to be using this context. So, 'According to the new rule 1 + 1 = 3. Therefore 1 + 1 + 1 would be equal to 3 + 1 which equals 4.' Kind of interesting how you can do that. Just wanted to show you that quick example.
Dynamic Prompts with Templates
So now we get into a slightly more interesting example where we can use another feature from LangChain known as a prompt template. Now you may have seen this before, but quite frequently what we want to do is actually inject some data into a prompt. And this prompt we've kind of crafted, engineered, and we know that it's going to give us a specific type of reply.
So in this case what we've done is we've set up a template. We say, 'You are a helpful assistant that translates some input message to some output language.' And we put those inside of curly braces. We then have a human template, and this is just some text, but we could also have something here as well. What we then do is create a prompt template from LangChain. So we say chat_prompt is equal to ChatPromptTemplate.from_messages and then we can specify as many messages as we'd like to be a part of this larger template. So what this does now is specify that this is a system message—so this template right here, kind of telling the model what it's about to do—and then we have a human message, which is what we're providing to it each time.
Then what we can do is we can actually create the messages that we want to pass the model from our chat_prompt. So we say chat_prompt.format_messages and we pass in the variables corresponding with what we've written here inside of the template and they're automatically going to get injected inside. Now obviously in Python you could do this manually, but having this API makes things a little bit easier. So we have input language, output language, and text. So that would make the template, 'You are a helpful assistant that translates English to French.' And then we pass our human template which is 'I love programming.' In this simple example, I know it seems very easy, but when you get into more complex templates and complex tasks, this can be quite useful. Then what we can do is we can predict messages again using the same chat model we had before and we can get the output. So let's see what this does now if we go up here and go python prompt_template, it should give us whatever the translation of 'I love programming' is in French. And it does, it says 'J'adore programmer'. Again, imagine you had like seven system messages, a bunch of different variables, you could create some really interesting applications here using this prompt template style.
Structuring Responses with Output Parsers
So continuing, we get even more complex here and what I'm now showing you is something known as an output parser. Again, all this stuff you can write manually, but having these hooks in this API is quite useful and can make your life a lot easier. So a lot of times when you're using a model what you actually want to do is parse the output into a specific format. For example, it might give you a comma-separated list, it might give you a JSON file, it might give you some code, but that's going to be in a string. And typically what you'll want to do is actually take that string and parse it based on some rules so you can actually get the data that you'd like, for example parsing a price or parsing a piece of code, JSON like I said, right? So what we can do here is actually write a custom output parser, and you'll see why this is useful in a sec when we kind of combine it in the chain. What this will do is return to us the parsed response in the format that we want.
So all we've done here is just overridden the base output parser, which I've imported up here. We've just overridden this parse method and inside of here we take in some text, we strip the text, and then we split it at 'answer ='. This now, the reason that makes sense is because in my template I said, 'You are a helpful assistant that solves math problems and shows your work. Output each step, then return the answer in the following format: answer = and then the answer provided here. Make sure the output answer is in all lower cases and to have exactly one space and one equal sign following.' Now I'm instructing the model to give me a specific reply in a specific format such that I can parse it, so I get the data that I'm looking for and I could use that in the rest of my application. Then I have the human template which is just whatever the math problem is. Again I use my chat prompt template here, and then what I do is format my message by providing some math problem, in this case just a basic, I guess, quadratic formula thing that you need to solve. Then what we do is we predict messages using the chat model, and then I'm manually invoking the output parser here and parsing the reply. You'll see in the next example how we actually combine this into a chain and make it even easier to use. Then what I'm doing is I'm parsing out the steps and the answer from my parsed reply, which is now a list that was split at 'answer='.
So you'll see now if I go ahead and run my code, so python output_parser.py, and you can see that we get X is equal to 3 over 2 or X is equal to 1. Now if we also wanted to see the steps here, then I could print out the steps and you can see how this could be useful because if we had some type of calculator, we could allow maybe the student or whoever is using it to either view the steps or hide the steps or just view the answer or hide the answer because we've parsed that reply. So let's have a look at this here. Gives us all of the different steps for solving the problem and then finally the answer down here.
The Power of Chains
All right so now we're going to kind of tie everything together and have a look at creating a chain. Now this is where LangChain really comes in handy and obviously you'd get much more complicated than this but you'll see in this example that we can combine all of those steps that we were doing manually before into a chain using some special syntax from LangChain.
So just like before we have our model, we have an output parser. This time what it does is just parse a comma-separated list. And then we have a template. It says, 'You are a helpful assistant who generates comma separated lists. A user will pass in a category and you should generate five objects in that category. Only return a comma separated list and nothing more.' We then have the human template again, we create our prompt template. This time though, rather than manually calling all these different methods, we create a chain. Now we use this pipe operator here, which is special syntax in LangChain, which combines these three operators into one kind of main object that we can utilize to invoke. So you see we have our chat prompt, we have our chat model, so the first thing we do right is we get the prompt, we pass that to the model, and then we pass the reply to the output parser. And again this happens automatically when we call chain.invoke.
So now we just pass in what we need for our prompt, so in this case we have an argument text which is equal to colors, and we can print the result. So let's go here and give this a run: python chain.py. So you can see we get our reply: red, blue, green, yellow, purple. And this is actually a Python object that has been parsed for us.
Use Case: Natural Language SQL Queries
So just to give you a bit more information on the capabilities of LangChain, let's have a look at one of the use cases they have in their documentation, which is SQL. Now as I was saying, LangChain can also connect to data sources, so they have a bunch of integrations for connecting with popular databases and even vector databases as well. Now in this case what we can actually do is use an LLM to generate SQL queries so that we can ask in natural language for information from our database. So imagine you had a large database, you had a bunch of information, and you wanted to actually provide an interface to your users so that they could use natural language to query the database and grab maybe information or analytics from their profile or whatever it is. In this case, you can see that we can build SQL queries, query a SQL database, and interact with the SQL database by using natural language. And this is kind of the diagram. We ask a question, goes to the LLM, generates the query, goes to SQL, SQL returns that to the LLM and the LLM parses that and gives us the answer. So in this case, we can have a quick look at how this might work. We say db_chain.run('How many employees are there?'). What it does is it generates the SQL query, gets the result, and then gives us an answer in a human readable format. Obviously a little bit easier said than done, but you can see the simple connection that happens here. Connect to the SQL database, connect to OpenAI, create the chain here, and then you can start using this exact example.
Use Case: Question-Answering Over Documents
So the next use case they have here which is interesting is question answering. So let's say we have a large piece of documentation, maybe related to code, maybe a PDF, maybe a website. What we can actually do is inject that into the model and then ask questions about that piece of data that the LLM can respond to. So you can see we have maybe some code, some structured data, some SQL, pass that into an LLM, and then interact with that directly by asking questions of the LLM. So where this becomes actually really interesting is we can ask the LLM in natural language what it is that we want and then it can go and retrieve the correct piece of data if we set this up in the correct way to actually give us the answer. So in some instances, we don't even need to provide all the context to the LLM immediately. It can actually ask for the specific data it needs and send the correct request using whatever code it's generating. This is a little bit more complicated than the example that they have here but you can kind of see how they're setting things up and how we would be able to input some data and then ask again in natural language questions about that that could be answered almost instantly.
Use Case: Adding Memory & Conclusion
Now as a last example here, I actually made a video on my channel a few weeks ago that injected memory into an LLM so that we could actually remember and have context about all the previous replies and answers. Now I did this by making a Choose Your Own Adventure AI based game. You guys can check it out from the link in the description. It's a full tutorial walkthrough of how this works, but pretty much what we can do is generate a Choose Your Own Adventure game that has multiple different variable paths, and where you're going is going to be based on previous answers that you've had. So if I said I was going left at the first step or I decided to have an axe as my weapon for the game, the LLM would actually use that context to continue to generate the story for me and make it context-relevant. Really, it's going to be cooler if you guys go check out that video and see exactly how that works, but really interesting stuff you can do here, and I did that all in LangChain.
Anyways, with that said guys, I'm going to wrap up the video here. I hope you found this helpful and this gave you a quick overview of LangChain and got you excited about using it in Python. If you enjoyed, make sure to leave a like, subscribe to the channel, and I will see you in the next one.