AgentApplication στο SDK παραγόντων Microsoft 365

AgentApplication είναι ο βασικός πυρήνας ενός παράγοντα που έχει δημιουργηθεί με το Agents SDK. Το AgentApplication αποτελεί το σημείο εισόδου για κάθε εισερχόμενη δραστηριότητα, συμπεριλαμβανομένων μηνυμάτων από χρήστες, συμβάντων κύκλου ζωής συνομιλίας, αλληλεπιδράσεων με προσαρμόσιμες κάρτες και OAuth callbacks.

Ένας παράγοντας είναι, στον πυρήνα του, ένας AgentApplication. Το διαμορφώνετε με χειριστές που περιγράφουν τι κάνει ο παράγοντας σας. Το SDK αναλαμβάνει τη δρομολόγηση, τη διαχείριση της κατάστασης και την υποδομή που απαιτείται για τη λειτουργία του.

Πώς λειτουργεί το AgentApplication

Κάθε παράγοντας έχει έναν κύκλο ζωής που ξεκινά όταν ένα κανάλι (όπως το Microsoft Teams, μια υπηρεσία bot ή ένας προσαρμοσμένος πελάτης) μεταφέρει μια δραστηριότητα στο endpoint του παράγοντα. AgentApplication βρίσκεται στο κέντρο αυτού του κύκλου ζωής:

Channel → Hosting layer → AgentApplication → Your handlers

Τα επίπεδα επεξεργασίας σε έναν παράγοντας που έχει δημιουργηθεί με το Agents SDK λειτουργούν ως εξής:

  1. Το επίπεδο φιλοξενίας λαμβάνει το αίτημα HTTP και πραγματοποιεί έλεγχο ταυτότητας.
  2. Το AgentApplication επεξεργάζεται την εισερχόμενη δραστηριότητα μέσω του pipeline του.
  3. Οι διαχειριστές καλούνται με βάση τις αντιστοιχισμένες διαδρομές.

Ο παράγοντάς σας φορτώνει την κατάσταση αλλαγής πριν την εκτέλεση των χειριστών. Στη συνέχεια, ο παράγοντας αποθηκεύει την κατάσταση γύρου.

Κύριες έννοιες

Δραστηριότητες

Όλα τα στοιχεία στο SDK παραγόντων ρέουν ως δραστηριότητα. Μια δραστηριότητα είναι ένα δομημένο μήνυμα που αντιπροσωπεύει κάτι που συνέβη. Μια δραστηριότητα έχει έναν τύπο, όπως message, event, invoke, conversationUpdate και ούτω καθεξής. Μεταφέρει ένα φορτίο σχετικό με αυτόν τον τύπο. AgentApplication λαμβάνει δραστηριότητες και τις δρομολογεί στον σωστό χειριστή.

Διαδρομές

Μια δρομολόγηση συνδέει έναν επιλογέα με ένα πρόγραμμα χειρισμού. Ο επιλογέας καθορίζει εάν μια διαδρομή αντιστοιχεί στην τρέχουσα δραστηριότητα. Ο χειριστής εκτελεί τη λογική σας όταν η διαδρομή ταιριάζει.

Καταχωρήστε διαδρομές όταν διαμορφώνετε τον παράγοντας σας. Μπορούν να ταιριάξουν:

  • Ένα μήνυμα που περιέχει συγκεκριμένο κείμενο ή ταιριάζει με μια κανονική έκφραση
  • Οποιαδήποτε δραστηριότητα συγκεκριμένου τύπου
  • Συμβάντα κύκλου ζωής συνομιλίας (προσθήκη μέλους, κατάργηση μέλους)
  • Ενέργειες προσαρμόσιμης κάρτας
  • Προσαρμοσμένες συνθήκες

Όταν φτάνει μια δραστηριότητα, το σύστημα αξιολογεί τις διαδρομές με τη σειρά μέχρι να βρει μια αντιστοιχία. Από προεπιλογή, εκτελείται μόνο μία διαδρομή.

Κατάσταση γύρου

AgentApplication διαχειρίζεται το _turn state—δομημένη αποθήκευση κατανεμημένη σε πεδία:

