Learn LangGraph - The Easy Way

Video Statistics and Information

Video
Captions Word Cloud
Reddit Comments
Captions
Hey folks, so some of you asked to make a video on LangGraph. this is something released by LangChain recently, where you can make agent applications or different LLM applications. And the concept here is that you can make a graph and call that. So there is a blog. There are some notebooks provided by the Langchain team. So I would suggest for you to check them out. But I wanted to start with something very basic. So the simplest graph you can make is what's shown here. Basically, you have two nodes and an edge that connects them, and then we have the user input that is in form of some sort of query, and then we go through the graph, and then we get some output for the user. So the way I like to see nodes is basically something where you can run functions. So you can make a function call here, a function call there, and in between that, there is some return value that comes out of this function that basically passes along to the next stage. just to understand, we have two functions here. Both are simple functions. We basically take a string from the user. In this case, we take Hello and then in our function one, we basically return that string concatenated or attached with another string, which is high. So when it goes through node one, We have hello. Hi. And then same thing with node two, we take the string we have from before and then add something more to it. So now we have hello. Hi there. this is a very Basic application of the graph in this case and the way this looks in our code. So there is a companion notebook that you can use. There is quite some notes that I tried to add in there. In case if you have any additional questions, feel free to reach out. So the functions that we looked at basically are these here function one, which takes an input and then it adds high. or a string to that input. Same thing. We take input two and our function two and then add what we saw before. So the whole thing becomes hello. Hi there. Okay. So now the fun part. So how do you build a graph? Or a land graph app. So first thing what you do is you're gonna import the land graph library. So something you can install pip install land graph. And this is a minimal version. you are assigning a workflow and we're using graph. In this case, we're also gonna cover something else just a few cells down. So now we start with an instance of graph that we're assigning to variable workflow. And to this, we add node one. So as we saw in our, sketch over here. for node one, we have function one, node two, we add function two. This could be any function we're just using something basic here. And then the edge between those, as we saw in this sketch here. That's going to be going from node one to node two. this is important because you start somewhere in the, graph in our case, node one. Then we pass some information to node two, and that's what's happening here. We're going from node one to node two, and then we set an entry point for this graph, and then we set an exit or a finish point, of this graph. And what happens is when you compile this app. And this notation is something you might want to remember. This is from the LangChain team. Once you compile it, so in our case, let's run the functions, and then also, let's run the graph. Now, we can invoke as we saw before, where we say hello, and then it goes through the graph. It concatenates string at each level, and this is something helpful I saw in one of the langchain provided notebooks, where it just looks at output at each node level. You can pretty much take as is. So what's happening is from node one, we're getting hello hi, as we saw here, and then it goes through node two, then we add all of that. And then at the end, we have this hello hi there. So at each level, we can basically print out what's happening in this graph. Now, this is quite simple, right? So just adding some sort of string, how about we make an LLM call, So the goal here would be node one will make a call to LLM and from there, it's going to get a response back. And once we get a response back, then we pass along to node two, and then we do something. And in this case, we'll do something very basic. Again, we just say Agent Says, and then we just provide what was said by the agent. So, let's keep going over here. what we want to do is we want to install LangChain OpenAI, the package that's available from LangChain team. And something else I've done is I have, an environment file, something along this, where I have Provided the open AI API key. So I will suggest for you to add your API key here, create a dot ENV file, and then you can pretty much call the model. So I'm using Python dot ENV. package here to load the environment variables, assigning the API key. And then I can call. So we know from our langchain knowledge that you can pretty much import any of the LM or chat models, and then call them. And in this case, I invoke the model with just a simple string saying, Hey there. And it comes back saying, Hello, how can I assist you? Right. So this is pretty simple. Now, We're going to take this content portion. just to start with a string. So if we do dot invoke, and then take the content portion dot content, we get the string out of that. Now we just modify our function one. So instead of just attaching or concatenating a What we're doing is we're saying we're going to take the input from user Pass it to the model and the response we get out of that, the content portion, we're going to pass to the next node. And the way we do it is that we have our first node. we call agent. this is something that you notice that many of these nodes will be called agent doing different tasks. So we attach or reassign. function one to agent node two the same. function two. The only thing it does now is it has this agency string. And to that we add the string that we get from node one or agent node. So again, we have the edge going from the agent to node two, as before. we can run the cells and get the response. So compile the graph app. And then we say, Hey there. Now what happens is it went through the whole, graph through the notes we had. And then we got this saying agent says, and then the text from the LLM. So if we were to see again, what's happening at each node level, our agent said, Hello, how can I assist you? And then basically took that and added this. And then we have the string at the end, which basically is what we expected from our graph. So now this is quite simple. At least we got started off with how we can build these land graph apps, right? So that's the benefit of using a graph structure where you can process at each stage and move on. So in this third, case, what we're going to do is we are going to make the LLM call, but then also we have a task for the LLM. We're not just going to say, Hey, how are you? we're going to take the city, and parse it out of the user. query. So in this particular example, if the user were to ask, what's the temperature in Vegas? We take this Las Vegas portion out, and we only pass that to the next node. And in this node, we're just going to make an API call to open weather map. This is something available in Lang chain. it's a tool as well as wrapper. So You can make an API call, and set that function separately outside as well. You don't necessarily have to use the Lang chain wrapper, but then at the end, the goal is that we get something back to the user saying in Vegas. This is what's happening. Okay, nice. let's keep going. So what I'm going to do right now is for the function one, we're going to change this to a different function where we're saying, your task is to parse the city name out of that and nothing else, right? And it is based on the input available and still. Input to our function still the same. So let's run this. The graph is still the same, nothing changed here. compile that. And now if you ask what's the temperature in Vegas, we get Las Vegas, Because that was the task we gave to the agent just to parse the city. Okay, nice. We're making some progress Now for the next stage, which is to call the API, I'm going to install the package for open weather map. with that, I'm also gonna assign the key. So this API key, you can get it from the open weather map website, There's also some documentation available on the LangChain website. the only thing I noticed is to get this key, you have to register an account. You can do a free account without adding your credit card. but then it takes a few hours to activate the key. You'll get an email. So that was a bit of a process. Probably, four to five hours or so just to get the API key. But then, if you were to use the lang chain wrapper available, for this open weather map, the usual way is you can provide a city name, and then it gets you this data right here. Now, we want to benefit from that, so we take our previous query, or this prompt that we gave to our LLM, and in the function 2, now we're changing this, weather run. So we're taking what we learned previously from our function up there, and then, assign that to function 2. Okay, nice. now everything else in how we set up the graph is the same. the only thing I'm doing different in this case is that I'm calling the node2 as tool. Uh, that's what, LangChain calls agent and tools. So with that, I'm gonna be passing the node one info and attaching the edge to with node two, which is tool in this case, Just make sure you're naming that you give for node is changed for each of these cases. And once we have that, we're going to compile it. And when we ask question, it's hopefully going to parse the name of the city and pass it. this is what happened. And then again, if we want to see it, what happened at. each node level, we see that agent said Vegas, and then our tool took that information, sent it, made the API call, and we got something back. And then we're seeing this whole thing is available to us. So that's the output that we got. Now, the thing that we realize is our user asks only for temperature, but what we get back is the whole weather report for the city, right? So that's something we need to change and what we know is if we were to make another call to an agent or to LLM application, we can ask for this particular node to take the info and see what was the user's question and then only respond with the information asked. So we want it to respond that the current temperature. In Vegas is this, right? So because that was a question by the user. Okay, so how can we do that? Basically, we add a new node, right? So what we want to do in this case is we have this task provided, and we want to provide the user input. But now the trouble is, since we're only returning one value from here, to the node two. And then from node two, we're passing just the the response of the API to node three, we don't have the user input that was available to us. So that's something we need to pass along. And something that's made easy in land graph is that you can pass some data types. across all of the nodes. So you can pretty much pass a, either a dictionary, or an array, or any data type where you can make changes. So basically you want to read something off of it, you want to attach some value to it. So, a common thing that you'll see in the notebooks provided by LangChain is that they use a dictionary, which is agent state, and within that, you'll have something called messages, which is an array. And the way it looks like, if I were to run this if we have no information or no text available within it, then this is how it looks like. This is the agent state that we're going to be modifying. basically we want to, take this dictionary, the state, and then either append some values to the array or, read something off of it, So in our function one, since we wanted it to be just the user input, we could have just actually used the user input and, not necessarily read off of this state, Then whatever was input, we can have provided here, but then, just to keep things uniform, what we're doing is we're going to pass this particular notation, this dictionary with the messages in there, and we're going to read what's in the messages and the last element that was in that array is the user input. Since we just started this, this is for the node one, we could have just used messages zero, or just whatever element is in there. But just to keep notation same across the functions, we'll use messages and the last message in that. array. And basically what we're saying is our previous prompt is the same. Our user input is that last message we saw. And then we provide that to the model. once we get a response back, we're going to append it. to that same, array that we're talking about. Same thing in our function two as well. We read what was the last element in the array, and then we pass that. So that's going to be Vegas, the city name in this case. we send that over to our model, and then we append it to The same array that we're talking about. now the change that we have now is function 3. we said we could use the function 3 here and invoke the model, but then we wanted to pass the user input. So the only thing that we added to it, in addition, to how we read the information. we also have the user input available to us, which is the first message in that array. the API information or response we have is the last message in that array. we take both of those. And provide that to our agent saying that your task is to respond back to the user query based on the available information here. And then we can now run this. And what's going to happen is our graph is going to change a bit here. We added this third node, as we mentioned before. And then to that node, we're basically attaching an edge. So this edge is from tool to the responder. So basically from node. to node three, and then we change our entry and exit point, basically node one and node three. In this case, let's compile our workflow again. And now if we ask the question it's important that we ask question in the data structure that we want our application. to, run with. So if we do that, what's going to happen is it's going to go through all three nodes and then it's going to provide us the information that we wanted. And if we want to look at each stage, what's happening here is that the first, node we attached the Las Vegas this is the response from the LLM. This is the first user input. And then we send it over to the tool, then tool senses some response back, which is the third element here. And then in our last node, this is where it reads off the API response. And then it basically gives us this response. That is the current temperature in Vegas is the value available. And that's something we want as a response back. Now, if we wanted, we could have also make it where the response from third node is also something we append to messages, as we did for function one and two, but we kept it where it's just a string that we get back. Now this is just for understanding, of course in our application we'll make it uniform, so all of it is using some state which is properly, passed along the nodes. that brings us to some of the notation you might have seen in the notebooks from LangChain. this state, this agent state, is a certain format, It's a dictionary which contains a list in there. we had to read from it, we had to append something to it. to make it easy on ourselves, something we can utilize. It's available from typing. we have a class for agent state. which is a dictionary, and within that we have messages, which is a list or a sequence, and then we say operator. add. Basically, if we were to assign any value to messages, by default, it adds it, or appends it, in that array. that makes it easy for us, so next time when we call this, we'll see something appending to it. Now, other thing is, we realize, that if we run this app, if we say something very basic, like, Hey, how are you? It's not going to run. So as an example, if I were to just run here saying messages, how are you? Right? So we're just passing something very simple. We would have expected our app to respond that, but it's not happening. the reason that's not happening is because it's expecting to parse this. city name from node one, and then pass that to node two, and then the API response back from node three, But if that's not happening, then our app freaks out. it wants that info. what if there was a way we could make it where only conditionally, it looks at the information asked by the user. If it is about the temperature, then it uses that tool. If not, then just respond back to user saying, Hey, I'm doing good. How can I help you? The way we can do that is using a conditional edge. That's something available in land graph, where Essentially, what you're saying is if the question is about the tool usage, then use the tool. If not, then just respond back to the user. So we're going to do a few changes. Now it might be quite a bit. So I would suggest for you to follow along and ask if you have any questions. first thing I'm going to do here is use the agent state as a class, as we mentioned earlier. And second is We know that there are something called tools available in LangChain. This is something you can import. There are many different types of tools available for agent applications. And what you can do is you can bind the tool directly to the model. So in that way, when we make the call, to the model, it knows that it has the possibility to use that particular tool. And this is made easy by LangChain, where, essentially using this convert to OpenAI function, it converts a tool to something that you can use for OpenAI function, and then you can bind that function to the model call. Now, with both of these or making both of these changes, what happens is our function 1 becomes as simple as that. Basically, just two lines here, and we are good to go to the next function. So it's calling the the model based on the user input. And then from there, we're going to be returning the response in the same state as we provided it. So in function two, we're going to change a few things. One is that we have this from before, where we saw that we can read the last message. And in our case, it's going to be from the agent or node one. And then second is we're going to parse the JSON that's available from that. a particular node. And the reason for that is I'm going to go down a few cells where actually I ran this before. So what happens is our message that we get back from the agent is in this form, where it says the AI message, it has some content, and it has some additional keyword arguments. And within that, the agent let's us know that it does not have that info, so it needs to make that function call. And that function call is going to have which tool are we using. So that name is available to us by the agent because it knows what all tools it has available to it. And then it also provides us arguments in the form. that it knows that the tool is going to be using. I'm kind of reading. what's available in the additional keyword arguments that's available in the last message. And within that, I'm looking at the function call. And within that, I'm looking at the arguments. And I'm basically parsing the tool and the argument for that. passing that info to this tool invocation. Now, tool invocation is something available for us within the land graph package. Also in addition to that is tool executor. So basically what you do is you assign the tool name and the argument it needs or the input to tool invocation, and then you invoke the tool using this tool. executor. So that's how you can utilize any of the tools. so once we get the response back, we can either pass it as a string or we can pass it as something called function message. This allows our next node or agent to to know that there was a response back from the tool. opposed to AI message or human message that is also available within link chain. So once we run this, we get a response back and this function message, we're going to send it in the same dictionary that we're looking at earlier. So this is the state and then. We have something else. Now, let's say, for example, we are done with our step one, where user provides input step two, step three, now we get something back, right? So the response is sent to node one. We want node one to make a decision. Right? it needs to know where to go from here. Does it go back to the user? Does it use some other tool or what happens from here, right? is the function we need to define where we say, if function call is available in our last message, then continue with the function call. you know, make a call for that function of or that tool. If not, then end this, right? Just take the information available to you. And then just end the discussion over there. So it might be information from one tool, it might be information from multiple tools, essentially, where we have everything what we need. And then we just provide that to the user. So now when we actually get to the implementation of the graph, there are a couple of things that you'll notice is different from the other cases. First thing, we import a graph. or what we can do is we can import the state graph. And in this case, we have to pass some sort of state. to the graph. And we know that we have already assigned agent state so we can pass agent straight from the beginning to the end node of this graph. So this is something available as state graph in the app. If we were to use this graph, then essentially the first Message the input that you're providing. It could be in the format that we want. So for our uniformity, what we did is we pass the message to our graph in this particular format from beginning. But then it didn't have to as long as there is something that goes into our first node. And then it there is some information returned from each node to all the way to the last. We can just use the graph in that case. If you know that you're going to be providing a certain state, a certain a data structure that we're going to be passing along, then in that case, you can use the state graph. So since we already have the state assigned, what I'm going to do is I'm just going to comment the old ones. And now we're going to use the state graph next is the, Each node gets function. So functions, we saw that we tweaked them a bit earlier. And then once we do that, then from node one, we have from the agent, we have an edge, which is conditional. This is something available in LangChain, where we Agent can decide if it wants to go here or not. So when we get to the agent, it has the option to decide where to go. And if it decides to continue to the tool, then it can go to the tool. If it decides, no, it wants to end, then it can basically end the discussion. And when that happens, in that case, it's going to return to the user, right? And if it goes to the tool, in that case, we have something that happens at the tool level, and we have this edge, which returns information back to the agent. So in this case, we're saying that if a tool is called, then The information from tool needs to go back to the agent using this edge. Whereas if there is something that was provided to the agent, it has an option to either use the tool or not use the tool. So that's the reason that particular edge from the agent. to the tool is conditional, this blue one here. But the red one here is something that is going to happen. If this is called, then it has to provide some information back. That's the reason we're using this edge. In that particular case, we assigned the entry point for this as well as the agent. And then what we're going to do is I'm just going to bring in This end. And with that, let's compile the app. Okay, let's go back. Let's make sure we run all the cells. Great. And then we call this as well. Nice. And now we're going to pass the first thing, right? This input, this message as we saw before in the format it likes, and then it's going to go through the whole thing. And then what it's going to do is, as you notice in this messages, it's going to have the human message, and then that goes on to the node where it processes that human message. It responds back saying that, okay, make a function call. And in that function call, we're going to be calling this tool, which is what we bind to the model. And then from there, we use the function or the tool, and then we get some response back. So now our final call, which is from the agent, it knows that. The function call was made. So we have that info available. And then based on all of that conversation previously, it's going to decide the final response to the user, which is the temperature that was asked by the user. Again, we can run this and see all of the steps separately, if we want to see that. So hopefully with that, you got an understanding of the usual notation, how The graphs work in LangGraph, And in case if you have any additional questions feel free to reach out. We'll do my best to make additional content around that.
Info
Channel: Menlo Park Lab
Views: 20,544
Rating: undefined out of 5
Keywords:
Id: R8KB-Zcynxc
Channel Id: undefined
Length: 28min 29sec (1709 seconds)
Published: Mon Feb 19 2024
Related Videos
Note
Please note that this website is currently a work in progress! Lots of interesting data and statistics to come.