AI

LLM Chat in .NET con IChatClient: guida completa all’integrazione

Dario Fadda Aprile 15, 2026

Introduzione: l’astrazione che unifica i servizi LLM

Integrare Large Language Model in .NET ha sempre comportato un problema: ogni servizio (OpenAI, Azure OpenAI, Ollama, Claude) ha il proprio SDK con API diverse. IChatClient della libreria Microsoft.Extensions.AI risolve questo problema fornendo un’astrazione unificata. Scrivi una volta, cambia provider senza modificare la logica applicativa.

Cosa è IChatClient?

IChatClient è un’interfaccia che rappresenta un client per servizi AI con capacità chat. Astrae i dettagli di comunicazione con LLM remoti o locali, permettendo di:

  • Inviare e ricevere messaggi con contenuto multi-modale (testo, immagini, audio)
  • Ottenere risposte complete o streaming incrementale
  • Mantenere contesto di conversazione
  • Usare funzionalità avanzate come tool calling e structured outputs

L’interfaccia fa parte del pacchetto Microsoft.Extensions.AI.Abstractions, mentre Microsoft.Extensions.AI aggiunge middleware per telemetria, caching, function calling automatico e patterns familiari di dependency injection.

Setup iniziale con DI

Il punto di partenza è registrare il chat client nel contenitore di dependency injection. Ecco l’approccio canonico:

var builder = Host.CreateApplicationBuilder();
builder.Services.AddChatClient(
    new OllamaChatClient(new Uri("http://localhost:11434"), "llama3"));
var app = builder.Build();
var chatClient = app.Services.GetRequiredService<IChatClient>();

In questo esempio, usiamo Ollama con il modello llama3 locale. La bellezza di questa astrazione: la stessa registrazione funziona con OpenAI, Azure OpenAI o qualsiasi provider che implementi IChatClient. Il codice che usa il client rimane invariato.

Risposta semplice da un LLM

Il caso più basilare: inviare un prompt e ottenere una risposta:

var response = await chatClient.GetResponseAsync("What is .NET? Reply in 50 words max.");
Console.WriteLine(response.Message.Text);

Il metodo GetResponseAsync restituisce un oggetto ChatCompletion con il messaggio della risposta. Semplice, sincrono dal punto di vista dello sviluppatore (anche se asincrono sottostante).

Streaming per risposte lunghe

Per applicazioni interattive come chatbot, lo streaming è essenziale. Permette all’utente di vedere il testo apparire gradualmente, come in ChatGPT:

var chatResponse = "";
await foreach (var item in chatClient.GetStreamingResponseAsync(chatHistory))
{
    Console.Write(item.Text);
    chatResponse += item.Text;
}

Il metodo GetStreamingResponseAsync ritorna un IAsyncEnumerable<StreamingChatCompletionUpdate>. Ogni item contiene un frammento di testo che puoi visualizzare in tempo reale.

Conversazioni multi-turno con cronologia

Mantenere una conversazione richiede di raccogliere la storia dei messaggi. Ecco un loop interattivo completo:

var chatHistory = new List<ChatMessage>();
while (true)
{
    Console.Write("You: ");
    var userPrompt = Console.ReadLine();
    
    chatHistory.Add(new ChatMessage(ChatRole.User, userPrompt));
    
    var chatResponse = "";
    Console.Write("Assistant: ");
    await foreach (var item in chatClient.GetStreamingResponseAsync(chatHistory))
    {
        Console.Write(item.Text);
        chatResponse += item.Text;
    }
    Console.WriteLine();
    
    chatHistory.Add(new ChatMessage(ChatRole.Assistant, chatResponse));
}

Ogni turno aggiunge alla lista: il user message, poi il response dell’assistant. Al turno successivo, passi l’intera cronologia a GetStreamingResponseAsync. L’LLM usa questo contesto per mantenere coerenza conversazionale.

Structured output: JSON tipizzato

Spesso vuoi che l’LLM restituisca dati strutturati (JSON). Puoi chiederlo esplicitamente nel prompt:

var prompt = $"""
You will receive an article and extract its metadata.
Respond ONLY with valid JSON following this format without any deviation.

{{
    "title": "...",
    "summary": "...",
    "keywords": ["...", "..."]
}}

Article:
{File.ReadAllText("article.md")}
""";