Τύπος πεδίου Περιγραφή
Συζήτηση Κοινή χρήση σε όλους τους χρήστες σε μια συνομιλία, παρέμεινε μεταξύ των γύρων
User Περιορίζεται σε έναν μεμονωμένο χρήστη σε όλες τις συνομιλίες
Προσωρινό Μόνο η τρέχουσα αλληλεπίδραση - ποτέ δεν διατηρήθηκε

Το σύστημα φορτώνει αυτόματα την κατάσταση πριν από την εκτέλεση των προγραμμάτων χειρισμού σας και την αποθηκεύει αυτόματα στη συνέχεια.

Περιβάλλον γύρου

Όταν ένα πρόγραμμα χειρισμού τρέχει, λαμβάνει ένα περιβάλλον γύρου. Το περιβάλλον της τρέχουσας αλληλεπίδρασης είναι μια στιγμιαία εικόνα της τρέχουσας δραστηριότητας, της σύνδεσης προσαρμογέα και βοηθητικών προγραμμάτων για την αποστολή αποκρίσεων. Το περιβάλλον γύρου είναι η διεπαφή σας με την τρέχουσα αλληλεπίδραση.

Ενδιάμεσο λογισμικό

AgentApplication υποστηρίζει μια αλυσίδα ενδιάμεσου λογισμικού. Το ενδιάμεσο λογισμικό είναι μια αλυσίδα στοιχείων που επεξεργάζονται κάθε αλληλεπίδραση πριν και μετά την εκτέλεση των χειριστών σας. Το ενδιάμεσο λογισμικό μπορεί να επιθεωρήσει, να μεταμορφώσει ή να βραχυκυκλώσει τη ροή δραστηριότητας. Οι συνήθεις χρήσεις περιλαμβάνουν την καταγραφή, ελέγχους αυθεντικοποίησης και κανονικοποίηση αιτημάτων.

Δημιουργία παράγοντα

Δημιουργήστε υποκλάση του AgentApplication και καταχωρήστε τους χειριστές σας στον κατασκευαστή. Το πλαίσιο φιλοξενίας εισάγει 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);
    }
}

Καταχωρίστε τον παράγοντα σας στο 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();

Καταχωρήστε χειριστές δραστηριοτήτων

Χειρισμός μηνυμάτων

Ταιριάξτε μηνύματα με ακριβές κείμενο (χωρίς διάκριση πεζών-κεφαλαίων):

OnMessage("help", async (context, state, ct) =>
{
    await context.SendActivityAsync("Here's what I can do...", cancellationToken: ct);
});

Αντιστοίχιση μηνυμάτων με χρήση κανονικής παράστασης:

OnMessage(new Regex(@"^order\s+\d+$", RegexOptions.IgnoreCase), async (context, state, ct) =>
{
    await context.SendActivityAsync("Looking up your order...", cancellationToken: ct);
});

Χειριστείτε ενημερώσεις συνομιλίας

Δηλώστε χειριστές για συμβάντα κύκλου ζωής της συνομιλίας, όπως μέλη που εισέρχονται ή αποχωρούν.

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
});

Χειριστείτε οποιονδήποτε τύπο δραστηριότητας

Αντιστοιχίστε οποιαδήποτε δραστηριότητα με τη συμβολοσειρά τύπου της για πλήρη έλεγχο της δρομολόγησης.

OnActivity(ActivityTypes.Message, async (context, state, ct) =>
{
    // Handles all message activities
});

OnActivity(ActivityTypes.Event, async (context, state, ct) =>
{
    // Handles event activities
});

Χρησιμοποιήστε ActivityTypesσταθερές αντί για ενσωματωμένες συμβολοσειρές.

Ελέγξτε τη σειρά αξιολόγησης διαδρομών

