0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

セルフホスト版 Dify と Snowflake Cortex Agents を Microsoft Agent 365 で統合管理・監視する

0
Last updated at Posted at 2026-07-11

複数プラットフォーム時代のエージェント統合管理という課題

 近年,Dify や Snowflake Cortex Agents をはじめ,複数のプラットフォームでAIエージェントを構築する機会が急速に増えている.その結果,組織としては,これらを横断的に管理・監視し,ガバナンスを効かせていくことが急務になりつつある.

 各プラットフォームの内部には,それぞれ独自の管理・監視機能が備わっている場合もある.しかしながら,複数プラットフォームを横断した統合的な監視となると,それを実現できるサービスは限られる.とりわけ,セルフホスト版の Dify をネイティブに監視できるサービスは,2026年6〜7月現在,私の知る限り存在しない.

 そこで本記事では,2026年5月に一般提供(GA)が開始された Microsoft Agent 365(以後 Agent 365)による統合監視に着目する[1][2].ただし,Agent 365 が外部プラットフォームとして対応しているのは,2026年6〜7月時点で AWS Bedrock,Google Cloud Vertex AI,Databricks Genie,Salesforce Agentforce の4つに限られる.このうち前者2つ(Bedrock と Vertex AI)については,公式ドキュメントでも取り込みが説明されており,かなり簡易な手順で Agent 365 の管理下に置けることを確認できた[3].一方で,本稿で主眼とするセルフホスト版 Dify については,将来的な公式対応も不透明であるため,Agent 365 SDK を用いて管理できるかどうかを実際に試みた.なお,Snowflake Cortex Agents については,比較的近いうちに公式対応がなされるのではないかと予想しているが,現時点では同じく SDK を用いたアプローチをとった.

 以上を踏まえ,本稿では,Agent 365 を用いて外部プラットフォーム製のエージェントを管理・監視下に置く実践的な方法について述べる.はじめに Agent 365 の位置づけと,公式対応済みプラットフォーム(Bedrock・Vertex AI)の簡易な取り込み手順を示す.次に,公式対応がない Dify・Cortex Agents を取り込むための「アダプタ方式」という設計を説明し,両者に共通する構成と,バックエンドごとに異なる実装上の勘所を整理する.最後にデプロイと動作確認,そして考察(限界を含む)をまとめる.なお,本稿の実装は次のリポジトリで公開している[18][19].

 本稿の内容は限られた検証環境での実装経験に基づいており,Agent 365 および各バックエンドのAPIは更新が続いているため,適用にあたっては最新の一次情報での確認が望ましい.

横断的な監視を担う既存サービス(Datadog・Dataiku)

 複数プラットフォームを横断したエージェントの監視・統制については,Agent 365 以外にも取り組んでいるサービスがある.代表的な例として Datadog と Dataiku を取り上げ,それぞれの方式と,本稿の対象であるセルフホスト版 Dify との関係を整理する.なお,各サービスの機能は更新が続いているため,詳細は一次情報での確認が望ましい.

Datadog

 Datadog は,LLM Observability の一環として Agent Observability(AIエージェントの可観測性)を提供している[15].OpenAI,Anthropic,Gemini,Vertex AI,LangChain,CrewAI,Bedrock,LiteLLM など,主要なモデル・エージェントフレームワークに対応し,開発から本番までを同一のトレーサで計装できる点が特徴である.さらに,2025年6月には,社内製・サードパーティ製の双方のエージェントを横断して可視化・統制する「AI Agents Console」がプレビューとして発表されている[16].

 一方で,これらは基本的に計装(トレーシング)を前提とする方式であり,対応フレームワークの一覧に Dify は明示されていない[15].したがって,セルフホスト版 Dify を対象とする場合には,OpenTelemetry などによる計装を自前で施す必要があると考えられる.

Dataiku

 Dataiku は,LLM Mesh と呼ばれるゲートウェイ層を提供している[17].これは,多様なLLMプロバイダやセルフホストのモデルへの接続を,安全でプロバイダ非依存のゲートウェイに集約し,ルーティング・スクリーニング・モデレーション・コスト追跡・監査を一元的に行うものである.利用状況や応答性能をリアルタイムに監視できる点も示されている[17].

 ただし,これはLLM トラフィックをゲートウェイ経由に集約するという前提の統制であり,エージェント個々の振る舞いというよりは,LLM 利用の入口を統制する性格が強い.Dify の内部で用いるモデル呼び出しをこのゲートウェイに寄せれば統制対象にできるが,Dify アプリそのものをネイティブに監視するものではないと考えられる.

