Megosztás a következőn keresztül:


Felhasználói megszakítások kezelése

A KÖVETKEZŐKRE VONATKOZIK: SDK v4

A megszakítások kezelése egy robusztus robot fontos eleme. A felhasználók nem mindig követik a megadott beszélgetési folyamatot, lépésről lépésre. Megpróbálhatnak kérdést feltenni a folyamat közepén, vagy egyszerűen csak le szeretnék mondani ahelyett, hogy befejezték volna. Ez a cikk a robot felhasználói megszakításainak kezelésének néhány gyakori módját ismerteti.

Feljegyzés

A Bot Framework JavaScript, C# és Python SDK-k továbbra is támogatottak lesznek, a Java SDK-t azonban 2023 novemberében végső hosszú távú támogatással kivonják.

A Java SDK-val létrehozott meglévő robotok továbbra is működni fognak.

Az új robotépítéshez fontolja meg a Microsoft Copilot Studio használatát, és olvassa el a megfelelő copilot-megoldás kiválasztását.

További információ: A robotépítés jövője.

Előfeltételek

Az alapvető robotminta a Language Understanding (LUIS) használatával azonosítja a felhasználói szándékokat; A felhasználói szándék azonosítása azonban nem a jelen cikk középpontjában van. A felhasználói szándékok azonosításával kapcsolatos információkért tekintse meg a természetes nyelv megértését és a természetes nyelv megértésének hozzáadását a robothoz.

Feljegyzés

A Language Understanding (LUIS) 2025. október 1-jén megszűnik. 2023. április 1-től nem hozhat létre új LUIS-erőforrásokat. Az Azure AI Language részeként már elérhető a nyelvértés újabb verziója.

Az Azure AI Language egyik funkciója, a beszélgetési nyelv megértése (CLU) a LUIS frissített verziója. További információ a Bot Framework SDK nyelvfelismerési támogatásáról: Természetes nyelvfelismerés.

A minta ismertetése

Az ebben a cikkben használt minta egy repülési foglalási robotot modell, amely párbeszédpaneleket használ a felhasználó repülési adatainak lekéréséhez. A robottal folytatott beszélgetés során a felhasználó bármikor kiadhat súgót, vagy megszakíthatja a parancsokat, hogy megszakítást okozzon. A megszakítások kétféleképpen kezelhetők:

  • Fordulási szint: Megkerülheti a feldolgozást a forduló szintjén, de hagyja meg a párbeszédpanelt a veremen a megadott információkkal. A következő lépésben folytassa onnan, ahol a beszélgetés abbahagyta.
  • Párbeszédpanel szintje: A feldolgozás teljes megszakítása, hogy a robot újrakezdhesse az egészet.

A megszakítási logika meghatározása és implementálása

Először határozza meg és implementálja a súgót, és szakítsa meg a megszakításokat.

A párbeszédpanelek használatához telepítse a Microsoft.Bot.Builder.Dialogs NuGet csomagot.

Párbeszédpanelek\CancelAndHelpDialog.cs

Implementálja az osztályt a CancelAndHelpDialog felhasználói megszakítások kezeléséhez. A lemondható párbeszédpanelek, BookingDialog és DateResolverDialog ebből az osztályból származnak.

public class CancelAndHelpDialog : ComponentDialog

CancelAndHelpDialog Az osztályban a OnContinueDialogAsync metódus meghívja a InterruptAsync metódust annak ellenőrzésére, hogy a felhasználó megszakította-e a normál folyamatot. Ha a folyamat megszakad, a rendszer alaposztály-metódusokat hív meg; ellenkező esetben a függvény visszaadja a visszaadott InterruptAsync értéket.

protected override async Task<DialogTurnResult> OnContinueDialogAsync(DialogContext innerDc, CancellationToken cancellationToken = default)
{
    var result = await InterruptAsync(innerDc, cancellationToken);
    if (result != null)
    {
        return result;
    }

    return await base.OnContinueDialogAsync(innerDc, cancellationToken);
}

Ha a felhasználó a "súgó" szöveget írja be, a InterruptAsync metódus üzenetet küld, majd meghívja DialogTurnResult (DialogTurnStatus.Waiting) , hogy jelezze, hogy a párbeszédpanel a felhasználó válaszára vár. Ily módon a beszélgetési folyamat csak egy kanyarban megszakad, a következő viszont pedig onnan folytatódik, ahol a beszélgetés abbahagyta.

