メインコンテンツへスキップ
見出し画像

【宣言型エージェントの構築 #0094】Copilot Developer Camp (Vol.20) :Microsoft Foundry Agent と M365 Agents SDK の統合

    記事を読みにご訪問いただきありがとうございます。

    今回は、Microsoft Foundry エージェントの生成AI と Microsoft 365 Agents SDK のマルチチャネルを統合する手順を説明します。
    ※元記事は、以下になりますので、必要時ご参照ください。


    エージェントプロパティの設定と Teams でのテスト

    ここでは、Microsoft Foundry エージェントの生成AI能力と、Microsoft 365 Agents SDK のマルチチャネル対応を組み合わせます。Semantic Kernel やエージェント設定を行い、Foundry ホストと安全に接続することで、Microsoft Teams 上で高度でエンタープライズ向けの回答を提供できるようにします。

    エージェントプロパティの設定とTeamsでのテスト

    基本的なボットを作成した後、生成AI機能を追加して AI エージェントへ強化します。そのために Semantic Kernel などの重要ライブラリを導入し、より高度な推論と応答ができるよう準備し、Teams や Copilot Chat に対応できる状態にします。

    • ソリューションエクスプローラーから「ContosoHRAgent」プロジェクトを選択し、右クリック

    • 表示されたメニューから「Nuget Packageの管理」を選択

    • 上部メニューから「参照」を選択し、「検索欄」には、「Microsoft.SemanticKernel.Agents.AzureAI」を入力し、「プレリリースを含める」をチェック

    • 表示された一覧から選択し、右側の「インストール」ボタンを選択

    画像
    図:パッケージのインストール

    Program.cs にセマンティックカーネルを追加

    • var app = builder の直前に「builder.Services.AddKernel(); 」を追加

    画像
    図:セマンティックカーネル登録

    文書引用とメッセージトラッキング用のカスタムクラスを追加

    • ContosoHRAgent プロジェクトを選択し、右クリック

    • 表示されたメニューから「追加」「クラス」を選択

    • 名前を「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;
        }
    }

    同様の手順で「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);
     }
    }

    Microsoft Foundry AgentをM365エージェントSDKと統合

    ここからは、Microsoft Foundry エージェントに接続する手順を説明していきます。

    Microsoft Foundry Agent との接続

    • Bot/EchoBot.cs ファイルを開き、クラス内に以下のコードを追加

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

    コード貼り付け後にエラー表示される場合がありますが、以下の手順で操作します。
    「AzureAIAgent」を選択し、右クリックし、「クイックアクションとリファクタリング」「問題を抑制または構成」「SKEXP0110の重要度の構成」「サイレント」を選択

    Azure AIエージェントサービスキーの設定

    • appsettings.json ファイル開く

    • 以下のコードを下部に追加

    ,
      "AIServices": {
       "AgentID": "<AzureAIFoundryAgentId>",
       "ProjectEndpoint": "<ProjectEndpoint>"
      }
    • 上記コードは、以下画像を参考に置換

    画像
    図:エージェントID 確認

    Teamsでエージェントをテストする

    • 上部メニューから「ツール」「コマンドライン」「開発者コマンドプロンプト」を選択

    az login
    • 上部メニューから「Microsoft 365 Agents Playground」「Dev Tunnels」「トンネルを作成」を選択

    画像
    図:新規トンネル作成
    • 名前:DevTunnel、種類:一時的、アクセス:公開を選択し、「OK」ボタンを選択

    • M365Agent プロジェクト を選択し、「Teams ツールキット」「Microsoft 365 アカウント」を選択

    • 表示されたダイアログから、前回のアカウントを選択、「続行」ボタンを選択

    • 上部メニューから「ContosoHRAgent」「Microsoft Teams (browser) 」を選択し、「実行」アイコン選択

    画像
    図:実行処理選択
    • ブラウザー表示後、ダイアログ表示されるので「追加」ボタンを選択し、エージェントを追加

    • 追加完了後、「開く」ボタン選択

    • 以下のプロンプトで動作確認
      「緊急およびメンタルヘルス補償に関して、ノースウィンド・スタンダードとヘルスプラスの違いは何ですか?」
      「PerksPlusを使ってロッククライミングのクラスとバーチャルフィットネスプログラムの両方に支払うことはできますか?」

    画像
    図:動作結果

     MSAL:invalid_client / AADSTS7000229
    上記エラー発生した場合は、API のアクセス権が設定されていない場合が多いです。その場合は、Entra ID から API アクセス権限の設定を行ってください。


    今回の記事では、Microsoft Foundry Agent の生成 AI 能力と、Microsoft 365 Agents SDK のマルチチャネル対応を統合するための手順を解説しました。
    Semantic Kernel の導入、Foundry との安全な接続設定、会話状態管理クラスの実装、そして Teams (ブラウザー) 上での動作確認まで、一連の流れを実際のプロジェクト構成に沿って進めてきました。

    Microsoft Foundry Agent と M365 Agents SDK を統合することで、エンタープライズ向けの高度な AI エージェントを、Teams や Copilot Chat などの複数チャネルから活用できる環境が整います。これにより、ユーザー体験の向上だけでなく、アプリケーション開発者にとっても 統一した API と運用モデルによる大幅な効率化が期待できます。

    引き続き、Copilot Developer Camp シリーズをお楽しみください。

    今回も記事を読んでいただきありがとうございました。



     
     
    「技術者のバイブル:Microsoft Learn」を軸に学習法・活用法・最新情報を発信。メンバーシップでは市民開発者に伴走し、認定資格取得と業務活用を支援。記事は MS Learn 情報を元に投稿していますが、更新頻度が高いため、内容の変更点や鮮度にご注意ください。