Condividi tramite


Guida introduttiva: introduzione all'uso degli assistenti OpenAI di Azure (anteprima)

Gli assistenti OpenAI di Azure (anteprima) consentono di creare assistenti di intelligenza artificiale personalizzati in base alle proprie esigenze tramite istruzioni personalizzate e ottimizzarli con strumenti avanzati come l'interprete del codice e funzioni personalizzate.

Importante

Gli elementi contrassegnati (anteprima) in questo articolo sono attualmente disponibili in anteprima pubblica. Questa anteprima viene fornita senza un contratto di servizio e non è consigliabile per i carichi di lavoro di produzione. Alcune funzionalità potrebbero non essere supportate o potrebbero presentare funzionalità limitate. Per altre informazioni, vedere le Condizioni supplementari per l'uso delle anteprime di Microsoft Azure.

Prerequisiti

Passare a Studio AI della piattaforma Azure (anteprima)

Azure AI Studio consente di usare Assistants v2 che offre diversi aggiornamenti, ad esempio lo strumento di ricerca file, più veloce e supporta più file.

  1. Accedere a Studio AI della piattaforma Azure.

  2. Passare al progetto o creare un nuovo progetto in Studio AI della piattaforma Azure.

  3. Nella panoramica del progetto selezionare Assistenti disponibile nel playground del progetto.

    Il playground degli assistenti consente di esplorare, creare prototipi e testare assistenti di intelligenza artificiale senza dover eseguire codice. Da questa pagina è possibile eseguire rapidamente l'iterazione e sperimentare le funzionalità.

    Il playground offre diverse opzioni per configurare l'assistente. Nei passaggi seguenti verrà usato il riquadro di configurazione dell’assistente per creare un nuovo assistente di intelligenza artificiale.

    Nome Descrizione
    Nome assistente Nome della distribuzione associata a un modello specifico.
    Istruzioni Le istruzioni sono simili ai messaggi di sistema; qui è dove si forniscono al modello le istruzioni sul comportamento e su qualsiasi contesto a cui deve fare riferimento durante la generazione di una risposta. È possibile descrivere la personalità dell'assistente, definire cosa deve e non deve rispondere e come formattare le risposte. È anche possibile fornire esempi dei passaggi da eseguire quando si risponde alle risposte.
    Distribuzione Qui è possibile impostare la distribuzione modello da usare con l'assistente.
    Funzioni Creare definizioni di funzioni personalizzate per i modelli per formulare chiamate API e strutturare gli output dei dati in base alle specifiche. Non usato in questa guida introduttiva.
    Interprete di codice L'interprete del codice fornisce l'accesso a un ambiente Python in modalità sandbox che può essere utilizzato per consentire al modello di testare ed eseguire codice.
    File È possibile caricare fino a 10.000 file, con dimensioni massime di 512 MB, da usare con gli strumenti. Non usato in questa guida introduttiva.

    Screenshot della schermata di configurazione dell'assistente senza tutti i valori inseriti.

Creare il primo assistente

  1. Selezionare la distribuzione dall'elenco a discesa Distribuzioni.

  2. Nell'elenco a discesa Configurazione assistente selezionare Nuovo.

  3. Assegnare un nome all'assistente.

  4. Immettere le istruzioni seguenti"Si è un assistente di intelligenza artificiale in grado di scrivere codice per rispondere alle domande matematiche”

  5. Selezionare una distribuzione del modello. È consigliabile eseguire test con uno dei modelli gpt-4 più recenti.

  6. Selezionare l'interruttore che abilita l'interprete del codice.

  7. Seleziona Salva.

    Screenshot dell'assistente con i dettagli di configurazione immessi.

  8. Immettere una domanda a cui l'assistente deve rispondere: "Devo risolvere l'equazione 3x + 11 = 14. Mi può aiutare?”

  9. Selezionare il pulsante Aggiungi ed esegui

    The solution to the equation (3x + 11 = 14) is (x = 1).
    

    Anche se la risposta è corretta, verrà posta una seconda domanda per verificare che il modello usi l'interprete del codice per ottenere questa risposta anziché ottenerla dai dati di training del modello e che il codice scritto sia valido.

  10. Immettere la domanda di completamento: "Mostra il codice eseguito per ottenere la soluzione".

    Sure. The code is very straightforward
    
    # calculation
    x = (14 - 11) / 3
    x
    
    
    First, we subtract 11 from 14, then divide the result by 3. This gives us the value of x which is 1.0.
    

    Screenshot della sessione di conversazione nel playground dell’assistente.

È anche possibile consultare i log nel pannello di destra per verificare che sia stato usato l'interprete del codice e per convalidare il codice eseguito per generare la risposta. È importante ricordare che mentre l'interprete del codice offre al modello la possibilità di rispondere a domande matematiche più complesse convertendo le domande in codice ed eseguendolo in modalità sandbox in un ambiente Python, è comunque necessario convalidare la risposta per verificare che il modello abbia convertito correttamente la domanda in una rappresentazione valida nel codice.

Concetti chiave

Durante l'uso del playground Assistenti, tenere presenti i concetti seguenti.

Strumenti

Un singolo assistente può accedere a un massimo di 128 strumenti, tra cui code interpreter, nonché a qualsiasi strumento personalizzato creato tramite le funzioni.

Sessione chat

La sessione di chat, denominata anche thread all'interno dell'API dell'assistente, rappresenta la posizione in cui si verifica la conversazione tra l'utente e l'assistente. A differenza delle chiamate di completamento della chat tradizionali non esiste alcun limite al numero di messaggi in un thread. L'assistente comprimerà automaticamente le richieste per adattarle al limite di token di input del modello.

Ciò significa anche che non si controlla il numero di token passati al modello durante ogni svolta della conversazione. La gestione dei token viene astratta e gestita interamente dall'API dell’assistente.

Selezionare il pulsante Cancella chat per eliminare la cronologia della conversazione corrente.

Sotto la casella di input di testo sono presenti due pulsanti:

  • Aggiungere un messaggio senza esecuzione.
  • Aggiungere ed eseguire.

Registri

I log forniscono uno snapshot dettagliato dell'attività dell'API dell’assistente.

Mostra pannelli

Per impostazione predefinita sono disponibili tre pannelli: configurazione assistente, sessione chat e impostazioni. Mostra pannelli consente di aggiungere, rimuovere e riorganizzare i pannelli. Se si chiude un pannello e si deve tornare indietro, usare Mostra pannelli per ripristinare il pannello perso.