本稿の位置づけ

 以上より,横断的な監視という観点では既に有力なサービスが存在する.しかしながら,(1) セルフホスト版 Dify を追加計装なしにそのまま監視する,(2) Microsoft Entra のID・Teams・M365 と一体で統制する[1][3],という2点においては,Agent 365 に固有の利点があると考えられる.どのサービスを採るかは,既存の監視基盤(Datadog 等の採用有無)や,統制の力点(LLM ゲートウェイか,M365 ネイティブか)によって判断することが望ましい.

Agent 365 とは

 Agent 365 は,2025年11月の Microsoft Ignite で発表され,2026年5月に一般提供が開始された,AIエージェントの「コントロールプレーン(管理基盤)」である[1][2].組織内のエージェントを観測(Observe)・統制(Govern)・保護(Secure)することを目的とし,レジストリ(インベントリ)・アクセス制御・可視化・相互運用・セキュリティといった機能を備える[2].Microsoft 製・オープンソース・サードパーティのいずれで作られたエージェントも管理対象にできる点が特徴である[1][3].

 一方で,開発不要で自動的に取り込める外部プラットフォームは限られている.そのため,公式対応のないプラットフォームを管理下に置くには,後述のとおり Agent 365 SDK による橋渡しの実装が別途必要になる[3][4].

参考:Bedrock / Vertex AI の取り込み(簡易手順)

 まず比較のために,公式対応済みである Amazon Bedrock と Google Cloud Vertex AI の取り込みについて簡単に触れる.公式ドキュメント「既存エージェントを Microsoft Agent 365 に接続する」によれば,これら2つのエージェントは,Agent 365 のレジストリに同期することで,一元的な可視化とガバナンスの対象にできる[3].すなわち,各社(Amazon / Google Cloud)のAPI経由でエージェントを同期でき,作り込みを伴わずに取り込める.

 手順の概要は次のとおりである[3].

  1. 事前準備:AWS / Google Cloud 側で必要な権限 に従い,必要な権限を付与したアクセスキーを発行する.
  2. Microsoft 365 管理センター(Agent 365)で,対象プロバイダ(Vertex AI もしくは Bedrock)への接続・APIアクセスを構成する.
  3. 構成後,各社のエージェントを Agent 365 のレジストリへ同期する.
  4. 登録後は,必要に応じて Agent 365 SDK を用いて,可観測性や Work IQ ツールアクセスなどの機能を段階的に付与できる[3][4].

 このように,Bedrock・Vertex AI については,コードを書くことなくレジストリへの登録まで到達できる[3].コンソール上の正確な操作手順は環境・時期により異なるため,最新の一次情報での確認が望ましい[3].

image.png

image.png

image.png

事前準備:AWS / Google Cloud 側で必要な権限

 Bedrock・Vertex AI を Agent 365 のレジストリへ同期するには,Agent 365 側の接続構成に加えて,各クラウド側で Agent 365 が読み取りに用いる資格情報と権限を用意しておく必要がある.基本的な考え方は,「エージェントの一覧・詳細を読み取れる最小権限のプリンシパル」を用意し,その資格情報を Microsoft 365 管理センターの接続設定に登録する,というものである.以下に,それぞれの構成例を示す.なお,必要な権限セットはコネクタの更新に伴い変わりうるため,最新の一次情報での確認が望ましい[3].

AWS Bedrock 側の設定

 AWS 側では,Agent 365 コネクタ専用の IAM プリンシパル(IAM ユーザーのアクセスキー,もしくは IAM ロール)を作成し,Bedrock のエージェント情報を読み取る権限を付与する.同期は読み取りのみで完結するため,書き込み系の権限は不要である.最小権限のポリシー例は次のとおりである.

