Hai imparato abbastanza nei capitoli precedenti. Tuttavia, possiamo migliorare ulteriormente. Alcune cose che possiamo affrontare sono come ottenere un formato di risposta più coerente per facilitare il lavoro con la risposta a valle. Inoltre, potremmo voler aggiungere dati da altre fonti per arricchire ulteriormente la nostra applicazione.
I problemi sopra menzionati sono ciò che questo capitolo cerca di affrontare.
Questa lezione coprirà:
- Spiegare cosa sia la chiamata di funzioni e i suoi casi d'uso.
- Creare una chiamata di funzione utilizzando Azure OpenAI.
- Come integrare una chiamata di funzione in un'applicazione.
Alla fine di questa lezione, sarai in grado di:
- Spiegare lo scopo dell'utilizzo della chiamata di funzioni.
- Configurare la chiamata di funzione utilizzando il servizio Azure OpenAI.
- Progettare chiamate di funzione efficaci per il caso d'uso della tua applicazione.
Per questa lezione, vogliamo costruire una funzionalità per la nostra startup educativa che permetta agli utenti di utilizzare un chatbot per trovare corsi tecnici. Consiglieremo corsi che si adattano al loro livello di abilità, ruolo attuale e tecnologia di interesse.
Per completare questo scenario, utilizzeremo una combinazione di:
Azure OpenAIper creare un'esperienza di chat per l'utente.Microsoft Learn Catalog APIper aiutare gli utenti a trovare corsi basati sulla richiesta dell'utente.Function Callingper prendere la query dell'utente e inviarla a una funzione per effettuare la richiesta API.
Per iniziare, vediamo perché vorremmo utilizzare la chiamata di funzioni in primo luogo:
Prima della chiamata di funzioni, le risposte di un LLM erano non strutturate e incoerenti. Gli sviluppatori erano tenuti a scrivere codice di validazione complesso per assicurarsi di poter gestire ogni variazione di una risposta. Gli utenti non potevano ottenere risposte come "Qual è il meteo attuale a Stoccolma?". Questo perché i modelli erano limitati al tempo in cui i dati sono stati addestrati.
La chiamata di funzioni è una funzionalità del servizio Azure OpenAI per superare le seguenti limitazioni:
- Formato di risposta coerente. Se possiamo controllare meglio il formato della risposta, possiamo integrare più facilmente la risposta a valle in altri sistemi.
- Dati esterni. Capacità di utilizzare dati da altre fonti di un'applicazione in un contesto di chat.
Ti consigliamo di utilizzare il notebook incluso se vuoi eseguire lo scenario sotto riportato. Puoi anche semplicemente leggere mentre cerchiamo di illustrare un problema in cui le funzioni possono aiutare a risolvere il problema.
Vediamo l'esempio che illustra il problema del formato di risposta:
Supponiamo di voler creare un database di dati degli studenti in modo da poter suggerire il corso giusto a loro. Di seguito abbiamo due descrizioni di studenti molto simili nei dati che contengono.
-
Crea una connessione alla nostra risorsa Azure OpenAI:
import os import json from openai import AzureOpenAI from dotenv import load_dotenv load_dotenv() client = AzureOpenAI( api_key=os.environ['AZURE_OPENAI_API_KEY'], # this is also the default, it can be omitted api_version = "2023-07-01-preview" ) deployment=os.environ['AZURE_OPENAI_DEPLOYMENT']
Di seguito è riportato del codice Python per configurare la nostra connessione ad Azure OpenAI dove impostiamo
api_type,api_base,api_versionandapi_key. -
Creating two student descriptions using variables
student_1_descriptionandstudent_2_description.student_1_description="Emily Johnson is a sophomore majoring in computer science at Duke University. She has a 3.7 GPA. Emily is an active member of the university's Chess Club and Debate Team. She hopes to pursue a career in software engineering after graduating." student_2_description = "Michael Lee is a sophomore majoring in computer science at Stanford University. He has a 3.8 GPA. Michael is known for his programming skills and is an active member of the university's Robotics Club. He hopes to pursue a career in artificial intelligence after finishing his studies."
Vogliamo inviare le descrizioni degli studenti sopra a un LLM per analizzare i dati. Questi dati possono essere utilizzati successivamente nella nostra applicazione e inviati a un'API o memorizzati in un database.
-
Creiamo due prompt identici in cui istruiamo il LLM su quali informazioni siamo interessati:
prompt1 = f''' Please extract the following information from the given text and return it as a JSON object: name major school grades club This is the body of text to extract the information from: {student_1_description} ''' prompt2 = f''' Please extract the following information from the given text and return it as a JSON object: name major school grades club This is the body of text to extract the information from: {student_2_description} '''
I prompt sopra istruiscono il LLM a estrarre informazioni e restituire la risposta in formato JSON.
-
Dopo aver configurato i prompt e la connessione ad Azure OpenAI, invieremo ora i prompt al LLM utilizzando
openai.ChatCompletion. We store the prompt in themessagesvariable and assign the role touser. Questo per imitare un messaggio scritto da un utente a un chatbot.# response from prompt one openai_response1 = client.chat.completions.create( model=deployment, messages = [{'role': 'user', 'content': prompt1}] ) openai_response1.choices[0].message.content # response from prompt two openai_response2 = client.chat.completions.create( model=deployment, messages = [{'role': 'user', 'content': prompt2}] ) openai_response2.choices[0].message.content
Ora possiamo inviare entrambe le richieste al LLM ed esaminare la risposta che riceviamo trovandola in questo modo openai_response1['choices'][0]['message']['content'].
-
Lastly, we can convert the response to JSON format by calling
json.loads:# Loading the response as a JSON object json_response1 = json.loads(openai_response1.choices[0].message.content) json_response1
Risposta 1:
{ "name": "Emily Johnson", "major": "computer science", "school": "Duke University", "grades": "3.7", "club": "Chess Club" }Risposta 2:
{ "name": "Michael Lee", "major": "computer science", "school": "Stanford University", "grades": "3.8 GPA", "club": "Robotics Club" }Anche se i prompt sono gli stessi e le descrizioni sono simili, vediamo valori di
Gradesproperty formatted differently, as we can sometimes get the format3.7or3.7 GPAfor example.This result is because the LLM takes unstructured data in the form of the written prompt and returns also unstructured data. We need to have a structured format so that we know what to expect when storing or using this data
So how do we solve the formatting problem then? By using functional calling, we can make sure that we receive structured data back. When using function calling, the LLM does not actually call or run any functions. Instead, we create a structure for the LLM to follow for its responses. We then use those structured responses to know what function to run in our applications.
We can then take what is returned from the function and send this back to the LLM. The LLM will then respond using natural language to answer the user's query.
There are many different use cases where function calls can improve your app like:
-
Calling External Tools. Chatbots are great at providing answers to questions from users. By using function calling, the chatbots can use messages from users to complete certain tasks. For example, a student can ask the chatbot to "Send an email to my instructor saying I need more assistance with this subject". This can make a function call to
send_email(to: string, body: string) -
Create API or Database Queries. Users can find information using natural language that gets converted into a formatted query or API request. An example of this could be a teacher who requests "Who are the students that completed the last assignment" which could call a function named
get_completed(student_name: string, assignment: int, current_status: string) -
Creating Structured Data. Users can take a block of text or CSV and use the LLM to extract important information from it. For example, a student can convert a Wikipedia article about peace agreements to create AI flashcards. This can be done by using a function called
get_important_facts(agreement_name: string, date_signed: string, parties_involved: list)
The process of creating a function call includes 3 main steps:
- Calling the Chat Completions API with a list of your functions and a user message.
- Reading the model's response to perform an action i.e. execute a function or API Call.
- Making another call to Chat Completions API with the response from your function to use that information to create a response to the user.
The first step is to create a user message. This can be dynamically assigned by taking the value of a text input or you can assign a value here. If this is your first time working with the Chat Completions API, we need to define the role and the content of the message.
The role can be either system (creating rules), assistant (the model) or user (the end-user). For function calling, we will assign this as user e una domanda di esempio.
messages= [ {"role": "user", "content": "Find me a good course for a beginner student to learn Azure."} ]Assegnando ruoli diversi, è chiaro per il LLM se è il sistema a dire qualcosa o l'utente, il che aiuta a costruire una cronologia della conversazione su cui il LLM può basarsi.
Successivamente, definiremo una funzione e i parametri di quella funzione. Utilizzeremo solo una funzione qui chiamata search_courses but you can create multiple functions.
Important : Functions are included in the system message to the LLM and will be included in the amount of available tokens you have available.
Below, we create the functions as an array of items. Each item is a function and has properties name, description and parameters:
functions = [
{
"name":"search_courses",
"description":"Retrieves courses from the search index based on the parameters provided",
"parameters":{
"type":"object",
"properties":{
"role":{
"type":"string",
"description":"The role of the learner (i.e. developer, data scientist, student, etc.)"
},
"product":{
"type":"string",
"description":"The product that the lesson is covering (i.e. Azure, Power BI, etc.)"
},
"level":{
"type":"string",
"description":"The level of experience the learner has prior to taking the course (i.e. beginner, intermediate, advanced)"
}
},
"required":[
"role"
]
}
}
]Descriviamo ciascuna istanza di funzione più nel dettaglio di seguito:
name- The name of the function that we want to have called.description- This is the description of how the function works. Here it's important to be specific and clear.parameters- A list of values and format that you want the model to produce in its response. The parameters array consists of items where the items have the following properties:type- The data type of the properties will be stored in.properties- List of the specific values that the model will use for its responsename- The key is the name of the property that the model will use in its formatted response, for example,product.type- The data type of this property, for example,string.description- Description of the specific property.
There's also an optional property required - required property for the function call to be completed.
After defining a function, we now need to include it in the call to the Chat Completion API. We do this by adding functions to the request. In this case functions=functions.
There is also an option to set function_call to auto. This means we will let the LLM decide which function should be called based on the user message rather than assigning it ourselves.
Here's some code below where we call ChatCompletion.create, note how we set functions=functions and function_call="auto" e quindi dando al LLM la scelta di quando chiamare le funzioni che gli forniamo:
response = client.chat.completions.create(model=deployment,
messages=messages,
functions=functions,
function_call="auto")
print(response.choices[0].message)La risposta che torna ora appare così:
{
"role": "assistant",
"function_call": {
"name": "search_courses",
"arguments": "{\n \"role\": \"student\",\n \"product\": \"Azure\",\n \"level\": \"beginner\"\n}"
}
}Qui possiamo vedere come la funzione search_courses was called and with what arguments, as listed in the arguments property in the JSON response.
The conclusion the LLM was able to find the data to fit the arguments of the function as it was extracting it from the value provided to the messages parameter in the chat completion call. Below is a reminder of the messages valore:
messages= [ {"role": "user", "content": "Find me a good course for a beginner student to learn Azure."} ]Come puoi vedere, student, Azure and beginner was extracted from messages and set as input to the function. Using functions this way is a great way to extract information from a prompt but also to provide structure to the LLM and have reusable functionality.
Next, we need to see how we can use this in our app.
After we have tested the formatted response from the LLM, we can now integrate this into an application.
To integrate this into our application, let's take the following steps:
-
First, let's make the call to the OpenAI services and store the message in a variable called
response_message.response_message = response.choices[0].message
-
Ora definiremo la funzione che chiamerà l'API Microsoft Learn per ottenere un elenco di corsi:
import requests def search_courses(role, product, level): url = "https://learn.microsoft.com/api/catalog/" params = { "role": role, "product": product, "level": level } response = requests.get(url, params=params) modules = response.json()["modules"] results = [] for module in modules[:5]: title = module["title"] url = module["url"] results.append({"title": title, "url": url}) return str(results)
Nota come ora creiamo una vera funzione Python che si mappa ai nomi delle funzioni introdotti in
functionsvariable. We're also making real external API calls to fetch the data we need. In this case, we go against the Microsoft Learn API to search for training modules.
Ok, so we created functions variables and a corresponding Python function, how do we tell the LLM how to map these two together so our Python function is called?
-
To see if we need to call a Python function, we need to look into the LLM response and see if
function_callè parte di essa e chiama la funzione indicata. Ecco come puoi effettuare il controllo menzionato di seguito:# Check if the model wants to call a function if response_message.function_call.name: print("Recommended Function call:") print(response_message.function_call.name) print() # Call the function. function_name = response_message.function_call.name available_functions = { "search_courses": search_courses, } function_to_call = available_functions[function_name] function_args = json.loads(response_message.function_call.arguments) function_response = function_to_call(**function_args) print("Output of function call:") print(function_response) print(type(function_response)) # 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, } )
Queste tre righe assicurano che estraiamo il nome della funzione, gli argomenti e facciamo la chiamata:
function_to_call = available_functions[function_name] function_args = json.loads(response_message.function_call.arguments) function_response = function_to_call(**function_args)
Di seguito è riportato l'output dall'esecuzione del nostro codice:
Output
{ "name": "search_courses", "arguments": "{\n \"role\": \"student\",\n \"product\": \"Azure\",\n \"level\": \"beginner\"\n}" } Output of function call: [{'title': 'Describe concepts of cryptography', 'url': 'https://learn.microsoft.com/training/modules/describe-concepts-of-cryptography/? WT.mc_id=api_CatalogApi'}, {'title': 'Introduction to audio classification with TensorFlow', 'url': 'https://learn.microsoft.com/en- us/training/modules/intro-audio-classification-tensorflow/?WT.mc_id=api_CatalogApi'}, {'title': 'Design a Performant Data Model in Azure SQL Database with Azure Data Studio', 'url': 'https://learn.microsoft.com/training/modules/design-a-data-model-with-ads/? WT.mc_id=api_CatalogApi'}, {'title': 'Getting started with the Microsoft Cloud Adoption Framework for Azure', 'url': 'https://learn.microsoft.com/training/modules/cloud-adoption-framework-getting-started/?WT.mc_id=api_CatalogApi'}, {'title': 'Set up the Rust development environment', 'url': 'https://learn.microsoft.com/training/modules/rust-set-up-environment/?WT.mc_id=api_CatalogApi'}] <class 'str'> -
Ora invieremo il messaggio aggiornato,
messagesal LLM in modo da poter ricevere una risposta in linguaggio naturale anziché una risposta formattata in JSON dell'API.print("Messages in next request:") print(messages) print() second_response = client.chat.completions.create( messages=messages, model=deployment, function_call="auto", functions=functions, temperature=0 ) # get a new response from GPT where it can see the function response print(second_response.choices[0].message)
Output
{ "role": "assistant", "content": "I found some good courses for beginner students to learn Azure:\n\n1. [Describe concepts of cryptography] (https://learn.microsoft.com/training/modules/describe-concepts-of-cryptography/?WT.mc_id=api_CatalogApi)\n2. [Introduction to audio classification with TensorFlow](https://learn.microsoft.com/training/modules/intro-audio-classification-tensorflow/?WT.mc_id=api_CatalogApi)\n3. [Design a Performant Data Model in Azure SQL Database with Azure Data Studio](https://learn.microsoft.com/training/modules/design-a-data-model-with-ads/?WT.mc_id=api_CatalogApi)\n4. [Getting started with the Microsoft Cloud Adoption Framework for Azure](https://learn.microsoft.com/training/modules/cloud-adoption-framework-getting-started/?WT.mc_id=api_CatalogApi)\n5. [Set up the Rust development environment](https://learn.microsoft.com/training/modules/rust-set-up-environment/?WT.mc_id=api_CatalogApi)\n\nYou can click on the links to access the courses." }
Per continuare il tuo apprendimento della chiamata di funzioni Azure OpenAI puoi costruire:
- Più parametri della funzione che potrebbero aiutare gli studenti a trovare più corsi.
- Creare un'altra chiamata di funzione che prenda più informazioni dallo studente, come la loro lingua madre.
- Creare una gestione degli errori quando la chiamata di funzione e/o la chiamata API non restituisce corsi adatti.
Suggerimento: Segui la pagina documentazione di riferimento API Learn per vedere come e dove sono disponibili questi dati.
Dopo aver completato questa lezione, dai un'occhiata alla nostra collezione di apprendimento Generative AI per continuare ad accrescere la tua conoscenza dell'Intelligenza Artificiale Generativa!
Vai al Capitolo 12, dove vedremo come progettare UX per applicazioni AI!
Disclaimer:
Questo documento è stato tradotto utilizzando il servizio di traduzione AI Co-op Translator. Sebbene ci impegniamo per l'accuratezza, si prega di essere consapevoli che le traduzioni automatiche possono contenere errori o imprecisioni. Il documento originale nella sua lingua nativa dovrebbe essere considerato la fonte autorevole. Per informazioni critiche, si raccomanda una traduzione professionale umana. Non siamo responsabili per eventuali fraintendimenti o interpretazioni errate derivanti dall'uso di questa traduzione.

