Remarque
L’accès à cette page nécessite une autorisation. Vous pouvez essayer de vous connecter ou de modifier des répertoires.
L’accès à cette page nécessite une autorisation. Vous pouvez essayer de modifier des répertoires.
AgentApplication est le bloc élémentaire central d’un assistant développé avec le SDK assistants.
AgentApplication est le point d’entrée pour toutes les activités entrantes, y compris les messages des utilisateurs, les événements du cycle de vie de la conversation, les interactions avec les cartes adaptatives et les rappels OAuth.
Un assistant est, à la base, une AgentApplication. Vous le configurez avec des gestionnaires qui décrivent ce que fait votre assistant. Le SDK prend en charge le routage, la gestion des états et l’infrastructure nécessaire à son fonctionnement.
Comment fonctionne AgentApplication
Chaque assistant possède un cycle de vie qui commence lorsqu’un canal (Microsoft Teams, un Bot Service ou un client personnalisé) envoie une activité au point de terminaison de votre assistant.
AgentApplication est au centre de ce cycle de vie :
Channel → Hosting layer → AgentApplication → Your handlers
Les différentes couches de traitement dans un assistant créé avec le SDK assistants opèrent comme suit :
- La couche d’hébergement reçoit la requête HTTP et l’authentifie.
- Le
AgentApplicationtraite l’activité entrante via son pipeline. - Vos gestionnaires sont appelés en fonction des routes correspondantes.
Votre assistant charge l’état du tour avant d’exécuter vos gestionnaires. Ensuite, l’assistant enregistre l’état du tour.
Concepts principaux
Activités
Dans le SDK assistants, tout est traité sous la forme d’une activité. Une activité est un message structuré représentant quelque chose qui s’est passé. Une activité possède un type, tel que message, event, invoke, conversationUpdate, etc. Elle contient une charge utile propre à ce type.
AgentApplication reçoit des activités et les redirige vers le bon gestionnaire.
Gammes
Un itinéraire associe un sélecteur à un gestionnaire. Le sélecteur détermine si une route correspond à l’activité en cours. Le gestionnaire exécute votre logique lorsque la route correspond.
Enregistrez les routes lorsque vous configurez votre assistant. Ils peuvent correspondre à :
- Un message contenant un texte spécifique ou correspondant à une expression régulière
- Toute activité d’un type donné
- Événements du cycle de vie de la conversation (membre ajouté, membre supprimé)
- Actions de carte adaptative
- Conditions personnalisées
Lorsqu’une activité arrive, le système évalue les routes dans l’ordre jusqu’à trouver une correspondance. Par défaut, une seule route s’exécute.
État de tour
AgentApplication gère l’état de tour : un stockage structuré partitionné en portées :
| Type d’étendue | Description |
|---|---|
| Conversation | Partagé entre tous les utilisateurs d’une conversation, conservé entre les tours |
| Utilisateur | Attribué à un utilisateur individuel sur toutes les conversations |
| Température | Tour actuel uniquement : jamais conservé |
Le système charge automatiquement l’état avant l’exécution de vos gestionnaires et l’enregistre automatiquement ensuite.
Contexte de tour
Lorsqu’un gestionnaire s’exécute, il reçoit un contexte de tour. Le contexte de tour est un instantané de l’activité en cours, de la connexion de l’adaptateur et des utilitaires pour envoyer des réponses. Le contexte de tour est votre interface avec l’interaction en cours.
Intergiciels
AgentApplication prend en charge un pipeline d’intergiciel. Le middleware est une chaîne de composants qui traitent chaque tour avant et après l’exécution de vos gestionnaires. Le middleware peut inspecter, transformer ou court-circuiter le flux d’activité. Les usages courants incluent la journalisation, les vérifications d’authentification et la normalisation des requêtes.
Créer un assistant
Sous-classez AgentApplication et enregistrez vos gestionnaires dans le constructeur. Le framework d’hébergement injecte automatiquement AgentApplicationOptions.
public class MyAgent : AgentApplication
{
public MyAgent(AgentApplicationOptions options) : base(options)
{
OnConversationUpdate(ConversationUpdateEvents.MembersAdded, WelcomeAsync);
OnActivity(ActivityTypes.Message, OnMessageAsync, rank: RouteRank.Last);
}
private async Task WelcomeAsync(ITurnContext context, ITurnState state, CancellationToken ct)
{
foreach (var member in context.Activity.MembersAdded)
{
if (member.Id != context.Activity.Recipient.Id)
{
await context.SendActivityAsync("Hello! How can I help you?", cancellationToken: ct);
}
}
}
private async Task OnMessageAsync(ITurnContext context, ITurnState state, CancellationToken ct)
{
await context.SendActivityAsync($"You said: {context.Activity.Text}", cancellationToken: ct);
}
}
Inscrivez votre assistant à Program.cs :
WebApplicationBuilder builder = WebApplication.CreateBuilder(args);
builder.Services.AddHttpClient();
builder.Services.AddSingleton<IStorage, MemoryStorage>();
builder.Services.AddAgent<MyAgent>();
builder.Services.AddAgentAspNetAuthentication(builder.Configuration);
WebApplication app = builder.Build();
app.UseAuthentication();
app.UseAuthorization();
app.MapAgentApplicationEndpoints(requireAuth: !app.Environment.IsDevelopment());
app.Run();
Enregistrer les gestionnaires d’activités
Gérer les messages
Faire correspondre les messages par texte exact (sans tenir compte de la casse) :
OnMessage("help", async (context, state, ct) =>
{
await context.SendActivityAsync("Here's what I can do...", cancellationToken: ct);
});
Faire correspondre les messages à l’aide d’une expression régulière :
OnMessage(new Regex(@"^order\s+\d+$", RegexOptions.IgnoreCase), async (context, state, ct) =>
{
await context.SendActivityAsync("Looking up your order...", cancellationToken: ct);
});
Gérer les mises à jour des conversations
Enregistrer des gestionnaires pour les événements du cycle de vie de la conversation, tels que l’arrivée ou le départ de membres.
OnConversationUpdate(ConversationUpdateEvents.MembersAdded, async (context, state, ct) =>
{
foreach (var member in context.Activity.MembersAdded)
{
if (member.Id != context.Activity.Recipient.Id)
{
await context.SendActivityAsync("Welcome!", cancellationToken: ct);
}
}
});
OnConversationUpdate(ConversationUpdateEvents.MembersRemoved, async (context, state, ct) =>
{
// Called when participants leave the conversation
});
Gérer tout type d’activité
Faites correspondre toute activité par sa chaîne de type pour un contrôle total du routage.
OnActivity(ActivityTypes.Message, async (context, state, ct) =>
{
// Handles all message activities
});
OnActivity(ActivityTypes.Event, async (context, state, ct) =>
{
// Handles event activities
});
Utilisez les constantes ActivityTypes plutôt que des chaînes codées en dur.
Contrôlez l’ordre d’évaluation des routes
Le système trie les routes dans un ordre d’évaluation fixe lors de leur enregistrement, et non pendant l’exécution. Le tri utilise deux niveaux :
Type de route : le système regroupe les routes par type, et il évalue toujours les types ayant une priorité supérieure avant les types de priorité inférieure, indépendamment du rang :
Priorité Type d’itinéraire 1 (le plus élevé) Routes d’invocation agentiques 2 Routes d’invocation (actions de cartes adaptatives, rappels OAuth et autres invocations sensibles au temps) 3 Itinéraires agentiques 4 (le plus bas) Toutes les autres routes Rang : au sein de chaque groupe de type de route, le système ordonne les routes selon leur valeur de rang. Les valeurs numériques inférieures sont évaluées en premier.
Utilisez les constantes RouteRank pour définir le rang lors de l’enregistrement d’un gestionnaire :
| Constante | active | Signifie |
|---|---|---|
RouteRank.First |
0 |
Évalué avant toutes les autres routes de son groupe |
RouteRank.Unspecified |
32767 |
Par défaut lorsqu’aucun rang n’est spécifié |
RouteRank.Last |
65535 |
Évalué après toutes les autres routes de son groupe |
Par défaut, l’évaluation s’arrête à la première route correspondante. Utilisez RouteRank.Last pour un repli global qui gère tout ce qui n’est pas associé à une route plus spécifique.
// Specific handlers use the default rank
OnMessage("status", HandleStatusAsync);
OnMessage("help", HandleHelpAsync);
// Catch-all — handles anything not matched above
OnActivity(ActivityTypes.Message, HandleUnknownMessageAsync, rank: RouteRank.Last);
Activer les hooks de cycle de vie
Définissez la logique qui s’exécute à chaque itération, avant ou après la correspondance de routage. Ces hooks sont utiles pour la journalisation, les préoccupations transversales et la gestion des erreurs.
OnBeforeTurn(async (context, state, ct) =>
{
logger.LogInformation("Turn started: {Type}", context.Activity.Type);
return true; // Return false to abort the turn
});
OnAfterTurn(async (context, state, ct) =>
{
logger.LogInformation("Turn completed");
return true; // Return false to skip state saving
});
OnTurnError(async (context, state, exception, ct) =>
{
logger.LogError(exception, "Turn error");
await context.SendActivityAsync("Something went wrong. Please try again.", cancellationToken: ct);
});
Lorsque OnBeforeTurn retourne false, le tour est annulé et aucune route ne s’exécute. Quand OnAfterTurn retourne false, l’état du tour n’est pas sauvegardé.
Utiliser l’état du tour
L’assistant charge automatiquement l’état de tour avant l’exécution de vos gestionnaires et l’enregistre ensuite. L’objet d’état de tour transmis à vos gestionnaires vous donne accès aux différentes portées afin que vous puissiez lire et écrire des données qui persistent entre les tours ou sont éphémères pour le tour en cours :
- Étendue de la conversation : pour les données partagées dans tous les tours d’une conversation
- Étendue de l’utilisateur : pour les données par utilisateur
- Étendue temporaire : pour les données qui doivent exister uniquement pendant le tour actuel
OnActivity(ActivityTypes.Message, async (context, state, ct) =>
{
// Conversation scope — persisted per conversation
var count = state.Conversation.GetValue<int>("messageCount", () => 0);
state.Conversation.SetValue("messageCount", count + 1);
// User scope — persisted per user
var name = state.User.GetValue<string>("displayName");
// Temp scope — current turn only
state.Temp.SetValue("parsedInput", context.Activity.Text?.Trim());
await context.SendActivityAsync($"Message #{count + 1}: {context.Activity.Text}", cancellationToken: ct);
});
Note
Utilisez MemoryStorage des fins de développement et de test en local. Pour les déploiements en production, notamment ceux exécutés sur plusieurs instances, utilisez un fournisseur de stockage persistant tel que Azure Cosmos DB ou Stockage Blob Azure. Voir Utiliser des fournisseurs de stockage dans votre assistant.