{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Sid": "Agent365BedrockSync",
      "Effect": "Allow",
      "Action": [
        "bedrock:ListAgents",
        "bedrock:GetAgent",
        "bedrock:ListAgentAliases",
        "bedrock:GetAgentAlias",
        "bedrock:ListAgentVersions",
        "bedrock:ListTagsForResource"
      ],
      "Resource": "*"
    }
  ]
}

 各アクションの意図は次のとおりである.

アクション 用途
bedrock:ListAgents アカウント内のエージェント一覧の取得(インベントリ同期の起点)
bedrock:GetAgent エージェントの詳細(名前・説明・状態など)の取得
bedrock:ListAgentAliases / bedrock:GetAgentAlias 呼び出し先となるエイリアス情報の取得
bedrock:ListAgentVersions バージョン情報の取得
bedrock:ListTagsForResource タグをレジストリ上のメタデータとして反映する場合に使用

 簡便には AWS 管理ポリシー AmazonBedrockReadOnly を付与する方法もあるが,これはエージェント以外の Bedrock リソース(モデル・ナレッジベース等)の読み取りも含むため,統制の観点では上記のようなカスタムポリシーで絞ることを推奨する.

  • リージョン:Bedrock のエージェントはリージョン単位のリソースであるため,接続構成で対象リージョンを正しく指定する(複数リージョンで運用している場合は接続を分ける).
  • クロスアカウント:複数の AWS アカウントを対象とする場合,アカウントごとにプリンシパルを用意するか,AssumeRole 構成が取れるかをコネクタの仕様で確認する.
  • キーのローテーション:IAM ユーザーのアクセスキーを用いる場合は,ローテーション方針を定めておく.

Google Cloud Vertex AI 側の設定

 Google Cloud 側では,まず対象プロジェクトで Vertex AI API(aiplatform.googleapis.com)を有効化したうえで,Agent 365 コネクタ用のサービスアカウントを作成し,JSON キーを発行して接続設定に登録する.権限としては,Vertex AI のエージェント(Agent Engine,リソース種別としては Reasoning Engine)を読み取れるロールが必要である.

 最も簡便なのは,事前定義ロールの roles/aiplatform.viewer(Vertex AI 閲覧者) をプロジェクトに対して付与する方法である.より最小権限に寄せる場合は,次の権限を含むカスタムロールを作成する.

aiplatform.reasoningEngines.list
aiplatform.reasoningEngines.get
resourcemanager.projects.get

 各権限の意図は次のとおりである.

権限 用途
aiplatform.reasoningEngines.list プロジェクト内のエージェント一覧の取得
aiplatform.reasoningEngines.get エージェントの詳細(表示名・説明など)の取得
resourcemanager.projects.get 接続検証時のプロジェクト情報の参照

 カスタムロールの作成と付与は,例えば次のように行える.

# カスタムロールの作成
gcloud iam roles create agent365Sync \
  --project=PROJECT_ID \
  --title="Agent365 Sync" \
  --permissions=aiplatform.reasoningEngines.list,aiplatform.reasoningEngines.get,resourcemanager.projects.get

# サービスアカウントへの付与
gcloud projects add-iam-policy-binding PROJECT_ID \
  --member="serviceAccount:agent365-sync@PROJECT_ID.iam.gserviceaccount.com" \
  --role="projects/PROJECT_ID/roles/agent365Sync"
  • ロケーション:Agent Engine はロケーション(us-central1 等)単位のリソースであるため,接続構成で対象ロケーションを指定する.
  • サービスアカウントキーの管理:JSON キーは長期資格情報であるため,組織ポリシーでキー発行を制限している場合は例外申請が必要になる.キーのローテーション方針も定めておく.
  • Dialogflow / Agentspace 系のエージェント:会話型エージェントを Conversational Agents(Dialogflow)側で構築している場合,上記とは別に roles/dialogflow.reader 相当の権限が必要になる可能性がある.

image.png

アダプタ方式という設計

 本記事で扱う Dify や Cortex Agents は,この自動取り込みの対象外である.そのため,以降で述べるアダプタ方式を用いる.

なぜ外部エージェントは「見えない」のか

 「管理」を分解すると,可視化・ID付与・監査ログ・アクセス制御・ライフサイクル管理といった機能に整理できる.Dify も Cortex Agents もそれぞれ内部にこれらの一部の機能を持つが,その情報は各システム内部に閉じており,Agent 365 とはつながっていない.したがって,両者を結ぶ橋渡しの層を用意しない限り,Agent 365 の管理コンソール上には現れない[3].

