Share via


Come usare la chiamata di funzione con il servizio Azure OpenAI (anteprima)

Le versioni più recenti di gpt-35-turbo e gpt-4 sono ottimizzate per funzionare con le funzioni e sono in grado di determinare quando e come deve essere chiamata una funzione. Se una o più funzioni sono incluse nella richiesta, il modello determina se una delle funzioni deve essere chiamata in base al contesto del prompt. Quando il modello determina che deve essere chiamata una funzione, risponde con un oggetto JSON, inclusi gli argomenti per la funzione.

I modelli formulano chiamate API e generano output dei dati della struttura, tutti basati sulle funzioni specificate. È importante notare che, mentre i modelli possono generare queste chiamate, è necessario eseguirle, assicurandosi di rimanere in controllo.

A livello generale è possibile suddividere l'uso delle funzioni in tre passaggi:

  1. Chiamare l'API di completamento della chat con le funzioni e l'input dell'utente
  2. Usare la risposta del modello per chiamare l'API o la funzione
  3. Chiamare di nuovo l'API di completamento della chat, inclusa la risposta dalla funzione per ottenere una risposta finale

Importante

I functions parametri e function_call sono stati deprecati con il rilascio della 2023-12-01-preview versione dell'API. La sostituzione di functions è il tools parametro . La sostituzione di function_call è il tool_choice parametro .

Chiamata di funzioni parallele

Le chiamate di funzione parallele sono supportate con:

Modelli supportati

  • gpt-35-turbo (1106)
  • gpt-35-turbo (0125)
  • gpt-4 (1106-Preview)
  • gpt-4 (0125-Preview)

Supporto dell'API

Il supporto per la funzione parallela è stato aggiunto per la prima volta nella versione dell'API 2023-12-01-preview

Le chiamate di funzione parallele consentono di eseguire più chiamate di funzione insieme, consentendo l'esecuzione parallela e il recupero dei risultati. In questo modo si riduce il numero di chiamate all'API che devono essere effettuate e possono migliorare le prestazioni complessive.

Ad esempio, per una semplice app meteo, è possibile recuperare il meteo in più posizioni contemporaneamente. Verrà generato un messaggio di completamento della chat con tre chiamate di funzione nella tool_calls matrice, ognuna con un oggetto univoco id. Se si vuole rispondere a queste chiamate di funzione, aggiungere 3 nuovi messaggi alla conversazione, ognuno contenente il risultato di una chiamata di funzione, con un tool_call_id riferimento a id da tools_calls.

Di seguito è disponibile una versione modificata dell'esempio di get_current_weather OpenAI. Questo esempio come con l'originale di OpenAI consiste nel fornire la struttura di base, ma non è un esempio autonomo completamente funzionante. Il tentativo di eseguire questo codice senza ulteriori modifiche genera un errore.

In questo esempio viene definita una singola funzione get_current_weather. Il modello chiama la funzione più volte e, dopo l'invio della risposta della funzione al modello, decide il passaggio successivo. Risponde con un messaggio rivolto all'utente che indicava all'utente la temperatura a San Francisco, Tokyo e Parigi. A seconda della query, può scegliere di chiamare di nuovo una funzione.

Per forzare il modello a chiamare una funzione specifica, impostare il tool_choice parametro con un nome di funzione specifico. È anche possibile forzare il modello a generare un messaggio rivolto all'utente impostando tool_choice: "none".

Nota

Il comportamento predefinito (tool_choice: "auto") è che il modello decida autonomamente se chiamare una funzione e, in tal caso, quale funzione chiamare.

import os
from openai import AzureOpenAI
import json

client = AzureOpenAI(
  azure_endpoint = os.getenv("AZURE_OPENAI_ENDPOINT"), 
  api_key=os.getenv("AZURE_OPENAI_API_KEY"),  
  api_version="2024-03-01-preview"
)


# Example function hard coded to return the same weather
# In production, this could be your backend API or an external API
def get_current_weather(location, unit="fahrenheit"):
    """Get the current weather in a given location"""
    if "tokyo" in location.lower():
        return json.dumps({"location": "Tokyo", "temperature": "10", "unit": unit})
    elif "san francisco" in location.lower():
        return json.dumps({"location": "San Francisco", "temperature": "72", "unit": unit})
    elif "paris" in location.lower():
        return json.dumps({"location": "Paris", "temperature": "22", "unit": unit})
    else:
        return json.dumps({"location": location, "temperature": "unknown"})