Pulire le risorse

Per pulire e rimuovere una risorsa OpenAI, è possibile eliminare la risorsa o il gruppo di risorse. L'eliminazione del gruppo di risorse comporta anche l'eliminazione di tutte le altre risorse associate.

In alternativa, è possibile eliminare l'assistenteo il thread tramite l'API dell’assistente.

Vedi anche

Documentazione di riferimento | Codice sorgente della libreria | Pacchetto di codice(PyPi) |

Prerequisiti

Per l'autenticazione senza password, è necessario

  1. Usare il pacchetto azure-identity.
  2. Assegnare il ruolo Cognitive Services User all'account utente. Questa operazione può essere eseguita nel portale di Azure in Controllo di accesso (IAM)>Aggiungi un'assegnazione di ruolo.
  3. Accedere con l'interfaccia della riga di comando di Azure, ad esempio az login.

Impostazione

  1. Installare la libreria client Python OpenAI con:
pip install openai
  1. Per l'autenticazione senza password consigliata:
pip install azure-identity

Nota

  • Ricerca file può inserire fino a 10.000 file per assistente, 500 volte più di prima. È veloce, supporta query parallele tramite ricerche multithread e include la riclassificazione avanzata e la riscrittura di query.
    • L’archivio di vettori è un nuovo oggetto nell’API. Dopo l’aggiunta a un archivio di vettori, un file viene analizzato, suddiviso in blocchi, incorporato e preparato per essere sottoposto a ricerca. Gli archivi di vettori possono essere usati in diversi assistenti e thread, semplificando quindi la gestione dei file e la fatturazione.
  • È stato aggiunto il supporto per il parametro tool_choice, che può essere usato per imporre l'uso di uno strumento specifico, ad esempio Ricerca file, interprete di codice o una funzione, in una determinata esecuzione.

Nota

Questa libreria viene gestita da OpenAI. Fare riferimento alla cronologia delle versioni per tenere traccia degli aggiornamenti più recenti della libreria.

Recuperare la chiave e l'endpoint

Per effettuare correttamente una chiamata al servizio Azure OpenAI, sarà necessario quanto segue:

Nome variabile Valore
ENDPOINT Questo valore è disponibile nella sezione Chiavi ed endpoint quando si esamina la risorsa dal portale di Azure. È anche possibile trovare l'endpoint tramite la pagina Distribuzioni in Azure AI Studio. Un endpoint di esempio è https://docs-test-001.openai.azure.com/.
API-KEY Questo valore è disponibile nella sezione Chiavi ed endpoint quando si esamina la risorsa dal portale di Azure. È possibile usare KEY1 o KEY2.
DEPLOYMENT-NAME Questo valore corrisponderà al nome personalizzato scelto per la distribuzione quando è stato distribuito un modello. Questo valore è disponibile in Distribuzioni di modelli di gestione>risorse nella portale di Azure o nella pagina Distribuzioni in Azure AI Studio.

Passare alla risorsa nel portale di Azure. Le chiavi e gli endpoint sono disponibili nella sezione Gestione risorse. Copiare l'endpoint e la chiave di accesso in base alle esigenze per l'autenticazione delle chiamate API. Puoi usare entrambi KEY1 o KEY2. Disporre sempre di due chiavi consente di ruotare e rigenerare in modo sicuro le chiavi senza causare un'interruzione del servizio.

Screenshot del pannello di panoramica per una risorsa OpenAI di Azure nel portale di Azure con la posizione dell'endpoint e delle chiavi di accesso evidenziata in rosso.

Variabili di ambiente

Creare e assegnare variabili di ambiente persistenti per la chiave e l'endpoint.

Importante

Se si usa una chiave API, archiviarla in modo sicuro in un'altra posizione, ad esempio in Azure Key Vault. Non includere la chiave API direttamente nel codice e non esporla mai pubblicamente.

Per altre informazioni sulla sicurezza dei servizi IA, vedere Autenticare richieste in Servizi di Azure AI.

setx AZURE_OPENAI_API_KEY "REPLACE_WITH_YOUR_KEY_VALUE_HERE" 
setx AZURE_OPENAI_ENDPOINT "REPLACE_WITH_YOUR_ENDPOINT_HERE" 

Creare un assistente

Nel codice verranno specificati i valori seguenti:

Nome Descrizione
Nome assistente Nome della distribuzione associata a un modello specifico.
Istruzioni Le istruzioni sono simili ai messaggi di sistema; qui è dove si forniscono al modello le istruzioni sul comportamento e su qualsiasi contesto a cui deve fare riferimento durante la generazione di una risposta. È possibile descrivere la personalità dell'assistente, definire cosa deve e non deve rispondere e come formattare le risposte. È anche possibile fornire esempi dei passaggi che deve eseguire quando risponde alle risposte.
Modello Qui è possibile impostare il nome della distribuzione del modello da usare con l'assistente. Lo strumento di recupero richiede il modello gpt-35-turbo (1106) o gpt-4 (1106-preview). Impostare questo valore sul nome della distribuzione, non sul nome del modello, a meno che non sia lo stesso.
Interprete di codice L'interprete del codice fornisce l'accesso a un ambiente Python in modalità sandbox che può essere usato per consentire al modello di testare ed eseguire codice.

Strumenti

Un singolo assistente può accedere a un massimo di 128 strumenti, tra cui code interpreter, nonché a qualsiasi strumento personalizzato creato tramite le funzioni.

Creare l'app Python

Accedere ad Azure con az login quindi creare ed eseguire un assistente con l'esempio Python senza password consigliato seguente:

import os
from azure.identity import DefaultAzureCredential, get_bearer_token_provider
from openai import AzureOpenAI

token_provider = get_bearer_token_provider(DefaultAzureCredential(), "https://cognitiveservices.azure.com/.default")

client = AzureOpenAI(
    azure_ad_token_provider=token_provider,
    azure_endpoint=os.environ["AZURE_OPENAI_ENDPOINT"],
    api_version="2024-05-01-preview",
)

# Create an assistant
assistant = client.beta.assistants.create(
    name="Math Assist",
    instructions="You are an AI assistant that can write code to help answer math questions.",
    tools=[{"type": "code_interpreter"}],
    model="gpt-4-1106-preview" # You must replace this value with the deployment name for your model.
)