アダプタ方式

 Agent 365 SDK は,エージェントを新たに「作る」ためのものではなく,既にあるエージェントに Entra ベースのID・OpenTelemetry による可観測性・通知・M365 へのアクセスを「後付け」する拡張層である[3][4].しかし,Dify も Cortex Agents もセルフホストないしSaaSの別サービスであり,その内部ランタイムに SDK を直接組み込むことは想定されていない.

 そこで本稿では,次の構成をとる.すなわち,Agent 365 SDK で計装した薄い「アダプタ・エージェント」を1つ用意し,その中から Dify や Cortex Agents のAPIを呼び出すという方式である(以後アダプタ方式).このアダプタが Agent 365 の管理対象となり,実際の推論は Dify や Cortex Agents がバックエンドとして担う.これにより,バックエンドを無改造のまま,レジストリへの登録・監査・アクセス制御の対象にできる[3].アダプタの実装は,公式の Python サンプルの構成に沿っている[5][7].

Teams / M365
     │
Azure Bot Service(Teams チャンネル)
     │  Bot Framework Activity Protocol
Azure App Service(アダプタ・エージェント / Python)
     ├─→ バックエンド(Dify もしくは Snowflake Cortex Agents)
     └─→ Agent 365 Observability(セッション追跡)
Microsoft 365 管理センター(Agent 365 ダッシュボード)

共通の土台:Agent 365 側の構成

 Dify であっても Cortex Agents であっても,Agent 365 側の構成は共通である.ここでの勘所は,実際の検証で最も苦戦した点でもある.なお,エージェントのセットアップや公開の一連の流れは,Agent 365 の SDK・CLI に沿って行う[4][6].

2つの Azure Entra ID アプリ

 最初に押さえるべき点は,Azure Entra ID アプリを2つに分けることである.Agent 365 が発行する Blueprint アプリは「Agentic Application」であり,Bot Framework Connector への app-only トークン取得が制限される(AADSTS82001).そのため,役割を次の2つに分離する必要がある.Agent 365 SDK が用いる ID モデルの詳細は開発者ドキュメントを参照していただきたい[4].

アプリ 役割 使う場所
① Blueprint(Agentic) Agent 365 登録・可観測性 observability 認証
② Bot Identity(通常) Bot Framework 送受信 Bot 認証・Teams マニフェストの botId

 この分離を怠ると,AADSTS82001 によるエラーや,後述のセッション未計測につながる.

Azure Bot Service と Teams

 Teams から利用するには,Bot Identity アプリを用いて Azure Bot Service を作成し,Teams チャンネルを有効化する必要がある[8].これを作成していないと,Teams 側で「無効なボット」と表示される.実際,Teams のドキュメントでも,Bot Framework 経由の Azure Bot は Teams アプリに接続されていないとチャットできない旨が示されている[9].加えて,Teams アプリパッケージ(manifest とアイコン)を作成してサイドロードする[9][10].マニフェストの botId には Bot Identity アプリのIDを用いる[10].

image.png

image.png

可観測性(セッション計測)

 Agent 365 のダッシュボードでアクティブユーザー数やセッション数を計上するには,可観測性の認証を Blueprint アプリ側に分離する必要がある.Bot 認証(Bot Identity)の資格情報で observability を送信しようとすると,メトリクスが増えない.具体的には,Blueprint アプリの資格情報で MSAL のトークンを取得し,可観測性の configure(...) に渡す形をとる.可観測性の初期化は,公式サンプルの計装コードに準じている[4][5].

Dify を管理する

呼び出し

 Dify 側は,対象アプリをチャットもしくはエージェント型で用意する.ワークフロー型は /v1/chat-messages エンドポイントを持たないため,本方式には適さない.アダプタからは Dify のチャットAPIを呼び出し,ユーザーごとに conversation_id を保持して会話を継続させる(Dify の API 仕様は公式ドキュメントを参照)[12].

