ChatGPT API Function Calling: A Python Tutorial

It’s less than 24 hours since OpenAI announced the addition of function calling to the ChatGPT API, and already it’s making my life easier.

The Problem

In my AI-powered podcast, I ask ChatGPT to generate a combined title and summary of news stories. Although in my prompt I try to specify that this should be in a Python dictionary format, the variability of the output means sometimes it breaks my parser, I get errors and the podcast generation fails. That should be a thing of the past now.

The Solution

The new function feature does not mean that ChatGPT has direct access to our functions (that naming confused me at first). Instead, you can now specify your function details so that ChatGPT returns output in the format you need. In my case, I tell ChatGPT my function requires a title property and a summary property, and it seems to reliably provide content in those two properties. Perfect for me to use in my code with less fear of breakage.

How it works

The official documentation has both an API guide and an annotated walkthrough for a thorough explanation, but for simple usage you just need to add an optional functions property to your API request, and then parse the response appropriately.

Let’s say you have a function called write_post() that takes a title and summary and drafts a blog post from them. The main difference with the previous API is the addition of an optional functions property we can send in the request to ChatGPT, alongside the required model and messages properties. In the functions property we give ChatGPT a definition of our function, like this:

# Definition of our local function(s).
# This is effectively telling ChatGPT what we're going to use its output for.

functions = [
    {
        "name": "write_post",
        "description": "Shows the title and summary of some text.",
        "parameters": {
            "type": "object",
            "properties": {
                "title": {
                    "type": "string",
                    "description": "Title of the text output."
                },
                "summary": {
                    "type": "string",
                    "description": "Summary of the text output."
                }
            }
        }
    }
]

The rest of the request is pretty much unchanged, although there’s also a new optional function_call property when you can indicate whether you do or don’t want ChatGPT to use your function definition, or just leave it to decide by itself (the default). In the following code, I’ve explicitly told the API I want it to take my function into account by including its name.

Note: To use function calling, currently (June 2023) you have to use gpt-3.5-turbo-0613 or gpt-4-0613 as the model, otherwise you’ll get a server error (HTTP status: 400).

# The request to the ChatGPT API.

response = openai.ChatCompletion.create(
    model = "gpt-3.5-turbo-0613",
    messages = [
        {
            "role": "system",
            "content": "You are a useful assistant."
        },
        {
            "role": "user",
            "content": f"Here is an article: {article}. Please return a title and summary."
        }
    ],
    functions = functions,
    function_call = {
        "name": functions[0]["name"]
    }
)

Finally, the response you get back should contain a valid JSON object several layers deep. You can access it and then convert it to a proper (i.e. not stringified) JSON object like this:

# Parsing the ChatGPT JSON response.

arguments = response["choices"][0]["message"]["function_call"]["arguments"]
json_obj = json.loads(arguments)

And of course this code is all in your environment, so you can control whether to actually execute the function or not, or whether to use the JSON object and its properties in other ways – even sending it in a follow-up request to ChatGPT.

You can see a video walkthrough based on this tutorial here:

Leave a comment