# Create a thread
thread = client.beta.threads.create()

# Add a user question to the thread
message = client.beta.threads.messages.create(
    thread_id=thread.id,
    role="user",
    content="I need to solve the equation `3x + 11 = 14`. Can you help me?"
)

# Run the thread and poll for the result
run = client.beta.threads.runs.create_and_poll(
    thread_id=thread.id,
    assistant_id=assistant.id,
    instructions="Please address the user as Jane Doe. The user has a premium account.",
)

print("Run completed with status: " + run.status)

if run.status == "completed":
    messages = client.beta.threads.messages.list(thread_id=thread.id)
    print(messages.to_json(indent=2))

Per usare la chiave API del servizio per l'autenticazione, è possibile creare ed eseguire un assistente con l'esempio Python seguente:

import os
from openai import AzureOpenAI

client = AzureOpenAI(
    api_key=os.environ["AZURE_OPENAI_API_KEY"],
    azure_endpoint=os.environ["AZURE_OPENAI_ENDPOINT"],
    api_version="2024-05-01-preview",
)

# Create an assistant
assistant = client.beta.assistants.create(
    name="Math Assist",
    instructions="You are an AI assistant that can write code to help answer math questions.",
    tools=[{"type": "code_interpreter"}],
    model="gpt-4-1106-preview" # You must replace this value with the deployment name for your model.
)

# Create a thread
thread = client.beta.threads.create()

# Add a user question to the thread
message = client.beta.threads.messages.create(
    thread_id=thread.id,
    role="user",
    content="I need to solve the equation `3x + 11 = 14`. Can you help me?"
)

# Run the thread and poll for the result
run = client.beta.threads.runs.create_and_poll(
    thread_id=thread.id,
    assistant_id=assistant.id,
    instructions="Please address the user as Jane Doe. The user has a premium account.",
)

print("Run completed with status: " + run.status)

if run.status == "completed":
    messages = client.beta.threads.messages.list(thread_id=thread.id)
    print(messages.to_json(indent=2))

Output

Esecuzione completa con stato: completed

{
  "data": [
    {
      "id": "msg_4SuWxTubHsHpt5IlBTO5Hyw9",
      "assistant_id": "asst_cYqL1RuwLyFV3HU1gkaE2k0K",
      "attachments": [],
      "content": [
        {
          "text": {
            "annotations": [],
            "value": "The solution to the equation \\(3x + 11 = 14\\) is \\(x = 1\\)."
          },
          "type": "text"
        }
      ],
      "created_at": 1716397091,
      "metadata": {},
      "object": "thread.message",
      "role": "assistant",
      "run_id": "run_hFgBPbUtO8ZNTnNPC8PgpH1S",
      "thread_id": "thread_isb7spwRycI5ueT9E7357aOm"
    },
    {
      "id": "msg_Z32w2E7kY5wEWhZqQWxIbIUB",
      "assistant_id": null,
      "attachments": [],
      "content": [
        {
          "text": {
            "annotations": [],
            "value": "I need to solve the equation `3x + 11 = 14`. Can you help me?"
          },
          "type": "text"
        }
      ],
      "created_at": 1716397025,
      "metadata": {},
      "object": "thread.message",
      "role": "user",
      "run_id": null,
      "thread_id": "thread_isb7spwRycI5ueT9E7357aOm"
    }
  ],
  "object": "list",
  "first_id": "msg_4SuWxTubHsHpt5IlBTO5Hyw9",
  "last_id": "msg_Z32w2E7kY5wEWhZqQWxIbIUB",
  "has_more": false
}

Informazioni sui risultati

In questo esempio viene creato un assistente con interprete di codice abilitato. Quando si pone all'assistente una domanda matematica, la domanda viene convertita in codice Python e viene eseguito il codice nell'ambiente sandbox per determinare la risposta alla domanda. Il codice che il modello crea e testa per arrivare a una risposta è:

from sympy import symbols, Eq, solve  
  
# Define the variable  
x = symbols('x')  
  
# Define the equation  
equation = Eq(3*x + 11, 14)  
  
# Solve the equation  
solution = solve(equation, x)  
solution  

È importante ricordare che, benché l'interprete di codice offra al modello la possibilità di rispondere a query più complesse convertendo le domande in codice ed eseguendo tale codice in modo iterativo nella sandbox Python fino a quando non raggiunge una soluzione, è comunque necessario convalidare la risposta per verificare che il modello abbia convertito correttamente la domanda in una rappresentazione valida nel codice.

Pulire le risorse

Per pulire e rimuovere una risorsa OpenAI, è possibile eliminare la risorsa o il gruppo di risorse. L'eliminazione del gruppo di risorse comporta anche l'eliminazione di tutte le altre risorse associate.

Vedi anche

Documentazione di riferimento | Pacchetto del codice | sorgente (NuGet)

Prerequisiti

Impostazione

Creare una nuova applicazione .NET Core

  1. In una finestra della console ,ad esempio cmd, PowerShell o Bash, usare il dotnet new comando per creare una nuova app console con il nome azure-openai-quickstart:

    dotnet new console -n azure-openai-assistants-quickstart
    
  2. Passare alla directory della cartella dell'app appena creata e compilare l'app con il dotnet build comando :

    dotnet build
    

    L'output di compilazione non deve contenere alcun avviso o errore.

    ...
    Build succeeded.
     0 Warning(s)
     0 Error(s)
    ...
    
  3. Installare la libreria client .NET OpenAI con il comando dotnet add package :

    dotnet add package Azure.AI.OpenAI --prerelease
    

Recuperare la chiave e l'endpoint

Per effettuare correttamente una chiamata ad Azure OpenAI, sono necessari un endpoint e una chiave.

Nome variabile Valore
ENDPOINT L'endpoint di servizio è disponibile nella sezione Chiavi ed endpoint quando si esamina la risorsa dal portale di Azure. In alternativa, è possibile trovare l'endpoint tramite la pagina Distribuzioni in Azure AI Studio. Un endpoint di esempio è https://docs-test-001.openai.azure.com/.
API-KEY Questo valore è disponibile nella sezione Chiavi ed endpoint durante l'esame della risorsa dalla portale di Azure. Puoi usare entrambi KEY1 o KEY2.