url = f"{DIFY_BASE_URL}/chat-messages"   # DIFY_BASE_URL は /v1 込みにし,重複させない
headers = {"Authorization": f"Bearer {DIFY_API_KEY}"}
payload = {
    "query": user_text, "user": user_id, "inputs": {},
    "response_mode": "blocking", "conversation_id": conv_id,
}

つまずき(Dify)

  • 環境変数 DIFY_BASE_URL/v1 を含める運用にしたため,コード側では /chat-messages のみを結合し,/v1 の重複を避けた.
  • Dify アプリがワークフロー型の場合,not_chat_app などのエラーになる.チャット型のアプリを用意することで解消した[12].

 実装の詳細は https://github.com/mshdtksk/agents365-dify-public を参照していただきたい[18].

image.png

image.png

image.png

image.png

image.png

image.png

Snowflake Cortex Agents を管理する

 Dify に続き,同じアダプタ方式で Snowflake Cortex Agents(以後 Cortex Agents)を管理対象とした.呼び出し方はバックエンド固有であり,Dify とは大きく異なる.エンドポイントの仕様は Snowflake の公式ドキュメントに基づく[13].なお,Connector を用いた呼び出しの具体については,過去の記事も参照している[14].

呼び出し(Connector → セッショントークン → :run → SSE)

 Cortex Agents は,Snowflake Python Connector で接続してセッショントークンを取得し,エージェント固有のREST エンドポイントを呼び出す方式が要点である.公式ドキュメントにおいても,エージェントのRESTは /api/v2/databases/{database}/schemas/{schema}/agents/... の形で定義されている[13].汎用エンドポイントではエージェントの設定が無視され,単なるLLM呼び出しになってしまうため,.../agents/{AGENT}:run の形を用いる必要がある.

import os, json, re, requests, snowflake.connector

def run_cortex(message: str) -> str:
    conn = snowflake.connector.connect(
        user=os.environ["SNOWFLAKE_USER"],
        password=os.environ["SNOWFLAKE_PASSWORD"],   # プレースホルダ.実値は環境変数で
        account=os.environ["SNOWFLAKE_ACCOUNT"],
        database=os.environ["SNOWFLAKE_DATABASE"],
        schema=os.environ["SNOWFLAKE_SCHEMA"],
        role=os.environ["SNOWFLAKE_ROLE"],
        warehouse=os.environ["SNOWFLAKE_WAREHOUSE"])
    try:
        token = conn.rest.token           # 接続を閉じる前に使う
        db, sc, ag = os.environ["SNOWFLAKE_CORTEX_AGENT"].split(".")
        url = (f"https://{os.environ['SNOWFLAKE_ACCOUNT']}"
               f".snowflakecomputing.com/api/v2/databases/{db}"
               f"/schemas/{sc}/agents/{ag}:run")
        headers = {
            "Authorization": f'Snowflake Token="{token}"',
            "Content-Type": "application/json; charset=utf-8",
            "Accept": "text/event-stream",
        }
        body = {"messages": [{"role": "user",
                 "content": [{"type": "text", "text": message}]}]}
        res = requests.post(url, headers=headers, json=body, timeout=120)
        res.raise_for_status()
        return parse_sse(res.text)        # SSE を解析して最終テキストを得る
    finally:
        conn.close()

 応答は SSE(Server-Sent Events)形式で返るため,data: 行を解析して最終的なテキストを組み立てる[13].累積型と差分型のイベントが混在しうるため重複を吸収し,UTF-8 でデコードする.また,応答先頭に混じるモデルの内部メタ(No tool needed 等)は正規表現で除去した.

管理コマンド

 「管理」の観点では,チャット内でエージェントを一覧・切替できるようにした.一覧は SHOW AGENTS IN SCHEMA で取得する.

コマンド 動作
/agents/list-agents スキーマ内のエージェント一覧を表示
/agent <DB.SCHEMA.AGENT> 使用エージェントをユーザー単位で切替
/reset/clear/new 会話をリセット

つまずき(Cortex)

  • 検証環境の httpx1.0.dev 系であり,従来のAPI(AsyncClient など)と非互換であった.そのため,呼び出し層を requests ベースに切り替えて安定動作させた.
  • 応答が空になる事象が発生した.原因は conn.close() の後にセッショントークンが失効することであり,接続を開いたままRESTを呼び出すことで解消した.
  • 汎用エンドポイントを用いるとエージェント設定が反映されないため,前述のとおりエージェント固有の :run を用いた[13].

 実装の詳細は https://github.com/mshdtksk/agents365-snowflake-public を参照していただきたい[19].

