Instructor: Just one minor change we need to make
to our get text function.
So sometimes the LLM may pass as our text
some unnecessary characters which are non-alphabetical.
So for example, backslash N or some single quote.
So here I'm simply removing those and cleaning it up.
Let's now review the React algorithm again.
And after the tool execution, we got back the observation.
It's the result of the tool after executing it.
So now we have a choice,
whether we want to give back an answer
because we have enough information
or we want to take the observation,
the tool execution result,
and we want to run another iteration of the React loop.
But this time with all the history
of what's been done so far
so the agent won't be making redundant steps.
So that's what we'll be implementing in this video.
So let's go back to our code
and let's head up to the React prompt.
Now, remember that we removed the agent scratchpad
from the original prompt.
So now we're going to bring it back.
And now we have better understanding
what it's supposed to do.
This is going to contain all the history
and all the information that we had so far
in the React execution.
So we need to also add it to the dictionary
that will be sending our prompt.
So we'll have here another key of agent scratchpad.
And just like before we're going to fill it up
with a Lambda function that is going to access the key
of agent scratchpad.
So in order to keep track of the history of our agent
and what happened so far,
we're going to create a new variable
called intermediate steps.
And this is going to be a list
which is going to start as an empty list.
So let's plug it in into our agent invocation.
So we're going to add here another he,
and it's going to be the agent scratch pad.
And this is going to hold the value of the empty list,
which is the intermediate steps.
Now, every time we run an iteration,
we want to update this list and append to it the history
and what we have performed.
So after we perform the tool selection and tool execution
and get back the observation, I'm going to append
to our intermediate steps which hold the history
our agent step.
So this is what we got back
after we parsed the LLM's answer,
and I'm going to append the observation,
what we got back from the tool after running it.
So that way our agent will have both
its reasoning engine history and what it has chosen already
and also the result of what was the result
of the tool execution.
Let's run it in debug.
And we want to examine the values of agent step
and the observation
and what we're saving in the intermediate steps,
which is our history.
So I'm simply going to select everything here
and evaluate it.
Now everything looks good so far except for the fact
that the first element in our typo is an agent action,
which is an LangChain object.
And the LLM doesn't understand LangChain object.
So we will need to translate this into text.
So we'll need to format it nicely.
So don't worry, we're not going to do it ourselves.
LangChain is going to supply us
with a utility function that performs it.
So I'm going to import the function format log to string.
And this function is going to take our intermediate steps,
which is a list that contains the tool of the agent action,
what the agent has decided, which tool to use,
and the observation, what was the result of the tool.
So it's then going to construct the scratchpad
that is going to enable the agent
to continue in its thought process
and basically it's going to format all those strings nicely.
So instead of passing the original agent scratchpad,
we're going to first format it nicely
by using the format log to STR function,
and that way we'll pass to the LLM only strings
and that's way the LLM would be able
to take account of our history.
So let's add another step of the agent.
So I'm simply going to copy this agent step invocation
and going to paste it.
So let's print what we get in the second step of the agent.
And now let's run everything in debug
and let's see what we get.
So when we run it in debug, we'll get an error
that the output parser got as an input an input
that also has a final answer and also a parsible action.
And that confuses the LLM
because it should either have an action
and action input to perform
or it should have the final answer.
It can't have both.
This is the React algorithm
and this is the logic of the output parser.
So from my experience, the usually fix for those kinds
of issue is to work around
and refine the prompt that is being sent to the agent.
So you can see right now that in this prompt,
we have a space at the end before the question mark,
so we're going to remove it.
And let's also not forget the previous invocation
of the agent.
So we also need to fix that.
And let's now rerun everything
and examine the output.
We can see right now we got the first step of the agent,
the first invocation.
It was the first iteration.
We saw that we got the answer from the LLM
that decided that we should use the tool get text length.
We then used the output parser to parse it,
and we then chose the correct tool
and we invoked its function.
We did that using the agent action object of LangChain,
which holds all the information about the tool to execute.
We then executed the tool
and we have now the result
of that tool of get text length.
So this result is considered as an observation,
and then we take the agent action and the observation
and we append it to the intermediate step list
and we send it as the agent scratchpad.
So this is the history of what has been done so far,
what tools were chosen and what was the result.
And this is being sent to the second iteration
of the React loop.
So now we're starting all over again, but with the history.
However, now in the second invocation in the scratchpad,
the agent has the observation,
which is the result of the tool
that counts the number of letters in the word doc.
So we have the final answer.
And actually the object that we're dealing with right now
is called agent finish and not agent action.
And I want to run it in debug
in order for you to see it for yourself.
So, remember that we told that the output parsing return
as either agent action and agent finish.
So in this case it returned the agent finish.
So if we'll go to the agent step, we can see
that we're dealing with an agent finish object,
and this is what the output passer returned for us.
And why did it return an agent finish
and not an agent action?
Because if you take a look at the log entry,
the LLM responded to us, I know the final answer
and then backslash then final answer,
and the output parser parsed it and noticed it,
and it decided that it now has the final answer,
so it should return an agent finish object.
Lastly, in the field of return values,
we have a dictionary with the output key
and the value is the answer of the agent for our question.
So now I remove the print statement of the agent action,
and we're checking if the agent step is an instance
of the class agent finish.
And if this is the case, then the agent step is going
to have the field of return values and we can print it
and finish our execution.
So let's now rerun it.
And we can indeed see that we had two React iterations
and we got the final answer for our agent,
which used our tool.