Azure AI Foundry のエージェントから Azure Logic Apps をツールとして呼び出す

## はじめに

本記事では、Azure AI Foundry のエージェントから Azure Logic Apps をツールとして呼び出す、最小構成のサンプルを解説します。
主に **「get-newsapi-org-data」** という Logic App をエージェントに登録し、ニュースデータを取得する流れを説明します。

> **補足**
> ニュースデータを Blob Storage に定期的に格納する別途の Logic App（例：`fetch-data-from-data`）は付録として後述します。

## 全体の構成
黄色で示した部分が記事のメインのトピックです。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/103139/4c3722f1-0e0d-4e71-bdd3-3afd15ca5430.png)

## 前提条件

1. ニュースデータが Blob Storage に保存されていること
2. Azure AI Foundry にエージェントが定義済みであること

ブログコンテナーにBlobが保存されている状態。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/103139/a47f920a-7d13-4989-843e-7d4de91ea74c.png)

"Agent856" という名前のエージェントが"MyFirstAiProject" というAzure AI Foundry プロジェクトに定義されています。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/103139/9385da5f-f21c-4c64-ac4b-e80e0c6b804a.png)



## 1. Logic Apps コネクション設定

カスタムキー接続 を Connected resources に登録します。概念図の (f) に相当します。

1. Azure AI Foundry ポータルで **Hub（または Project）** の「Connected resources」画面を開きます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/103139/bfa8e3a2-2e40-4eaf-a9f6-00fb72a3ef78.png)

2. **Hub** に登録すると、他プロジェクトでも同じ接続情報を使い回せます。
1. 「+ New connection」から **Custom keys** を選択します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/103139/b0760cb5-c7a3-4759-ba88-18a6753af6d6.png)

2. 任意の名前を付けます（例：`LogicApps_Tool_Connection_getnewsapiorgdata`）。
3. **Key name** に `sig`、**Value** に Logic App のトリガー URL 内の `sig` クエリ文字列を貼り付けて保存します。

   * Logic App 側：「When a HTTP request is received」アクションの URL に `?sig=xxxx` が含まれていますので、この値をコピーします。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/103139/20c0a372-c831-4e9e-9807-1eb85a8f4c47.png)

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/103139/6af4abb9-430a-4f51-a679-532b28f3b81f.png)

---

## 2. エージェントに OpenAPI 3.0 接続（Action）を登録

概念図での (g) を (h) に登録する部分を設定します

1. Azure AI Foundry ポータルで対象エージェントを開き、「Add Action」を選択。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/103139/313cb12f-535d-4c2f-94d8-4730cd6d179e.png)

2. **Tool type** に **OpenAPI3.0 specification tool** を選び、

   * **Name**：任意（例：`GetNewsApiOrgData`）
   * **Description**：エージェントに表示される説明文
     を入力します。
     
 ![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/103139/dfe3c87a-9cd6-42d9-b01c-1cdd8537a7e1.png)

 ![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/103139/f2460d36-5c42-4994-815b-0133019e1141.png)


3. **Authentication method** に先ほど作成した **カスタムキー接続** を指定します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/103139/dacae68b-ef68-45a5-9545-b45ed23bbb5f.png)

4. OpenAPI 3.0 スキーマを定義
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/103139/b3807103-3587-42d6-8e67-9fe8fd08498a.png)


以下のような最小サンプルをベースに、実際の Logic App の構成に合わせて調整してください。

```json
{
  "openapi": "3.0.3",
  "info": {
    "version": "1.0.0.0",
    "title": "Get NewAPI data from storage",
    "description": "Get NewAPI data from storage"
  },
  "servers": [
    {
      "url": "https://prod-123.westus.logic.azure.com:443/workflows/aaaaaaaa0a544cf482e1570cf516d19b/triggers/When_a_HTTP_request_is_received/paths"
    }
  ],
  "security": [
    {
      "sig": []
    }
  ],
  "paths": {
    "/invoke": {
      "post": {
        "description": "Get NewAPI data from storage",
        "operationId": "When_a_HTTP_request_is_received-invoke",
        "parameters": [
          {
            "name": "api-version",
            "in": "query",
            "description": "`2016-10-01` is the most common generally available version",
            "required": true,
            "schema": {
              "type": "string",
              "default": "2016-10-01"
            },
            "example": "2016-10-01"
          },
          {
            "name": "sv",
            "in": "query",
            "description": "The version number",
            "required": true,
            "schema": {
              "type": "string",
              "default": "1.0"
            },
            "example": "1.0"
          },
          {
            "name": "sp",
            "in": "query",
            "description": "The permissions",
            "required": true,
            "schema": {
              "type": "string",
              "default": "%2Ftriggers%2FWhen_a_HTTP_request_is_received%2Frun"
            },
            "example": "%2Ftriggers%2FWhen_a_HTTP_request_is_received%2Frun"
          }
        ],
        "responses": {
          "200": {
            "description": "The Logic App Response.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                }
              }
            }
          },
          "default": {
            "description": "The Logic App Response.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                }
              }
            }
          }
        },
        "deprecated": false,
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "location": {
                    "description": "Location for the news",
                    "type": "string",
                    "default": "none"
                  }
                }
              }
            }
          },
          "required": true
        }
      }
    }
  },
  "components": {
    "securitySchemes": {
      "sig": {
        "type": "apiKey",
        "description": "The SHA 256 hash of the entire request URI with an internal key.",
        "name": "sig",
        "in": "query"
      }
    }
  }
}
```
注目する点

* **servers** の `url` はロジックアップのHTTPトリガーのエンドポイントなのでロジックアップからコピーします。
* **security** で `sig` を使うことを定義しています。この値はカスタムキー接続に指定したものが実際には送信されます。
* **requestBody** は Logic App 側の「Request BODY JSON Schema」に合わせて調整可能（例では `location` のみ）。例えばエージェント側からブロブ名などを指定できます。
* **default** プロパティが指定してある要素はエージェント側から渡す必要はない（定数として理解してかまわない）。


---

## 3. Agent Playground で動作確認

概念図のエージェント (h) に対しての要求が、アクション(g)に委任され、Logic Apps (e) がストレージからデータを読み取り結果を返し、エージェントが最終的に結果をユーザに返す流れに相当します。

1. Azure AI Foundry の Agent Playground を開き、対象エージェントを選択。

2. チャットプロンプトに例として以下を入力します。

```
ニュースの要約を取得するツールを使ってください。
```

3. エージェントが登録済みの Action を呼び出し、Logic App 経由で Blob Storage からニュースデータを取得して返してくれることを確認します。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/103139/efe5f477-122f-4018-a9b1-be31f34e6cc7.png)


---

## 付録：`fetch-data-from-data` Logic Apps の設定手順

1. **NewsAPI** で API キーを取得（無料プランあり）
2. Azure Key Vault に API キーをシークレットとして登録
3. Logic Apps のマネージド ID (**System-assigned managed identity**)を有効化
4. ストレージアカウントの「Storage Blob Contributor」ロールを Logic Apps のマネージド ID に付与
5. Key Vault のシークレット取得権限（Get,List）を Logic Apps のマネージド ID に付与
6. Logic Apps に以下アクションを追加

   1. **Get secret**（Key Vault から API キー取得）
   2. **HTTP**（NewsAPI のエンドポイントを呼び出し、`X-Api-Key` ヘッダーにキーを設定）
   3. **Create blob (V2)**（HTTP レスポンスを Blob Storage に保存）