Let's keep going with our project to equip our LM with a tool.
We just created this piece of code to describe our function, which I'll now execute.
And then the next step is we just create something called tools, which now has a single it's a it's
a list of tools.
And in our case we only have one.
It's one element type is function.
And the function is this thing right here.
So that is now in a list that's called tools.
And now the moment it's time to give an LM in our case GPT.
For many the power to use this tool.
How is that going to work.
So it's a bit fiddly I gotta warn you, be be mentally prepared for something a bit fiddly.
It starts with something that will look very familiar to you.
This is our usual chat function.
You know it well.
It has a message in history that you know and then it uses that to craft the messages that go to OpenAI.
Now there is a small, subtle difference here.
Something has changed.
Something has been added.
I'm going to wait a moment for you to spot it.
Once you've spotted it, it's super obvious, but there is a little addition that's been slipped in
there.
And if you saw it, very nice.
If you didn't, it's very obvious.
Here it is.
We pass in the tools.
The API is exactly the same chat dot completions, dot create.
We give it a model, we give it the messages and then we also give it the tools.
In other words, we give it this object right here.
Uh, and when ChatGPT sorry when chat when OpenAI is taking that and building the prompt, the tokens
that get sent to the to the LLM, to the GPT four LLM, it's going to take this and convert it into
a series of tokens that are going to describe our function.
It's going to use this English to say what it does, and it's going to inform the LLM that this is a
function that it can call.
Uh, and the reason that works is because it's been trained with lots of examples that use tokens in
that way to give the LLM that ability.
And so the some of the magic is about to be lost when you see what's going to happen next.
What comes back from the LLM you remember is in response choices zero.
And what we do is we find out whether or not the finish reason is this thing tool calls.
That happens when GPT four is telling us, I don't have an answer for you yet.
Instead, I'm going to stop because I want you to call one of your tools and provide me with its output.
So if that happens, what we then need to do is collect the message from GPT four.
So this collects that response choice zero dot message.
It contains the whatever it's sent back, which will in fact be a request for us to run a tool.
And then there's a bit of work to do to unpack that message.
Figure out what it wants to do and do it.
And I've put all of that in a separate function.
I've cheated.
I could put it all in here, but it becomes quite messy.
So instead I've separated that out.
So at this point we'll see it in a second.
Believe me that this function will unpack the message back from GPT four zero and if necessary, well,
it will be necessary.
It will call our tool and it will return the result of that tool.
The response to go back to GPT four zero and the city that was called, uh, what we then do is we have
to add two more rows to our list of messages.
Our messages, you remember, have like user assistant, user assistant.
We're now going to add two new rows.
One of those rows is this thing message, which is nothing more than what we got back from GPT four
zero asking us to call a tool.
So the first thing we add in is the assistant asking us to run a tool.
We put that in the list of messages, and then after that, what we put next in the list of messages
is our result of calling the function.
So what's now in this list of messages is user assistant, user assistant, user assistant says run
tool.
We say this is the tool result.
And then that is what we're now sending back to OpenAI.
I hope that made sense.
If not, you simply put some print statements in here when you run it and you'll see it's exactly what
I said.
And once you print the whole messages thing, I think it will be crystal clear to you.
You'll see that full exchange appearing in those messages.
And then at the end here, as usual, we just return the ultimate answer from the LM.
Uh, what I should point out probably is that I've decided I don't pass in the tools a second time,
because we wouldn't expect it to run our tool twice, but there'd be no harm in putting it in there.
But it obviously wouldn't use it, So the final missing ingredient, of course, is that I now have
to write this function here, which is again a little bit more involved than than one might like it,
but you can just use it verbatim in your own projects.
It's just some stuff to know.
Um, so we've got this, this thing, this message that's come back from GPT four.
And what we have to do is unpack it to find out which tool was it wanting to call.
Now, in our case, we know what tool it wants to call because we only have one tool and it's the tool
to get prices.
Um, but I'm keeping this in here anyway so that you can see how it works.
Um, and what we should really do here is say if tool call equals, uh, get ticket price, then.
So there should really be a sort of like, like if or some sort of, uh, a series of, uh, like a,
like a, like a switch of all the possible, uh, things that it could ask to, to call.
But in our case, we know there's only one tool available.
So that's what it is.
What we can then do is load the arguments that it wants to call.
So in this this tool call there is a tool called dot function.
Dot arguments that tells us what parameters it's chosen.
Um, and that comes back in the form of JSON.
Uh, just a string.
So we have to use the Json.loads Loadstring function to convert that into a dictionary.
And then we look up the only actual argument that we have, which is destination city.
We look that up and put that in a variable city.
So we have now unpacked the tool and the argument.
And what remains to be done is this line here.
And that line obviously is nothing very clever.
That line is quite simply calling our get ticket price function.
We've established that's the tool it wants to run, and we've plucked out the city and we now call that
function.
Um, we then build a response.
And here is the response.
This is the thing that's going to get shoved at the bottom of the the messages.
There it goes.
It's going to get shoved in there and what their response looked like is this.
Now, you know, each of these rows has a role and content.
And in the past we've seen that role can be user or it can be system user or assistant system user assistant,
user assistant.
Well, there's something else it can be too.
It can be this word tool.
So in this case we put into the response tool.
And for the content we put in a string which is this.
This dictionary turned into a string using the JSON dump string function.
So we put in the destination city and the price.
We do also need to add this tool call ID into the the message, which is a way that it links this response
to the request that came right before it.
So we're putting message.tool.id into this guy so that when it sees these two, it fully understands
that that is associated with this request.
And that's all there is to it.
Although this time This time it was a fair amount.
There's quite a lot to take on board there.
But as I say, step through it, put some print statements, see that working.
But let's see now what happens if we bring this up in a chat.
Hi there.
Hello.
How can I assist you today?
I'd like to go to London.
Sure.
Would you like to know the price?
Yes.
The ticket price for a return trip to London is $7.99.
So it got the right price.
So what we're hoping is if we turn back to our Jupyter lab, what we should see is that it's printed
that our tool was called, uh.
And I think we can be pretty confident that it will, but let's have a look.
It is indeed tool get ticket price called for London.
Let's keep going.
Uh, and how about, uh, Paris?
899 and Tokyo.
The ticket price for a return trip to Tokyo is 1400.
And Berlin.
Berlin was the one we just added in.
Let's see if it's got that.
Yes, 499.
It certainly seems to work and timbuk2.
I'm sorry, but I don't have information on ticket prices to timbuk2.
Uh, let's have a look here.
And you can see the series of tools called.
And we know that when it was called for Timbuk2, it would replied unknown.
And as a result, because we gave it the system prompt to say when it doesn't know, it was quite clear
that it didn't know.
And with that, there was a lot going on.
I hope you got a sense.
This is in fact, a powerful, uh, piece of functionality.
It's a powerful technique to allow you to give more powers to your LM, but but under the covers, it's
not magical.
It's really a bunch of if statements and some complicated messages to and fro, so that we can allow
the LLM to inform us that it needs more information about something.
And that's how it works under the covers.
And I hope that makes sense to you.
And I hope you're able to use this in your own projects.
As ways to extend this.
You can look at adding more kinds of tools and tools that might say something about the availability
of that flight or something like that.
So you can use more tools.
Or if you want to be really bold, you can add a tool to actually book the flight.
It's a tool that, when it's called again, could just print something or could write something to a
file or whatever.
And that would allow the LLM to call back into your second tool and actually book a flight when the
user asks for it.
So that would be a fun one, and you'd have a bunch of arguments about the dates and the like.
So give that a shot, and by the end of that, you will be very proficient in how to write tools and
how to equip your LLM to carry out actions that run in your software.