-: In this video we're gonna have a look at
how you can customize LangGraph state
beyond just using the messages key
inside of the state graph.
This is important because
what you wanna do is not just have specifically
the message history, but if you can have lots of other keys
inside LangGraph, that's gonna give you the flexibility
to have lots of different types of Boolean flags
so that you can control different types of edges and nodes
and conditional edges based on some Booleans
or some state that's stored
inside of the LangGraph state machine.
We've got some imports that we do
and we're also just setting up my Tavily key,
and then we're gonna have a look at customizing the state.
So again, the important point of this lesson is
that we're doing exactly the same stuff we've done before,
but we've got a new flag, which is to ask_human
and the reason why we are using this ask flag,
and you could have lots of different pieces of state here,
so I could also have ask_for_final_review.
And I could have a Boolean piece of state here,
but we can add lots and lots of different pieces of state.
But the important point is that you can,
if you want to do more complex things outside
of just the message history, then it can be useful
to have extra bits of state inside of LangGraph
that you can manipulate.
So you can see here we have a RequestAssistance
piece of schema and we are going to create a tool,
and the tool that we have is TavilySearchResults.
And we're also going to have this RequestAssistance
as a separate tool that we use.
So you can see where here we have a Pydantic model,
which is escalate the conversation to an expert.
Use this if you're unable to assist directly.
And so we're binding the LLM with both
the Tavily search tool and also the RequestAssistance tool.
And we have a chatbot which will invoke with the tools
and it sets the ask_human to false.
If there are tool calls,
and the tool calls name is the RequestAssistance name,
we set the ask_human to true and then we return the messages
and the ask_human.
Now we then build the state graph
and we have our chatbot node that we had before,
which is now this Python function.
And we have the tools
and the tool node being just the Tavily search results.
Now, when we have a response,
we are also going to have a little helper message
for returning a tool message,
which will just return the response from the AI
and the tool call from the first one inside of that AI.
And we have a human node which is
basically getting a list of messages.
And if the messages,
if there isn't any messages at the moment,
then we don't have a response from the human.
So typically the user will have updated the state
during the interrupt.
If they've chosen not to, we'll include a placeholder,
a tool message just to let the LLM continue.
So that's a nice way of us being able to
always add a tool message on just in case
of the human node doesn't have
a response from the human from the new messages.
But if it does, then what we're gonna do
is then unset the flag to false.
And we have this node now called human.
So we've got a couple of different nodes.
We've got the chatbot node, the tools node,
and also the human node.
And we need a function to define
what is the next node going to be.
So if the ask_humans flag in the LangGraph state
is set to true, we are going to return the human.
And otherwise we're going to have the tool condition,
which will either go to tools or __end__.
We then build our graph with the chatbots
and we select the next node.
And if it's returned to human,
we're gonna go into the human node,
and remembering that the human node
will run this Python function.
And if it's the tools, that will run the tools node,
which we've defined up here.
And remember that the tools node is only using
the Tavily search results.
We have bound two tools to the chat model,
which is the RequestAssistance tool.
But that is only being used not inside
of the tool node directly.
And we also have the end which gets mapped to the end.
And so we've built our conditional edges
and we then add the edges from the tool to the chatbot
and the human to the chatbot.
And we set the entry point to chatbot.
And then we're using a chat pointer here
whilst we compile our graph.
And we are also interrupting before the human node.
And this is important
because we want to update the state of the human node,
but if there wasn't a updated state,
then we would have a placeholder.
But you can assume that before this human node runs,
we are actually gonna update it
so that this one wouldn't happen.
But we would actually have another message
directly already updated.
And then we would go from the human node onwards.
So let's have a look at how this looks.
So you can see this is what we have.
So we've got the chatbot,
which goes into the human if it needs it,
and then goes back into the chatbot.
We also have the tools.
If there are tool calls,
then those will get filtered into the tool node.
And then after that, then it will end.
Now you can say, I need some help guiding for assistance
with an AI agent.
We'll give a thread ID of one
and we'll stream that with the user input.
And let's see what happens.
It's decided it wants to call
the human RequestAssistance tool.
And what we can then do is get the state of the graph
and you can see that the next node is human.
So we've essentially, if we scroll up a bit,
we first enter the chatbot node
and it decided to go to the human node,
but we have interrupted it
before it's gone into the human node.
And then what we are then basically gonna do
is create a tool message.
So we'll get the values, the messages,
the most recent message from the AI.
And you can see this gives us things like
the tool calls that we can get.
And so what we want to do is
we want to use this create_response function
and we'll just have a look at that what that does again.
So that will take the AI message
and it will get the first tool call ID
and it will have a response to that tool.
So if we're gonna scroll down again,
now that we know that it's gonna get the AI message ID
and create a tool message for us, you can see that there.
And then we have the human response,
we are the experts here,
recommend check out our LangGraph to build your agent,
it's much more reliable and flexible and extensible.
And then we're gonna update the state
with the config and the messages.
And we're gonna add on the tool message
that comes back from the create_response.
And now that we've done that, if we get the config,
you'll see that we've also now got a tool message
that has been added on after the AI has decided
that it needed to request assistance.
And so we've almost answered
the request assistance from this.
And therefore if we do a none configuration,
it will resume the graph.
So if we were to do, for example, graph dot,
and then I could do get the state,
and I just wanna prove to you that the next node here
will still be the human node.
But we already know that we've got a input for,
if we just scroll up a bit, we already have an input
for the messages being a tool message
because you've added on a tool message specifically.
And therefore we would skip this step
and we would go straight here
and we're just basically setting
the ask_human flag to be false.
And we've got the messages that are being returned.
So that's basically how it's working
is by adding on this extra tool message.
When we go back into that human node,
which is the next node,
we're actually just gonna return the messages
and then you'll see what happens from there.
So we've got the tool message
and then the AI has said,
experts have recommended using LangGraph
as a reliable and accessible tool.
So then the graph has specifically ended.
So what happened was we went into the chatbot,
we interrupted before the human node,
and then after that what we did was we added on a message,
we then went into the human node,
which went back into the chatbot.
There was now no tools to be called.
And so what we then did is we decided
to end the LangGraph state machine.
So, cool, so that's a bit of what we've done there.
So hopefully that made sense.
The important point here is you want
to have your interrupt befores
or interrupt afters as you build your state machine.
And you could also have done it with an interrupt after.
The important point here is if you did do
an interrupt after, you would need to make sure
that the node kind of handles for the fact
that you wouldn't have that after inside the node.
There's various different strategies.
One is interrupting before the node
and then resuming from there.
One is interrupting after
and then updating the previous bit of state.
And again, we're using a checkpoint to which allows us
to run different threads.
And LangGraph is clever enough to allow us
to specifically customize the state
and we can use that customizable state
to run different types of conditional edges.
Cool, so in the next one we're gonna have a look at
a concept called time travel.
Time travel will allow you to specifically wind
forwards or backwards graph state inside of LangGraph
from using a check pointer.
This can be useful if you want users to be able
to undo changes they've had or revert changes,
and having the version control over the graph
as well as being able to update the graph.
Cool, I'll see you in the next one.