Emulated multi-function calls within one request

Hello Community,

I want to share my insights in how to call multiple functions within one function API call.
This is the function API schema I use:

{
            "name": "multi_Func",
            "description": "Call two functions in one call",
            "parameters": {
                "type": "object",
                "properties": {
                    "get_Weather": {
                        "name": "get_Weather",
                        "description": "Get the weather for the location.",
                        "parameters": {
                            "type": "object",
                            "properties": {
                                "location": {
                                    "type": "string",
                                    "description": "The city and state, e.g. San Francisco, CA",
                                }
                            },
                            "required": ["location"],
                        }
                    },
                    "get_Events": {
                        "name": "get_Events",
                        "description": "Get events for the location at specified date",
                        "parameters": {
                            "type": "object",
                            "properties": {
                                "location": {
                                    "type": "string",
                                    "description": "The city and state, e.g. San Francisco, CA",
                                },
                                "date": {
                                    "type": "string",
                                    "description": "The date of the event, e.g. 2021-01-01."
                                }
                            },
                            "required": ["location", "date"],
                        }
                    }
                }, "required": ["get_Weather", "get_Events"],
            }
        }
  1. Scenario 1: User asks: “Get the events for San Francisco at 25th May 2023.” Response:
'function_call': {'name': 'multi_Func', 'arguments': '{\n  "get_Weather": null,\n  "get_Events": {\n    "location": "San Francisco",\n    "date": "2023-05-25"\n  }\n}'}}, 'finish_reason': 'function_call'}

You see, that the function call to get_Weather is null. Scenario 2: User asks: “Get the weather for San Franciso.” Response:

'function_call': {'name': 'multi_Func', 'arguments': '{\n  "get_Weather": {\n    "location": "San Francisco"\n  },\n  "get_Events": null\n}'}}

Here the get_Events is null Scenario 3: User asks: “Get the weather for San Francisco and the events for May 25th 2023.” Response:

'function_call': {'name': 'multi_Func', 'arguments': '{\n  "get_Weather": {\n    "location": "San Francisco"\n  },\n  "get_Events": {\n    "date": "2023-05-25",\n    "location": "San Francisco"\n  }\n}'}}

You get both functions called.
It is not calling the function_call twice, but it emulates it.

14 Likes

Since the announcement of the integration of function call I had been looking if I could get multiple responses for a request with a single call.

I think I will use this as a workaround.
Thanx :slight_smile:

2 Likes

I tried it. It works as expected. Thanks for this.

I should note however, from my testing, that adding previous conversation even in the function call is needed to maintain context.
For example, if I ask “what is the event for New York”, it will give me the event. But if I continue the conversation, “will the weather be any good?”, it will not return any function calls and sometimes it returns San Francisco, the example.

Yes, exactly.

My examples are all one-shot examples. For conversational style, a well defined system-prompt is needed and when the user asks for several locations in an ongoing convo, GPT could be confused.

Replying the same I did on another post:

You can actually specify function_call: 'none' and then specify on your prompt something like “you are an assistant that always replies with multiple function calls. Reply with straight JSON ready to be parsed.”. It works as expected.

3 Likes

Would you be willling to elaborate on that please?

1 Like

Assuming you are referring to magalhas’ method. I think he’s basically using the ChatGPT output as a function call. Instead of outputing a natural language response. the ChatGPT would output a JSON for any and all of your functions to process.

It’s more straightforward than encapsulating multiple functions inside a single function call, but the downside is you don’t get a natural language response. Basically you have run a 2nd API call to get a natural language response for your user.

1 Like

@magalhas I tried your method, but I had trouble getting a consistent format. The JSON keys change, how did you fix that?

Do you mean the format it uses? Sometimes it might be functions.functionName others straight functionName? If that’s the case you can also ask in the prompt to use a specific format that fits your code.

1 Like