def run_conversation():
    # Step 1: send the conversation and available functions to the model
    messages = [{"role": "user", "content": "What's the weather like in San Francisco, Tokyo, and Paris?"}]
    tools = [
        {
            "type": "function",
            "function": {
                "name": "get_current_weather",
                "description": "Get the current weather in a given location",
                "parameters": {
                    "type": "object",
                    "properties": {
                        "location": {
                            "type": "string",
                            "description": "The city and state, e.g. San Francisco, CA",
                        },
                        "unit": {"type": "string", "enum": ["celsius", "fahrenheit"]},
                    },
                    "required": ["location"],
                },
            },
        }
    ]
    response = client.chat.completions.create(
        model="<REPLACE_WITH_YOUR_MODEL_DEPLOYMENT_NAME>",
        messages=messages,
        tools=tools,
        tool_choice="auto",  # auto is default, but we'll be explicit
    )
    response_message = response.choices[0].message
    tool_calls = response_message.tool_calls
    # Step 2: check if the model wanted to call a function
    if tool_calls:
        # Step 3: call the function
        # Note: the JSON response may not always be valid; be sure to handle errors
        available_functions = {
            "get_current_weather": get_current_weather,
        }  # only one function in this example, but you can have multiple
        messages.append(response_message)  # extend conversation with assistant's reply
        # Step 4: send the info for each function call and function response to the model
        for tool_call in tool_calls:
            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(
                location=function_args.get("location"),
                unit=function_args.get("unit"),
            )
            messages.append(
                {
                    "tool_call_id": tool_call.id,
                    "role": "tool",
                    "name": function_name,
                    "content": function_response,
                }
            )  # extend conversation with function response
        second_response = client.chat.completions.create(
            model="<REPLACE_WITH_YOUR_1106_MODEL_DEPLOYMENT_NAME>",
            messages=messages,
        )  # get a new response from the model where it can see the function response
        return second_response
print(run_conversation())

Uso della funzione nell'API di completamento della chat (deprecato)

La chiamata a funzioni è disponibile nella versione DELL'API e funziona con la 2023-07-01-preview versione 0613 di gpt-35-turbo, gpt-35-turbo-16k, gpt-4 e gpt-4-32k.

Per usare la chiamata di funzione con l'API Completamento chat, è necessario includere due nuove proprietà nella richiesta: functions e function_call. È possibile includere una o più functions nella richiesta ed è possibile ottenere altre informazioni su come definire le funzioni nella sezione definizione delle funzioni . Tenere presente che le funzioni vengono inserite nel messaggio di sistema sotto le quinte in modo che le funzioni vengano conteggiati in base all'utilizzo del token.

Quando vengono fornite le funzioni, per impostazione predefinita function_call è impostato su "auto" e il modello decide se deve essere chiamata una funzione. In alternativa, è possibile impostare il function_call parametro su {"name": "<insert-function-name>"} per forzare l'API a chiamare una funzione specifica oppure impostare il parametro su per "none" impedire al modello di chiamare qualsiasi funzione.

Nota

La versione della libreria Python OpenAI 0.28.1 è deprecata. Ti consigliamo di usare 1.x. Vedere la Guida alla migrazione per informazioni sul passaggio da 0.28.1 a 1.x.


import os
import openai

openai.api_key = os.getenv("AZURE_OPENAI_API_KEY")
openai.api_version = "2023-07-01-preview"
openai.api_type = "azure"
openai.api_base = os.getenv("AZURE_OPENAI_ENDPOINT")

messages= [
    {"role": "user", "content": "Find beachfront hotels in San Diego for less than $300 a month with free breakfast."}
]

functions= [  
    {
        "name": "search_hotels",
        "description": "Retrieves hotels from the search index based on the parameters provided",
        "parameters": {
            "type": "object",
            "properties": {
                "location": {
                    "type": "string",
                    "description": "The location of the hotel (i.e. Seattle, WA)"
                },
                "max_price": {
                    "type": "number",
                    "description": "The maximum price for the hotel"
                },
                "features": {
                    "type": "string",
                    "description": "A comma separated list of features (i.e. beachfront, free wifi, etc.)"
                }
            },
            "required": ["location"]
        }
    }
]  

response = openai.ChatCompletion.create(
    engine="gpt-35-turbo-0613", # engine = "deployment_name"
    messages=messages,
    functions=functions,
    function_call="auto", 
)

print(response['choices'][0]['message'])
{
  "role": "assistant",
  "function_call": {
    "name": "search_hotels",
    "arguments": "{\n  \"location\": \"San Diego\",\n  \"max_price\": 300,\n  \"features\": \"beachfront,free breakfast\"\n}"
  }
}

La risposta dell'API include una function_call proprietà se il modello determina che deve essere chiamata una funzione. La function_call proprietà include il nome della funzione da chiamare e gli argomenti da passare alla funzione. Gli argomenti sono una stringa JSON che è possibile analizzare e usare per chiamare la funzione.