Passare alla risorsa nel portale di Azure. La sezione Chiavi ed endpoint è disponibile nella sezione Gestione risorse. Copiare l'endpoint e la chiave di accesso in base alle esigenze per l'autenticazione delle chiamate API. Puoi usare entrambi KEY1 o KEY2. Disporre sempre di due chiavi consente di ruotare e rigenerare in modo sicuro le chiavi senza causare un'interruzione del servizio.

Screenshot di panoramica dell'interfaccia utente per una risorsa OpenAI di Azure nel portale di Azure con l'endpoint e la posizione delle chiavi di accesso evidenziati in rosso.

Variabili di ambiente

Creare e assegnare variabili di ambiente persistenti per la chiave e l'endpoint.

Importante

Se si usa una chiave API, archiviarla in modo sicuro in un'altra posizione, ad esempio in Azure Key Vault. Non includere la chiave API direttamente nel codice e non esporla mai pubblicamente.

Per altre informazioni sulla sicurezza dei servizi IA, vedere Autenticare richieste in Servizi di Azure AI.

setx AZURE_OPENAI_API_KEY "REPLACE_WITH_YOUR_KEY_VALUE_HERE" 
setx AZURE_OPENAI_ENDPOINT "REPLACE_WITH_YOUR_ENDPOINT_HERE" 

L'autenticazione senza password è più sicura rispetto alle alternative basate su chiave ed è l'approccio consigliato per la connessione ai servizi di Azure. Se si sceglie l'autenticazione senza password, è necessario completare le operazioni seguenti:

  1. Aggiungere il pacchetto Azure.Identity.

    dotnet add package Azure.Identity
    
  2. Assegnare il ruolo Cognitive Services User all'account utente. Questa operazione può essere eseguita nella portale di Azure nella risorsa OpenAI in Controllo di accesso (IAM)>Aggiungi assegnazione di ruolo.

  3. Accedere ad Azure usando Visual Studio o l'interfaccia della riga di comando di Azure tramite az login.

Creare l'assistente

Aggiornare il Program.cs file con il codice seguente per creare un assistente:

using Azure;
using Azure.AI.OpenAI.Assistants;

// Assistants is a beta API and subject to change
// Acknowledge its experimental status by suppressing the matching warning.
string endpoint = Environment.GetEnvironmentVariable("AZURE_OPENAI_ENDPOINT");
string key = Environment.GetEnvironmentVariable("AZURE_OPENAI_API_KEY");

var openAIClient = new AzureOpenAIClient(new Uri(endpoint), new AzureKeyCredential(key));

// Use for passwordless auth
//var openAIClient = new AzureOpenAIClient(new Uri(endpoint), new DefaultAzureCredential()); 

FileClient fileClient = openAIClient.GetFileClient();
AssistantClient assistantClient = openAIClient.GetAssistantClient();

// First, let's contrive a document we'll use retrieval with and upload it.
using Stream document = BinaryData.FromString("""
            {
                "description": "This document contains the sale history data for Contoso products.",
                "sales": [
                    {
                        "month": "January",
                        "by_product": {
                            "113043": 15,
                            "113045": 12,
                            "113049": 2
                        }
                    },
                    {
                        "month": "February",
                        "by_product": {
                            "113045": 22
                        }
                    },
                    {
                        "month": "March",
                        "by_product": {
                            "113045": 16,
                            "113055": 5
                        }
                    }
                ]
            }
            """).ToStream();

OpenAIFileInfo salesFile = await fileClient.UploadFileAsync(
    document,
    "monthly_sales.json",
    FileUploadPurpose.Assistants);

// Now, we'll create a client intended to help with that data
AssistantCreationOptions assistantOptions = new()
{
    Name = "Example: Contoso sales RAG",
    Instructions =
        "You are an assistant that looks up sales data and helps visualize the information based"
        + " on user queries. When asked to generate a graph, chart, or other visualization, use"
        + " the code interpreter tool to do so.",
    Tools =
            {
                new FileSearchToolDefinition(),
                new CodeInterpreterToolDefinition(),
            },
    ToolResources = new()
    {
        FileSearch = new()
        {
            NewVectorStores =
                    {
                        new VectorStoreCreationHelper([salesFile.Id]),
                    }
        }
    },
};

Assistant assistant = await assistantClient.CreateAssistantAsync(deploymentName, assistantOptions);

// Create and run a thread with a user query about the data already associated with the assistant
ThreadCreationOptions threadOptions = new()
{
    InitialMessages = { "How well did product 113045 sell in February? Graph its trend over time." }
};

ThreadRun threadRun = await assistantClient.CreateThreadAndRunAsync(assistant.Id, threadOptions);

// Check back to see when the run is done
do
{
    Thread.Sleep(TimeSpan.FromSeconds(1));
    threadRun = assistantClient.GetRun(threadRun.ThreadId, threadRun.Id);
} while (!threadRun.Status.IsTerminal);

// Finally, we'll print out the full history for the thread that includes the augmented generation
AsyncCollectionResult<ThreadMessage> messages
    = assistantClient.GetMessagesAsync(
        threadRun.ThreadId,
        new MessageCollectionOptions() { Order = MessageCollectionOrder.Ascending });

await foreach (ThreadMessage message in messages)
{
    Console.Write($"[{message.Role.ToString().ToUpper()}]: ");
    foreach (MessageContent contentItem in message.Content)
    {
        if (!string.IsNullOrEmpty(contentItem.Text))
        {
            Console.WriteLine($"{contentItem.Text}");

            if (contentItem.TextAnnotations.Count > 0)
            {
                Console.WriteLine();
            }

            // Include annotations, if any.
            foreach (TextAnnotation annotation in contentItem.TextAnnotations)
            {
                if (!string.IsNullOrEmpty(annotation.InputFileId))
                {
                    Console.WriteLine($"* File citation, file ID: {annotation.InputFileId}");
                }
                if (!string.IsNullOrEmpty(annotation.OutputFileId))
                {
                    Console.WriteLine($"* File output, new file ID: {annotation.OutputFileId}");
                }
            }
        }
        if (!string.IsNullOrEmpty(contentItem.ImageFileId))
        {
            OpenAIFileInfo imageInfo = await fileClient.GetFileAsync(contentItem.ImageFileId);
            BinaryData imageBytes = await fileClient.DownloadFileAsync(contentItem.ImageFileId);
            using FileStream stream = File.OpenWrite($"{imageInfo.Filename}.png");
            imageBytes.ToStream().CopyTo(stream);

            Console.WriteLine($"<image: {imageInfo.Filename}.png>");
        }
    }
    Console.WriteLine();
}

