Login Sign Up

Executing OpenAI Functions

OpenAI introduced a structure specification for defining the interface between functions/plugins that an LLM can execute. This specification is becoming a standard, enabling LLM systems to provide actionable responses.

Adding Functions to LLM API Calls

A function definition allows an LLM to interpret and format its response as a function call. 

Key Elements in Function Definition

Here we are providing an example of an LLM API call that includes tools and a function definition.

Code Example: first_function.py (API call)

response = client.chat.completions.create(
        model="gpt-4-1106-preview",
        messages=[{"role": "system",
                   "content": "You are a helpful assistant."},
                  {"role": "user", "content": user_message}],
        temperature=0.7,
        tools=[  # 1
            {
                "type": "function",  # 2
                "function": {
                    "name": "recommend",
                    "description": "Provide a recommendation for a topic.",  # 3
                    "parameters": {
                        "type": "object",  # 4
                        "properties": {
                            "topic": {
                                "type": "string",
                                "description": "The topic to get a recommendation for.",  # 5
                            },
                            "rating": {
                                "type": "string",
                                "description": "The rating to be given.",  # 5
                                "enum": ["good", "bad", "terrible"],  # 6
                            },
                        },
                        "required": ["topic"],
                    },
                },
            }
        ]
)

Explanation

  • #1: Introduces a new tools parameter.
  • #2: Specifies the tool type as function.
  • #3: Describes the function’s purpose.
  • #4: Defines input parameters as an object (JSON document).
  • #5: Gives descriptions for each input parameter.
  • #6: Uses enumerations for controlled values.

To test this, open Visual Studio Code (VS Code) and set up the environment by installing dependencies from requirements.txt.

Running API Calls

The following example demonstrates calling the function with different user inputs.

Code Example: first_function.py (exercising the API)

user = "Can you please recommend me a time travel movie?"
response = ask_chatgpt(user)  # 1
print(response)

# Output
Function(arguments='{"topic":"time travel movie"}', name='recommend')  # 2

user = "Can you please recommend me a good time travel movie?"
response = ask_chatgpt(user)  # 3
print(response)

# Output
Function(arguments='{"topic":"time travel movie", "rating":"good"}', name='recommend')  # 4

Explanation

  • #1, #3: Calls the defined function.
  • #2, #4: Returns the function name and extracted input parameters.

Note: The actual function isn’t being executed; the LLM only suggests the function with relevant input parameters. You must extract and pass these into a function for execution.

Executing Function Calls

Since an LLM does not directly execute functions or plugins, we need to integrate a separate execution layer. The following example demonstrates calling a recommendation function.

Process Overview

  1. Submit a request that includes a function definition.
  2. The LLM responds with function calls and input parameters.
  3. Execute the functions and return results to the LLM.
  4. The LLM processes the responses into natural language.

Code Example: parallel_functions.py (recommend function)

def recommend(topic, rating="good"):

    if "time travel" in topic.lower():  # 1

        return json.dumps({"topic": "time travel",

                           "recommendation": "Back to the Future",

                           "rating": rating})

    elif "recipe" in topic.lower():  # 1

        return json.dumps({"topic": "recipe",

                           "recommendation": "The best thing I ever ate.",

                           "rating": rating})

    elif "gift" in topic.lower():  # 1

        return json.dumps({"topic": "gift",

                           "recommendation": "A glorious new watch.",

                           "rating": rating})

    else:  # 2

        return json.dumps({"topic": topic,

                           "recommendation": "unknown"})  # 3

Explanation

  • #1: Checks if the input contains predefined topics.
  • #2: Returns a default response if no match is found.
  • #3: Outputs a JSON object.

Making a Request with Multiple Function Calls

Now, let’s see how to construct a request for multiple recommendations.

Code Example: parallel_functions.py (run_conversation, request)

user = """Can you please make recommendations for the following:
Time travel movies
Recipes
Gifts"""  # 1
messages = [{"role": "user", "content": user}]  # 2

tools = [  # 3

    {

        "type": "function",

        "function": {

            "name": "recommend",

            "description": "Provide a recommendation for any topic.",

            "parameters": {

                "type": "object",

                "properties": {

                    "topic": {

                        "type": "string",

                        "description": "The topic to get a recommendation for.",

                    },

                    "rating": {

                        "type": "string",

                        "description": "The rating given.",

                        "enum": ["good", "bad", "terrible"]

                    },

                },

                "required": ["topic"],

            },

        },

    }

]

Explanation

  • #1: User request includes multiple recommendations.
  • #2: No system message is included.
  • #3: Adds the function definition to the tools parameter.

Processing the Function Calls

After making the request, the API will return multiple function call outputs.

Code Example: parallel_functions.py (run_conversation, tool_calls)

tool_calls = response_message.tool_calls  # 1

if tool_calls:  # 1

    available_functions = {

        "recommend": recommend,

    }  # 2




    for tool_call in tool_calls:  # 3

        function_name = tool_call.function.name

        function_to_call = available_functions[function_name]

        function_args = json.loads(tool_call.function.arguments)

        function_response = function_to_call(

            topic=function_args.get("topic"),  # 4

            rating=function_args.get("rating"),

        )

        messages.append(  # 5

            {

                "tool_call_id": tool_call.id,

                "role": "tool",

                "name": function_name,

                "content": function_response,

            }

        )




    second_response = client.chat.completions.create(  # 6

        model="gpt-3.5-turbo-1106",

        messages=messages,

    )

    return second_response.choices[0].message.content  # 6

Explanation

  • #1: If the response contains function calls, execute them.
  • #2: Defines available functions.
  • #3: Loops through the calls and extracts relevant arguments.
  • #4: Calls the function with extracted parameters.
  • #5: Adds function responses to the conversation.
  • #6: Sends function results back to the LLM for a final response.