Hey there.
Eden here.
Remember this diagram?
So in this video we're going to be integrating tool calling into our react agent architecture.
So instead of leveraging React Prompt we're going to be leveraging tool calling capabilities of large
language models.
And we're going to see how it's going to make our agent much more reliable.
And it's going to save us a lot of boilerplate code.
And it's a much better evolution of this react agent.
Now, even though we are going to be using function calling and not using react from, this is still
referred to as react agent because the main algorithm here leverages reasoning and acting.
However, this time the reasoning is shifted into function calling instead of react prompt.
So my goal is that by the end of this video, you'll really understand why function calling is more
useful and why it's now the go to when implementing AI agents.
So for this video I opened cursor IDE with our project here.
So here we have the react algorithm which we implemented in previous videos.
And what I'm going to do is ask cursor to replace the react prompt and use and leverage the tool calling
capabilities of modern llms.
And in case you're wondering, I have a couple of reasons for coding this video.
The first reason is that I am lazy.
Just kidding, I am really lazy, but this is not the reason why I'm coding it.
So the reason why I want to code it is that I want to show you the latest and greatest tech tools to
show you the diff, because cursor is going to output us a very beautiful diff where we can see what
exactly the changes were.
And by doing so, we can really see how simpler tool calling is and a tool calling agent, comparing
it to an original react agent with the react prompt.
So this is the main reason why I do want to code it so we can see the diff.
And of course I will be attaching the code in the repository by the end of this video, so you can find
it in the course's resources.
So if you want you can simply copy and paste it.
Or if you have an AI coding editor like Cursor or Cloud Code, you can write a prompt like I'm writing
or a similar prompt, and it should work as fine.
All right, so let me go and write the prompt to cursor.
I want you to use now dot bind tools instead of the react prompt.
So let me now go and fast forward it because it is going to run for a while here.
So cursor now is going to read all our files.
It's going to do some rag by the way, and we're going to talk about it in the course in the rest of
the course.
And let's start to take a look at the diff here.
So we can see that it removed the union typing.
This is not that interesting.
But what is interesting it removed the format log to STR here.
Now the reason why I did that because with function calling we don't really get the reasoning.
So we don't really get why the agent decided which tool to call, which is a trade off, but it's totally
worth it and it's much more reliable using function calling.
Next, it removed the react single input output parser, and I remind you this class is implementing
a bunch of regular expressions.
So with the function calling features of large language models, we don't need to parse the text generation
of the LM to look with regular expression for the action.
Because we get the tool to invoke, we get it in a special key in the response, which is called tool
calls.
And in that key the value is going to be a beautiful JSON, which is very easy to access.
And we're going to see everything very, very soon.
So please, please don't worry about it.
Now we also can remove the agent action class and the agent class, which helped us to organize our
code and help us to distinguish whether we need to continue to perform a tool call and to actually run
the code, or we need to finish here.
So this is in case we find this agent finish string again with regular expression here.
So the reason why we do not need those um indicators, whether to execute a tool call or whether to
finish and output the response of the LM is because we are going to be deriving this from the tool calls
argument from the LM response.
So if there are tool calls in that special key argument in the LM response, then we need to perform
the tool call because it's going to have the information about the tool call and if it's empty.
So this means that we can simply return the response of the LM to the user.
And again once you see everything running and once you'll be seeing the traces, everything will be
much clearer.
Alrighty.
So now we can also remove the prompt template and the prompt template used to hold the react prompt,
leveraging the LM as the reasoning engine.
And, you know, writing this prompt.
So we don't need this anymore because what we're doing is shifting now the responsibility of selecting
the correct tool to the LM provider, which is OpenAI, Google or anthropic for the LM vendor, which
is implementing tool calling.
All right.
Here we're also removing the render text description, which we used in order to populate the react
prompt with the description of the tools.
So we don't need this anymore.
So now let's see the other divs.
All right.
Let me go down a bit in the code here.
Cool.
So we can see it changed the Hello World to Hello World with linking tools.
And right now you can see that we're removing the react prompt.
And this prompt has a very special place in my heart because it's really what started it all.
And this was the beginning of the agent era.
And by the way, you know, one of the most underrated joys of being a developer is deleting code.
So there's just something about hitting that backspace and cleaning things up that gives you a dopamine
spike.
So it's very satisfying.
All right.
So now you can see we deleted the entire react prompt the template and the prompt itself.
And notice that from the LM we also deleted the stop arguments because we used to rely on that to stop
the LM from hallucinating tool calls.
And we really relied on the LM adhering to the react prompt for that.
So it was also a bit problematic and a little bit flaky.
So we are now removing it because with two calls we don't need this.
The tool simply is going to be in the tool calls key.
Let's go now to the rest of the file.
And we can see we are here removing the intermediate steps which held all of the observations, which
held all of the result of the tool executions.
And that was our agent scratchpad.
So we don't really need this now because we're going to be relying on something which is called a tool
message, which encompasses exactly that.
It holds the result of a tool execution.
And LMS these days are more than capable and are actually fine tuned in order to be able to digest this
very, very well.
And I'll be showing you it very, very soon.
When we run everything now, we also delete the agent variable, which was a runnable instance, which
was the react prompt piped to the LM.
And then we use the output parser in order to parse the LMS response and use that as a reasoning engine.
So we don't need all of this.
We can simply invoke our query, and the LM is going to respond with the tool calls.
So this is now going to be deleted.
All right.
So now let's talk about the logic here.
So first we want now to bind the LM with our tools here.
So for that we're using now LM bind the built in method.
And here we're going to provide the link chain tools.
We want to give it here.
So this is going to give the LM all of the descriptions and all of the interfaces of the tool we want
to equip our LM with.
And now the LM is going to be able to make the decision of making a tool call to those tools.
Now I remind you, the LM is going to decide only when and with which arguments we need to invoke these
tools.
It doesn't really invoke it.
We invoke it in our back end.
So we need to do it in our application layer.
Anyways.
What the bind tools behind the scenes is going to do.
It's going to take the tool description and the tool arguments and all the metadata on the tool and
every request we're going to be making to the LM.
Then link chain is going to append that information to the request.
So then the LLM is going to be able to make the decision whether to call this tool or not.
All right.
So here in the messages variable we're going to put a list here with the human message with the input
here.
And by the way these messages variable here this list this is going to be our agent scratchpad.
We're going to be appending to this list after every iteration of the agent.
All right.
So similar for before we're going to have a while loop.
So it's going to continuously run.
And we're going to be sending these messages list.
Now for the first iteration it's going to be a list with one value which is going to be a human message.
So this is what's going to start our agent work.
So once we invoke now the LLM when we have tool calling.
And let me focus now on this edit code here.
So we're going to get back a result.
And in the result we're going to have a very special field which is going to be tool calls.
And if that field is going to be non-empty.
Empty, so it's going to have an object in it.
Then we have a tool call.
So this is what we're seeing in this F here.
And if we have a tool call then we need to execute a tool here.
And notice this is a list.
So this means there can be multiple tool calls and llms these days support parallel tool calling.
So this is also possible.
So this line over here simply extracts from the iMessage.
If there is a tool call.
And if not it's going to give us an empty list.
So tool calls is going to be either a list with the tool calls needs to be executed or an empty list
in case they shouldn't.
And you can probably get the point that if there are no tool calls, then we simply need to finish and
to break the while loop.
However, if there are tool calls.
So if this list has more than zero items in it, so at least one, then first we want to append everything
to the history.
So this is going to be to append the decision of the LLM to make the function calls to make the tool
calls.
So this is appending the reasoning to the scratchpad.
So this is what we're doing over here.
And by the way the concept of appending everything to the messages key.
So we are going to hold a bunch of messages.
And we're going to send those messages every time to the LM.
So this is an interesting prompt engineering or context engineering strategy here.
And it's actually proving itself over the years very, very useful because the LM is going to derive
its reasoning logic and its trajectory through these messages as it is.
So we don't need to have anything special here.
And I remind you, when we get a message back from the LM, if there is a tool call, then we're going
to see all the information about the tool call in the tool call argument in the AI response.
So it's going to be a list containing all of the tool calls.
Now each element of this list is a dictionary containing the information about the tool that needs to
be invoked and executed.
And what we do here is to simply iterate over that list, and in our case, is going to be only one
element.
And we're going to extract the tool name, we're going to extract the arguments for the tool, which
is going to be a dictionary as well.
And the tool called ID.
Now this is way, way easier than what we did in the react algorithm, because now we don't need to
rely on link chains ability to be able to parse well the LM output with regular expressions.
So here we simply access it.
And by the way in the link chain tool calling agent, this is exactly what it does.
This is the output parsing of the LM response.
This is simply accessing the relevant fields on the tool execution.
So once we execute this part of the code, we have all of the information of which tool we want to use
and we want to invoke.
And now all we need to do is to use defined tool by name function that we implemented herself and we
send a list of tools and we give it the tool name, and we get back the tool that needs to be executed.
And we simply execute and invoke these tools with the arguments with which we extracted.
And we have the observation.
Right.
And once we have the observation, we want to append to the message history a tool message containing
the result of the tool execution, along with the tool call ID and the tool ID is super important because
it helps us and the LM and this is the keyword.
And to match the result of the tool execution back to the correct function call that the LM has made.
Now, this is especially useful when the LM is going to be making parallel tool calling.
At one API call.
You can really see the importance of it.
In this example, where we send to the LM one call with a complex query and it has Multipole in parallel
tool calls.
All right.
Let's continue.
So once we append the tool result as a tool message to the message list, we then continue the iteration
in our while loop and start all over again.
So now this is the input.
The LM is going to receive the entire message list containing the user input, the agent trajectory,
and the result of the tool executions.
And now the let him knows that it needs to return a response.
So the answer is going to give.
It's not going to be an answer containing a tool call, but it's going to be the final answer.
So now in the while loop we see that the number of tool calls is zero.
So we do not execute this if clause here.
And we continue to this part where we simply print the content of the message and break this entire
while loop.