Zelfstudie: Personalizer gebruiken in .NET-chatbot
Belangrijk
Vanaf 20 september 2023 kunt u geen nieuwe Personalizer-resources maken. De Personalizer-service wordt op 1 oktober 2026 buiten gebruik gesteld.
Gebruik een C# .NET-chatbot met een Personalizer-lus om de juiste inhoud te bieden aan een gebruiker. Deze chatbot biedt gebruikers een suggestie voor een specifieke soort koffie of thee. De gebruiker kan deze suggestie accepteren of afwijzen. Hierdoor krijgt Personalizer informatie die helpt om de volgende suggestie geschikter te maken.
In deze zelfstudie leert u het volgende:
- Azure-resources instellen
- De bot configureren en uitvoeren
- Werken met de bot met behulp van Bot Framework Emulator
- Begrijpen waar en hoe de bot gebruikmaakt van Personalizer
Hoe werkt de chatbot?
Een chatbot is doorgaans een tweezijdig gesprek met een gebruiker. Deze specifieke chatbot maakt gebruik van Personalizer om de beste actie (koffie of thee) voor te stellen voor de gebruiker. Personalizer maakt gebruik van conditionering om deze selectie te maken.
De chatbot moet wendingen in het gesprek beheren. De chatbot maakt gebruik van Bot Framework om de botarchitectuur en het gesprek te beheren en maakt gebruik van Azure AI Language Understanding (LUIS), om inzicht te krijgen in de intentie van de natuurlijke taal van de gebruiker.
De chatbot is een website met een specifieke route die beschikbaar is voor het beantwoorden van aanvragen, http://localhost:3978/api/messages
. U kunt de Bot Framework Emulator gebruiken om visueel te communiceren met de actieve chatbot terwijl u een bot lokaal ontwikkelt.
Gebruikersinteracties met de bot
Dit is een eenvoudige chatbot waarmee u tekstquery's kunt invoeren.
Gebruiker voert tekst in | Bot reageert met tekst | Beschrijving van de actie die de bot onderneemt om de antwoordtekst te bepalen |
---|---|---|
Geen tekst ingevoerd - bot begint het gesprek. | This is a simple chatbot example that illustrates how to use Personalizer. The bot learns what coffee or tea order is preferred by customers given some context information (such as weather, temperature, and day of the week) and information about the user. To use the bot, just follow the prompts. To try out a new imaginary context, type “Reset” and a new one will be randomly generated. Welcome to the coffee bot, please tell me if you want to see the menu or get a coffee or tea suggestion for today. Once I’ve given you a suggestion, you can reply with ‘like’ or ‘don’t like’. It’s Tuesday today and the weather is Snowy. |
De bot begint het gesprek met instructietekst en laat u weten wat de context is: Tuesday , Snowy . |
Show menu |
Here is our menu: Coffee: Cappuccino Espresso Latte Macchiato Mocha Tea: GreenTea Rooibos |
Bepaalt de intentie van de query met behulp van LUIS, en geeft vervolgens de menuopties voor typen koffie en thee weer. Functies van de acties zijn |
What do you suggest |
How about Latte? |
Bepaalt de intentie van de query met behulp van LUIS, roept vervolgens de Rank API aan, en geeft de bovenste keuze weer als vraag How about {response.RewardActionId}? . Geeft ter illustratie ook een JSON-aanroep en -respons weer. |
I like it |
That’s great! I’ll keep learning your preferences over time. Would you like to get a new suggestion or reset the simulated context to a new day? |
Bepaalt de intentie van de query met behulp van LUIS, roept vervolgens de Reward API aan met een beloning van 1 , en geeft ter illustratie een JSON-aanroep en -respons weer. |
I don't like it |
Oh well, maybe I’ll guess better next time. Would you like to get a new suggestion or reset the simulated context to a new day? |
Bepaalt de intentie van de query met behulp van LUIS, roept vervolgens de Reward API aan met een beloning van 0 , en geeft ter illustratie een JSON-aanroep en -respons weer. |
Reset |
Retourneert instructietekst. | Bepaalt de intentie van de query met behulp van LUIS, geeft vervolgens de instructietekst weer, en stelt de context opnieuw in. |
Personalizer in deze bot
Deze chatbot maakt gebruik van Personalizer om de bovenste actie (specifiek type koffie of thee) te selecteren, op basis van een lijst met acties (bepaald type inhoud) en contextfuncties.
De bot verzendt de lijst met acties, samen met contextfuncties, naar de Personalizer-lus. Personalizer retourneert de beste actie voor de bot. Vervolgens wordt deze actie weergegeven.
In deze zelfstudie zijn de acties typen koffie en thee:
Koffie | Thee |
---|---|
Cappuccino Espresso Latte Mokka |
Groene thee Rooibos |
Rank API: Om Personalizer te helpen meer te weten te komen over uw acties, verzendt de bot het volgende met elke Rank API-aanvraag:
- Acties met functies
- Contextfuncties
Een functie van het model is informatie over de actie of context die kan worden geaggregeerd (gegroepeerd) voor leden van de gebruikersdatabase van uw chatbot. Een functie is niet individueel specifiek (zoals een gebruikers-ID) of uiterst specifiek (zoals een exacte tijdstip op de dag).
Functies worden gebruikt om acties af te stemmen met de huidige context in het model. Het model is een weergave van de laatste kennis van Personalizer over acties, context en hun functies, waarmee deze gefundeerde beslissingen kan nemen.
Het model, inclusief functies, wordt bijgewerkt volgens een schema op basis van de updatefrequentie van uw model in Azure Portal.
Functies moeten worden geselecteerd met dezelfde planning en hetzelfde ontwerp als u zou toepassen op elk schema of model in uw technische architectuur. De functiewaarden kunnen worden ingesteld met bedrijfslogica of systemen van derden.
Let op
Functies in deze toepassing zijn voor demonstratiedoeleinden. Dit zijn niet noodzakelijkerwijs de beste functies om voor uw gebruikscase te gebruiken in een web-app.
Actiefuncties
Elke actie (inhoudsitem) heeft functies waarmee u het type koffie of thee kunt onderscheiden.
De functies zijn niet geconfigureerd als onderdeel van de lusconfiguratie in de Azure Portal. In plaats daarvan worden ze verzonden als een JSON-object met elke Rank API-aanroep. Dit biedt flexibiliteit voor de acties en hun functies om in de loop van de tijd te groeien, te wijzigen en te krimpen, waardoor Personalizer trends kan volgen.
Functies voor koffie en thee omvatten:
- Herkomstlocatie van de koffiebonen, zoals Kenia en Brazilië
- Of de koffie of thee organisch is.
- Licht of donker gebrande koffie
Koffie heeft in de voorafgaande lijst drie functies, terwijl thee er maar één heeft. Geef alleen functies door aan Personalizer die zinvol zijn voor de actie. Geef geen lege waarde door voor een functie als deze niet van toepassing is op de actie.
Contextfuncties
Contextfuncties helpen Personalizer de context van de omgeving te begrijpen, zoals het weergaveapparaat, de gebruiker, de locatie, en andere functies die relevant zijn voor uw gebruikerscase.
De context voor deze chatbot omvat:
- Type weer (sneeuw, regen, zon)
- Dag van de week
Functies worden in deze chatbot in willekeurige volgorde geselecteerd. In een echte bot gebruikt u echte gegevens voor uw contextfuncties.
Ontwerpoverwegingen voor deze bot
Er zijn enkele dingen waar u rekening mee moet houden met betrekking tot dit gesprek:
- Botinteractie: het gesprek is heel eenvoudig omdat het Rank and Reward in een eenvoudige use-case demonstreert. Het biedt geen demonstratie van de volledige functionaliteit van de Bot Framework SDK of van de Emulator.
- Personalizer: De functies worden willekeurig geselecteerd om gebruik te simuleren. Selecteer functies in een productiescenario van Personalizer niet willekeurig.
- Language Understanding (LUIS):de weinige voorbeelduitingen van het LUIS-model zijn alleen bedoeld voor dit voorbeeld. Gebruik voor uw LUIS-toepassing in productie niet zo weinig voorbeelduitingen.
Vereiste software installeren
- Visual Studio 2019. De opslagplaats met downloadbare voorbeelden omvat instructies, als u liever de .NET Core CLI gebruikt.
- Microsoft Bot Framework Emulator is een desktoptoepassing waarmee botontwikkelaars hun bots kunnen testen en fouten erin kunnen opsporen, op localhost of extern uitgevoerd via een tunnel.
Download de voorbeeldcode van de chatbot
De chatbot is beschikbaar in de opslagplaats met Personalizer-voorbeelden. Kloon of download de opslagplaats. Open vervolgens het voorbeeld in de map /samples/ChatbotExample
met Visual Studio 2019.
Als u de opslagplaats wilt klonen, gebruikt u de volgende Git-opdracht in een Bash-shell (terminal).
git clone https://github.com/Azure-Samples/cognitive-services-personalizer-samples.git
Personalizer en LUIS-resources maken en configureren
Azure-resources maken
Als u deze chatbot wilt gebruiken, moet u Azure-resources maken voor Personalizer en LUIS (Language Understanding).
- LUIS-resources maken. Maak zowel een ontwerp- als voorspellingsresource.
- Maak een Personalizer-resource en kopieer vervolgens de sleutel en het eindpunt in de Azure-portal. U moet deze waarden instellen in het
appsettings.json
-bestand van het .NET-project.
Een LUIS-app maken
Als u nog niet bekend bent met LUIS, moet u zich aanmelden en uw account meteen migreren. U hoeft geen nieuwe resources te maken. Selecteer in plaats hiervan de resources die u hebt gemaakt in de vorige sectie van deze zelfstudie.
- Als u een nieuwe LUIS-toepassing wilt maken, selecteert u in de LUIS-portal uw abonnement en creatieresource.
- Selecteer vervolgens op dezelfde pagina de optie + Nieuwe app voor gesprek en Importeren als JSON.
- Selecteer in het pop-upvenster de optie Bestand kiezen en selecteer vervolgens het
/samples/ChatbotExample/CognitiveModels/coffeebot.json
-bestand. Voer de naamPersonalizer Coffee bot
in. - Selecteer de knop Trainen in het navigatievenster rechtsboven in de LUIS-portal.
- Selecteer de knop Publiceren om de app te publiceren in de Productiesleuf voor de voorspellingsruntime.
- Selecteer Beheren en vervolgens Instellingen. Kopieer de waarde van de App-id. U moet deze waarde instellen in het
appsettings.json
-bestand van het .NET-project. - Blijf in de sectie Beheren en selecteer Azure-resources. Hiermee worden de gekoppelde resources in de app weergegeven.
- Selecteer Voorspellingsresource toevoegen. Selecteer in het pop-updialoogvenster uw abonnement en de voorspellingsresource die u in een eerdere sectie van deze zelfstudie hebt gemaakt. Selecteer vervolgens Gereed.
- Kopieer de waarden van Primaire sleutel en Eindpunt-URL. U moet deze waarden instellen in het
appsettings.json
-bestand van het .NET-project.
Bot configureren met het appsettings.json-bestand
Open het oplossingsbestand van de chatbot,
ChatbotSamples.sln
, met Visual Studio 2019.Open
appsettings.json
in de hoofdmap van het project.Stel alle vijf de instellingen in die u in de vorige sectie van deze zelfstudie hebt gekopieerd.
{ "PersonalizerChatbot": { "LuisAppId": "", "LuisAPIKey": "", "LuisServiceEndpoint": "", "PersonalizerServiceEndpoint": "", "PersonalizerAPIKey": "" } }
De bot bouwen en uitvoeren
Zodra u de appsettings.json
hebt geconfigureerd, bent u klaar om de chatbot te bouwen en uit te voeren. Wanneer u dit doet, wordt een browser geopend met de actieve website, http://localhost:3978
.
Zorg ervoor dat de website actief blijft, omdat in de zelfstudie wordt uitgelegd wat de bot doet, zodat u kunt werken met de bot.
Bot Framework Emulator instellen
Open de Bot Framework Emulator en selecteer Bot openen.
Configureer de bot met de volgende bot-URL. Selecteer vervolgens Verbinding maken:
http://localhost:3978/api/messages
De emulator maakt verbinding met de chatbot en geeft de instructietekst weer, samen met informatie over logboekregistratie en foutopsporing die nuttig is voor lokale ontwikkeling.
De bot gebruiken in de Bot Framework Emulator
Vraag de bot om het menu weer te geven, door
I would like to see the menu
in te voeren. De chatbot geeft de items weer.Laat de bot een item voorstellen door
Please suggest a drink for me.
in te voeren. De Emulator geeft in het chatvenster Rank-aanvraag en -antwoord weer, zodat u de volledige JSON kunt zien. En de bot doet een suggestie, bijvoorbeeldHow about Latte?
Antwoord dat u dit bevalt. Dit betekent dat u de bovenste geclassificeerde selectie van Personalizer accepteert,
I like it.
. De Emulator geeft in het chatvenster de Reward-aanvraag weer met beloningsscore 1, zodat u de volledige JSON kunt zien. De bot reageert metThat’s great! I’ll keep learning your preferences over time.
enWould you like to get a new suggestion or reset the simulated context to a new day?
Als u met
no
antwoordt op de selectie, wordt de beloningsscore 0 verzonden naar Personalizer.
De .NET-code begrijpen met behulp van Personalizer
De .NET-oplossing is een eenvoudige Bot Framework-chatbot. De code die betrekking heeft op Personalizer, bevindt zich in de volgende mappen:
/samples/ChatbotExample/Bots
PersonalizerChatbot.cs
: bestand voor de interactie tussen bot en Personalizer
/samples/ChatbotExample/ReinforcementLearning
: beheert de acties en functies voor het Personalizer-model/samples/ChatbotExample/Model
: bestanden voor de Personalizer-acties en -functies, en voor de LUIS-intenties
PersonalizerChatbot.cs: werken met Personalizer
De klasse PersonalizerChatbot
is afgeleid van de Microsoft.Bot.Builder.ActivityHandler
. Deze heeft drie eigenschappen en methoden voor het beheren van de gespreksstroom.
Let op
Kopieer niet de code uit deze zelfstudie. Gebruik de voorbeeldcode in de opslagplaats met Personalizer-voorbeelden.
public class PersonalizerChatbot : ActivityHandler
{
private readonly LuisRecognizer _luisRecognizer;
private readonly PersonalizerClient _personalizerClient;
private readonly RLContextManager _rlFeaturesManager;
public PersonalizerChatbot(LuisRecognizer luisRecognizer, RLContextManager rlContextManager, PersonalizerClient personalizerClient)
{
_luisRecognizer = luisRecognizer;
_rlFeaturesManager = rlContextManager;
_personalizerClient = personalizerClient;
}
}
public override async Task OnTurnAsync(ITurnContext turnContext, CancellationToken cancellationToken = default(CancellationToken))
{
await base.OnTurnAsync(turnContext, cancellationToken);
if (turnContext.Activity.Type == ActivityTypes.Message)
{
// Check LUIS model
var recognizerResult = await _luisRecognizer.RecognizeAsync(turnContext, cancellationToken);
var topIntent = recognizerResult?.GetTopScoringIntent();
if (topIntent != null && topIntent.HasValue && topIntent.Value.intent != "None")
{
Intents intent = (Intents)Enum.Parse(typeof(Intents), topIntent.Value.intent);
switch (intent)
{
case Intents.ShowMenu:
await turnContext.SendActivityAsync($"Here is our menu: \n Coffee: {CoffeesMethods.DisplayCoffees()}\n Tea: {TeaMethods.DisplayTeas()}", cancellationToken: cancellationToken);
break;
case Intents.ChooseRank:
// Here we generate the event ID for this Rank.
var response = await ChooseRankAsync(turnContext, _rlFeaturesManager.GenerateEventId(), cancellationToken);
_rlFeaturesManager.CurrentPreference = response.Ranking;
await turnContext.SendActivityAsync($"How about {response.RewardActionId}?", cancellationToken: cancellationToken);
break;
case Intents.RewardLike:
if (!string.IsNullOrEmpty(_rlFeaturesManager.CurrentEventId))
{
await RewardAsync(turnContext, _rlFeaturesManager.CurrentEventId, 1, cancellationToken);
await turnContext.SendActivityAsync($"That's great! I'll keep learning your preferences over time.", cancellationToken: cancellationToken);
await SendByebyeMessageAsync(turnContext, cancellationToken);
}
else
{
await turnContext.SendActivityAsync($"Not sure what you like. Did you ask for a suggestion?", cancellationToken: cancellationToken);
}
break;
case Intents.RewardDislike:
if (!string.IsNullOrEmpty(_rlFeaturesManager.CurrentEventId))
{
await RewardAsync(turnContext, _rlFeaturesManager.CurrentEventId, 0, cancellationToken);
await turnContext.SendActivityAsync($"Oh well, maybe I'll guess better next time.", cancellationToken: cancellationToken);
await SendByebyeMessageAsync(turnContext, cancellationToken);
}
else
{
await turnContext.SendActivityAsync($"Not sure what you dislike. Did you ask for a suggestion?", cancellationToken: cancellationToken);
}
break;
case Intents.Reset:
_rlFeaturesManager.GenerateRLFeatures();
await SendResetMessageAsync(turnContext, cancellationToken);
break;
default:
break;
}
}
else
{
var msg = @"Could not match your message with any of the following LUIS intents:
'ShowMenu'
'ChooseRank'
'RewardLike'
'RewardDislike'.
Try typing 'Show me the menu','What do you suggest','I like it','I don't like it'.";
await turnContext.SendActivityAsync(msg);
}
}
else if (turnContext.Activity.Type == ActivityTypes.ConversationUpdate)
{
// Generate a new weekday and weather condition
// These will act as the context features when we call rank with Personalizer
_rlFeaturesManager.GenerateRLFeatures();
// Send a welcome message to the user and tell them what actions they may perform to use this bot
await SendWelcomeMessageAsync(turnContext, cancellationToken);
}
else
{
await turnContext.SendActivityAsync($"{turnContext.Activity.Type} event detected", cancellationToken: cancellationToken);
}
}
// code removed for brevity, full sample code available for download
private async Task SendWelcomeMessageAsync(ITurnContext turnContext, CancellationToken cancellationToken)
private async Task SendResetMessageAsync(ITurnContext turnContext, CancellationToken cancellationToken)
private async Task SendByebyeMessageAsync(ITurnContext turnContext, CancellationToken cancellationToken)
private async Task<RankResponse> ChooseRankAsync(ITurnContext turnContext, string eventId, CancellationToken cancellationToken)
private async Task RewardAsync(ITurnContext turnContext, string eventId, double reward, CancellationToken cancellationToken)
}
Met de methoden die worden voorafgegaan door Send
, worden gesprekken met de bot en LUIS beheerd. De methoden ChooseRankAsync
en RewardAsync
werken met Personalizer.
Rank API aanroepen en resultaten weergeven
Met de methode ChooseRankAsync
worden de JSON-gegevens gebouwd die moeten worden verzonden naar de Personalizer Rank-API door de acties te verzamelen met functies en de contextfuncties.
private async Task<RankResponse> ChooseRankAsync(ITurnContext turnContext, string eventId, CancellationToken cancellationToken)
{
IList<object> contextFeature = new List<object>
{
new { weather = _rlFeaturesManager.RLFeatures.Weather.ToString() },
new { dayofweek = _rlFeaturesManager.RLFeatures.DayOfWeek.ToString() },
};
Random rand = new Random(DateTime.UtcNow.Millisecond);
IList<RankableAction> actions = new List<RankableAction>();
var coffees = Enum.GetValues(typeof(Coffees));
var beansOrigin = Enum.GetValues(typeof(CoffeeBeansOrigin));
var organic = Enum.GetValues(typeof(Organic));
var roast = Enum.GetValues(typeof(CoffeeRoast));
var teas = Enum.GetValues(typeof(Teas));
foreach (var coffee in coffees)
{
actions.Add(new RankableAction
{
Id = coffee.ToString(),
Features =
new List<object>()
{
new { BeansOrigin = beansOrigin.GetValue(rand.Next(0, beansOrigin.Length)).ToString() },
new { Organic = organic.GetValue(rand.Next(0, organic.Length)).ToString() },
new { Roast = roast.GetValue(rand.Next(0, roast.Length)).ToString() },
},
});
}
foreach (var tea in teas)
{
actions.Add(new RankableAction
{
Id = tea.ToString(),
Features =
new List<object>()
{
new { Organic = organic.GetValue(rand.Next(0, organic.Length)).ToString() },
},
});
}
// Sending a rank request to Personalizer
// Here we are asking Personalizer to decide which drink the user is most likely to want
// based on the current context features (weather, day of the week generated in RLContextManager)
// and the features of the drinks themselves
var request = new RankRequest(actions, contextFeature, null, eventId);
await turnContext.SendActivityAsync(
"===== DEBUG MESSAGE CALL TO RANK =====\n" +
"This is what is getting sent to Rank:\n" +
$"{JsonConvert.SerializeObject(request, Formatting.Indented)}\n",
cancellationToken: cancellationToken);
var response = await _personalizerClient.RankAsync(request, cancellationToken);
await turnContext.SendActivityAsync(
$"===== DEBUG MESSAGE RETURN FROM RANK =====\n" +
"This is what Rank returned:\n" +
$"{JsonConvert.SerializeObject(response, Formatting.Indented)}\n",
cancellationToken: cancellationToken);
return response;
}
Reward API aanroepen en resultaten weergeven
Met de methode RewardAsync
worden de JSON-gegevens gebouwd die naar de Personalizer Reward-API moeten worden verzonden door de score te bepalen. De score wordt bepaald op basis van de LUIS-intentie die is geïdentificeerd in de gebruikerstekst en verzonden vanuit de methode OnTurnAsync
.
private async Task RewardAsync(ITurnContext turnContext, string eventId, double reward, CancellationToken cancellationToken)
{
await turnContext.SendActivityAsync(
"===== DEBUG MESSAGE CALL REWARD =====\n" +
"Calling Reward:\n" +
$"eventId = {eventId}, reward = {reward}\n",
cancellationToken: cancellationToken);
// Sending a reward request to Personalizer
// Here we are responding to the drink ranking Personalizer provided us
// If the user liked the highest ranked drink, we give a high reward (1)
// If they did not, we give a low reward (0)
await _personalizerClient.RewardAsync(eventId, new RewardRequest(reward), cancellationToken);
}
Ontwerpoverwegingen voor een bot
Dit voorbeeld is bedoeld om een eenvoudige end-to-end-oplossing van Personalizer in een bot te demonstreren. Uw gebruikscase is mogelijk ingewikkelder.
Als u Personalizer wilt gebruiken in een productiebot, plant u:
- Toegang tot Personalizer in realtime telkens wanneer u een geclassificeerde selectie nodig hebt. De Rank API kan niet in een batch worden geplaatst of in de cache worden opgeslagen. De Reward-aanroep kan worden vertraagd of geoffload naar een afzonderlijk proces. Als u geen beloning retourneert in de opgegeven tijdsperiode, wordt een standaardbeloningswaarde ingesteld voor de gebeurtenis.
- Op use-case gebaseerde berekening van de beloning: in dit voorbeeld werden twee beloningen van nul weergegeven en één zonder bereik tussen en geen negatieve waarde voor een score. Uw systeem heeft mogelijk meer gedetailleerde scores nodig.
- Botkanalen: In dit voorbeeld wordt één kanaal gebruikt, maar als u meer dan één kanaal of variaties van bots op één kanaal wilt gebruiken, moet dit mogelijk worden beschouwd als onderdeel van de contextfuncties van het Personalizer-model.
Resources opschonen
Wanneer u klaar bent met deze zelfstudie, moet u de volgende resources opschonen:
- Verwijder de map met uw voorbeeldproject.
- Verwijder Personalizer en uw LUIS-resource in de Azure-portal.
Volgende stappen
- Hoe Personalizer werkt
- Functies: meer informatie over concepten over functies met behulp van acties en context
- Beloningen: meer informatie over het berekenen van beloningen