Eseguire l'app usando il dotnet run comando :

dotnet run

L'output della console dovrebbe essere simile al seguente:

[USER]: How well did product 113045 sell in February? Graph its trend over time.

[ASSISTANT]: Product 113045 sold 22 units in February. Let's visualize its sales trend over the given months (January through March).

I'll create a graph to depict this trend.

[ASSISTANT]: <image: 553380b7-fdb6-49cf-9df6-e8e6700d69f4.png>
The graph above visualizes the sales trend for product 113045 from January to March. As seen, the sales peaked in February with 22 units sold, and fluctuated over the period from January (12 units) to March (16 units).

If you need further analysis or more details, feel free to ask!

Pulire le risorse

Per pulire e rimuovere una risorsa OpenAI, è possibile eliminare la risorsa o il gruppo di risorse. L'eliminazione del gruppo di risorse comporta anche l'eliminazione di tutte le altre risorse associate.

Vedi anche

Documentazione di riferimento | Codice sorgente della libreria | Pacchetto (npm) |

Prerequisiti

Per l'autenticazione senza chiave, è necessario

  1. Usare il pacchetto @azure/identity.
  2. Assegnare il ruolo Cognitive Services User all'account utente. Questa operazione può essere eseguita nel portale di Azure in Controllo di accesso (IAM)>Aggiungi un'assegnazione di ruolo.
  3. Accedere con l'interfaccia della riga di comando di Azure, ad esempio az login.

Impostazione

  1. Creare una nuova cartella assistants-quickstart per contenere l'applicazione e aprire Visual Studio Code in tale cartella con il comando seguente:

    mkdir assistants-quickstart && code assistants-quickstart
    
  2. package.json Creare con il comando seguente:

    npm init -y
    
  3. Aggiornare in package.json ECMAScript con il comando seguente:

    npm pkg set type=module
    
  4. Installare la libreria client degli assistenti OpenAI per JavaScript con:

    npm install openai
    
  5. Per l'autenticazione senza password consigliata:

    npm install @azure/identity
    

Recuperare le informazioni sulle risorse

Nome variabile Valore
AZURE_OPENAI_ENDPOINT Questo valore è disponibile nella sezione Chiavi ed endpoint quando si esamina la risorsa dal portale di Azure.
AZURE_OPENAI_DEPLOYMENT_NAME Questo valore corrisponderà al nome personalizzato scelto per la distribuzione quando è stato distribuito un modello. Questo valore è disponibile in Distribuzioni di modelli di gestione>risorse nella portale di Azure.
OPENAI_API_VERSION Altre informazioni sulle versioni api.

Altre informazioni sull'autenticazione senza chiave e sull'impostazione delle variabili di ambiente.

Attenzione

Per usare l'autenticazione senza chiave consigliata con l'SDK, assicurarsi che la AZURE_OPENAI_API_KEY variabile di ambiente non sia impostata.

Creare un assistente

Nel codice verranno specificati i valori seguenti:

Nome Descrizione
Nome assistente Nome della distribuzione associata a un modello specifico.
Istruzioni Le istruzioni sono simili ai messaggi di sistema; qui è dove si forniscono al modello le istruzioni sul comportamento e su qualsiasi contesto a cui deve fare riferimento durante la generazione di una risposta. È possibile descrivere la personalità dell'assistente, definire cosa deve e non deve rispondere e come formattare le risposte. È anche possibile fornire esempi dei passaggi che deve eseguire quando risponde alle risposte.
Modello Si tratta del nome della distribuzione.
Interprete di codice L'interprete del codice fornisce l'accesso a un ambiente Python in modalità sandbox che può essere usato per consentire al modello di testare ed eseguire codice.

Strumenti

Un singolo assistente può accedere a un massimo di 128 strumenti, inclusi code interpretere tutti gli strumenti personalizzati creati tramite funzioni.

Creare una nuova applicazione JavaScript

  1. Creare il index.js file con il codice seguente:

    const { AzureOpenAI } = require("openai");
    const {
      DefaultAzureCredential,
      getBearerTokenProvider,
    } = require("@azure/identity");
    
    // Get environment variables
    const azureOpenAIEndpoint = process.env.AZURE_OPENAI_ENDPOINT;
    const azureOpenAIDeployment = process.env.AZURE_OPENAI_DEPLOYMENT_NAME;
    const azureOpenAIVersion = process.env.OPENAI_API_VERSION;
    
    // Check env variables
    if (!azureOpenAIEndpoint || !azureOpenAIDeployment || !azureOpenAIVersion) {
      throw new Error(
        "Please ensure to set AZURE_OPENAI_DEPLOYMENT_NAME and AZURE_OPENAI_ENDPOINT in your environment variables."
      );
    }
    
    // Get Azure SDK client
    const getClient = () => {
      const credential = new DefaultAzureCredential();
      const scope = "https://cognitiveservices.azure.com/.default";
      const azureADTokenProvider = getBearerTokenProvider(credential, scope);
    
      const assistantsClient = new AzureOpenAI({
        endpoint: azureOpenAIEndpoint,
        apiVersion: azureOpenAIVersion,
        azureADTokenProvider,
      });
      return assistantsClient;
    };
    
    const assistantsClient = getClient();
    
    const options = {
      model: azureOpenAIDeployment, // Deployment name seen in Azure AI Studio
      name: "Math Tutor",
      instructions:
        "You are a personal math tutor. Write and run JavaScript code to answer math questions.",
      tools: [{ type: "code_interpreter" }],
    };
    const role = "user";
    const message = "I need to solve the equation `3x + 11 = 14`. Can you help me?";
    
    // Create an assistant
    const assistantResponse = await assistantsClient.beta.assistants.create(
      options
    );
    console.log(`Assistant created: ${JSON.stringify(assistantResponse)}`);
    
    // Create a thread
    const assistantThread = await assistantsClient.beta.threads.create({});
    console.log(`Thread created: ${JSON.stringify(assistantThread)}`);
    
    // Add a user question to the thread
    const threadResponse = await assistantsClient.beta.threads.messages.create(
      assistantThread.id,
      {
        role,
        content: message,
      }
    );
    console.log(`Message created:  ${JSON.stringify(threadResponse)}`);
    
    // Run the thread and poll it until it is in a terminal state
    const runResponse = await assistantsClient.beta.threads.runs.createAndPoll(
      assistantThread.id,
      {
        assistant_id: assistantResponse.id,
      },
      { pollIntervalMs: 500 }
    );
    console.log(`Run created:  ${JSON.stringify(runResponse)}`);
    
    // Get the messages
    const runMessages = await assistantsClient.beta.threads.messages.list(
      assistantThread.id
    );
    for await (const runMessageDatum of runMessages) {
      for (const item of runMessageDatum.content) {
        // types are: "image_file" or "text"
        if (item.type === "text") {
          console.log(`Message content: ${JSON.stringify(item.text?.value)}`);
        }
      }
    }
    
  2. Accedere ad Azure con il comando seguente:

    az login
    
  3. Eseguire il file JavaScript.

    node index.js
    

