If you try to ask an LLM through the OpenAI API to send an email or access your database, it will not be able to do that.
This is expected because LLMs just know how to respond to your message. They don’t know how to perform tasks.
This is just a JavaScript function that you write to send an email through your email service.
You call it like sendemail({ email: 'test@example.com’, message: ‘Hi there!’}), and then tell the LLM that email was sent or not (the result).
This is the most important idea of tools. The LLM does not call the function; you call the function from your code and give the LLM the result.
The LLM tells you in its response. So the response could be the final answer, or a request to call a function for it.
Notice how when it asks you to call a tool, the content is null and there’s a new field: toolcalls.
In the second case, the LLM is “waiting” for us to call the function and hand it the results back.
You tell it! In the OpenAI API example, we can pass a tools array when prompting an LLM:
We call this array tool schemas! It’s just a description of the functions you have in your code that the LLM can ask you to call.
The format of the schema is not the important part. You just need to use it to describe the tool you have: The description: What it does. The LLM uses this to know when it should call the function. The function name: So you know which function to call. The properties: The parameters the function accepts.
In the example above, the toolcalls has an object where it specifies the function it wants to call. We can read its name (sendemail) and arguments to send to the function ({"email":"test@example.com","message":"Hi!"}).
So if toolcalls is undefined or empty, then we execute the else branch, which in this case just logs the answer.
However, if toolcalls has at least one object, then it means we need to call the function for the LLM. Let’s zoom into the if branch:
You can see in the code above that we need to know what function it’s asking us to call and whether it exists in our code.
But if it exists, we will handle calling the function for the LLM. Let’s zoom into that if branch if (functionName === 'sendemail'):
Note how we prompted the LLM again after the tool call. This time it would return the final answer.
One thing I want to draw your attention to is how we used role: tool instead of user.
