Condividi tramite


Creare un agente OpenAI .NET usando un server MCP in Azure Container Apps

Questo articolo illustra come creare un agente MCP (Model Context Protocol) usando .NET. In questo esempio, il client MCP (scritto in C#/.NET) si connette a un server MCP (scritto in TypeScript) per gestire un elenco di todo. Il client trova gli strumenti disponibili dal server e li invia a un modello OpenAI Azure. Gli utenti possono quindi parlare con il sistema todo usando il linguaggio quotidiano.

Accedere al codice

Scoprite il modello di blocco di costruzione di agenti AI di OpenAI MCP. Questo esempio illustra come compilare un agente OpenAI che usa un client MCP per utilizzare un server MCP esistente.

Passare alla sezione della procedura dettagliata del codice per comprendere il funzionamento di questo esempio.

Panoramica dell'architettura

Il diagramma seguente illustra la semplice architettura dell'app di esempio: Diagram che mostra l'architettura da Visual Studio Code che ospita l'agente e il client MCP a MCP Server.

  • Client MCP: si connette al server MCP e trova gli strumenti disponibili
  • Chat Client: funziona con Azure OpenAI per comprendere il linguaggio naturale
  • Interfaccia utente Blazor: fornisce un'interfaccia Web in cui gli utenti possono chattare
  • Livello di trasporto: usa eventi di Server-Sent (SSE) per inviare messaggi in tempo reale
  • Autenticazione: usa i token JWT per proteggere la connessione

Il server MCP viene eseguito come app containerizzata su Azure Container Apps (ACA). Usa un back-end TypeScript per fornire strumenti al client MCP tramite il protocollo del contesto del modello. Tutti gli strumenti funzionano con un database SQLite back-end.

Annotazioni

Visitare Build a TypeScript MCP server using Azure Container Apps per visualizzare la procedura dettagliata del codice del server MCP TypeScript usato in questo articolo.

Costo

Per ridurre i costi, questo esempio usa piani tariffari di base o a consumo per la maggior parte delle risorse. Modificare il livello in base alle esigenze ed eliminare le risorse al termine per evitare addebiti.

Prerequisiti

Un contenitore di sviluppo include tutte le dipendenze necessarie per questo articolo. È possibile eseguirlo in GitHub Codespaces (in un browser) o in locale usando Visual Studio Code.

Per seguire questo articolo, assicurarsi di soddisfare questi prerequisiti:

Distribuire un modello foundry gpt-5-mini usando l'estensione Foundry VS Code

Distribuire un modello gpt-5-mini usando l'estensione Foundry in Visual Studio Code seguendo questa procedura:

Creare un progetto Foundry e distribuire il modello

Creare la stringa di connessione del modello OpenAI

  1. Dopo aver distribuito il gpt-5-mini modello, fare clic con il pulsante destro del mouse sul modello nell'estensione Foundry e selezionare Copia chiave API per copiare la chiave API del modello negli Appunti.

  2. Fare quindi clic con il pulsante destro del mouse sul modello distribuito gpt-5-mini nell'estensione Foundry e selezionare Copia endpoint per copiare l'endpoint del modello negli Appunti, come illustrato nello screenshot seguente:

    Screenshot che mostra il menu di scelta rapida per il modello distribuito con le opzioni Copia endpoint e Copia chiave API evidenziate.

  3. Creare infine un connection string per il modello distribuito gpt-5-mini usando l'endpoint copiato e la chiave API nel formato seguente: Endpoint=<AZURE_OPENAI_ENDPOINT>;Key=<AZURE_OPENAI_API_KEY>. Questa connection string sarà necessaria più avanti nell'articolo.

  • Una sottoscrizione Azure: Crearne una gratuitamente
  • Azure autorizzazioni dell'account: l'account Azure deve avere autorizzazioni Microsoft.Authorization/roleAssignments/write, ad esempio Role Based Access Control Administrator, User Access Administrator o Owner. Se non si dispone delle autorizzazioni a livello di sottoscrizione, è necessario ricevere RBAC per un gruppo di risorse esistente e distribuire le risorse in tale gruppo.
    • L'account Azure richiede anche autorizzazioni Microsoft.Resources/deployments/write a livello di sottoscrizione.
  • account su GitHub

Ambiente di sviluppo aperto

Seguire questa procedura per configurare un ambiente di sviluppo preconfigurato con tutte le dipendenze necessarie.

GitHub Codespaces esegue un contenitore di sviluppo gestito da GitHub con Visual Studio Code per web come interfaccia. Usare GitHub Codespaces per la configurazione più semplice, perché include gli strumenti e le dipendenze necessari preinstallati per questo articolo.

Importante

Tutti gli account GitHub possono usare Codespaces per un massimo di 60 ore gratuite ogni mese con due istanze principali. Per altre informazioni, vedere l'archiviazione e le ore di base mensili incluse di GitHub Codespaces.

Usare la procedura seguente per creare un nuovo GitHub Codespace nel ramo main del repository Azure-Samples/openai-mcp-agent-dotnet GitHub.

  1. Fare clic con il pulsante destro del mouse sul pulsante seguente e scegliere Apri collegamento nella nuova finestra. Questa azione consente di avere l'ambiente di sviluppo e la documentazione aperta side-by-side.

    Apri in GitHub Codespaces

  2. Nella pagina Create codespace esaminare e quindi selezionare Create new codespace.

  3. Attendere l'avvio dello spazio di codice. Potrebbero essere necessari alcuni minuti.

  4. Assicurarsi che il nome del modello distribuito sia gpt-5-mini. Se il modello distribuito è diverso, aggiornare src/McpTodo.ClientApp/appsettings.json con il nome di distribuzione corretto.

    {
      "OpenAI": {
        // Make sure this is the right deployment name.
        "DeploymentName": "gpt-5-mini"
      }
    }
    
  5. Accedi ad Azure con l'interfaccia della riga di comando Azure Developer nel terminale nella parte inferiore dello schermo.

    azd auth login
    
  6. Copiare il codice dal terminale e incollarlo in un browser. Seguire le istruzioni per eseguire l'autenticazione con l'account Azure.

Si eseguono le altre attività in questo contenitore di sviluppo.

Annotazioni

Per eseguire l'agente MCP in modo locale:

  1. Configurare l'ambiente come descritto nella sezione Introduzione del repository di esempio.
  2. Installare il server MCP seguendo le istruzioni nella sezione Get MCP Server App del repository di esempio.
  3. Eseguire l'agente MCP localmente seguendo le istruzioni nella sezione Esegui localmente del repository di esempio.
  4. Passare alla sezione Usare l'agente TODO MCP per continuare.

Distribuire ed eseguire

Il repository di esempio contiene tutti i file di codice e configurazione per la distribuzione dell'agente MCP Azure. La procedura seguente illustra il processo di distribuzione dell'agente MCP di esempio Azure.

Distribuire in Azure

Importante

Le risorse di Azure in questa sezione iniziano a generare costi immediatamente, anche se si interrompe il comando prima che sia completato.

Impostare il token JWT

  • Impostare il token JWT per il server MCP eseguendo il comando seguente nel terminale nella parte inferiore della schermata:

    # zsh/bash
    ./scripts/set-jwttoken.sh
    
    # PowerShell
    ./scripts/Set-JwtToken.ps1
    

Aggiungere un token JWT alla configurazione dell'ambiente azd

  1. Aggiungere il token JWT a azd environment configuration eseguendo il comando seguente nel terminale nella parte inferiore della schermata:

    # zsh/bash
    env_dir=".azure/$(azd env get-value AZURE_ENV_NAME)"
    mkdir -p "$env_dir"
    cat ./src/McpTodo.ServerApp/.env >> "$env_dir/.env"
    
    # PowerShell
    $dotenv = Get-Content ./src/McpTodo.ServerApp/.env
    $dotenv | Add-Content -Path ./.azure/$(azd env get-value AZURE_ENV_NAME)/.env -Encoding utf8 -Force
    

    Annotazioni

    Per impostazione predefinita, l'app client MCP è protetta dalla funzionalità di autenticazione predefinita di ACA. È possibile disattivare questa funzionalità prima di eseguire azd up impostando:

    azd env set USE_LOGIN false
    
  2. Eseguire il seguente comando della CLI sviluppatore di Azure per il provisioning delle risorse di Azure e la distribuzione del codice sorgente.

    azd up
    
  3. Usare la tabella seguente per rispondere alle richieste:

    Rapido Risposta
    Nome dell'ambiente Usare un nome breve e minuscolo. Aggiungere il nome o l'alias. Ad esempio: my-mcp-agent. Il nome dell'ambiente diventa parte del nome del gruppo di risorse.
    Subscription Scegliere la sottoscrizione in cui si vogliono creare risorse.
    Posizione (per l'hosting) Selezionare il percorso di distribuzione del modello dall'elenco.
    Stringa di connessione OpenAI Incollare il connection string per il modello OpenAI creato in precedenza nella sezione Creare il modello OpenAI connection string.
  4. La distribuzione delle app richiede da 5 a 10 minuti.

  5. Al termine della distribuzione, è possibile accedere all'agente MCP usando l'URL nell'output. L'URL è simile al seguente:

    https://<env-name>.<container-id>.<region>.azurecontainerapps.io
    
  6. Aprire l'URL in un Web browser per usare l'agente MCP.

Usare l'agente MCP TODO

Dopo l'esecuzione dell'agente MCP, è possibile usare gli strumenti forniti in modalità agente. Per usare gli strumenti MCP in modalità agente:

  1. Passare all'URL dell'app client e accedere all'app.

    Annotazioni

    se si imposta il USE_LOGIN valore su false, potrebbe non essere richiesto di accedere.

  2. Immettere un prompt, ad esempio "È necessario inviare un messaggio di posta elettronica al mio manager mercoledì" nella casella di input della chat e notare come gli strumenti vengono richiamati automaticamente in base alle esigenze.

  3. L'agente MCP usa gli strumenti forniti dal server MCP per soddisfare la richiesta e restituire una risposta nell'interfaccia di chat.

  4. Sperimenta altri prompt come:

    Give me a list of to dos.
    Set "meeting at 1pm".
    Give me a list of to dos.
    Mark #1 as completed.
    Delete #1 from the to-do list.
    

Esplorare il codice

Il repository di esempio contiene tutti i file di codice e configurazione per la distribuzione dell'agente MCP Azure. Le sezioni seguenti illustrano i componenti chiave del codice dell'agente MCP.

Configurazione e impostazione del client MCP

L'applicazione configura il client MCP in Program.cs. Questa configurazione definisce come connettersi e quali opzioni usare. Il codice usa diversi modelli avanzati, tra cui l'integrazione .NET Aspire e le impostazioni predefinite del servizio:

builder.Services.AddSingleton<IMcpClient>(sp =>
{
    var config = sp.GetRequiredService<IConfiguration>();
    var loggerFactory = sp.GetRequiredService<ILoggerFactory>();

    var uri = new Uri(config["McpServers:TodoList"]!);

    var clientTransportOptions = new SseClientTransportOptions()
    {
        Endpoint = new Uri($"{uri.AbsoluteUri.TrimEnd('/')}/mcp"),
        AdditionalHeaders = new Dictionary<string, string>
        {
            { "Authorization", $"Bearer {config["McpServers:JWT:Token"]!}" }
        }
    };
    var clientTransport = new SseClientTransport(clientTransportOptions, loggerFactory);

    var clientOptions = new McpClientOptions()
    {
        ClientInfo = new Implementation()
        {
            Name = "MCP Todo Client",
            Version = "1.0.0",
        }
    };

    return McpClientFactory.CreateAsync(clientTransport, clientOptions, loggerFactory).GetAwaiter().GetResult();
});

Dettagli principali sull'implementazione:

  • Configurazione del trasporto: SseClientTransportOptions supporta sia Eventi Server-Sent (SSE) che il trasporto HTTP trasmissibile in streaming. Il metodo di trasporto dipende dall'URL dell'endpoint: gli endpoint che terminano con /sse usano eventi Server-Sent, mentre gli endpoint che terminano con /mcp usano HTTP trasmissibile. Questo approccio consente la comunicazione in tempo reale tra client e server
  • Intestazioni di autenticazione: i token JWT vengono inseriti in AdditionalHeaders per proteggere la comunicazione del server
  • Informazioni client: McpClientOptions indica al server il nome e la versione del client
  • Factory Pattern: McpClientFactory.CreateAsync() connette e completa il protocollo handshake

integrazione predefinita del servizio .NET Aspire

L'applicazione utilizza il pattern dei default del servizio di .NET Aspire per le preoccupazioni trasversali.

// McpTodo.ServiceDefaults/Extensions.cs
public static TBuilder AddServiceDefaults<TBuilder>(this TBuilder builder) where TBuilder : IHostApplicationBuilder
{
    builder.ConfigureOpenTelemetry();
    builder.AddDefaultHealthChecks();
    builder.Services.AddServiceDiscovery();
    
    builder.Services.ConfigureHttpClientDefaults(http =>
    {
        // Turn on resilience by default
        http.AddStandardResilienceHandler();
        // Turn on service discovery by default
        http.AddServiceDiscovery();
    });
    
    return builder;
}

Vantaggi delle impostazioni predefinite del servizio:

  • Metodi di estensione componibili: il sistema usa un modello di generatore pulito per aggiungere funzionalità condivise
  • Gestori di resilienza standard: il sistema aggiunge regole predefinite di ripetizione, interruttore e timeout
  • Integrazione dell'individuazione dei servizi: il sistema trova automaticamente i servizi negli ambienti contenitore
  • OpenTelemetry per impostazione predefinita: il sistema ottiene il monitoraggio completo senza alcun lavoro di configurazione

Il diagramma seguente illustra la relazione tra problemi trasversali e servizi applicativi:

Diagramma che mostra la relazione tra problemi trasversali e servizi applicativi.

Risoluzione dell'URL di configurazione

L'esempio include una risoluzione url sofisticata per ambienti diversi:

// AspireUrlParserExtensions.cs
public static Uri Resolve(this Uri uri, IConfiguration config)
{
    var absoluteUrl = uri.ToString();
    if (absoluteUrl.StartsWith("https+http://"))
    {
        var appname = absoluteUrl.Substring("https+http://".Length).Split('/')[0];
        var https = config[$"services:{appname}:https:0"]!;
        var http = config[$"services:{appname}:http:0"]!;
        
        return string.IsNullOrWhiteSpace(https) ? new Uri(http) : new Uri(https);
    }
    // Handle other URL formats...
}

Funzionalità di gestione della configurazione:

  • Astrazione dell'individuazione dei servizi: il sistema gestisce gli URL di sviluppo e produzione in modo efficiente
  • Negoziazione del protocollo: il sistema sceglie prima HTTPS, quindi esegue il fallback a HTTP
  • Configuration Convention: il sistema usa modelli di configurazione del servizio .NET Aspire standard

Implementazione dell'autenticazione

Questo esempio usa l'autenticazione JWT (JSON Web Token) per proteggere la connessione tra il client MCP e il server.

dotnet user-secrets --project ./src/McpTodo.ClientApp set McpServers:JWT:Token "$TOKEN"

Annotazioni

Gli script hanno creato automaticamente la variabile $TOKEN quando è stato eseguito lo script Bash (set-jwttoken.sh) o PowerShell (Set-JwtToken.ps1) in precedenza nella sezione Deploy in Azure. Questi script eseguono i passaggi seguenti:

  1. Eseguire npm run generate-token nell'app server MCP per creare un token JWT
  2. Analizzare il file generato .env per estrarre il valore JWT_TOKEN
  3. Archiviarlo automaticamente in .NET segreti utente per MCPClient

Il client MCP recupera il token JWT dalla configurazione e lo include nelle intestazioni HTTP per l'autenticazione durante la connessione al server MCP:

AdditionalHeaders = new Dictionary<string, string>
{
    { "Authorization", $"Bearer {config["McpServers:JWT:Token"]!}" }
}

Questo approccio garantisce:

  • Comunicazione sicura: il sistema consente solo ai client con token validi di connettersi al server MCP
  • autorizzazioneToken-Based: i token JWT consentono al sistema di verificare gli utenti senza archiviare i dati della sessione
  • Gestione della configurazione: il sistema archivia i token sensibili in modo sicuro nei segreti utente durante lo sviluppo

Integrazione dell'autenticazione di Azure Container Apps

L'infrastruttura mostra modelli di autenticazione avanzati usando Azure Container Apps funzionalità di autenticazione e autorizzazione predefinite ("Easy Auth"):

// containerapps-authconfigs.bicep
resource containerappAuthConfig 'Microsoft.App/containerApps/authConfigs@2024-10-02-preview' = {
  properties: {
    identityProviders: {
      azureActiveDirectory: {
        enabled: true
        registration: {
          clientId: clientId
          openIdIssuer: openIdIssuer
        }
      }
    }
    login: {
      tokenStore: {
        enabled: true
        azureBlobStorage: {
          blobContainerUri: '${storageAccount.properties.primaryEndpoints.blob}/token-store'
          managedIdentityResourceId: userAssignedIdentity.id
        }
      }
    }
  }
}

Funzionalità avanzate di autenticazione:

  • Zero-Code Authentication: Azure Container Apps fornisce l'autenticazione predefinita
  • Identità gestita per l'archiviazione: il sistema archivia i token in modo sicuro senza stringhe di connessione
  • Credenziali di identità federate: il sistema abilita l'identità di carico di lavoro per l'autenticazione secondo il modello Kubernetes

Il diagramma seguente illustra l'handshake di sicurezza tra i componenti:

Diagramma che mostra l'handshake di sicurezza tra i componenti.

Individuazione e registrazione degli strumenti

Il client MCP individua gli strumenti disponibili dal server durante l'inizializzazione dei componenti in Chat.razor:

protected override async Task OnInitializedAsync()
{
    messages.Add(new(ChatRole.System, SystemPrompt));
    tools = await McpClient.ListToolsAsync();
    chatOptions.Tools = [.. tools];
}

Funzionamento della ricerca degli strumenti:

  1. Query server: McpClient.ListToolsAsync() invia una richiesta al server MCP per elencare gli strumenti disponibili
  2. Recupero schema: il server invia le definizioni degli strumenti con nomi, descrizioni e schemi di input
  3. Registrazione dello strumento: il sistema registra gli strumenti con l'oggetto ChatOptions , rendendoli disponibili per il client OpenAI
  4. Type Safety: la McpClientTool classe eredita da AIFunction, offrendo un'integrazione uniforme con Microsoft.Extensions.AI

Il diagramma seguente mostra come vengono analizzati e registrati gli schemi degli strumenti:

Diagramma che mostra il flusso di individuazione e registrazione degli strumenti.

Integrazione e chiamata di funzione OpenAI

La configurazione del client di chat illustra come gli strumenti MCP si integrano con Azure OpenAI:

var chatClient = openAIClient.GetChatClient(config["OpenAI:DeploymentName"]).AsIChatClient();

builder.Services.AddChatClient(chatClient)
                .UseFunctionInvocation()
                .UseLogging();

Vantaggi dell'integrazione:

  • Chiamata automatica delle funzioni: l'estensione .UseFunctionInvocation() attiva l'esecuzione automatica degli strumenti in base alle decisioni LLM
  • Facile accesso agli strumenti: gli strumenti MCP funzionano come funzioni predefinite per il modello OpenAI
  • Elaborazione della risposta: il sistema aggiunge automaticamente i risultati dello strumento al flusso di conversazione

implementazione di chat Real-Time

L'interfaccia della chat in Chat.razor illustra le risposte in streaming e l'esecuzione degli strumenti con modelli Blazor avanzati:

private async Task AddUserMessageAsync(ChatMessage userMessage)
{
    CancelAnyCurrentResponse();

    // Add the user message to the conversation
    messages.Add(userMessage);
    chatSuggestions?.Clear();
    await chatInput!.FocusAsync();

    // Stream and display a new response from the IChatClient
    var responseText = new TextContent("");
    currentResponseMessage = new ChatMessage(ChatRole.Assistant, [responseText]);
    currentResponseCancellation = new();
    await foreach (var update in ChatClient.GetStreamingResponseAsync([.. messages], chatOptions, currentResponseCancellation.Token))
    {
        messages.AddMessages(update, filter: c => c is not TextContent);
        responseText.Text += update.Text;
        ChatMessageItem.NotifyChanged(currentResponseMessage);
    }

    // Store the final response in the conversation, and begin getting suggestions
    messages.Add(currentResponseMessage!);
    currentResponseMessage = null;
    chatSuggestions?.Update(messages);
}

Funzionalità di implementazione di streaming:

  • Aggiornamenti in tempo reale: GetStreamingResponseAsync() invia gli aggiornamenti delle risposte un po' alla volta
  • Esecuzione degli strumenti: il sistema elabora automaticamente le chiamate di funzione durante lo streaming
  • Velocità di risposta dell'interfaccia utente: ChatMessageItem.NotifyChanged() aggiorna l'interfaccia utente in tempo reale
  • Supporto per l'annullamento: gli utenti possono annullare operazioni a esecuzione prolungata

Modelli avanzati dell'interfaccia utente Blazor

L'implementazione usa modelli avanzati dell'interfaccia utente per gli aggiornamenti in tempo reale:

Gestione degli eventi sicura per la memoria:

// ChatMessageItem.razor
private static readonly ConditionalWeakTable<ChatMessage, ChatMessageItem> SubscribersLookup = new();

public static void NotifyChanged(ChatMessage source)
{
    if (SubscribersLookup.TryGetValue(source, out var subscriber))
    {
        subscriber.StateHasChanged();
    }
}

Integrazione di componenti Web personalizzati:

// ChatMessageList.razor.js
window.customElements.define('chat-messages', class ChatMessages extends HTMLElement {
    connectedCallback() {
        this._observer = new MutationObserver(mutations => this._scheduleAutoScroll(mutations));
        this._observer.observe(this, { childList: true, attributes: true });
    }
    
    _scheduleAutoScroll(mutations) {
        // Debounce the calls and handle smart auto-scrolling
        cancelAnimationFrame(this._nextAutoScroll);
        this._nextAutoScroll = requestAnimationFrame(() => {
            const addedUserMessage = mutations.some(m => 
                Array.from(m.addedNodes).some(n => 
                    n.parentElement === this && n.classList?.contains('user-message')));
            // Smart scrolling logic...
        });
    }
});

Gestione avanzata dello stato:

// Chat.razor
private void CancelAnyCurrentResponse()
{
    // If a response was cancelled while streaming, include it in the conversation so it's not lost
    if (currentResponseMessage is not null)
    {
        messages.Add(currentResponseMessage);
    }
    
    currentResponseCancellation?.Cancel();
    currentResponseMessage = null;
}

Vantaggi dell'interfaccia utente blazor:

  • Componenti Web ibridi: il sistema combina Blazor Server con elementi personalizzati per ottenere prestazioni migliori
  • Memory-Safe gestione degli eventi: il sistema usa ConditionalWeakTable per evitare perdite di memoria
  • Scorrimento automatico intelligente: il sistema fornisce un comportamento di chat semplice da usare con la debouncing
  • Annullamento normale: il sistema salva il lavoro parziale quando gli utenti annullano le operazioni

Flusso di richiesta/risposta

Ecco come un'interazione utente tipica scorre attraverso il sistema:

  1. Input utente: l'utente digita un messaggio come "Aggiungi "Acquista generi alimentari" alla mia lista todo"
  2. Elaborazione messaggi: il sistema aggiunge il messaggio alla cronologia delle conversazioni
  3. LLM Analysis: Azure OpenAI analizza la richiesta e decide quali strumenti usare
  4. Individuazione degli strumenti: il modello trova lo strumento MCP corretto (ad esempio, addTodo)
  5. Esecuzione dello strumento: il client MCP chiama il server con i parametri necessari
  6. Elaborazione della risposta: il sistema aggiunge la risposta del server alla conversazione
  7. Aggiornamento dell'interfaccia utente: il sistema mostra il risultato all'utente in tempo reale

Il diagramma seguente illustra il flusso dei messaggi dall'input dell'utente tramite OpenAI all'esecuzione degli strumenti e di nuovo all'interfaccia utente:

Diagramma che mostra il flusso di richiesta/risposta.

Gestione dei modelli asincroni

L'applicazione illustra modelli asincroni sofisticati per le operazioni in background:

// ChatSuggestions.razor
public void Update(IReadOnlyList<ChatMessage> messages)
{
    // Runs in the background and handles its own cancellation/errors
    _ = UpdateSuggestionsAsync(messages);
}

private async Task UpdateSuggestionsAsync(IReadOnlyList<ChatMessage> messages)
{
    cancellation?.Cancel();
    cancellation = new CancellationTokenSource();
    
    try
    {
        var response = await ChatClient.GetResponseAsync<string[]>(
            [.. ReduceMessages(messages), new(ChatRole.User, Prompt)],
            cancellationToken: cancellation.Token);
        // Handle response...
    }
    catch (Exception ex) when (ex is not OperationCanceledException)
    {
        await DispatchExceptionAsync(ex);
    }
}

Vantaggi delle attività in background:

  • Fire-and-Forget with Safety: il sistema usa il modello con una corretta gestione delle eccezioni _ =
  • Riduzione del contesto intelligente: il sistema limita la storia delle conversazioni per impedire l'overflow di token
  • Annullamento intelligente: il sistema pulisce correttamente le operazioni concorrenti

Gestione degli errori e resilienza

L'implementazione include diversi modelli di resilienza:

private void CancelAnyCurrentResponse()
{
    // If a response was cancelled while streaming, include it in the conversation so it's not lost
    if (currentResponseMessage is not null)
    {
        messages.Add(currentResponseMessage);
    }

    currentResponseCancellation?.Cancel();
    currentResponseMessage = null;
}

Funzionalità di resilienza:

  • Annullamento normale: il sistema salva le risposte in corso quando gli utenti li annullano
  • Ripristino connessione: il trasporto SSE gestisce automaticamente le interruzioni della connessione
  • Gestione dello stato: lo stato dell'interfaccia utente rimane coerente durante gli errori
  • Logging Integration: il sistema offre un supporto di logging completo per il debug e il monitoraggio

Controlli di osservabilità e verifiche di stato

L'applicazione include modelli di osservabilità sofisticati:

Configurazione della verifica intelligente dello stato:

// Extensions.cs
public static WebApplication MapDefaultEndpoints(this WebApplication app)
{
    if (app.Environment.IsDevelopment())
    {
        // All health checks must pass for app to be considered ready
        app.MapHealthChecks(HealthEndpointPath);
        
        // Only health checks tagged with "live" must pass for app to be considered alive
        app.MapHealthChecks(AlivenessEndpointPath, new HealthCheckOptions
        {
            Predicate = r => r.Tags.Contains("live")
        });
    }
    return app;
}

OpenTelemetry con filtro intelligente:

// Extensions.cs
.AddAspNetCoreInstrumentation(tracing =>
    // Exclude health check requests from tracing
    tracing.Filter = context =>
        !context.Request.Path.StartsWithSegments(HealthEndpointPath)
        && !context.Request.Path.StartsWithSegments(AlivenessEndpointPath)
)

Vantaggi dell'osservabilità:

  • Endpoint consapevole dell'ambiente: esposizione del controllo della sicurezza e della salute
  • Liveness vs Readiness: modelli di controllo dell'integrità in stile Kubernetes
  • Riduzione del rumore di telemetria: filtrare i controlli di stato di routine dalle tracce

Configurazione e configurazione dell'ambiente

L'applicazione supporta più ambienti tramite la configurazione:

var openAIClient = Constants.GitHubModelEndpoints.Contains(endpoint.TrimEnd('/'))
                   ? new OpenAIClient(credential, openAIOptions)
                   : new AzureOpenAIClient(new Uri(endpoint), credential);

Opzioni di configurazione:

  • Azure OpenAI: le distribuzioni di produzione usano in genere Azure OpenAI Service
  • GitHub Models: gli scenari di sviluppo possono usare modelli GitHub
  • Sviluppo locale: supporto per le istanze del server MCP locali
  • distribuzione Container: Azure Container Apps per l'hosting di produzione

Pulire le risorse

Al termine dell'uso dell'agente MCP, pulire le risorse create per evitare di incorrere in costi non necessari.

Per pulire le risorse, seguire questa procedura:

  • Eliminare le risorse Azure create dall'interfaccia della riga di comando per sviluppatori Azure eseguendo il comando seguente nel terminale nella parte inferiore della schermata:

    azd down --purge --force
    

Pulire GitHub Codespaces

Per ottimizzare le ore gratuite per singolo core, elimina l'ambiente Codespaces di GitHub.

Importante

Per ulteriori informazioni sull'archiviazione gratuita e sulle ore core incluse nel tuo account GitHub, consulta Archiviazione e ore core mensili incluse in GitHub Codespaces.

  1. Accedere al dashboard GitHub Codespaces.

  2. Trova il tuo spazio di codice attivo creato dal repository Azure-Samples/openai-mcp-agent-dotnet GitHub.

  3. Aprire il menu di scelta rapida per lo spazio di codice e selezionare Elimina.

Ottenere assistenza

Registrare il tuo problema nel repository Issues.