Nota
L'accesso a questa pagina richiede l'autorizzazione. È possibile provare ad accedere o modificare le directory.
L'accesso a questa pagina richiede l'autorizzazione. È possibile provare a modificare le directory.
AgentApplication è il blocco centrale di un agente creato con l'Agents SDK.
AgentApplication è il punto di ingresso per tutte le attività in ingresso, inclusi i messaggi degli utenti, gli eventi del ciclo di vita della conversazione, le interazioni con schede adattive, i callback OAuth.
Un agente è, nella sua essenza, un oggetto AgentApplication. È possibile configurarlo con i gestori che descrivono le operazioni dell'agente. L'SDK si occupa del routing, della gestione dello stato e dell'infrastruttura necessaria per eseguirlo.
Funzionamento di AgentApplication
Ogni agente ha un ciclo di vita che inizia quando un canale (Microsoft Teams, un servizio bot o un client personalizzato) recapita un'attività all'endpoint dell'agente.
AgentApplication si trova al centro del ciclo di vita:
Channel → Hosting layer → AgentApplication → Your handlers
I livelli di elaborazione in un agente creato con Agents SDK funzionano nel modo seguente:
- Il livello di hosting riceve la richiesta HTTP e la autentica.
- Il
AgentApplicationgestisce l'attività in ingresso tramite la sua pipeline. - I gestori vengono chiamati in base alle route corrispondenti.
L'agente carica lo stato del turno prima dell'esecuzione delle funzioni di gestione. Successivamente, l'agente salva lo stato del turno.
Concetti di base
Impegni
Nell'Agents SDK, tutto scorre come un'attività. Un'attività è un messaggio strutturato che rappresenta un evento che si è verificato. Un'attività ha un tipo, ad esempio message, event, invoke, conversationUpdate e così via. Trasporta un carico utile pertinente a quel tipo.
AgentApplication riceve le attività e le instrada al gestore corretto.
Routes
Una route associa un selettore a un gestore. Il selettore determina se una route corrisponde all'attività corrente. Il gestore esegue la tua logica quando il percorso corrisponde.
Registrare le route quando si configura l'agente. Possono corrispondere a:
- Messaggio contenente testo specifico o corrispondenza di un'espressione regolare
- Qualsiasi attività di un determinato tipo
- Eventi del ciclo di vita della conversazione (membro aggiunto, membro rimosso)
- Azioni della scheda adattiva
- Condizioni personalizzate
Quando arriva un'attività, il sistema valuta i percorsi in ordine finché non trova una corrispondenza. Per impostazione predefinita, viene eseguito un solo percorso.
Stato di rotazione
AgentApplication gestisce lo stato _turn, ovvero l'archiviazione strutturata partizionata in ambiti:
| Tipo di ambito | Description |
|---|---|
| Conversazione | Condiviso tra tutti gli utenti in una conversazione, persistente tra turni |
| Utente | Limitato a un singolo utente in tutte le conversazioni |
| Temp | Solo turno corrente- mai persistente |
Il sistema carica automaticamente lo stato prima che i handler siano eseguiti e lo salva in seguito automaticamente.
Contesto di turno
Quando viene eseguito un gestore, riceve un contesto di turno. Il contesto del turno è un'istantanea dell'attività corrente, della connessione dell'adattatore e delle utilità per l'invio di risposte. Il contesto del turno è l'interfaccia dell'interazione corrente.
Middleware
AgentApplication supporta una pipeline middleware. Il middleware è una catena di componenti che elaborano ogni operazione prima e dopo l'esecuzione dei gestori. Il middleware può esaminare, trasformare o interrompere bruscamente il flusso delle attività. Gli usi comuni includono la registrazione, i controlli di autenticazione e la normalizzazione delle richieste.
Creare un agente
Subclassa AgentApplication e registra i gestori nel costruttore. Il framework di hosting inserisce AgentApplicationOptionsautomaticamente .
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);
}
}
Registrare l'agente in 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();
Registrare i gestori di attività
Gestire i messaggi
Trova la corrispondenza dei messaggi in base al testo esatto (senza distinzione tra maiuscole e minuscole):
OnMessage("help", async (context, state, ct) =>
{
await context.SendActivityAsync("Here's what I can do...", cancellationToken: ct);
});
Trova la corrispondenza dei messaggi usando un'espressione regolare:
OnMessage(new Regex(@"^order\s+\d+$", RegexOptions.IgnoreCase), async (context, state, ct) =>
{
await context.SendActivityAsync("Looking up your order...", cancellationToken: ct);
});
Gestire gli aggiornamenti delle conversazioni
Registrare i gestori per gli eventi del ciclo di vita della conversazione, ad esempio l'aggiunta o l'uscita dei membri.
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
});
Gestire qualsiasi tipo di attività
Confronta qualsiasi attività in base al tipo di stringa per un controllo completo sull'instradamento.
OnActivity(ActivityTypes.Message, async (context, state, ct) =>
{
// Handles all message activities
});
OnActivity(ActivityTypes.Event, async (context, state, ct) =>
{
// Handles event activities
});
Usare costanti ActivityTypes anziché stringhe codificate.
Controllare l'ordine di valutazione del percorso
Il sistema ordina le route in un ordine di valutazione fisso quando le si registra, non in fase di esecuzione. L'ordinamento usa due livelli:
Tipo di route: il sistema raggruppa le route per tipo e valuta sempre i tipi con priorità più alta prima dei tipi con priorità più bassa, indipendentemente dalla classificazione:
Priorità Tipo di route 1 (più alto) Procedura di invocazione delle route agentiche 2 Attivare percorsi (azioni della scheda adattiva, callback OAuth e altre chiamate a tempo) 3 Route agentiche 4 (più basso) Tutti gli altri percorsi Classificazione: all'interno di ogni gruppo di tipi di percorsi, il sistema ordina i percorsi in base al loro valore di classificazione. I valori numerici inferiori vengono valutati per primi.
Usare RouteRank le costanti per impostare la classificazione durante la registrazione di un gestore:
| Costante | Value | Significato |
|---|---|---|
RouteRank.First |
0 |
Valutato prima di tutte le altre rotte nel gruppo |
RouteRank.Unspecified |
32767 |
Impostazione predefinita quando non viene specificato alcun rango |
RouteRank.Last |
65535 |
Valutato dopo tutti gli altri percorsi del suo gruppo |
Per impostazione predefinita, la valutazione si arresta alla prima route corrispondente. Usare RouteRank.Last per un fallback onnicomprensivo che gestisce tutto ciò che non corrisponde a una route più specifica.
// 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);
Turn lifecycle hooks
Registra la logica che viene eseguita a ogni passaggio, prima o dopo la corrispondenza del percorso. Questi hook sono utili per la registrazione, gli aspetti trasversali e la gestione degli errori.
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);
});
Quando OnBeforeTurn restituisce false, il turno viene interrotto e non viene eseguito alcun percorso. Quando OnAfterTurn restituisce false, lo stato del turno non viene salvato.
Usare lo stato di turno
L'agente carica automaticamente lo stato di turno prima dell'esecuzione dei gestori e lo salva in seguito. L'oggetto di stato del turno passato ai gestori consente di accedere ai diversi ambiti, in modo da poter leggere e scrivere dati persistenti tra turni o temporanei per il turno corrente:
- Ambito della conversazione: per i dati condivisi tra tutti i turni in una conversazione
- Ambito utente: per i dati per utente
- Ambito temporaneo: per i dati che devono esistere solo durante il turno corrente
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
Usare MemoryStorage per lo sviluppo e il test locali. Per le distribuzioni di produzione, in particolare le distribuzioni in esecuzione in più istanze, usare un provider di archiviazione permanente, ad esempio Azure Cosmos DB o Archiviazione BLOB di Azure. Vedere Usare i provider di archiviazione nell'agente.