コンテンツにスキップ

ラボ BMA3 - Microsoft Foundry エージェントと M365 Agents SDK の統合

このラボでは、Microsoft Foundry エージェントの生成 AI パワーと、Microsoft 365 Agents SDK のマルチチャネルの柔軟性を組み合わせ、両者の長所を最大限に活用します。Semantic Kernel を構成し、エージェント プロパティを設定し、Foundry でホストされているエージェントへ安全に接続して、エンタープライズに対応した充実した回答を Microsoft Teams へ直接提供します。

エクササイズ 1: エージェント プロパティの構成と Teams でのテスト

基本的なボットを作成したので、次は生成 AI 機能を追加して AI エージェントへアップグレードします。このエクササイズでは、Semantic Kernel などの主要ライブラリをインストールし、Teams や Copilot Chat でより高度な推論と応答ができるように準備します。

手順 1: Semantic Kernel Nuget パッケージを追加

この手順で追加するパッケージは、Azure AI 連携をサポートします。ContosoHRAgent プロジェクトを右クリックし、Manage Nuget Packages... を選択して Browse タブを開き、Microsoft.SemanticKernel.Agents.AzureAI を検索します。 Include prerelease をチェックし、パッケージを選択して Install をクリックします。

Semantic Kernel Nuget Package

手順 2: Program.cs に Semantic Kernel を追加

Program.cs を開き、var app = builder.Build(); の直前に次のコード スニペットを追加します。

builder.Services.AddKernel();

これにより、生成 AI モデルと連携するためのコア コンポーネントである Semantic Kernel が登録されます。

手順 3: ドキュメント引用とメッセージ追跡用のカスタム クラスを追加

ContosoHRAgent プロジェクトを右クリックし、Add > Class を選択してクラス名を FileReference.cs とします。既存のコードを次の内容に置き換えます。

このクラスは、応答でアップロードされたファイルの内容を引用する際に使用するドキュメント参照の構造を定義します。

using Microsoft.Agents.Core.Models;

namespace ContosoHRAgent
{
    public class FileReference(string fileId, string fileName, string quote, Citation citation)
    {
        public string FileId { get; set; } = fileId;
        public string FileName { get; set; } = fileName;
        public string Quote { get; set; } = quote;
        public Citation Citation { get; set; } = citation;
    }
}

再度 ContosoHRAgent プロジェクトを右クリックし、Add > Class を選択してクラス名を ConversationStateExtensions.cs とします。既存のコードを次の内容に置き換えます。

このクラスは、進行中の会話でユーザー メッセージ数を管理・追跡するヘルパー メソッドを追加し、状態の保存と更新方法を示します。

using Microsoft.Agents.Builder.State;

namespace ContosoHRAgent
{
 public static class ConversationStateExtensions
 {
     public static int MessageCount(this ConversationState state) => state.GetValue<int>("countKey");

     public static void MessageCount(this ConversationState state, int value) => state.SetValue("countKey", value);

     public static int IncrementMessageCount(this ConversationState state)
     {
         int count = state.GetValue<int>("countKey");
         state.SetValue("countKey", ++count);
         return count;
     }

     public static string ThreadId(this ConversationState state) => state.GetValue<string>("threadId");

     public static void ThreadId(this ConversationState state, string value) => state.SetValue("threadId", value);
 }
}

エクササイズ 2: Microsoft Foundry エージェントを M365 Agents SDK と統合

M365 Agents SDK を使ってエージェントを構築し、生成 AI 機能で構成しました。次は、このローカル エージェントを先に作成した Microsoft Foundry エージェントへ接続します。これにより、Foundry プロジェクトに保存されたエンタープライズ データと指示を用いて応答できるようになり、すべてが一体化します。

手順 1: EchoBot.cs を構成して Microsoft Foundry エージェントへ接続

この手順では、EchoBot.cs 内で Foundry でホストされているモデルを取得・呼び出すクライアントを追加し、Microsoft Foundry エージェントへ接続します。

ContosoHRAgent プロジェクトで Bot/EchoBot.cs を開き、EchoBot パブリック クラス内に次の行を追加します。

private readonly PersistentAgentsClient _projectClient;
private readonly string _agentId;

既存の EchoBot コンストラクターを次の内容に置き換えます。