Output

Assistant created: {"id":"asst_zXaZ5usTjdD0JGcNViJM2M6N","createdAt":"2024-04-08T19:26:38.000Z","name":"Math Tutor","description":null,"model":"daisy","instructions":"You are a personal math tutor. Write and run JavaScript code to answer math questions.","tools":[{"type":"code_interpreter"}],"fileIds":[],"metadata":{}}
Thread created: {"id":"thread_KJuyrB7hynun4rvxWdfKLIqy","createdAt":"2024-04-08T19:26:38.000Z","metadata":{}}
Message created:  {"id":"msg_o0VkXnQj3juOXXRCnlZ686ff","createdAt":"2024-04-08T19:26:38.000Z","threadId":"thread_KJuyrB7hynun4rvxWdfKLIqy","role":"user","content":[{"type":"text","text":{"value":"I need to solve the equation `3x + 11 = 14`. Can you help me?","annotations":[]},"imageFile":{}}],"assistantId":null,"runId":null,"fileIds":[],"metadata":{}}
Created run
Run created:  {"id":"run_P8CvlouB8V9ZWxYiiVdL0FND","object":"thread.run","status":"queued","model":"daisy","instructions":"You are a personal math tutor. Write and run JavaScript code to answer math questions.","tools":[{"type":"code_interpreter"}],"metadata":{},"usage":null,"assistantId":"asst_zXaZ5usTjdD0JGcNViJM2M6N","threadId":"thread_KJuyrB7hynun4rvxWdfKLIqy","fileIds":[],"createdAt":"2024-04-08T19:26:39.000Z","expiresAt":"2024-04-08T19:36:39.000Z","startedAt":null,"completedAt":null,"cancelledAt":null,"failedAt":null}
Message content: "The solution to the equation \\(3x + 11 = 14\\) is \\(x = 1\\)."
Message content: "Yes, of course! To solve the equation \\( 3x + 11 = 14 \\), we can follow these steps:\n\n1. Subtract 11 from both sides of the equation to isolate the term with x.\n2. Then, divide by 3 to find the value of x.\n\nLet me calculate that for you."
Message content: "I need to solve the equation `3x + 11 = 14`. Can you help me?"

È importante ricordare che, mentre l'interprete di codice offre al modello la possibilità di rispondere a query più complesse convertendo le domande in codice ed eseguendo tale codice in modo iterativo in JavaScript fino a quando non raggiunge una soluzione, è comunque necessario convalidare la risposta per verificare che il modello ha convertito correttamente la domanda in una rappresentazione valida nel codice.

Pulire le risorse

Per pulire e rimuovere una risorsa OpenAI, è possibile eliminare la risorsa o il gruppo di risorse. L'eliminazione del gruppo di risorse comporta anche l'eliminazione di tutte le altre risorse associate.

Codice di esempio

Vedi anche

Documentazione di riferimento | Codice sorgente della libreria | Pacchetto (npm) |

Prerequisiti

Per l'autenticazione senza password, è necessario

  1. Usare il pacchetto @azure/identity.
  2. Assegnare il ruolo Cognitive Services User all'account utente. Questa operazione può essere eseguita nel portale di Azure in Controllo di accesso (IAM)>Aggiungi un'assegnazione di ruolo.
  3. Accedere con l'interfaccia della riga di comando di Azure, ad esempio az login.

Impostazione

  1. Creare una nuova cartella assistants-quickstart per contenere l'applicazione e aprire Visual Studio Code in tale cartella con il comando seguente:

    mkdir assistants-quickstart && code assistants-quickstart
    
  2. package.json Creare con il comando seguente:

    npm init -y
    
  3. Aggiornare in package.json ECMAScript con il comando seguente:

    npm pkg set type=module
    
  4. Installare la libreria client degli assistenti OpenAI per JavaScript con:

    npm install openai
    
  5. Per l'autenticazione senza password consigliata:

    npm install @azure/identity
    

Recuperare le informazioni sulle risorse

Nome variabile Valore
AZURE_OPENAI_ENDPOINT Questo valore è disponibile nella sezione Chiavi ed endpoint quando si esamina la risorsa dal portale di Azure.
AZURE_OPENAI_DEPLOYMENT_NAME Questo valore corrisponderà al nome personalizzato scelto per la distribuzione quando è stato distribuito un modello. Questo valore è disponibile in Distribuzioni di modelli di gestione>risorse nella portale di Azure.
OPENAI_API_VERSION Altre informazioni sulle versioni api.

Altre informazioni sull'autenticazione senza chiave e sull'impostazione delle variabili di ambiente.

Attenzione

Per usare l'autenticazione senza chiave consigliata con l'SDK, assicurarsi che la AZURE_OPENAI_API_KEY variabile di ambiente non sia impostata.

Creare un assistente

Nel codice verranno specificati i valori seguenti:

Nome Descrizione
Nome assistente Nome della distribuzione associata a un modello specifico.
Istruzioni Le istruzioni sono simili ai messaggi di sistema; qui è dove si forniscono al modello le istruzioni sul comportamento e su qualsiasi contesto a cui deve fare riferimento durante la generazione di una risposta. È possibile descrivere la personalità dell'assistente, definire cosa deve e non deve rispondere e come formattare le risposte. È anche possibile fornire esempi dei passaggi che deve eseguire quando risponde alle risposte.
Modello Si tratta del nome della distribuzione.
Interprete di codice L'interprete del codice fornisce l'accesso a un ambiente Python in modalità sandbox che può essere usato per consentire al modello di testare ed eseguire codice.

Strumenti

Un singolo assistente può accedere a un massimo di 128 strumenti, inclusi code interpretere tutti gli strumenti personalizzati creati tramite funzioni.

