back to indexLangGraph 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
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