public EchoBot(AgentApplicationOptions options, IConfiguration configuration) : base(options)
{

    OnConversationUpdate(ConversationUpdateEvents.MembersAdded, WelcomeMessageAsync);

    // Listen for ANY message to be received. MUST BE AFTER ANY OTHER MESSAGE HANDLERS 
    OnActivity(ActivityTypes.Message, OnMessageAsync);

    // Microsoft Foundry Project ConnectionString
    string projectEndpoint = configuration["AIServices:ProjectEndpoint"];
    if (string.IsNullOrEmpty(projectEndpoint))
    {
        throw new InvalidOperationException("ProjectEndpoint is not configured.");
    }
    _projectClient = new PersistentAgentsClient(projectEndpoint, new AzureCliCredential());

    // Microsoft Foundry Agent Id
    _agentId = configuration["AIServices:AgentID"];
    if (string.IsNullOrEmpty(_agentId))
    {
        throw new InvalidOperationException("AgentID is not configured.");
    }

}

OnMessageAsync メソッドを次の内容に置き換えます。

protected async Task OnMessageAsync(ITurnContext turnContext, ITurnState turnState, CancellationToken cancellationToken)
{
    // send the initial message to the user
    await turnContext.StreamingResponse.QueueInformativeUpdateAsync("Working on it...", cancellationToken);

    // get the agent definition from the project
    var agentDefinition = await _projectClient.Administration.GetAgentAsync(_agentId, cancellationToken);

    // initialize a new agent instance from the agent definition
    var agent = new AzureAIAgent(agentDefinition, _projectClient);

    // retrieve the threadId from the conversation state
    // this is set if the agent has been invoked before in the same conversation
    var threadId = turnState.Conversation.ThreadId();

    // if the threadId is not set, we create a new thread
    // otherwise, we use the existing thread
    var thread = string.IsNullOrEmpty(threadId)
        ? new AzureAIAgentThread(_projectClient)
        : new AzureAIAgentThread(_projectClient, threadId);

    try
    {
        // increment the message count in state and queue the count to the user
        int count = turnState.Conversation.IncrementMessageCount();
        turnContext.StreamingResponse.QueueTextChunk($"({count}) ");

        // create the user message to send to the agent
        var message = new ChatMessageContent(AuthorRole.User, turnContext.Activity.Text);

        // invoke the agent and stream the responses to the user
        await foreach (AgentResponseItem<StreamingChatMessageContent> agentResponse in agent.InvokeStreamingAsync(message, thread, cancellationToken: cancellationToken))
        {
            // if the threadId is not set, we set it from the agent response
            // and store it in the conversation state for future use
            if (string.IsNullOrEmpty(threadId))
            {
                threadId = agentResponse.Thread.Id;
                turnState.Conversation.ThreadId(threadId);
            }

            turnContext.StreamingResponse.QueueTextChunk(agentResponse.Message.Content);
        }
    }
    finally
    {
        // ensure we end the streaming response
        await turnContext.StreamingResponse.EndStreamAsync(cancellationToken);
    }
}

⚠️ 注意: 以下のコードを貼り付けると、プレビュー機能のため警告 (SKEXP0110) が表示される場合があります。現時点では安全に無視できます。AzureAIAgent を右クリックし、Quick Actions and Refactorings > Suppress or configure issues > Configure SKEXP0110 Severity > Silent を選択して警告を抑制してください。

The Warning provided by Visual Studio when pasting code about a preview feature. There is the SKEXP0110 warning highlighted and the commands to silent related notifications.

OnMessageAsync では何が起きるのですか?

OnMessageAsync メソッドは、エージェントの応答ロジックの中心です。既定のエコー動作を置き換えることで、ユーザー メッセージを Microsoft Foundry エージェントへ送信し、リアルタイムでストリーミングされた応答をユーザーへ返し、透過性のために引用情報とファイル参照を追跡・添付し、さらに機密度や AI 生成ラベルを追加してセキュリティとトレーサビリティを確保します。

手順 2: Azure AI Agent Service キーを構成

Foundry 接続情報を appsettings.json に追加します。これらの値は、M365 エージェントを正しい Foundry プロジェクトとエージェントに接続します。ContosoHRAgent プロジェクトで appsettings.json を開き、設定リストの末尾に次の行を追加します。