var response = await chatClient.GetResponseAsync(prompt);
var jsonText = response.Message.Text;
var metadata = JsonSerializer.Deserialize<ArticleMetadata>(jsonText);

L’approccio funziona, ma richiede gestione manuale di parsing e validazione. C’è una soluzione migliore.

Deserialization tipizzata con generics

La libreria Microsoft.Extensions.AI supporta il generic GetResponseAsync<T> che deserializza automaticamente il JSON in una classe C#:

public class ArticleMetadata
{
    public string Title { get; set; } = string.Empty;
    public string Summary { get; set; } = string.Empty;
    public string[] Keywords { get; set; } = [];
}

var metadata = await chatClient.GetResponseAsync<ArticleMetadata>(prompt);
Console.WriteLine($"Title: {metadata.Result.Title}");
Console.WriteLine($"Keywords: {string.Join(", ", metadata.Result.Keywords)}");

Questa API offre sicurezza in fase di compilazione e supporto IDE completo per il refactoring. Se cambi la struttura di ArticleMetadata, il compilatore avvisa i punti di utilizzo.

Portabilità tra provider: da locale a cloud

Una delle promesse di IChatClient è la portabilità. Ecco come implementare una strategia “local in dev, cloud in prod”:

// Avvio locale con Ollama
if (app.Environment.IsDevelopment())
{
    builder.Services.AddChatClient(
        new OllamaChatClient(new Uri("http://localhost:11434"), "mistral"));
}
else
{
    // Avvio cloud con Azure OpenAI
    builder.Services.AddChatClient(
        new AzureOpenAIClient(
            new Uri(azureEndpoint),
            new DefaultAzureCredential()).AsChatClient());
}

Il resto dell’applicazione non cambia. Chiede semplicemente IChatClient al DI container e riceve l’implementazione appropriata. Niente hardcoding, niente API specifiche sparse nel codice.

Middleware per telemetria e caching

Il pacchetto Microsoft.Extensions.AI fornisce middleware composabile. Uno uso comune è aggiungere OpenTelemetry:

var builder = Host.CreateApplicationBuilder();

// Registra OpenTelemetry
builder.Services.AddOpenTelemetry()
    .WithTracing(tracing => tracing
        .AddAspNetCoreInstrumentation()
        .AddHttpClientInstrumentation());

// Registra il chat client con middleware di telemetria
builder.Services.AddChatClient(baseChatClient)
    .UseOpenTelemetry(builder.Services.BuildServiceProvider()
        .GetRequiredService<ILoggerFactory>());

Con questo setup, ogni chiamata a IChatClient genera automaticamente span OpenTelemetry tracciabili in strumenti come Application Insights o Jaeger. Nessuna strumentazione manuale necessaria.

Integrazione con il framework Agent

Il framework Agent di Microsoft costruisce sopra IChatClient aggiungendo astrazioni a livello agent: gestione persistente del contesto, tool calling automatico, prompt di sistema, API streaming pulita. Se usi agent, IChatClient rimane il cuore della comunicazione LLM.

Conclusione

IChatClient rappresenta una maturazione nell’integrazione LLM in .NET. Invece di accoppiare il codice a provider specifici, definisci un’astrazione e lascia che l’infrastruttura scelga l’implementazione. Lo streaming, la deserialization tipizzata, la composizione di middleware e la portabilità del provider diventano proprietà di prima classe dell’architettura.

Per qualsiasi team che integra LLM in .NET 2026, IChatClient è il fondamento su cui costruire. Richiede poca configurazione iniziale e ripaga con flessibilità architetturale a lungo termine.

Fonte originale: Microsoft.Extensions.AI libraries – .NET | Microsoft Learn e Working with LLMs in .NET using Microsoft.Extensions.AI

💬 Unisciti alla discussione!


Questo è un blog del Fediverso: puoi trovare quindi questo articolo ovunque con @blog@spcnet.it e ogni commento/risposta apparirà qui sotto.

Se vuoi commentare su LLM Chat in .NET con IChatClient: guida completa all’integrazione, utilizza la discussione sul Forum.
Condividi la tua esperienza, confrontati con altri professionisti e approfondisci i dettagli tecnici nel nostro 👉 forum community