Condividi tramite


Salvare i dati dell'utente e della conversazione

SI APPLICA A: SDK v4

Un bot è intrinsecamente senza stato. Dopo la distribuzione, il bot potrebbe non essere eseguito nello stesso processo o nello stesso computer da un turno all'altro. È tuttavia possibile che il bot debba tenere traccia del contesto di una conversazione per poterne gestire il comportamento e ricordare le risposte alle domande precedenti. Le funzionalità di stato e archiviazione di Bot Framework SDK consentono di aggiungere lo stato al bot. I bot usano oggetti di gestione dello stato e archiviazione per gestire e rendere persistente lo stato. Il gestore dello stato offre un livello di astrazione che consente di accedere alle proprietà di stato usando funzioni di accesso alle proprietà indipendentemente dal tipo di archiviazione sottostante.

Nota

Gli SDK JavaScript, C# e Python di Bot Framework continueranno a essere supportati, ma Java SDK verrà ritirato con il supporto finale a lungo termine che termina a novembre 2023.

I bot esistenti creati con Java SDK continueranno a funzionare.

Per la creazione di nuovi bot, prendere in considerazione l'uso di Power Virtual Agents e leggere la scelta della soluzione chatbot appropriata.

Per altre informazioni, vedere Il futuro della compilazione di bot.

Prerequisiti

Informazioni sull'esempio

Dopo aver ricevuto l'input utente, l'esempio controlla lo stato della conversazione archiviato per verificare se all'utente è stato chiesto in precedenza il suo nome. Se non è stato fatto, viene richiesto il nome dell'utente e l'input viene archiviato nello stato dell'utente. In tal caso, il nome archiviato all'interno dello stato utente viene usato per conversare con l'utente e i relativi dati di input, insieme all'ora ricevuta e all'ID del canale di input, viene restituito all'utente. I valori relativi all'ora e all'ID canale vengono recuperati dai dati della conversazione utente e quindi salvati nello stato della conversazione. Il diagramma seguente illustra la relazione tra il bot, il profilo utente e le classi dei dati della conversazione.

Definire le classi

Il primo passaggio per configurare la gestione dello stato consiste nel definire le classi che conterranno le informazioni da gestire nello stato dell'utente e della conversazione. L'esempio usato in questo articolo definisce le classi seguenti:

  • In UserProfile.cs si definisce una UserProfile classe per le informazioni utente raccolte dal bot.
  • In ConversationData.cs definisci una ConversationData classe per controllare lo stato della conversazione durante la raccolta delle informazioni utente.

Gli esempi di codice seguenti illustrano le definizioni per le classi UserProfile e ConversationData.

UserProfile.cs

public class UserProfile
{
    public string Name { get; set; }
}

ConversationData.cs

public class ConversationData
{
    // The time-stamp of the most recent incoming message.
    public string Timestamp { get; set; }

    // The ID of the user's channel.
    public string ChannelId { get; set; }

    // Track whether we have already asked the user's name
    public bool PromptedUserForName { get; set; } = false;
}

Creare gli oggetti di stato della conversazione e dell'utente

Successivamente, si registra MemoryStorage che viene usato per creare UserState oggetti e ConversationState . Gli oggetti di stato dell'utente e della conversazione vengono creati in Startup e la dipendenza viene inserita nel costruttore del bot. Gli altri servizi registrati per un bot includono un provider di credenziali, un adattatore e l'implementazione del bot.

Startup.cs

// {
//     TypeNameHandling = TypeNameHandling.All,
// var storage = new BlobsStorage("<blob-storage-connection-string>", "bot-state");

// With a custom JSON SERIALIZER, use this instead.
// var storage = new BlobsStorage("<blob-storage-connection-string>", "bot-state", jsonSerializer);

/* END AZURE BLOB STORAGE */

Bots/StateManagementBot.cs

private BotState _conversationState;
private BotState _userState;

public StateManagementBot(ConversationState conversationState, UserState userState)
{
    _conversationState = conversationState;
    _userState = userState;
}

Aggiungere le funzioni di accesso alle proprietà di stato

A questo punto si creano funzioni di accesso alle proprietà usando il CreateProperty metodo che fornisce un handle all'oggetto BotState . Ogni funzione di accesso alle proprietà di stato consente di ottenere o impostare il valore della proprietà di stato associata. Prima di usare le proprietà di stato, usare ogni funzione di accesso per caricare la proprietà dall'archiviazione e recuperarla dalla cache di stato. Per ottenere la chiave con ambito corretta associata alla proprietà di stato, chiamare il GetAsync metodo .

Bots/StateManagementBot.cs

var conversationStateAccessors = _conversationState.CreateProperty<ConversationData>(nameof(ConversationData));
var userStateAccessors = _userState.CreateProperty<UserProfile>(nameof(UserProfile));

Accedere allo stato dal bot