In alcuni casi, il modello genera sia content che .function_call Ad esempio, per il prompt sopra il contenuto potrebbe dire qualcosa come "Certo, posso aiutarti a trovare alcuni hotel a San Diego che soddisfano i tuoi criteri" insieme al function_call.

Uso della chiamata di funzione

La sezione seguente illustra in modo più dettagliato come usare in modo efficace le funzioni con l'API Completamento chat.

Definizione delle funzioni

Una funzione ha tre parametri principali: name, descriptione parameters. Il description parametro viene usato dal modello per determinare quando e come chiamare la funzione in modo che sia importante fornire una descrizione significativa delle operazioni che la funzione esegue.

parameters è un oggetto schema JSON che descrive i parametri accettati dalla funzione. Altre informazioni sugli oggetti dello schema JSON sono disponibili nelle informazioni di riferimento sullo schema JSON.

Se si vuole descrivere una funzione che non accetta parametri, usare {"type": "object", "properties": {}} come valore per la parameters proprietà .

Gestione del flusso con le funzioni

Esempio in Python.


response = openai.ChatCompletion.create(
    deployment_id="gpt-35-turbo-0613",
    messages=messages,
    functions=functions,
    function_call="auto", 
)
response_message = response["choices"][0]["message"]

# Check if the model wants to call a function
if response_message.get("function_call"):

    # Call the function. The JSON response may not always be valid so make sure to handle errors
    function_name = response_message["function_call"]["name"]

    available_functions = {
            "search_hotels": search_hotels,
    }
    function_to_call = available_functions[function_name] 

    function_args = json.loads(response_message["function_call"]["arguments"])
    function_response = function_to_call(**function_args)

    # Add the assistant response and function response to the messages
    messages.append( # adding assistant response to messages
        {
            "role": response_message["role"],
            "function_call": {
                "name": function_name,
                "arguments": response_message["function_call"]["arguments"],
            },
            "content": None
        }
    )
    messages.append( # adding function response to messages
        {
            "role": "function",
            "name": function_name,
            "content": function_response,
        }
    ) 

    # Call the API again to get the final response from the model
    second_response = openai.ChatCompletion.create(
            messages=messages,
            deployment_id="gpt-35-turbo-0613"
            # optionally, you could provide functions in the second call as well
        )
    print(second_response["choices"][0]["message"])
else:
    print(response["choices"][0]["message"])

Esempio in PowerShell.

# continues from the previous PowerShell example

$response = Invoke-RestMethod -Uri $url -Headers $headers -Body $body -Method Post -ContentType 'application/json'
$response.choices[0].message | ConvertTo-Json

# Check if the model wants to call a function
if ($null -ne $response.choices[0].message.function_call) {

    $functionName  = $response.choices[0].message.function_call.name
    $functionArgs = $response.choices[0].message.function_call.arguments

    # Add the assistant response and function response to the messages
    $messages += @{
        role          = $response.choices[0].message.role
        function_call = @{
            name      = $functionName
            arguments = $functionArgs
        }
        content       = 'None'
    }
    $messages += @{
        role          = 'function'
        name          = $response.choices[0].message.function_call.name
        content       = "$functionName($functionArgs)"
    }

    # Call the API again to get the final response from the model
    
    # these API arguments are introduced in model version 0613
    $body = [ordered]@{
        messages      = $messages
        functions         = $functions
        function_call   = 'auto'
    } | ConvertTo-Json -depth 6

    $url = "$($openai.api_base)/openai/deployments/$($openai.name)/chat/completions?api-version=$($openai.api_version)"

    $secondResponse = Invoke-RestMethod -Uri $url -Headers $headers -Body $body -Method Post -ContentType 'application/json'
    $secondResponse.choices[0].message | ConvertTo-Json
}

Output di esempio.

{
  "role": "assistant",
  "content": "I'm sorry, but I couldn't find any beachfront hotels in San Diego for less than $300 a month with free breakfast."
}

Negli esempi non viene eseguita alcuna convalida o gestione degli errori in modo da assicurarsi di aggiungerlo al codice.

Per un esempio completo dell'uso delle funzioni, vedere il notebook di esempio sulla chiamata a funzioni. È anche possibile applicare una logica più complessa per concatenare più chiamate di funzione, descritte anche nell'esempio.

Progettazione prompt con funzioni