Creare una nuova applicazione TypeScript

  1. Creare il index.ts file con il codice seguente:

    import { AzureOpenAI } from "openai";
    import {
      Assistant,
      AssistantCreateParams,
      AssistantTool,
    } from "openai/resources/beta/assistants";
    import { Message, MessagesPage } from "openai/resources/beta/threads/messages";
    import { Run } from "openai/resources/beta/threads/runs/runs";
    import { Thread } from "openai/resources/beta/threads/threads";
    
    // Add `Cognitive Services User` to identity for Azure OpenAI resource
    import {
      DefaultAzureCredential,
      getBearerTokenProvider,
    } from "@azure/identity";
    
    // Get environment variables
    const azureOpenAIEndpoint = process.env.AZURE_OPENAI_ENDPOINT as string;
    const azureOpenAIDeployment = process.env
      .AZURE_OPENAI_DEPLOYMENT_NAME as string;
    const openAIVersion = process.env.OPENAI_API_VERSION as string;
    
    // Check env variables
    if (!azureOpenAIEndpoint || !azureOpenAIDeployment || !openAIVersion) {
      throw new Error(
        "Please ensure to set AZURE_OPENAI_DEPLOYMENT_NAME and AZURE_OPENAI_ENDPOINT in your environment variables."
      );
    }
    
    // Get Azure SDK client
    const getClient = (): AzureOpenAI => {
      const credential = new DefaultAzureCredential();
      const scope = "https://cognitiveservices.azure.com/.default";
      const azureADTokenProvider = getBearerTokenProvider(credential, scope);
      const assistantsClient = new AzureOpenAI({
        endpoint: azureOpenAIEndpoint,
        apiVersion: openAIVersion,
        azureADTokenProvider,
      });
      return assistantsClient;
    };
    
    const assistantsClient = getClient();
    
    const options: AssistantCreateParams = {
      model: azureOpenAIDeployment, // Deployment name seen in Azure AI Studio
      name: "Math Tutor",
      instructions:
        "You are a personal math tutor. Write and run JavaScript code to answer math questions.",
      tools: [{ type: "code_interpreter" } as AssistantTool],
    };
    const role = "user";
    const message = "I need to solve the equation `3x + 11 = 14`. Can you help me?";
    
    // Create an assistant
    const assistantResponse: Assistant =
      await assistantsClient.beta.assistants.create(options);
    console.log(`Assistant created: ${JSON.stringify(assistantResponse)}`);
    
    // Create a thread
    const assistantThread: Thread = await assistantsClient.beta.threads.create({});
    console.log(`Thread created: ${JSON.stringify(assistantThread)}`);
    
    // Add a user question to the thread
    const threadResponse: Message =
      await assistantsClient.beta.threads.messages.create(assistantThread.id, {
        role,
        content: message,
      });
    console.log(`Message created:  ${JSON.stringify(threadResponse)}`);
    
    // Run the thread and poll it until it is in a terminal state
    const runResponse: Run = await assistantsClient.beta.threads.runs.createAndPoll(
      assistantThread.id,
      {
        assistant_id: assistantResponse.id,
      },
      { pollIntervalMs: 500 }
    );
    console.log(`Run created:  ${JSON.stringify(runResponse)}`);
    
    // Get the messages
    const runMessages: MessagesPage =
      await assistantsClient.beta.threads.messages.list(assistantThread.id);
    for await (const runMessageDatum of runMessages) {
      for (const item of runMessageDatum.content) {
        // types are: "image_file" or "text"
        if (item.type === "text") {
          console.log(`Message content: ${JSON.stringify(item.text?.value)}`);
        }
      }
    }
    
  2. Creare il file per eseguire la tsconfig.json transpile del codice TypeScript e copiare il codice seguente per ECMAScript.

    {
        "compilerOptions": {
          "module": "NodeNext",
          "target": "ES2022", // Supports top-level await
          "moduleResolution": "NodeNext",
          "skipLibCheck": true, // Avoid type errors from node_modules
          "strict": true // Enable strict type-checking options
        },
        "include": ["*.ts"]
    }
    
  3. Transpile da TypeScript a JavaScript.

    tsc
    
  4. Accedere ad Azure con il comando seguente:

    az login
    
  5. Eseguire il codice con il comando seguente:

    node index.js
    

Output

Assistant created: {"id":"asst_zXaZ5usTjdD0JGcNViJM2M6N","createdAt":"2024-04-08T19:26:38.000Z","name":"Math Tutor","description":null,"model":"daisy","instructions":"You are a personal math tutor. Write and run JavaScript code to answer math questions.","tools":[{"type":"code_interpreter"}],"fileIds":[],"metadata":{}}
Thread created: {"id":"thread_KJuyrB7hynun4rvxWdfKLIqy","createdAt":"2024-04-08T19:26:38.000Z","metadata":{}}
Message created:  {"id":"msg_o0VkXnQj3juOXXRCnlZ686ff","createdAt":"2024-04-08T19:26:38.000Z","threadId":"thread_KJuyrB7hynun4rvxWdfKLIqy","role":"user","content":[{"type":"text","text":{"value":"I need to solve the equation `3x + 11 = 14`. Can you help me?","annotations":[]},"imageFile":{}}],"assistantId":null,"runId":null,"fileIds":[],"metadata":{}}
Created run
Run created:  {"id":"run_P8CvlouB8V9ZWxYiiVdL0FND","object":"thread.run","status":"queued","model":"daisy","instructions":"You are a personal math tutor. Write and run JavaScript code to answer math questions.","tools":[{"type":"code_interpreter"}],"metadata":{},"usage":null,"assistantId":"asst_zXaZ5usTjdD0JGcNViJM2M6N","threadId":"thread_KJuyrB7hynun4rvxWdfKLIqy","fileIds":[],"createdAt":"2024-04-08T19:26:39.000Z","expiresAt":"2024-04-08T19:36:39.000Z","startedAt":null,"completedAt":null,"cancelledAt":null,"failedAt":null}
Message content: "The solution to the equation \\(3x + 11 = 14\\) is \\(x = 1\\)."
Message content: "Yes, of course! To solve the equation \\( 3x + 11 = 14 \\), we can follow these steps:\n\n1. Subtract 11 from both sides of the equation to isolate the term with x.\n2. Then, divide by 3 to find the value of x.\n\nLet me calculate that for you."
Message content: "I need to solve the equation `3x + 11 = 14`. Can you help me?"

