Finora abbiamo utilizzato GPT per implementare una chat, ma in alcuni casi vorremmo invece sfruttarlo per avere delle risposte "strutturate" a partire da un input generico. Consideriamo l'esempio che abbiamo visto finora: siamo in grado di creare una ChatHistory persistente, salvata su database, ma abbiamo lasciato un punto "aperto", ossia la definizione del titolo, che al momento contiene solo un placeholder.
L'obiettivo è di usare GPT per generare questo titolo ma, dato che si tratterà di un'interrogazione a sé stante e, soprattutto, "una tantum", invece che usare ChatCompletionService, sfrutteremo direttamente l'oggetto Kernel per eseguire il prompt.
Come prima cosa, quindi, dobbiamo registrarlo nell'IoC container di ASP.NET Core:
builder.Services.AddTransient<Kernel>();
Non dobbiamo configurare alcuna stringa di connessione o chiave, perché sfrutterà automaticamente quanto già impostato per ChatCompletionService.
A questo punto possiamo aggiungere un nuovo metodo al nostro controller, che si occuperà di generare e impostare il titolo:
private async Task SetTitleAsync(ChatSession session) { if (session.Title != "Placeholder Title") { // title was already set previously return; } string prompt = "Determine the title of the following conversation in a single JSON property named 'Title': " + JsonSerializer.Serialize(session.History.Skip(1)); var settings = new AzureOpenAIPromptExecutionSettings() { ResponseFormat = "json_object" }; var response = await _kernel.InvokePromptAsync(prompt, new KernelArguments(settings)); var title = JsonDocument.Parse(response.ToString()).RootElement.GetProperty("Title").GetString(); if (!string.IsNullOrEmpty(title)) { session.Title = title; } }
Questo metodo accetta una ChatSession come parametro, e verifichiamo inizialmente che il titolo sia ancora il placeholder iniziale e non sia stato già reimpostato.
Successivamente creiamo un semplice prompt per GPT, in cui chiediamo di restituire una risposta di tipo JSON con una proprietà Title. A questo prompt alleghiamo poi l'intera serializzazione della history, escludendo però il system message, così che il titolo venga generato solo a partire dall'effettiva conversazione.
Un aspetto importante da sottolineare è l'uso di AzureOpenAIPromptExecutionSettings, e in particolare della proprietà ResponseFormat, che abbiamo impostato a "json_object". Questo parametro ha l'effetto di forzare GPT a restituire un risultato JSON, evitando risposte del tipo "Certamente, ecco il tuo JSON: .." che inevitabilmente creerebbero problemi alla nostra logica di deserializzazione. Attenzione a un requisito non immediatamente ovvio: il prompt deve contenere la parola "JSON", non basta limitarsi a impostare ResponseFormat!
Proprio grazie a questo constraint, possiamo effettuare il parsing diretto della risposta tramite JsonDocument, recuperare il titolo e assegnarlo alla nostra ChatSession.
A questo punto non ci resta che invocare questo metodo durante la Action per rispondere a un messaggio utente:
public async IAsyncEnumerable<string> PostMessage(int sessionId, [FromBody] string message) { var session = await _dbContext.ChatSession.FindAsync(sessionId); // .. altro codice qui .. session.History.AddAssistantMessage(responseMessage); await SetTitleAsync(session); _dbContext.Entry(session).State = EntityState.Modified; await _dbContext.SaveChangesAsync(); }
Commenti
Per inserire un commento, devi avere un account.
Fai il login e torna a questa pagina, oppure registrati alla nostra community.
Approfondimenti
Utilizzare una qualunque lista per i parametri di tipo params in C#
Estrarre dati randomici da una lista di oggetti in C#
Filtrare i dati di una QuickGrid in Blazor con una drop down list
Utilizzare Hybrid Cache in .NET 9
Aprire una finestra di dialogo per selezionare una directory in WPF e .NET 8
Esporre i propri servizi applicativi con Semantic Kernel e ASP.NET Web API
Fissare una versione dell'agent nelle pipeline di Azure DevOps
Utilizzare un numero per gestire la concorrenza ottimistica con SQL Server ed Entity Framework
Utilizzare EF.Constant per evitare la parametrizzazione di query SQL
Conoscere il rendering Server o WebAssembly a runtime in Blazor
Triggerare una pipeline su un altro repository di Azure DevOps
Persistere la ChatHistory di Semantic Kernel in ASP.NET Core Web API per GPT
I più letti di oggi
- .NET Conference Italia 2018 - Milano
- Tutorial ASP.NET
- Seconda preview per i Dynamic Data Control 4.0
- Disponibile al download la versione finale di Mozilla Firefox 4
- Microsoft Security Bulletin MS02-044
- Shared Source Initiative per gli MVP
- Mono 1.1.10 per un po' di ASP.NET 2.0
- Webcast 'ASP.NET 2.0 HttpRuntime'