To understand function calling, you should have an understanding of Prem SDK. If not, please check that out first.

Function calling allows models to connect with external tools, which is a great way to give hallucination-free precise answers. Functions can be any user-defined function or API call, etc. Prem SDK supports function calling for only a few model providers. Here is the list of models that supports function calling:

Model NameTier
gpt-4oHigh
gpt-4-turboHigh
gpt-4High
mistral-small-latestHigh
claude-3.5-sonnetHigh
claude-3-haikuHigh
claude-3-opusHigh
claude-3-sonnetHigh

Setup prem client

We first instantiate our prem client.

Make sure you have an account at Prem AI Platform and a valid project id and an API Key. The project_id used here is a dummy id.

Define functions

Let’s start with defining some simple functions. In our example, we will define simple arithmetic functions like addition and division. At the end of this example, we will show you why you need to define simple arithmetic functions when dealing with something related to LLMs and crunching numbers.

Testing LLMs without using external functions

We first test an LLM’s arithmetic capability without providing any external tool. This will help us understand the significance of using tools.

We intentionally used such big numbers and here is what we got as result:

The LLM answered as 371410150275.0, but the answer was 355140529450725.56. They do not match, and hence, we get an impression of the LLM hallucinating when the number gets too large. Let’s do the same thing, but we will use function calling this time.

Using function calls

The whole point of using function/tool calls is that we do not want LLM to guess answers. Instead, we want it to get the information with the help of external tools and then use its expressive power to give a better and more complete answer. So, the objective becomes LLM’s capability to understand the functions given to it and when to call what.

Define the set of tools for the LLM.

We first define all the tools that the LLM needs to choose from that set of tools when given a user’s query.

If you look carefully, each element in the above list is a dictionary, which has the type of the tool (which is a function here). Then, we define the properties of the function, like name, description, parameters (which are function arguments), their type (whether the parameter is an integer or a string or some object), and all the required parameters of the function.

Feeding the tools to the LLM

The overall tool calling of an LLM can be divided into two phases (which use two explicit LLM calls) as follows:

  1. In the first pass, we pass our query along with the tools (as shown above), and we get a JSON response back, which gives us the information about what functions the LLM calls sequentially.

  2. In the second pass, we parse all the functions LLM needs to call, and we call it and get the results with the arguments that the LLM gave us and get our result. We gather the results to feed them into the LLM.

After this, we get our final result from the LLM, which will always be more precise and have fewer chances of hallucination than when a function call is not used.

We start with our first pass, which is when we pass the tools to our LLM.

Here is the result from the first pass.

If you see, the LLM followed the BODMAS rule in math, where it called the division operation first and then addition.

Now we parse this output and then call the functions (as mentioned by the LLM) on by one and gather our results.

Calling and gathering the functions response

We first define a simple map between name of the function and the function object.

After this, we write a helper function that does the following:

  1. First, take all the intermediate results (sequence of tools called by the LLM, shown above) inside a text prompt and then append that prompt inside the messages list with the role of assistant.
  2. Parse each tool in tool_calls and then call the function, get the result, take all three values, and fit them into our prompt.
  3. Finally, append this prompt as the role user in our existing messages list.

Let’s use this function to get our updated messages that we can use it in our second pass.

Here is what our meessages look like, before we pass it to our LLM in the second time:

Now, we pass this to our LLM:

And here is our final result:

And this time, our LLM gives the correct answer which is: 355140529450725.56

Summary

So that is how you do function calling using Prem. You can re-use this helper function: insert_tool_messages so that your toolcalling workflow becomes easier. Here is your final code:

Congratulations on completion of tool calling. Now you can replace this function/tools with the function/tools of your choice.