デプロイ

 アダプタは Azure App Service(Linux, Python 3.11)にデプロイした[11].ここでも実装とは別のつまずきがあった.

  • requirements.txt を依存解決ツールの出力(約77行の固定版)のまま用いると,B1 プランの Oryx ビルドがタイムアウトした.そのため,宣言的な最小セットに絞り直した.
  • ZIP デプロイがルートに展開されず起動に失敗する事象があったため,SCM_DO_BUILD_DURING_DEPLOYMENT=true を設定し,az webapp up でデプロイした[11].
  • az webapp up が「Site failed to start」を返すことがあったが,/api/health200 を返していれば実際には起動できていた.Azure 側の health 判定による誤タイムアウトである.
az webapp up -g <resource-group> -n <app-name> --runtime PYTHON:3.11
curl https://<app-name>.azurewebsites.net/api/health   # {"status":"ok"}

 なお,秘匿情報(Dify の API キー,Snowflake のユーザー・パスワード・アカウント識別子など)は,コードやZIPに含めず,App Service の設定にのみ置くようにした.本稿中の <...> はすべてプレースホルダである.

動作確認

 ローカルおよびデプロイ環境で,次の動作を確認した.

  • Cortex Agents: /agents によるエージェント一覧の取得,/agent による切替,通常質問に対する日本語での応答(例として,経路最適化を担うエージェントが訪問順・距離・地図リンクを案内する応答を確認した).
  • Dify: Teams からのメッセージ送信に対する Dify の応答.
  • 共通: /api/health{"status":"ok"} を返し,ルートパス /404 となる(Bot のバックエンドであるため,これは正常である).

image.png

image.png

まとめと考察

 本記事では,Agent 365 を用いて,セルフホスト版 Dify と Snowflake Cortex Agents を統合的に管理・監視下に置く方法について述べた.前提として,Agent 365 が開発不要で取り込める外部プラットフォームは,私の理解では2026年6〜7月時点で4つに限られ,Dify や Cortex Agents はその対象外である[3].そこで,公式対応のない両者に対しては,Agent 365 SDK で計装したアダプタからバックエンドを呼ぶ「アダプタ方式」をとった[3][4].

 両者に共通する要点として,(1) アダプタ方式をとること,(2) Azure Entra ID アプリを Blueprint と Bot Identity の2つに分けること,(3) Azure Bot Service と Teams パッケージを用意すること,(4) 可観測性の認証を Blueprint 側に分離することが挙げられる.一方で,バックエンド固有の差分として,Dify では /v1/chat-messages とチャット型アプリの前提が,Cortex Agents では Connector によるセッショントークンとエージェント固有 :run エンドポイント,そして SSE の解析が必要になることを示した.

 以上の結果は,Dify や Cortex Agents に限らず,REST でアクセスできる外部エージェント一般を Agent 365 の統制下に置く際にも応用できると考えられる.ただし,本稿の内容は特定の検証環境での限られた実装に基づいており,Agent 365 の仕様や各バックエンドのAPIは変化が続いている.そのため,実運用に向けては,最新の一次情報での確認と,秘匿情報の適切な管理(本稿で用いた Snowflake のパスワードはプログラマティックアクセストークンであり,定期的なローテーションが望ましい)が必要になると思われる.また,多数のエージェントを扱う場合には,個々のアプリを手動で登録するのではなく,バックエンド側の一覧APIを定期取得して自動登録する仕組みへ拡張することが望ましいが,その自動追従の実装と評価については今後の課題としたい.

 なお,Snowflake Cortex Agents については,比較的近いうちに Agent 365 の公式対応がなされる可能性もあると筆者は考えている.その場合には,本記事のアダプタ方式から公式の取り込み方式へ移行することも選択肢になると思われる.

参考

Microsoft Agent 365(公式)

Azure / Microsoft Teams(公式)

バックエンド(公式・参考)

横断的な監視サービス

本稿の実装

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?