Ha a felhasználó a "mégse" típust írja be, a belső párbeszédpanel környezetét hívja CancelAllDialogsAsync meg, amely törli a párbeszédpanel-vermet, és megszakított állapottal és eredményérték nélkül lép ki. MainDialog A (később megjelenő) ablakban megjelenik, hogy a foglalási párbeszédpanel véget ért, és null értéket adott vissza, hasonlóan ahhoz, mint amikor a felhasználó úgy dönt, hogy nem erősíti meg a foglalást.

private async Task<DialogTurnResult> InterruptAsync(DialogContext innerDc, CancellationToken cancellationToken)
{
    if (innerDc.Context.Activity.Type == ActivityTypes.Message)
    {
        var text = innerDc.Context.Activity.Text.ToLowerInvariant();

        switch (text)
        {
            case "help":
            case "?":
                var helpMessage = MessageFactory.Text(HelpMsgText, HelpMsgText, InputHints.ExpectingInput);
                await innerDc.Context.SendActivityAsync(helpMessage, cancellationToken);
                return new DialogTurnResult(DialogTurnStatus.Waiting);

            case "cancel":
            case "quit":
                var cancelMessage = MessageFactory.Text(CancelMsgText, CancelMsgText, InputHints.IgnoringInput);
                await innerDc.Context.SendActivityAsync(cancelMessage, cancellationToken);
                return await innerDc.CancelAllDialogsAsync(cancellationToken);
        }
    }

    return null;
}

A megszakítások ellenőrzése minden egyes turnön

A megszakításkezelési osztály implementálása után tekintse át, mi történik, ha a robot új üzenetet kap a felhasználótól.

Párbeszédpanelek\MainDialog.cs

Az új üzenettevékenység érkezésekor a robot futtatja a MainDialog. A MainDialog rendszer megkérdezi a felhasználót, hogy miben segíthet. Ezután elindítja a BookingDialog MainDialog.ActStepAsync metódust, az alább látható hívással BeginDialogAsync .

private async Task<DialogTurnResult> ActStepAsync(WaterfallStepContext stepContext, CancellationToken cancellationToken)
{
    if (!_luisRecognizer.IsConfigured)
    {
        // LUIS is not configured, we just run the BookingDialog path with an empty BookingDetailsInstance.
        return await stepContext.BeginDialogAsync(nameof(BookingDialog), new BookingDetails(), cancellationToken);
    }

    // Call LUIS and gather any potential booking details. (Note the TurnContext has the response to the prompt.)
    var luisResult = await _luisRecognizer.RecognizeAsync<FlightBooking>(stepContext.Context, cancellationToken);
    switch (luisResult.TopIntent().intent)
    {
        case FlightBooking.Intent.BookFlight:
            await ShowWarningForUnsupportedCities(stepContext.Context, luisResult, cancellationToken);

            // Initialize BookingDetails with any entities we may have found in the response.
            var bookingDetails = new BookingDetails()
            {
                // Get destination and origin from the composite entities arrays.
                Destination = luisResult.ToEntities.Airport,
                Origin = luisResult.FromEntities.Airport,
                TravelDate = luisResult.TravelDate,
            };

            // Run the BookingDialog giving it whatever details we have from the LUIS call, it will fill out the remainder.
            return await stepContext.BeginDialogAsync(nameof(BookingDialog), bookingDetails, cancellationToken);

        case FlightBooking.Intent.GetWeather:
            // We haven't implemented the GetWeatherDialog so we just display a TODO message.
            var getWeatherMessageText = "TODO: get weather flow here";
            var getWeatherMessage = MessageFactory.Text(getWeatherMessageText, getWeatherMessageText, InputHints.IgnoringInput);
            await stepContext.Context.SendActivityAsync(getWeatherMessage, cancellationToken);
            break;

        default:
            // Catch all for unhandled intents
            var didntUnderstandMessageText = $"Sorry, I didn't get that. Please try asking in a different way (intent was {luisResult.TopIntent().intent})";
            var didntUnderstandMessage = MessageFactory.Text(didntUnderstandMessageText, didntUnderstandMessageText, InputHints.IgnoringInput);
            await stepContext.Context.SendActivityAsync(didntUnderstandMessage, cancellationToken);
            break;
    }

    return await stepContext.NextAsync(null, cancellationToken);
}

Ezután az FinalStepAsync osztály módszerében a MainDialog foglalási párbeszédpanel véget ért, és a foglalás befejezettnek vagy lemondottnak minősül.