Quando si definisce una funzione come parte della richiesta, i dettagli vengono inseriti nel messaggio di sistema usando una sintassi specifica su cui è stato eseguito il training del modello. Ciò significa che le funzioni usano i token nel prompt e che è possibile applicare tecniche di progettazione richieste per ottimizzare le prestazioni delle chiamate di funzione. Il modello usa il contesto completo del prompt per determinare se deve essere chiamata una funzione, inclusa la definizione di funzione, il messaggio di sistema e i messaggi utente.

Miglioramento della qualità e dell'affidabilità

Se il modello non chiama la funzione quando o come ci si aspetta, è possibile provare a migliorare la qualità.

Specificare altri dettagli nella definizione della funzione

È importante fornire un significato description della funzione e fornire descrizioni per qualsiasi parametro che potrebbe non essere ovvio per il modello. Ad esempio, nella descrizione del location parametro è possibile includere dettagli aggiuntivi ed esempi sul formato della posizione.

"location": {
    "type": "string",
    "description": "The location of the hotel. The location should include the city and the state's abbreviation (i.e. Seattle, WA or Miami, FL)"
},
Fornire più contesto nel messaggio di sistema

Il messaggio di sistema può essere usato anche per fornire più contesto al modello. Ad esempio, se si dispone di una funzione denominata search_hotels è possibile includere un messaggio di sistema simile al seguente per indicare al modello di chiamare la funzione quando un utente chiede aiuto per trovare un hotel.

{"role": "system", "content": "You're an AI assistant designed to help users search for hotels. When a user asks for help finding a hotel, you should call the search_hotels function."}
Indicare al modello di porre domande chiare

In alcuni casi, si vuole indicare al modello di porre domande chiare per evitare di fare ipotesi sui valori da usare con le funzioni. Ad esempio, con search_hotels si vuole che il modello richieda chiarimenti se la richiesta dell'utente non include dettagli su location. Per indicare al modello di porre una domanda chiara, è possibile includere contenuto come l'esempio successivo nel messaggio di sistema.

{"role": "system", "content": "Don't make assumptions about what values to use with functions. Ask for clarification if a user request is ambiguous."}

Riduzione degli errori

Un'altra area in cui l'ingegneria della richiesta può essere utile consiste nel ridurre gli errori nelle chiamate di funzione. I modelli vengono sottoposti a training per generare chiamate di funzione corrispondenti allo schema definito, ma i modelli generano una chiamata di funzione che non corrisponde allo schema definito o tenta di chiamare una funzione non inclusa.

Se il modello genera chiamate di funzione non specificate, provare a includere una frase nel messaggio di sistema che indica "Only use the functions you have been provided with.".

Uso responsabile della chiamata di funzioni

Analogamente a qualsiasi sistema di intelligenza artificiale, l'uso della chiamata di funzione per integrare modelli linguistici con altri strumenti e sistemi presenta potenziali rischi. È importante comprendere i rischi che le chiamate di funzione potrebbero presentare e adottare misure per assicurarsi di usare le funzionalità in modo responsabile.

Ecco alcuni suggerimenti che consentono di usare le funzioni in modo sicuro e sicuro:

  • Convalida chiamate di funzione: verificare sempre le chiamate di funzione generate dal modello. Ciò include il controllo dei parametri, la funzione chiamata e la verifica dell'allineamento della chiamata all'azione desiderata.
  • Usare dati e strumenti attendibili: usare solo i dati provenienti da origini attendibili e verificate. I dati non attendibili nell'output di una funzione possono essere usati per indicare al modello di scrivere chiamate di funzione in modo diverso da quello previsto.
  • Seguire il principio dei privilegi minimi: concedere solo l'accesso minimo necessario per la funzione per eseguire il proprio lavoro. In questo modo si riduce il potenziale impatto se una funzione viene utilizzata in modo improprio o sfruttata. Ad esempio, se si usano chiamate di funzione per eseguire query su un database, è consigliabile concedere all'applicazione solo l'accesso in sola lettura al database. Non è inoltre consigliabile dipendere esclusivamente dall'esclusione delle funzionalità nella definizione della funzione come controllo di sicurezza.
  • Prendere in considerazione l'impatto reale: tenere presente l'impatto reale delle chiamate di funzione che si prevede di eseguire, in particolare quelle che attivano azioni come l'esecuzione di codice, l'aggiornamento di database o l'invio di notifiche.
  • Implementare i passaggi di conferma utente: in particolare per le funzioni che eseguono azioni, è consigliabile includere un passaggio in cui l'utente conferma l'azione prima dell'esecuzione.

Per altre informazioni sulle raccomandazioni su come usare i modelli OpenAI di Azure in modo responsabile, vedere Panoramica delle procedure di intelligenza artificiale responsabili per i modelli OpenAI di Azure.

Passaggi successivi