,
  "AIServices": {
   "AgentID": "<AzureAIFoundryAgentId>",
   "ProjectEndpoint": "<ProjectEndpoint>"
  }

これらの値は Microsoft Foundry の OverviewAgents Playground セクションで確認できます。

<AzureAIFoundryAgentId>Agents Playground にある Agent id で置き換えます。

The Agents Playground of Microsoft Foundry with the Agent id field highlighted.

<ProjectEndpoint> を AI Foundry の Overview ページ、Endpoints and keys の ProjectEndpoint で置き換えます。

最終的な appsettings.json は次のようになります。

{
  "AgentApplicationOptions": {
    "StartTypingTimer": false,
    "RemoveRecipientMention": false,
    "NormalizeMentions": false
  },

  "TokenValidation": {
    "Audiences": [
      "{{ClientId}}" // this is the Client ID used for the Azure Bot
    ]
  },

  "Logging": {
    "LogLevel": {
      "Default": "Information",
      "Microsoft.AspNetCore": "Warning",
      "Microsoft.Agents": "Warning",
      "Microsoft.Hosting.Lifetime": "Information"
    }
  },
  "AllowedHosts": "*",
  "Connections": {
    "BotServiceConnection": {
      "Settings": {
        "AuthType": "UserManagedIdentity", // this is the AuthType for the connection, valid values can be found in Microsoft.Agents.Authentication.Msal.Model.AuthTypes.
        "ClientId": "{{BOT_ID}}", // this is the Client ID used for the connection.
        "TenantId": "{{BOT_TENANT_ID}}",
        "Scopes": [
          "https://api.botframework.com/.default"
        ]
      }
    }
  },
  "ConnectionsMap": [
    {
      "ServiceUrl": "*",
      "Connection": "BotServiceConnection"
    }
  ],
  "AIServices": {
   "AgentID": "<AzureAIFoundryAgentId>",
   "ProjectEndpoint": "<ProjectEndpoint>"
  }
}

手順 3: Teams でエージェントをテスト

Tools > Command Line > Developer Command Prompt を開き、次を実行します。

az login

ブラウザー ウィンドウが開き、Microsoft アカウントでサインインして az login を完了する必要があります。

Start を展開し、Dev Tunnels > Create a Tunnel を選択します:

  • Sign inWork or school account を選択し、上記と同じ資格情報でログインします。
  • トンネル名に DevTunnel などを入力します。
  • Tunnel Type は Temporary のままにします。
  • Access を Public に設定し、Create を選択します。

The UI of Visual Studio to create a Dev Tunnel for the agent. There is a "Create a Tunnel" command highlighted.

M365Agent プロジェクトを右クリックし、Microsoft 365 Agents Toolkit > Select Microsoft 365 Account を選択します。

The context menu of the the M365 Agents Toolkit when selecting the Microsoft 365 Account to use, highlighted in the screenshot.

同じアカウントを選択して Continue をクリックします。表示されない場合は Sign inWork or school account を選択してください。

Visual Studio 上部のスタートアップ項目 ( が既定) を展開し、Microsoft Teams (browser) を選択します。

The UI of Visual Studio when configuring Microsoft Teams (browser) for testing the agent in debug mode.

これで統合済みエージェントを実行し、Microsoft Teams でライブ テストする準備が整いました。Dev Tunnel が作成され、アカウントが認証済みであることを確認してください。

Dev Tunnel が作成できたら Start または F5 を押してデバッグを開始します。Microsoft Teams が自動的に起動し、エージェント アプリが表示されます。AddOpen を選択してチャットを開始してください。

以下のような質問をしてエージェントと対話できます。

  • Northwind Standard と Health Plus の緊急・メンタルヘルス保険の違いは何ですか?
  • PerksPlus を利用してロッククライミング クラスとバーチャル フィットネス プログラムの両方を支払えますか?
  • Contoso Electronics の行動と意思決定を導くバリューは何ですか?

Microsoft Foundry で作成したエージェントと同様の応答が得られるはずです。

The Agent running in Microsoft Teams with evidence of the counter to count the number of interactions with the user.

おめでとうございます!

ラボ BMA3 - Microsoft Foundry エージェントと M365 Agents SDK の統合 を完了しました!

次のラボ BMA4 - エージェントを Copilot Chat へ展開 に進む準備ができました。Next を選択してください。