La sezione precedente descrive i passaggi in fase di inizializzazione per aggiungere le funzioni di accesso alle proprietà di stato al bot. A questo punto, è possibile usare queste funzioni di accesso in fase di esecuzione per leggere e scrivere informazioni sullo stato. Il codice di esempio usa il flusso logico seguente:

  • Se userProfile.Name è vuoto ed conversationData.PromptedUserForName è true, si recupera il nome utente specificato e lo si archivia all'interno dello stato utente.
  • Se userProfile.Name è vuoto ed conversationData.PromptedUserForName è false, viene richiesto il nome dell'utente.
  • Se userProfile.Name è stato archiviato in precedenza, si recuperano l'ora del messaggio e l'ID canale dall'input dell'utente, vengono restituiti tutti i dati all'utente e i dati recuperati all'interno dello stato della conversazione.

Bots/StateManagementBot.cs

protected override async Task OnMessageActivityAsync(ITurnContext<IMessageActivity> turnContext, CancellationToken cancellationToken)
{
    // Get the state properties from the turn context.

    var conversationStateAccessors = _conversationState.CreateProperty<ConversationData>(nameof(ConversationData));
    var conversationData = await conversationStateAccessors.GetAsync(turnContext, () => new ConversationData());

    var userStateAccessors = _userState.CreateProperty<UserProfile>(nameof(UserProfile));
    var userProfile = await userStateAccessors.GetAsync(turnContext, () => new UserProfile());

    if (string.IsNullOrEmpty(userProfile.Name))
    {
        // First time around this is set to false, so we will prompt user for name.
        if (conversationData.PromptedUserForName)
        {
            // Set the name to what the user provided.
            userProfile.Name = turnContext.Activity.Text?.Trim();

            // Acknowledge that we got their name.
            await turnContext.SendActivityAsync($"Thanks {userProfile.Name}. To see conversation data, type anything.");

            // Reset the flag to allow the bot to go through the cycle again.
            conversationData.PromptedUserForName = false;
        }
        else
        {
            // Prompt the user for their name.
            await turnContext.SendActivityAsync($"What is your name?");

            // Set the flag to true, so we don't prompt in the next turn.
            conversationData.PromptedUserForName = true;
        }
    }
    else
    {
        // Add message details to the conversation data.
        // Convert saved Timestamp to local DateTimeOffset, then to string for display.
        var messageTimeOffset = (DateTimeOffset)turnContext.Activity.Timestamp;
        var localMessageTime = messageTimeOffset.ToLocalTime();
        conversationData.Timestamp = localMessageTime.ToString();
        conversationData.ChannelId = turnContext.Activity.ChannelId.ToString();

        // Display state data.
        await turnContext.SendActivityAsync($"{userProfile.Name} sent: {turnContext.Activity.Text}");
        await turnContext.SendActivityAsync($"Message received at: {conversationData.Timestamp}");
        await turnContext.SendActivityAsync($"Message received from: {conversationData.ChannelId}");
    }
}

Prima di uscire dal gestore dei turni, usare il metodo SaveChangesAsync() degli oggetti di gestione dello stato per scrivere tutte le modifiche di stato nell'archiviazione.

Bots/StateManagementBot.cs

public override async Task OnTurnAsync(ITurnContext turnContext, CancellationToken cancellationToken = default(CancellationToken))
{
    await base.OnTurnAsync(turnContext, cancellationToken);

    // Save any state changes that might have occurred during the turn.
    await _conversationState.SaveChangesAsync(turnContext, false, cancellationToken);
    await _userState.SaveChangesAsync(turnContext, false, cancellationToken);
}

Esegui il test del tuo bot

  1. Scaricare e installare l'ultima versione di Bot Framework Emulator
  2. Eseguire l'esempio in locale nel computer. Per istruzioni, vedere README per C#, JavaScript, Java o Python.
  3. Usare l'emulatore per testare il bot di esempio.

Informazioni aggiuntive

Questo articolo descrive come aggiungere lo stato al bot. Per altre informazioni sugli argomenti correlati, vedere la tabella seguente.

Argomento Note
Riservatezza Se si intende memorizzare i dati personali dell'utente, è necessario garantire la conformità al Regolamento generale sulla protezione dei dati.
Gestione dello stato Tutte le chiamate di gestione dello stato sono asincrone e la scrittura più recente ha la precedenza per impostazione predefinita. In pratica è necessario ottenere, impostare e salvare lo stato a distanza il più possibile ravvicinata nel bot. Per informazioni su come implementare il blocco ottimistico, vedere Implementare l'archiviazione personalizzata per il bot.
Dati aziendali critici Usare lo stato del bot per archiviare le preferenze, il nome utente o l'ultima cosa ordinata, ma non usarla per archiviare i dati aziendali critici. Per i dati critici creare componenti di archiviazione personalizzati oppure scrivere i dati direttamente nell'archivio.
Riconoscimento del testo L'esempio usa le librerie Microsoft/Recognizers-Text per analizzare e convalidare l'input dell'utente. Per altre informazioni, vedere la pagina della panoramica.

Passaggi successivi

Informazioni su come porre all'utente una serie di domande, convalidare le risposte e salvare l'input.