private async Task<DialogTurnResult> FinalStepAsync(WaterfallStepContext stepContext, CancellationToken cancellationToken)
{
    // If the child dialog ("BookingDialog") was cancelled, the user failed to confirm or if the intent wasn't BookFlight
    // the Result here will be null.
    if (stepContext.Result is BookingDetails result)
    {
        // Now we have all the booking details call the booking service.

        // If the call to the booking service was successful tell the user.

        var timeProperty = new TimexProperty(result.TravelDate);
        var travelDateMsg = timeProperty.ToNaturalLanguage(DateTime.Now);
        var messageText = $"I have you booked to {result.Destination} from {result.Origin} on {travelDateMsg}";
        var message = MessageFactory.Text(messageText, messageText, InputHints.IgnoringInput);
        await stepContext.Context.SendActivityAsync(message, cancellationToken);
    }

    // Restart the main dialog with a different message the second time around
    var promptMessage = "What else can I do for you?";
    return await stepContext.ReplaceDialogAsync(InitialDialogId, promptMessage, cancellationToken);
}

A beadási BookingDialog kód nem jelenik meg itt, mivel nem kapcsolódik közvetlenül a megszakításkezeléshez. A rendszer a foglalás részleteinek megadására kéri a felhasználókat. Ezt a kódot a Dialogs\BookingDialogs.cs webhelyen találja.

Váratlan hibák kezelése

Az adapter hibakezelője kezeli a robotban nem észlelt kivételeket.

AdapterWithErrorHandler.cs

A mintában az adapter kezelője OnTurnError megkapja a robot fordulatlogikája által kidobott kivételeket. Ha kivétel történt, a kezelő törli az aktuális beszélgetés beszélgetési állapotát, hogy megakadályozza a robotot abban a hibahurkban, amelyet a hibás állapot okoz.

    {
        // Log any leaked exception from the application.
        // NOTE: In production environment, you should consider logging this to
        // Azure Application Insights. Visit https://aka.ms/bottelemetry to see how
        // to add telemetry capture to your bot.
        logger.LogError(exception, $"[OnTurnError] unhandled error : {exception.Message}");

        // Send a message to the user
        var errorMessageText = "The bot encountered an error or bug.";
        var errorMessage = MessageFactory.Text(errorMessageText, errorMessageText, InputHints.IgnoringInput);
        await turnContext.SendActivityAsync(errorMessage);

        errorMessageText = "To continue to run this bot, please fix the bot source code.";
        errorMessage = MessageFactory.Text(errorMessageText, errorMessageText, InputHints.ExpectingInput);
        await turnContext.SendActivityAsync(errorMessage);

        if (conversationState != null)
        {
            try
            {
                // Delete the conversationState for the current conversation to prevent the
                // bot from getting stuck in a error-loop caused by being in a bad state.
                // ConversationState should be thought of as similar to "cookie-state" in a Web pages.
                await conversationState.DeleteAsync(turnContext);
            }
            catch (Exception e)
            {
                logger.LogError(e, $"Exception caught on attempting to Delete ConversationState : {e.Message}");
            }
        }

        // Send a trace activity, which will be displayed in the Bot Framework Emulator
        await turnContext.TraceActivityAsync("OnTurnError Trace", exception.Message, "https://www.botframework.com/schemas/error", "TurnError");
    };
}

Szolgáltatások regisztrálása

Startup.cs

Végül a Startup.csrobot átmenetiként jön létre, és minden egyes lépésben létrejön a robot új példánya.


// Register the BookingDialog.

Referenciaként az alábbi osztálydefiníciókat használjuk a fenti robot létrehozásához használt hívásban.

public class DialogAndWelcomeBot<T> : DialogBot<T>
public class DialogBot<T> : ActivityHandler
    where T : Dialog
public class MainDialog : ComponentDialog

A robot tesztelése

  1. Ha még nem tette meg, telepítse a Bot Framework Emulatort.
  2. Futtassa a mintát helyileg a számítógépen.
  3. Indítsa el az Emulátort, csatlakozzon a robothoz, és küldjön üzeneteket az alábbiak szerint.

További információk

  • A 24.bot-authentication-msgraph minta C#, JavaScript, Python vagy Java nyelven bemutatja, hogyan kezelheti a bejelentkezési kéréseket. Az itt láthatóhoz hasonló mintát használ a megszakítások kezelésére.

  • Ahelyett, hogy semmit sem tesz, alapértelmezett választ kellene küldenie, és a felhasználót arra kell hagynia, hogy kíváncsi legyen, mi történik. Az alapértelmezett válasznak meg kell mondania a felhasználónak, hogy milyen parancsokat ért a robot, hogy a felhasználó visszatérjen a pályára.

  • A turn környezet választulajdonságának bármely pontján jelzi, hogy a robot üzenetet küldött-e a felhasználónak ebben a fordulóban. A turn vége előtt a robotnak üzenetet kell küldenie a felhasználónak, még akkor is, ha ez a bemenet egyszerű visszaigazolása.