Isn’t that the classical (old) way of calling functions with all the problems we had to deal with in the many months before OpenAI published the function calling API? The three most severe ones always being:

  • Despite an emphasising system message, not picking a presented function and instead answering that it cannot do what you asked it to do
  • NL intro and extros you need to detect and cut out
  • Sloppy json (I used yaml; less mistakes the LLM could do with formatting and quotes)

It’s such a relief that this is now over and we have a proper API and model trained to actually invoke the presented functions. I am very happy that the system message approach is finally no longer necessary, aren’t you? Was your experience negative with that feature?

1 Like

You still provide functions through the proper API and from my experience it replies always in the intended format. Problem with current functions implementation is if you want more than one function to be called.

When I read this thread I was hopeful that this will provide the solution but in my case, gpt just returns the text as the value for the property.

{
  extractMeetingLog: {
    text: "Met with John Smith. His wife is Mary, daughter is Sarah, and son Henderson. He's 45 now and wanting to retire by 60. Has 100k in retirement savings. He just changed jobs to work as a Project Manager with IBM. Mary's email address for future reference is mary@gmail.com. As next steps, need to set up John's sample portfolio, and send him a follow-up with a reminder with the onboarding materials by Friday. Separately Mary was interested in learning more about the Soundwaters charity, send her a link to the site tomorrow."
  },
  extractActionItems: {
    text: "As next steps, need to set up John's sample portfolio, and send him a follow-up with a reminder with the onboarding materials by Friday. Separately Mary was interested in learning more about the Soundwaters charity, send her a link to the site tomorrow."
  }
}

and this is my schema

{
    name: "multiFunctionCalls",
    description: "Call two functions in one call",
    parameters: {
      type: "object",
      properties: {
        extractMeetingLog: {
          name: "extractMeetingLog",
          description:
            "Extract date, names of attendees and summary of the meeting.",
          parameters: {
            type: "object", // specify that the parameter is an object
            properties: {
              date: {
                type: "string", // specify the parameter type as a string
                description: "The date of the meeting, e.g 26 July 2023",
              },
              attendees: {
                type: "string", // specify the parameter type as a string
                description:
                  "Names of attendees in the meeting, ['John', 'Sanjay', 'Mary']",
              },
              summary: {
                type: "string", // specify the parameter type as a string
                description: "Summary of the meeting.",
              },
            },
            required: ["date", "attendees", "summary"],
          },
        },
        extractActionItems: {
          name: "extractActionItems",
          description:
            "Extract a list of action item objects from the meeting notes.",
          parameters: {
            type: "object",
            properties: {
              actionItems: {
                type: "array",
                items: {
                  type: "object",
                  properties: {
                    relatedTo: {
                      type: "string",
                      description:
                        "The name of the person or item the task is related to, e.g John Smith",
                    },
                    assignedTo: {
                      type: "string",
                      description:
                        "The person the task is assigned to, e.g Me, Mary Smith",
                    },
                    dueDate: {
                      type: "string",
                      description:
                        "The date when the task is due, e.g 28 July 2023",
                    },
                    action: {
                      type: "string",
                      description:
                        "The task which needs to be done, e.g Setup onboarding materials",
                    },
                  },
                },
              },
            },
            required: ["actionItems"],
          },
        },
      },
    },
  },

Any help would be greatly appreciated. I’ve been stuck on this for some time now.

Hello @amartyasingh84 and welcome to the forum.

Sorry, for my late reply.

In the recommend solution, I put an extra required field for the function calls in the schema.
I don’t know, if this helps.
It seems also depending on the model be used.

I do not follow the development more closely like weeks before, because my priorities changed.

I hope my suggestion helps.

1 Like

+1 for adding multi-function calls as a feature to API

1 Like

You can actually do better than this. You can force the API to use a specific function called “response_with_multi_func_calls”. You can include a parameter called “reply” to capture a natural language response at the same time you also call multiple functions. To handle multiple function calls, add a parameter to “response_with_multi_func_calls” called “func_calls”. Make the parameter an array of objects. Give the objects a definition like:

properties: {
    name:{type:'string',description:'The unqualified name of the function to call from your set of known functions.'},
    args:{type:'object',description:'Set the function call arguments on this object using the definition of the function being called.',
    properties:{
        delete_me:{type:'string',description:'You MUST remove this placeholder property (name and value) and add the actual arguments from the function definition being invoked.'}
                                }
                            }
                        },
                        required:['name','arguments']

Then in the system prompt put something like “You must use the “response_with_multi_func_calls” function’s “func_calls” parameter in order to invoke secondary functions in the same way that you invoke “response_with_multi_func_calls”. You must set the function name and an argument object representing its arguments.” It’s a hack for sure, but this has worked for me without any real issue since functions were released other than it sometimes prepends “functions.” to the function names being called which I just look for and ignore.

1 Like

I’ve been stuck for awhile as well in implementing emulated function calls as I’m planning to create an AI tutor that assists me in the English language. There are instances that it works well but there are also times that it outputs this error “InvalidRequestError: Invalid value for ‘content’: expected a string, got null.” Let me know if there are incorrect approaches done in my function call and I am open to suggestions to improve the performance of my personal project.

{
    "name": "error_checker_function",
    "description":"Call three functions in one call",
    "parameters":{
        "type":"object",
        "properties":{
            "check_grammatical_error":{
                "name":"check_grammatical_error",
                "description": "Check for grammatical errors from the input",
                "parameters":{
                    "type":"object",
                    "properties":{
                        "grammar_error":{
                            "type":"string",
                            "description":"Parts of a text that do not follow standard English grammar rules, e.g I is happy"
                        },
                        "grammar_correction":{
                            "type":"string",
                            "description":"Correct the grammatical error that violates English grammar rules from the input, e.g. Instead of saying 'I is happy' it should be 'I'm happy' or 'I am happy'"
                        }
                    },
                    "required": ["grammar_error", "grammar_correction"],
                }
            },
            "check_spelling_error":{
                "name":"check_spelling_error",
                "description": "Check for spelling errors from the input",
                "parameters":{
                    "type":"object",
                    "properties":{
                        "spelling_error":{
                            "type":"string",
                            "description":"Mistakes made in writing when the proper letter arrangement in a word is not followed in the English language, e.g 'Riecive'; 'Acomodate'"
                        },
                        "spelling_correction":{
                            "type":"string",
                            "description":"Correct the improper letter arrangement done from the input, e.g. 'Receive' is the proper spelling and not 'Riecive'; 'Accomodate' is the correct spelling, not 'Acomodate'"
                        }
                    },
                    "required": ["spelling_error", "spelling_correction"],
                }
            },
            "check_improper_punctuations":{
                "name":"check_improper_punctuations",
                "description": "Check for imporer punctuations usage from the input",
                "parameters":{
                    "type":"object",
                    "properties":{
                        "punctuation_error":{
                            "type":"string",
                            "description":"Incorrect punctuation usage that does not follow proper English punctuation rules, e.g The cat's are playful"
                        },
                        "punctuation_correction":{
                            "type":"string",
                            "description":"Correct the improper usage of punctuations from the input, e.g. Instead of saying 'The cat's are playful' it should be 'The cats are playful'"
                        }
                    },
                    "required": ["punctuation_error", "punctuation_correction"],
                }
            }
        }, "required":["check_grammatical_error","check_spelling_error","check_improper_punctuations"]
    }
}

I am wondering if it’s possible to add more functions to your current schema and ultimately allow GPT to output scripts like what Microsoft did in their GPT robotic paper. [ChatGPT for Robotics]

When one actually examines the language that the AI receives from trying to make these combined multi-purpose functions, one does not see the benefit beyond increased confusion.

In fact, the reason why trying to follow examples seen in this topic won’t work well is that second-level nested objects are not provided any description to the AI, so it has nothing to go on except the property name.

1 Like

Sure, of course. You can put more properties as multiple functions. I do not now the fuzzy limit, when the AI stops to call the function correctly under a specified threshold.
It is important to give reasonable descriptions to the fields added.

That makes a lot of sense. But is it documented anywhere? Or is there a way to find out what is being sent to the model?