Openai Assistant returns random values after a function call

Hi, I’m creating an order support chat bot for a pizzeria with the gpt-3.5-turbo model in italian language. I’m using openAi Assistants using “function calls” to retrieve information.
I have two problems:

  1. The agent allows you to include pizzas not on the menu in your order, despite the instruction not to do so.
  2. Generates random information in response to the function call to retrieve address, telephone, name and surname.

This is the entire prompt:

**your_assistant = client.beta.assistants.create(
name=“Order Assistant”,
description="Assistente che chiede l’ordine delle pizze al cliente. ",
instructions=“Sei un assistente per ordinare la pizza, ti chiami Pizzo e aiuti i clienti nell’eseguire un’ordinazione. Puoi vendere solo pizze e bibite presenti nel menu, se non ci sono, rifiuta. Ci sono 2 menu: MENU PIZZE e MENU BIBITE. Le pizze presenti nel MENU PIZZE possono essere di 2 tipologie: pizza classica o scrocchiarella. Chiedi sempre la tipologia. Le bibite ordinabili sono solo quelle del MENU BIBITE. Mostra sempre un riepilogo dell’ordine dopo la scelta del cliente. Mostra il menu pizze se richiesto (MENU PIZZE) o il menu bibite (MENU BIBITE), visualizza il nome del prodotto (prodotto), la descrizione del prodotto (descrizione) e il prezzo del prodotto (prezzo). Mostra la tipologia (tipologia) se mostri il MENU BIBITE.\n Accetti ordinazioni di prodotti presenti nel menu, altri prodotti non presenti nel menu non possono essere ordinati.\n Ad ogni ordine chiedi al cliente se ha terminato o se vuole una bibita dal menu (MENU BIBITE). Se ha completato l’ordine mostra l’intero ordine e il totale da pagare. Chiedi una conferma dell’ordine. Chiedi l’indirizzo di recapito (indirizzo), un recapito telefonico (telefono) e il nome (nome) sul campanello. La transazione è conclusa solo se hai recuperato le informazioni di indirizzo, telefono, nome e cognome. Chiedi queste informazioni prima di concludere l’ordine.”
**.

When the assistant starts, I’m automaticaly sending “assistant” type messages to the assistant in order to provide further information, such as the pizza and drinks menu in json format and the instruction not to accept orders other than the menu:

msg = 'Questo è il MENU PIZZE in formato json: \n [{ "prodotto": "pizza capricciosa", "descrizione": "pomodoro, mozzarella, prosciutto cotto, funghi, carciofini", "prezzo classica": "8,00", "prezzo scrocchiarella": "20,00" }, { "prodotto": "diavola", "descrizione": "pomodoro, mozzarella, salamino piccante", "prezzo classica": "7,00", "prezzo scrocchiarella": "18,50" }, { "prodotto": "pizza margherita", "descrizione": "pomodoro, mozzarella", "prezzo classica": "6,00", "prezzo scrocchiarella": "18,00" }]'
send_sys_message(thread,msg)

msg = 'questo è il MENU BIBITE in formato json: \n [{ "prodotto": "birra moretti piccola", "descrizione": "33cl", "prezzo": "3,00" }, { "prodotto": "birra moretti grande", "descrizione": "66cl", "prezzo": "6,00" }, { "prodotto": "acqua ", "descrizione": "0,5cl", "prezzo classica": "1,50" }]'
send_sys_message(thread,msg)

msg = 'Se il cliente conferma il suo ordine, ma non hai recueperato le informazioni di: indirizzo di recapito, numero di telefono, nome sul campanello, continua a chiederle al cliente. L''ordine si conclude solo se ho tutte le informazioni valorizzate. Una stringa vuota non viene accettata. Chiedere nuovamente al cliente fino al recupero dell''informazione.'   
send_sys_message(thread,msg)

this is the definition of the 2 function-call:

tools = [
   {
       "type": "function",
       "function": {
           "name": "get_order",
           "description": "Usa questa funzione per recuperare l'ordine",
           "parameters": {
               "type": "object",
               "properties": {
                   "prodotto": {
                       "type": "string",
                       "description": "Il prodotto selezionato dal cliente"
                   },
                   "tipologia": {
                       "type": "string",
                       "enum": ["pizza classica", "scrocchiarella"],
                       "description": "La tipologia di prodotto ordinato"
                   },
                  "prezzo": {
                        "type":"string",
                        "description": "Il prezzo del prodotto, basato sulla tipologia (prezzo pizza classica o prezzo scrocchiarella)"
                  }
               },
               "required": ["prodotto", "tipologia", "prezzo"]
           }
       }
   },
  {
       "type": "function",
       "function": {
           "name": "get_delivery_info",
           "description": "Usa questa funzione per recuperare l'indirizzo del cliente, il numero di telefono o il nome sul campanello. Inizializza il dato a null o nullo. Il dato è obbligatorio, non deve essere generata randomicamente.",
           "parameters": {
               "type": "object",
               "properties": {
                   "indirizzo": {
                       "type": "string",
                       "description": "L'indirizzo di recapito dell'ordine"
                   },
                    "telefono": {
                       "type": "string",
                       "description": "Il numero di telefono del cliente"
                   },
                  "nomeCongnome": {
                        "type":"string",
                        "description": "Nome e cognome del cliente"
                  }
               },
               "required": ["indirizzo", "telefono","nomeCognome"]
           }
       }
   }]

For example, the assistant accepts the “Viennese” pizza even though it is not on the menu. In addition to this, when asking for address, telephone and person data, it generates random information (namesurname: “Mario Rossi”) never entered by the customer.

send_message(thread, "Vorrei una pizza viennese classica e una diavola tipologia scrocchiarella. vorrei anche una birra moretti grande")

RequiredAction(submit_tool_outputs=RequiredActionSubmitToolOutputs(tool_calls=[RequiredActionFunctionToolCall(id=‘call_HRbnuWbDIM8NNph5qJdR5c8S’, function=Function(arguments=‘{“prodotto”:“viennese”,“tipologia”:“pizza classica”,“prezzo”:“5,00”}’, name=‘get_order’), type=‘function’)]), type=‘submit_tool_outputs’)
Tool ID: call_HRbnuWbDIM8NNph5qJdR5c8S
Tool name: get_order
Tool args:
{‘prodotto’: ‘viennese’, ‘tipologia’: ‘pizza classica’, ‘prezzo’: ‘5,00’}

if I confirm the order, the assistant generates a random response for the function call get_delivery_info:

Tool ID: call_zc6KXSYCrsJey727KxuuIjLR
Tool name: get_delivery_info
Tool args:
{‘indirizzo’: ‘Via Roma 10’, ‘telefono’: ‘1234567890’, ‘nomeCongnome’: ‘Mario Rossi’}

I’m probably doing something wrong in the prompt or in the definition of the function-call object, but I don’t understand what.
I would add that using the gpt-4 model this behavior does not occur. Is this perhaps a limitation of the gpt-3.5 model?

Thank you
Matteo

  1. The agent allows you to include pizzas not on the menu in your order, despite the instruction not to do so.

With regards to your first problem, is it practical to use an “enum: […]” to limit the product property, or do you need your ‘get_order’ function to do a database table lookup to validate what the user selected?

1 Like

hi, thanks for the reply. I inserted the list of enums:

"prodotto": {
                       "type": "string",
                       **"enum": ["pizza capricciosa", "pizza diavola", "pizza margherita","birra moretti piccola","birra moretti grande","acqua"]**,
                       "description": "Il prodotto selezionato dal cliente"
                   }

in the two tests performed, asking for “Viennese” pizza the agent populates the product field with random values ​​(“Capricciosa” or “Margherita”). The result seems unpredictable.

1 Like

Yes, this is quite common. You may need to build guardrails to check the information programmatically before sending to the user. Newer models notably perform better, but will nonetheless some times fail.

It’s a risk inherent with using stochastic models for customer-facing applications, a lot has to be built around it to prevent these issues.

2 Likes

I’m experimenting with “guard rails” at the moment.

For example, if the Chatbot replies with a post that includes illegal URLs that won’t resolve to a suitable page, a reply is sent back to the LLM to ask it to regenerate its response (and so on until we reach a safe iteration limit).

It’s too early to say if this technique will improve things materially.

It would also make sense to me to only allow things to be added to the order with your function and the function would have to validate what it was being asked to add to the order before doing so. If it was unable to validate it would have to circle back with the LLM to tell the LLM that the item didn’t exist and to ask for an alternative?

1 Like

Out of interest, in your case your bot has an “agenda” - presumably it needs to gather and fulfil an order and lead the user through that process pro-actively?

What techniques are you using to achieve that?

1 Like