Το σύστημα ταξινομεί τις δρομολογήσεις σε μια σταθερή σειρά αξιολόγησης όταν τις καταχωρείτε, όχι κατά το χρόνο εκτέλεσης. Η ταξινόμηση χρησιμοποιεί δύο επίπεδα:

  1. Τύπος δρομολόγησης: Το σύστημα ομαδοποιεί τις διαδρομές ανά τύπο και αξιολογεί πάντα τους τύπους υψηλότερης προτεραιότητας πριν από τους τύπους χαμηλότερης προτεραιότητας, ανεξάρτητα από την κατάταξη.

    Προτεραιότητα Τύπος δρομολόγησης
    1 (υψηλότερο) Η παραγοντική εφαρμόζει τις διαδρομές
    2 Διαδρομές invoke (ενέργειες προσαρμόσιμων καρτών, OAuth callbacks και άλλες κλήσεις ευαίσθητες στον χρόνο)
    3 Παραγοντικές διαδρομές
    4 (χαμηλότερο) Όλες οι άλλες διαδρομές
  2. Κατάταξη: Σε κάθε ομάδα τύπων δρομολόγησης, το σύστημα ταξινομεί τις δρομολογήσεις με βάση την τιμή κατάταξής τους. Οι χαμηλότερες αριθμητικές τιμές αξιολογούνται πρώτα.

Χρησιμοποιήστε τις σταθερές RouteRank για να ορίσετε την κατάταξη κατά την καταχώριση ενός χειριστή:

Σταθερά Τιμή Νόημα
RouteRank.First 0 Αξιολογείται πριν από όλες τις άλλες διαδρομές της ομάδας του
RouteRank.Unspecified 32767 Προεπιλογή όταν δεν έχει καθοριστεί κατάταξη
RouteRank.Last 65535 Αξιολογείται μετά από όλες τις άλλες διαδρομές της ομάδας του

Από προεπιλογή, η αξιολόγηση σταματά στην πρώτη διαδρομή που αντιστοιχεί. Χρησιμοποιήστε το RouteRank.Last για μια εφεδρική διαδρομή catch-all που χειρίζεται οτιδήποτε δεν ταιριάζει με μια πιο συγκεκριμένη διαδρομή.

// 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);

Σημεία παρέμβασης στον κύκλο ζωής μιας αλληλεπίδρασης

Καταχωρίστε τη λογική που εκτελείται σε κάθε κύκλο, πριν ή μετά την αντιστοίχιση διαδρομής. Αυτά τα σημεία παρέμβασης είναι χρήσιμα για την καταγραφή, τις διατομεακές ανησυχίες και τον χειρισμό σφαλμάτων.

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);
});

Όταν το OnBeforeTurn επιστρέφει το false, ο κύκλος ματαιώνεται και δεν εκτελούνται διαδρομές. Όταν το OnAfterTurn επιστρέφει false, η κατάσταση γύρου δεν αποθηκεύεται.

Χρήση κατάστασης γύρου

Ο παράγοντας φορτώνει αυτόματα την κατάσταση αλληλεπίδρασης πριν από την εκτέλεση των χειριστών σας και την αποθηκεύει στη συνέχεια. Το αντικείμενο κατάστασης γύρου που μεταβιβάζεται στους χειριστές σας σάς δίνει πρόσβαση στα διαφορετικά πεδία, ώστε να μπορείτε να διαβάσετε και να γράψετε δεδομένα που παραμένουν σε όλους τους γύρους ή είναι εφήμερα για τον τρέχοντα γύρο:

  • Εύρος συνομιλίας: Για δεδομένα που διατηρούνται σε όλους τους γύρους μιας συνομιλίας
  • Εύρος χρήστη: Για δεδομένα ανά χρήστη
  • Εύρος προσωρινό: Για δεδομένα που χρειάζεται να υπάρχουν μόνο κατά τον τρέχοντα κύκλο
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);
});

Σημείωμα

Χρησιμοποιήστε MemoryStorage για τοπική ανάπτυξη και δοκιμές. Για αναπτύξεις παραγωγής, ειδικά όταν εκτελούνται σε πολλαπλά instances, χρησιμοποιήστε έναν μόνιμο πάροχο αποθήκευσης, όπως το Azure Cosmos DB ή το Azure Blob Storage. Δείτε Χρήση υπηρεσιών παροχής χώρου αποθήκευσης στον παράγοντά σας

Επόμενα βήματα