È importante ricordare che, mentre l'interprete di codice offre al modello la possibilità di rispondere a query più complesse convertendo le domande in codice ed eseguendo tale codice in modo iterativo in JavaScript fino a quando non raggiunge una soluzione, è comunque necessario convalidare la risposta per verificare che il modello ha convertito correttamente la domanda in una rappresentazione valida nel codice.

Pulire le risorse

Per pulire e rimuovere una risorsa OpenAI, è possibile eliminare la risorsa o il gruppo di risorse. L'eliminazione del gruppo di risorse comporta anche l'eliminazione di tutte le altre risorse associate.

Codice di esempio

Vedi anche

Prerequisiti

Impostazione

Recuperare la chiave e l'endpoint

Per eseguire correttamente una chiamata a OpenAI di Azure, è necessario quanto segue:

Nome variabile Valore
ENDPOINT L'endpoint di servizio è disponibile nella sezione Chiavi ed endpoint quando si esamina la risorsa dal portale di Azure. In alternativa, è possibile trovare l'endpoint tramite la pagina Distribuzioni in Azure AI Studio. Un endpoint di esempio è https://docs-test-001.openai.azure.com/.
API-KEY Questo valore è disponibile nella sezione Chiavi ed endpoint durante l'esame della risorsa dalla portale di Azure. È possibile usare KEY1 o KEY2.
DEPLOYMENT-NAME Questo valore corrisponderà al nome personalizzato scelto per la distribuzione quando è stato distribuito un modello. Questo valore è disponibile in Distribuzioni di Gestione>risorse nella portale di Azure o nella pagina Distribuzioni in Azure AI Studio.

Passare alla risorsa nel portale di Azure. Endpoint e Chiavi sono disponibili nella sezione Gestione risorse. Copiare l'endpoint e la chiave di accesso in base alle esigenze per l'autenticazione delle chiamate API. Puoi usare entrambi KEY1 o KEY2. Disporre sempre di due chiavi consente di ruotare e rigenerare in modo sicuro le chiavi senza causare un'interruzione del servizio.

Screenshot del pannello di panoramica per una risorsa OpenAI di Azure nel portale di Azure con la posizione dell'endpoint e delle chiavi di accesso evidenziata in rosso.

Variabili di ambiente

Creare e assegnare variabili di ambiente persistenti per la chiave e l'endpoint.

Importante

Se si usa una chiave API, archiviarla in modo sicuro in un'altra posizione, ad esempio in Azure Key Vault. Non includere la chiave API direttamente nel codice e non esporla mai pubblicamente.

Per altre informazioni sulla sicurezza dei servizi IA, vedere Autenticare richieste in Servizi di Azure AI.

setx AZURE_OPENAI_API_KEY "REPLACE_WITH_YOUR_KEY_VALUE_HERE" 
setx AZURE_OPENAI_ENDPOINT "REPLACE_WITH_YOUR_ENDPOINT_HERE" 

REST API

Creare un assistente

Nota

Con OpenAI di Azure è necessario specificare il nome della distribuzione del modello per il parametro model. Se il nome della distribuzione del modello è diverso dal nome del modello sottostante, è necessario modificare il codice in "model": "{your-custom-model-deployment-name}".

curl https://YOUR_RESOURCE_NAME.openai.azure.com/openai/assistants?api-version=2024-05-01-preview \
  -H "api-key: $AZURE_OPENAI_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "instructions": "You are an AI assistant that can write code to help answer math questions.",
    "name": "Math Assist",
    "tools": [{"type": "code_interpreter"}],
    "model": "gpt-4-1106-preview"
  }'

Strumenti

Un singolo assistente può accedere a un massimo di 128 strumenti, tra cui code interpreter, nonché a qualsiasi strumento personalizzato creato tramite le funzioni.

Creare un thread

curl https://YOUR_RESOURCE_NAME.openai.azure.com/openai/threads \
  -H "Content-Type: application/json" \
  -H "api-key: $AZURE_OPENAI_API_KEY" \
  -d ''

Aggiungere una domanda utente al thread

curl https://YOUR_RESOURCE_NAME.openai.azure.com/openai/threads/thread_abc123/messages \
  -H "Content-Type: application/json" \
  -H "api-key: $AZURE_OPENAI_API_KEY" \
  -d '{
      "role": "user",
      "content": "I need to solve the equation `3x + 11 = 14`. Can you help me?"
    }'

Eseguire il thread

curl https://YOUR_RESOURCE_NAME.openai.azure.com/openai/threads/thread_abc123/runs \
  -H "api-key: $AZURE_OPENAI_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "assistant_id": "asst_abc123",
  }'

Recuperare lo stato dell'esecuzione

curl https://YOUR_RESOURCE_NAME.openai.azure.com/openai/threads/thread_abc123/runs/run_abc123 \
  -H "api-key: $AZURE_OPENAI_API_KEY" \

Risposta dell'assistente

curl https://YOUR_RESOURCE_NAME.openai.azure.com/openai/threads/thread_abc123/messages \
  -H "Content-Type: application/json" \
  -H "api-key: $AZURE_OPENAI_API_KEY" \

Informazioni sui risultati

In questo esempio viene creato un assistente con interprete di codice abilitato. Quando si pone all'assistente una domanda matematica, la domanda viene convertita in codice Python e viene eseguito il codice nell'ambiente sandbox per determinare la risposta alla domanda. Il codice che il modello crea e testa per arrivare a una risposta è:

    from sympy import symbols, Eq, solve  
      
    # Define the variable  
    x = symbols('x')  
      
    # Define the equation  
    equation = Eq(3*x + 11, 14)  
      
    # Solve the equation  
    solution = solve(equation, x)  
    solution  

È importante ricordare che, benché l'interprete di codice offra al modello la possibilità di rispondere a query più complesse convertendo le domande in codice ed eseguendo tale codice in modo iterativo nella sandbox Python fino a quando non raggiunge una soluzione, è comunque necessario convalidare la risposta per verificare che il modello abbia convertito correttamente la domanda in una rappresentazione valida nel codice.

Pulire le risorse

Per pulire e rimuovere una risorsa OpenAI, è possibile eliminare la risorsa o il gruppo di risorse. L'eliminazione del gruppo di risorse comporta anche l'eliminazione di tutte le altre risorse associate.

Vedi anche