Condividi tramite


Creare un agente OpenAI .NET usando un server MCP nelle app Azure Container

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 di Azure. Gli utenti possono quindi parlare con il sistema todo usando il linguaggio quotidiano.

Accedere al codice

Vedere il modello OpenAI MCP Agent Building Block PER intelligenza artificiale. 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: diagramma che mostra l'architettura da Visual Studio Code che ospita l'agente e il client MCP al server MCP.

  • Client MCP: si connette al server MCP e trova gli strumenti disponibili
  • Client Chat: 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 in contenitori in App Azure Container. 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

Vedere Creare un server MCP TypeScript con App Azure Container 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 Gpt-5-mini di AI Foundry usando l'estensione di AI Foundry VS Code

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

Creare un progetto di AI Foundry e distribuire il modello

  • Per creare un progetto di AI Foundry e distribuire un gpt-5-mini modello, seguire le istruzioni introduttive nell'articolo Usare l'estensione Azure AI Foundry per Visual Studio Code (anteprima).

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 AI 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 AI 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 una stringa di connessione 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 stringa di connessione è necessaria più avanti nell'articolo.

  • Una sottoscrizione di Azure: crearne una gratuitamente
  • Autorizzazioni dell'account Azure: l'account Azure deve disporre Microsoft.Authorization/roleAssignments/write di autorizzazioni, ad esempio Amministratore controllo degli accessi in base al ruolo, Amministratore accesso utenti o Proprietario. Se non si dispone delle autorizzazioni a livello di sottoscrizione, è necessario concedere il controllo degli accessi in base al ruolo per un gruppo di risorse esistente e distribuirlo in tale gruppo.
    • L'account Azure necessita anche delle Microsoft.Resources/deployments/write autorizzazioni a livello di sottoscrizione.
  • Account 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 il 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 GitHub Codespaces mensilmente incluso archiviazione e ore di core.

Usare la procedura seguente per creare un nuovo GitHub Codespace nel main ramo del Azure-Samples/openai-mcp-agent-dotnet repository 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.

    Aprire in GitHub Codespaces

  2. Nella pagina Crea spazio codici esaminare e quindi selezionare Crea nuovo spazio di codice.

  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. Accedere ad Azure con l'interfaccia della riga di comando per sviluppatori di Azure nel terminale nella parte inferiore della schermata.

    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 locale:

  1. Configurare l'ambiente come descritto nella sezione Introduzione nel repository di esempio.
  2. Installare il server MCP seguendo le istruzioni nella sezione Get MCP Server App (Scarica app server MCP ) nel repository di esempio.
  3. Eseguire l'agente MCP in locale seguendo le istruzioni nella sezione Esegui localmente nel 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 di Azure dell'agente MCP. La procedura seguente illustra il processo di distribuzione dell'agente MCP di azure di esempio.

Distribuzione in Azure

Importante

Le risorse di Azure in questa sezione iniziano a costare denaro immediatamente, anche se si arresta il comando prima del completamento.

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 a azd environment configuration

  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 comando seguente dell'interfaccia della riga di comando per sviluppatori 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.
    Località (per l'hosting) Selezionare il percorso di distribuzione del modello dall'elenco.
    Stringa di connessione OpenAI Incollare la stringa di connessione per il modello OpenAI creato in precedenza nella sezione Creare la stringa di connessione del modello OpenAI .
  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 eseguire l'accesso.

  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. Sperimentare altri prompt, ad esempio:

    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 di Azure dell'agente MCP. Le sezioni seguenti illustrano i componenti chiave del codice dell'agente MCP.

Configurazione e configurazione 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 e le impostazioni predefinite del servizio .NET Aspire:

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 Server-Sent Eventi (SSE) che il trasporto HTTP streamable. Il metodo di trasporto dipende dall'URL dell'endpoint, ovvero gli endpoint che terminano con /sse l'uso di eventi Server-Sent, mentre gli endpoint terminano con /mcp l'uso di HTTP di flusso. 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
  • Modello factory: McpClientFactory.CreateAsync() connette e completa l'handshake del protocollo

Integrazione predefinita del servizio .NET Aspire

L'applicazione usa il modello di impostazione predefinita del servizio .NET Aspire per le problematiche 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 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 pulito
  • Negoziazione del protocollo: il sistema sceglie prima HTTPS, quindi esegue il fallback a HTTP
  • Convenzione di configurazione: il sistema usa modelli di configurazione del servizio .NET Aspirabili 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 $TOKEN variabile quando è stato eseguito lo script Bash (set-jwttoken.sh) o PowerShell (Set-JwtToken.ps1) in precedenza nella sezione Distribuisci 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 nei segreti utente .NET 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 App Azure Container

L'infrastruttura mostra modelli di autenticazione avanzati usando le funzionalità predefinite di autenticazione e autorizzazione di App Azure Container ("Autenticazione semplice"):

// 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:

  • autenticazioneZero-Code: App Azure Container 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à del carico di lavoro per l'autenticazione in stile 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 dell'individuazione 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:

  • Real-Time Aggiornamenti: GetStreamingResponseAsync() invia gli aggiornamenti delle risposte bit per bit
  • 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:

Memory-Safe gestione degli eventi:

// 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. Analisi LLM: 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 cronologia delle conversazioni per impedire l'overflow del 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 l'eliminazione della connessione
  • Gestione dello stato: lo stato dell'interfaccia utente rimane coerente durante gli errori
  • Integrazione registrazione: il sistema fornisce la registrazione completa per il debug e il monitoraggio

Controlli di osservabilità e integrità

L'applicazione include modelli di osservabilità sofisticati:

Configurazione controllo integrità intelligente:

// 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à:

  • endpointEnvironment-Aware: esposizione al controllo dell'integrità consapevole della sicurezza
  • Liveness vs Readiness: modelli di controllo dell'integrità in stile Kubernetes
  • Riduzione del rumore di telemetria: filtro dei controlli di integrità delle 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 il servizio Azure OpenAI
  • Modelli GitHub: gli scenari di sviluppo possono usare modelli GitHub
  • Sviluppo locale: supporto per le istanze del server MCP locali
  • Distribuzione di contenitori: App Azure Container 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 di Azure create dall'interfaccia della riga di comando per sviluppatori di Azure eseguendo il comando seguente nel terminale nella parte inferiore della schermata:

    azd down --purge --force
    

Pulire GitHub Codespaces

Eliminare l'ambiente GitHub Codespaces per ottimizzare le ore gratuite per core.

Importante

Per altre informazioni sull'archiviazione gratuita e sulle ore di base dell'account GitHub, vedere GitHub Codespaces mensilmente incluso archiviazione e ore di core.

  1. Accedere al dashboard di GitHub Codespaces.

  2. Trovare gli spazi di codice attivi creati dal Azure-Samples/openai-mcp-agent-dotnet repository GitHub.

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

Ottenere assistenza

Registrare il problema nei problemi del repository.