Microsoft 365 Agents SDK 中的 AgentApplication

AgentApplication 是使用 Agents SDK 建置之 Agent 的核心建構元素。 AgentApplication 是所有傳入活動的進入點,包括來自使用者的訊息、交談生命週期事件、調適型卡片互動,以及 OAuth 回呼。

Agent 究其核心,本質上是 AgentApplication。 您可以使用描述 Agent 功能的處理常式對其進行設定。 SDK 會處理路由、狀態管理,以及執行所需的基礎結構。

AgentApplication 的運作方式

每個 Agent 都有生命週期,當管道 (Microsoft Teams、 Bot Service 或自訂用戶端) 將活動傳遞至您的 Agent 端點時,該生命週期便會開始。 AgentApplication 位於該生命週期的中心:

Channel → Hosting layer → AgentApplication → Your handlers

使用 Agents SDK 建置之 Agent 中的處理層運作方式如下:

  1. 裝載層會接收 HTTP 要求並加以驗證。
  2. AgentApplication 會透過其管線處理傳入的活動。
  3. 系統會根據相符路由來呼叫處理常式。

您的 Agent 會在處理常式執行前載入回合狀態。 之後,Agent 會儲存回合狀態。

核心概念

活動

Agents SDK 中的所有項目都會以活動的形式流動。 活動是代表所發生事情的結構化訊息。 活動具有類型,例如 message、event、invoke、conversationUpdate 等。 此活動會帶有與該類型相關的裝載內容。 AgentApplication 會接收活動,並將其路由至正確的處理常式。

路線

路由會將選取器處理常式配對。 選取器會判斷路由是否與目前的活動相符。 當路由相符時,處理常式會執行您的邏輯。

設定 Agent 時,請註冊路由。 這些處理常式可以比對下列路由:

  • 包含特定文字或符合規則運算式的訊息
  • 指定類型的任何活動
  • 交談生命週期事件 (新增成員、移除成員)
  • 調適型卡片動作
  • 自訂條件

有活動到達時,系統會依序評估路由,直到找到相符的路由。 根據預設,只會執行一個路由。

回合狀態

AgentApplication 管理 _turn 狀態 — 結構化儲存體已分割成不同範圍:

範圍類型 Description
交談 在交談中的所有使用者之間共用,並在回合之間保存
使用者 範圍限定為所有交談中的個別使用者
暫存 僅限目前回合 - 永不保存

系統在處理常式執行前自動載入狀態,然後自動儲存。

回合內容

處理常式會在執行時接收回合內容。 回合內容是目前活動、配接器連線和回應傳送公用程式的快照集。 回合內容是您與目前互動的介面。

中介軟體

AgentApplication 支援中介軟體管線。 中介軟體是一連串元件,這些元件會在處理常式執行前後處理每個回合。 中介軟體可檢查、轉換活動流程,或讓流程提前結束。 常見用途包括記錄、驗證檢查,以及要求正規化。

建立 Agent

建立 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 中註冊您的 Agent:

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 (最高) Agent 叫用路由
    2 叫用路由 (調適型卡片動作、OAuth 回撥以及其他有時效性的叫用)
    3 Agent 路由
    4 (最低) 所有其他路由
  2. 排名:在每個路由類型群組中,系統會依路由的排名值排序。 數值較低者會優先評估。

註冊處理常式時使用 RouteRank 常數設定順位。

定額 意義
RouteRank.First 0 在群組中的所有其他路由之前進行評估
RouteRank.Unspecified 32767 未指定排名時的預設值
RouteRank.Last 65535 在群組中的所有其他路由之後進行評估

根據預設,評估會在第一個相符的路由處停止。 使用 RouteRank.Last 做為通用後援,處理任何未與更明確路由比對相符的情況。

// 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 時,系統不會儲存回合狀態。

使用回合狀態

Agent 會在處理常式執行前自動載入回合狀態,並在執行後儲存回合狀態。 傳遞至處理常式的回合狀態物件可讓您存取不同的範圍,因而可以讀取和寫入跨回合存續或目前回合中短暫存在的資料:

  • 交談範圍:適用於在交談中所有回合間共用的資料
  • 使用者範圍:適用於個別使用者的資料
  • 暫存範圍:適用於僅需於目前回合期間存在的資料
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。 正式環境部署 (尤其是在多個執行個體上執行的部署),請使用持續性儲存體提供者,例如 Azure Cosmos DB 或 Azure Blob 儲存體。 請參閱在 Agent 中使用儲存體提供者

後續步驟