back to index

LangGraph 101: it's better than LangChain


Chapters

0:0 Intro to LangGraph
0:52 Graphs in LangGraph
3:0 More Complex LangGraph Agent
8:12 LangGraph Graph State
14:0 LangGraph Agent Node
17:8 Forcing a Specific LLM Output
20:0 Building the Graph
23:23 Using our Agent Graph
28:32 LangGraph vs LangChain

Whisper Transcript | Transcript Only Page

00:00:00.000 | Today we are going to be taking a look at langraph. Now langraph is another library
00:00:06.800 | within the line chain ecosystem and what it allows us to do is build very highly custom
00:00:15.840 | and flexible agents which I believe that agents are the sort of short-term future of AI. Now you
00:00:25.760 | can build agents with the core line chain library and I've spoken about this a lot before but from
00:00:32.400 | experimenting with both line chain and langraph I'm still forming my opinion but I think langraph
00:00:39.440 | is simply a much more powerful solution for building agents. Now let's take a quick look
00:00:48.800 | at the general concept of what langraph is. Now as you may have guessed by the name langraph has
00:00:56.880 | a big emphasis on graphs so whereas lang chain thought of agents as objects that you
00:01:05.120 | kind of attach tools to insert some prompts so on and so on langraph instead thinks of agents
00:01:12.240 | as more of a graph so you have your initial starting point that could be anything well
00:01:19.360 | it's a function some sort of runnable function so that could actually just be an agent
00:01:24.480 | or it could be a chain or it could be some other runnable function.
00:01:35.520 | Now from here rather than just you know finishing with this agent we can control what happens next
00:01:44.800 | so down here we might have something like a search tool right so we could do rag in this in this way
00:01:53.280 | so we could come down here and we could say okay this is our search tool and this is going to get
00:01:59.040 | us information based on you know what the agent or chain has decided up here to do then from there
00:02:07.200 | we could continue we could finish with another either lm more likely than not so an lm
00:02:15.920 | and that lm may have a prompt where it consumes the the context that you got from your search tool
00:02:24.000 | your initial query which would have come up here from your user consumes both of those and then it
00:02:30.640 | will output an answer and that answer will go to the end node okay so this is a very simple example
00:02:39.040 | now whilst we're looking at this I just want to point out a few things so here this circle is a
00:02:46.320 | node here this arrow is a edge and everything in our graph basically consists of nodes and edges in
00:02:58.400 | some combination now this is a incredibly simple agent let's have a look at something
00:03:07.120 | maybe a little more realistic I'll keep it simple still but still a little more realistic
00:03:12.560 | so we could start with an agent up here and this agent actually has a few tools that it contains
00:03:23.360 | but it will use them via function calling so it won't actually execute the tool itself it will
00:03:30.160 | just output the input to a to a tool that we should use so I'm going to connect to this agent the
00:03:39.040 | schemas for a final answer because I'm going to create a slightly different final answer than
00:03:47.440 | usual I'm going to have a final answer where you get a like an output from your agent and also a
00:03:55.040 | citation so it's a you know it's like a json output in a particular format and we want to
00:04:00.880 | enforce that and I'm also going to input that search tool from before okay now this agent is
00:04:10.400 | going to output which one of these tools we should use and the parameters that we should pass to it
00:04:15.280 | now because there are two tools here we have like two alternative paths that we could go down
00:04:21.840 | and this is a another component of line graph graphs which is called a conditional edge now
00:04:30.240 | a conditional edge is what it's what it sounds like it's an edge or a couple of edges that are
00:04:38.240 | conditional on a on some sort of condition being satisfied okay so the condition being satisfied
00:04:45.520 | here will be whether our agent has decided to go with the search or the final answer tool now to
00:04:53.040 | implement a conditional edge we need something called a router
00:04:56.080 | and that router is basically an if else segment
00:05:02.960 | then based on that we can go well one of two ways we can go to our search node over here
00:05:19.760 | or we go to our final answer which is actually going to go to the end node now with the search
00:05:28.080 | we're going to perform a search and return an answer what will that answer look like well we
00:05:34.720 | will be outputting some context okay so the output of this is some text basically let's put context
00:05:42.720 | now that isn't an answer by itself that's it's just some text that we've pulled from somewhere
00:05:49.840 | it hasn't been formatted into a natural language answer so we now need to pass this through another
00:05:56.160 | lm we will say rather than agent because an agent is nice when we have multiple tools in this case
00:06:06.480 | we just have one tool that we want to use and that is the final answer tool and all the final answer
00:06:11.920 | tool is doing is creating that format for us so we're going to say okay you need to provide an
00:06:16.640 | answer and a citation and from there we have our final answer and that will go to the end node now
00:06:25.920 | this again is a very simple graph there's nothing particularly complex about this
00:06:34.800 | but it is just far more flexible and far more easy to work with than what at least what i'm used to
00:06:45.200 | in line chain and i have not been using this for a long time so i think there's a lot of potential
00:06:52.320 | to using line graph and just learning it and i think when it comes to building agents
00:06:59.920 | so far this is by far my preferred method or preferred library now that is a quick overview
00:07:10.400 | let's have a look at how we actually implement all of this in code so we're going to go into
00:07:15.760 | this notebook here there'll be a link in the both the description and the comments for you to open
00:07:21.760 | this same notebook and you can follow along now there are a few things additional things that we
00:07:27.440 | need to do here and this first thing is to install this library here this pygraph viz
00:07:36.960 | pygraph viz is not needed to use line graph it is needed to visualize graphs that are built
00:07:45.600 | in line graph so if you're if you're just developing with this library you don't you
00:07:50.400 | don't need this but yeah for this example you know taking you through things it's
00:07:55.520 | it's very nice to be able to visualize what you're building
00:07:59.360 | and we have a few libraries that we need here as it's all the line chain ones we are going to use
00:08:06.320 | open ai here so yeah we will initialize that and we move on to our graph state now there are multiple
00:08:15.760 | ways of doing this you can you can create your own graph state which is what we're doing here
00:08:23.760 | or you can use a built-in i think it's like message state that are built into the library
00:08:29.920 | and you can just use those it depends on you know what you're wanting to do i i prefer this method
00:08:36.320 | because you can define what is in there and it's just easier to to understand and this has taken
00:08:43.760 | some inspiration from a very good video from sam witween on the same topic on on line graph
00:08:51.040 | he did a really good intro actually i would recommend that as well so what we are doing here
00:08:58.720 | is we're defining this agency and as we go through each node and as we pass through the graph
00:09:05.680 | we have this agent state that you know goes with us all right so as we go through all of the new
00:09:13.680 | information for example from our search tool that we retrieve will be stored in here and you'll
00:09:21.360 | recognize this so intermediate steps if you've used line chain agents before it's very typical
00:09:26.960 | so intermediate steps are okay between the user asking a question or typing some sort of query
00:09:33.600 | and the output that you get there are there can be many multiple steps as we have seen in that graph
00:09:40.960 | and we saw the information from them in here and another thing that we have here is this agent out
00:09:47.440 | this is output from an agent there's nothing nothing fancy there the other thing is the
00:09:55.120 | inputs so that's the input from the user and we would also have chat history in here as well
00:10:00.880 | i'm not including here because i just want to strip things down to like be as simple as possible
00:10:06.480 | but that being said we're going to build like a what i think is a very cool agent
00:10:13.680 | using line graph pretty soon i'm working on it that will be interesting far more complex
00:10:22.640 | and i think it will show us a bit more of what this library can actually be useful but this
00:10:28.960 | is a good intro so the first thing i want to do within the graph is define those different nodes
00:10:37.920 | okay so the two tool nodes that i want to create are the search node or search tool
00:10:48.240 | and the final answer tool so here we are you know we would usually implement a rag pipeline here but
00:10:57.040 | i'm just going to emulate that so i'm going to say okay this is the information that we're going to
00:11:01.600 | retrieve from our rag you know our emulated rag pipeline it's from an archive paper on some
00:11:08.400 | embeddings in there we have the title of that paper we have the summary we have the authors
00:11:14.960 | and the source so it's going to be up to our llm the final answer llm or the initial agent to
00:11:21.760 | decide how to build the citation when it gets this information and of course the answer as well so
00:11:30.400 | yes that is our information for our emulated search tool and we are going to define our
00:11:40.560 | define the search tool which is just here when we define a tool we use this tool decorator here we
00:11:46.160 | name the tool we pass okay what do we what needs to go into that tool so we just have a query here
00:11:52.400 | at this side of the schema and we give a description here now this description is okay
00:11:58.720 | it's for us but it's also actually for the llm okay it's for our agent it will read this and
00:12:03.520 | decide which tools use and also how to use it based on what we put here now in here you'd put
00:12:08.880 | your you know your right stuff but i'm just going to return the sort of emulated content there
00:12:15.200 | then we also have that final answer tool now final answer tool it doesn't do anything right it like
00:12:24.320 | it there's what it doesn't do anything like you can see here it's just returning empty the reason
00:12:30.320 | it doesn't do anything is because it doesn't need to do anything all i'm using this for is to tell
00:12:38.240 | my llm or agent to use this structure when it's outputting a final answer
00:12:46.960 | so the llm or agent is set up to use this as a tool but when it uses the tool all it does is
00:12:54.800 | generates the what should be the input to that tool it doesn't actually execute it
00:12:59.280 | so i mean that's all we need we just need this format we give it a little description here
00:13:06.480 | explaining what we want in both of those fields and the llm will produce that for us okay it just
00:13:14.080 | gives us our the final answer in that structure that we need both of these we're going to be
00:13:23.040 | executing uh via opening our tools which is uh like the latest version of their function calling
00:13:29.200 | and you can kind of see how that works here so if we yeah we see search tool um we pass this
00:13:35.200 | information to our llm so it's going to see okay this is the search tool to use it it will need to
00:13:41.120 | enter the word search then we have this description so this is the the function this is the inputs to
00:13:49.040 | that function and then it tells us searches for information on topic ai so on and so on right
00:13:55.920 | it's just what i wrote up here okay so we have that then we're going to come down a little further
00:14:03.360 | and we're going to initialize our first agent now that first agent i'm actually going to be
00:14:09.120 | using the core line chain to just implement a very simple or typical openai tools agent
00:14:16.800 | all it will have is a prompt which i'm just getting from the line chain hub it will have
00:14:23.360 | our lm which is a you know it's a chat model from openai gpt 3.5 i'm not actually sure what the
00:14:31.760 | default is now i assume it's still 3.5 uh yes gpt 3.5 turbo and we have our tools okay so the
00:14:41.840 | final answer tool and the search tool now you'll need to pass in your api key here and then you
00:14:47.040 | can run okay and we can just test that very quickly to confirm that it works so i'm going
00:14:54.080 | to ask it what are ehi embeddings uh yes we we run that and okay you can see it outputs this far is
00:15:05.200 | this tool agent action and this is what we're going to be using uh in our our router for that
00:15:11.680 | those conditional edges later so we're going to be looking at the the tool item there and we're
00:15:18.160 | going to then be taking this tool input taking that as a keyword arguments for our function so
00:15:26.880 | query and in that query we'll be passing ehi embeddings now of course we're just emulating
00:15:33.680 | right here so it's not actually going to do anything other than return that text for us
00:15:40.160 | but that is what we would actually need so okay we keep going uh oh yeah i'm just showing you here
00:15:47.760 | what we'd actually be outputting there so we'd be taking the function we have our arguments and we
00:15:53.680 | have the name okay cool then okay what else do we have we're going to define nodes for our graph so
00:16:02.080 | we defined the the tools and the agent and now we just need to define the functions that are going
00:16:10.400 | to run as nodes within our graph so we have the runner query agent that's going to consume our
00:16:17.200 | state and it is going to run our query agent so the query agent i defined where did i uh here
00:16:24.640 | okay so i see you know the the one that makes decision between the final answer and search
00:16:29.360 | then we're going to execute our search so this is a function for rag obviously you know it's
00:16:37.040 | emulated again we have our router which is what we use with our conditional edge to decide which
00:16:45.360 | direction to go in and that kind of covers that first component of our graph so basically all of
00:16:57.360 | this but we also have this component here so these connections okay so search so we have defined this
00:17:07.840 | but we do need to define this final answer llm now the final answer llm something that is quite
00:17:16.320 | useful that we can do is we can create our llm we bind a tool so the final answer tool to our llm
00:17:25.920 | and then we can say that the llm must call that tool so this is just to help us reduce the
00:17:33.680 | likelihood of it hallucinating and doing something else other than use the tool because we want to
00:17:38.880 | enforce that it does output that sort of structure that we'd like so we can do that and that is it's
00:17:45.440 | it's pretty cool i'll show you how so we are here we have our llm this is the one we defined earlier
00:17:50.880 | it's just our chat llm and then we bind tools to it we just bind one tool it's the final answer tool
00:17:55.680 | and then we enforce the tool that it has to use we're going to say you must use the final answer
00:18:03.200 | tool okay and yeah that's the llm we do need to define a function to handle that so we have our
00:18:14.240 | rag final answer we're taking the user input from our state also taking the context from the the
00:18:19.840 | previous steps from the intermediate steps feeding both of those into a very simple prompt here where
00:18:26.160 | we just have the context and question we invoke on our prompt so we run the llm and that will
00:18:33.440 | output a function call okay to our to our final answer tool okay and then we just return that now
00:18:42.160 | the final one that we are also going to add so i didn't visualize this before is this handle error
00:18:48.640 | so what we do have with the the current the query agent is that it's not forced to make a
00:18:54.960 | function call so sometimes basically when you say something like hi or hello like you know a very
00:19:02.960 | short message that is very conversational the agent will want to respond in a you know without
00:19:09.360 | using any tools and i'm sure you could prompt this to be very rare but nonetheless it will still
00:19:16.800 | happen sometimes and to handle that we can actually create another function this is going to
00:19:24.320 | still use this final answer llm and basically what it will do is the router will take a look at our
00:19:31.920 | output from our agent it should see either search or final answer but if it doesn't see those tools
00:19:38.320 | being used we're going to assume there's an error and then we're going to enforce the use of that
00:19:45.760 | final answer okay just like that it you know it's it's pretty straightforward so we do that uh now
00:19:56.320 | we've you know we've built all those nodes we've got all that logic now it's time for us to you
00:20:01.920 | know put it all together to construct a graph so we initialize our graph first we do that with this
00:20:10.720 | state graph object and we're passing our agent state that we defined earlier and then what we
00:20:18.080 | do is we add some nodes okay our query agent which is you know our query agent we have the search
00:20:26.800 | tool we have this error handling tool and then we have our rag final answer like formatter basically
00:20:34.000 | it takes our original user query the output from the rag tool puts them together and produces a
00:20:39.120 | final answer for us then we also define where in the graph we begin which is with our query agent
00:20:47.280 | okay so we set the entry point okay we run that okay then what we need to do is define our edges
00:20:55.520 | to define our edges what we do is we we add an edge i think it's literally add edge and we just
00:21:07.200 | say where we are coming from so you know we could be going from the the agent here so this would be
00:21:13.600 | our x and where we are going to so in this case it would be our our router and yeah i mean that
00:21:22.160 | that's how we do that because we have defined the nodes in our graph using strings it's just
00:21:29.520 | that's just what we do we will also define most of these as those strings so the agent for example
00:21:36.960 | we defined as query agent it's a string so that's that is exactly what we would put inside x here
00:21:44.480 | the one exception that we always have to this is our end node here so the end is actually is
00:21:50.640 | it's a function or it's an object and there's no string value linked to that so we just pass
00:21:56.160 | in the actual end method which we'll see in a moment so let's do that you can see some examples
00:22:01.760 | of what i was talking about so we add an edge between our search node and our rag final answer
00:22:07.600 | node and then we can add another one between our rag final answer and our end node okay so here
00:22:13.760 | i have some repetition actually so let's remove that okay so we import that end node there we
00:22:22.720 | add our edges which is what i'm doing here so these are the like the single edges like they
00:22:28.240 | will be taken so if you go to the search node you will next go to the rag final answer node
00:22:34.640 | if you go to the error node you will go to the end node and same here the one other thing that
00:22:40.640 | we have here is this conditional edge right so this is what i mentioned before for a conditional
00:22:44.960 | edge you can you can go in different directions depending on a particular condition now the
00:22:51.440 | starting point for that is the query agent that will then go to our router which will decide which
00:22:58.960 | direction we go okay so that router is going to output a string which is going to be either search
00:23:04.400 | error or final answer and based on that output we'll either go to the search node the error node
00:23:13.520 | or we will go to the end node okay it's pretty simple once we've done all that we can compile
00:23:20.880 | our graph so we run that and then the thing that we installed earlier that i mentioned is this so
00:23:27.440 | that we can visualize these things and you can kind of well you can see what we've built here
00:23:34.080 | okay so we have our starting point our entry point which is actually just a query agent here
00:23:40.880 | we go to our router that decides where we should go uh we if there's an error we go to the error
00:23:47.920 | that will form our force that structured output we can also go to a final answer tool or we can
00:23:56.320 | go to the search tool go to the search tool we do our you know emulated rag in this node then
00:24:02.320 | we pass the state which includes both the context and our original query into this final answer llm
00:24:10.480 | and then we end and that's it it's pretty simple now let's see how that let's see how it runs okay
00:24:18.720 | so we can see the path that is deciding to take here so we have we're asking what is ai okay so
00:24:25.840 | our search tool is defined as it should be used when someone is asking about ai so we
00:24:34.880 | have our starting point which is our query agent goes through to the router as it always will
00:24:40.000 | and our router decides that we should use the search tool right and and it's it's deciding
00:24:45.760 | that based on the output from our query agent so all it's doing is passing the output from the
00:24:50.480 | query agent and then deciding okay which direction do we go we then execute our search and then we
00:24:56.080 | go to our final answer lm and we finish and we can see here you can see what we get right so we have
00:25:03.280 | the answer you know there's some answer and then we also have our source now the source here that
00:25:10.560 | it's using is not actually our ehi embedding source because that okay it's embeddings in the
00:25:18.400 | same way that we use rag in ai to uh do more do right to search but it doesn't describe what ai
00:25:28.160 | is right so the lm is actually not using our information even though we've given it that
00:25:32.960 | information and instead it is using something that is remembered which is the wikipedia page
00:25:38.080 | on artificial intelligence and this link should actually work they usually do yeah yeah this uh
00:25:46.720 | it remember it's always surprises me how much lms remember like just random blog sites or
00:25:57.280 | websites obviously this one is a less impressive one but they come up with some crazy links
00:26:02.880 | sometimes cool so we have that now let's try something else i'm going to ask what are ehi
00:26:11.120 | embeddings and we can test the citation ability of our lm now let's see what it see what it gives us
00:26:17.520 | okay so it's using that context we provided it it's uh you know this is basically just
00:26:26.640 | information from that context from the emulated rag pipeline and then we have the source here
00:26:31.840 | and that source again will work okay you see here that's the paper and this is a relatively new
00:26:41.920 | paper and we're using an older gpt 3.5 model so i don't believe this is in the training data of the
00:26:49.520 | current turbo model although they are changing them so it might but in any case you can also
00:26:55.520 | use the older models and it will do the same thing all right that's cool uh i can ask you
00:27:00.080 | just ask more questions tell me about uh these embeddings it will do and it will give me a you
00:27:06.720 | know citation again i would have i suppose in in the citation here i would have liked to actually
00:27:12.480 | generate these citations so like you know put together the authors and and whatever else in
00:27:17.840 | there and yes you could you could prompt it to do so but obviously in this use case it's a bit of a
00:27:25.440 | silly use case because in reality you would probably just pull in the source from the document
00:27:29.840 | that has been used as we're only returning one document that is uh is you know it's pretty easy
00:27:34.800 | but anyway uh we we have that and this is kind of useful when it's you know returning stuff from its
00:27:40.960 | own memory you can actually see where you know what it has been trained on in order to you know
00:27:49.760 | find that information or in order to remember that information which is kind of cool then okay
00:27:55.920 | this is where it's like this is where it would usually break right if we didn't have that error
00:28:01.920 | so you can see that we're handling this error if we didn't have that it would just try and output
00:28:06.480 | you know a normal sentence here we see that it actually forces it to use that answer source
00:28:13.200 | format which is pretty cool and and then i can literally like beg this agent to not use this
00:28:21.280 | format and it still will uh which is you know i i that that is cool that's it's useful uh depending
00:28:28.160 | on what you're building of course but it's a nice little nice little thing that we have there
00:28:32.480 | so yeah that is line graph i think you know this is a very basic example there is a lot more that
00:28:42.240 | you can do with line graph i just build far more complicated agents than what we've done here but
00:28:48.960 | the same time you can also build these simple agents and you can make them pretty custom like
00:28:53.120 | we did with you know the the rag emulator and the final answer and also the final answer you know
00:29:00.240 | error handling right we build all that and it is not that complicated and you can you can add many
00:29:07.360 | nodes and many different edges and build something quite sophisticated without too much difficulty
00:29:16.480 | and the code and one one thing that you know a lot of people say and i you know i understand to some
00:29:24.400 | degree with lang chain is that the code is very convoluted there's like a million ways to do one
00:29:31.280 | single thing and i'm not saying that is perfect here but i feel with line graph it is much more
00:29:38.160 | refined and you this you know we've just shown you you to build a graph you need to add the edges you
00:29:45.280 | add the nodes and yes there are many different ways of building those nodes but the logic is
00:29:54.240 | pretty intuitive and easy to follow and simply very extensible right i would use basically the
00:30:03.440 | same functions whether i'm building this very simple agent or some super big research agent
00:30:10.720 | that you know has a million different sources of information you know we would be using you know
00:30:17.120 | roughly the same functions without too much difference we would just be you know putting
00:30:22.960 | a lot more into it and that is something that i quite like so far with lang graph and i think the
00:30:29.280 | other thing is just the ability to really control what your agent is doing with lang chain everything
00:30:38.800 | is kind of hidden behind abstractions and there are still abstractions here i you know i will not
00:30:45.040 | lie but they are they feel far more useful and far less frustrating than line chain abstractions
00:30:56.400 | which i appreciate and although this can be slightly you know complex to get started with
00:31:09.920 | after a few hours i think it's it's becomes quite intuitive and that is something that i
00:31:17.200 | i just like about this library so for now i am building agents with line graph rather than
00:31:26.320 | line chain or the core line chain of course there are still a lot of line chain components in here
00:31:32.640 | and you know i'm sure i will continue using them for a long time into the future but this is the
00:31:39.280 | way that i'm building the the logic or the paths within agents and i think it works pretty well
00:31:46.400 | so that is it for this introduction to line graph as i mentioned there will be more line
00:31:52.320 | graph videos we'll do we'll build some more complicated stuff but yes that is it for this
00:31:58.640 | introduction so i hope this has been a useful and interesting video so thank you very much
00:32:06.080 | for watching and i will see you again in the next one bye