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?

APIM + Azure OpenAI + Logic Apps : 予算超過時にAPIアクセスを自動遮断できるようにしてみた - part②

0
Last updated at Posted at 2025-12-25

はじめに

この記事では、APIM と Logic Apps の機能を利用し、予算の設定値を超過したときに API アクセスを自動的にストップする仕組みを構築します。

前提として、以下の記事の手順を実施している必要があります。
APIM + Logic Apps + Azure OpenAI: 予算超過時にAPIアクセスを自動遮断できるようにしてみた - part①

目次

  • 全体の流れ
  • 実際に試してみよう
  • まとめ

全体の流れ

概要図

image.png

流れ

  1. APIM で NamedValue を作成し、Policy を修正
  2. Logic Apps を作成
  3. Monitor のアクショングループを作成
  4. 予算を作成
  5. テスト

実際に試してみよう

1. APIM で NamedValue(名前付きの値) を作成し、Policy を修正

① Azure ポータルの検索窓で APIM と検索し、以前に作成した APIM 名を選択

② APIM の画面で、[APIs] > [名前付きの値]をクリック

image.png

③ [追加]を選択

image.png

④ 名前、表示名に[ExceedBudget]を入力し、値には[false]と入力してください

image.png

名前や表示名は任意の値を入力してOKですが、APIM のポリシーで適切に置き換えることを忘れないようにしてください。

⑤ [API] > [作成したAPI名] > [POST Create a completion for the chat message] > [Inbound processing]の順番に選択

image.png

⑥ ポリシーを以下に置き換え、[保存]をクリック

<!-- APIM ポリシー(例) -->
<policies>
    <inbound>
        <!-- ベースポリシーの読み込み -->
        <base />

        <!-- 先ほど設定した表示名を nvStr に格納 -->
        <set-variable name="nvStr" value="{{ExceedBudget}}" />

        <!-- nvStr を bool 型に変換して ExceedBudgetFlag に格納 -->
        <set-variable name="ExceedBudgetFlag" value="@{
            bool result = false;
            string s = (string)context.Variables["nvStr"];
            bool.TryParse(s, out result);
            return result;
        }" />

        <!-- ExceedBudgetFlag が true の場合、リクエストをブロック -->
        <choose>
            <when condition="@( context.Variables.GetValueOrDefault<bool>("ExceedBudgetFlag") )">
                <return-response>
                    <!-- HTTPステータス 403 を返す -->
                    <set-status code="403" reason="Disabled by policy" />
                    <!-- レスポンスヘッダーを application/json に設定 -->
                    <set-header name="Content-Type" exists-action="override">
                        <value>application/json</value>
                    </set-header>
                    <!-- JSON形式のエラーメッセージを返す -->
                    <set-body>@("{\"error\":\"LLMアクセスは禁止されています。\",\"code\":\"LLM_DISABLED\"}")</set-body>
                </return-response>
            </when>
        </choose>

        <!-- バックエンドサービスを指定 -->
        <set-backend-service id="lb-backend" backend-id="backend-pool" />

        <!-- マネージドIDによるバックエンド認証を設定 -->
        <authentication-managed-identity resource="https://cognitiveservices.azure.com" />

        <!-- Azure OpenAI のトークン制限を設定 -->
        <azure-openai-token-limit 
            tokens-per-minute="1000" 
            counter-key="@(context.Request.IpAddress)" 
            estimate-prompt-tokens="true" 
            tokens-consumed-header-name="consumed-tokens" 
            remaining-tokens-header-name="remaining-tokens" />

        <!-- Azure OpenAI のメトリクスを発行 -->
        <azure-openai-emit-token-metric namespace="genaimetrics">
            <!-- Subscription ID をメトリクスのディメンションとして追加 -->
            <dimension name="Subscription ID" />
            <!-- クライアント IP をメトリクスのディメンションとして追加 -->
            <dimension name="Client IP" value="@(context.Request.IpAddress)" />
        </azure-openai-emit-token-metric>
    </inbound>

    <backend>
        <!-- 429(Too Many Requests)の場合、リトライ処理を行う -->
        <retry condition="@(context.Response.StatusCode == 429)" count="2" interval="1" first-fast-retry="true">
            <!-- リトライ時にリクエストをバックエンドに再送 -->
            <forward-request />
        </retry>
    </backend>

    <outbound>
        <base />
    </outbound>

    <on-error>
        <base />
    </on-error>
</policies>

このポリシーでは、先ほど設定した APIM 名前付きの値がtrueであれば、ユーザーからのリクエストに対してエラーを返すようにしています。(falseであれば後続の処理をそのまま実行します)

2. Logic Apps を作成

① 検索バーで[Logic apps]を検索し、[Create]をクリック

image.png

② ホスティングプランとして、今回は[従量課金]を選択

スクリーンショット 2025-10-19 094651.png

③ 画像の項目に適切な値を入力して、[確認および作成]の後、[作成]をクリック

スクリーンショット 2025-10-19 094725.png

④ Logic Apps の[ID]に移動し、[システム割り当て済み]の状態を[オン]に変更
スクリーンショット 2025-10-19 095318.png

⑤ 以下の画面になっていることを確認

スクリーンショット 2025-10-19 095417.png

⑥ [ロジックアプリデザイナー]をクリック

image.png

⑦ [トリガーを追加]をクリックし、検索バーで「request」を検索し、画像の名称のトリガーをクリック

スクリーンショット 2025-10-19 095049.png

⑧ Request Body JSON Schema を以下に変更

{
  "type": "object",
  "properties": {
    "schemaId": {
      "type": "string"
    },
    "data": {
      "type": "object",
      "properties": {
        "essentials": {
          "type": "object",
          "properties": {
            "alertId": {
              "type": "string"
            },
            "alertRule": {
              "type": "string"
            },
            "severity": {
              "type": "string"
            },
            "signalType": {
              "type": "string"
            },
            "monitorCondition": {
              "type": "string"
            },
            "monitoringService": {
              "type": "string"
            },
            "alertTargetIDs": {
              "type": "array",
              "items": {
                "type": "string"
              }
            },
            "originAlertId": {
              "type": "string"
            },
            "firedDateTime": {
              "type": "string"
            },
            "resolvedDateTime": {
              "type": "string"
            },
            "description": {
              "type": "string"
            },
            "essentialsVersion": {
              "type": "string"
            },
            "alertContextVersion": {
              "type": "string"
            }
          }
        },
        "alertContext": {
          "type": "object",
          "properties": {}
        }
      }
    }
  }
}

⑨ [アクションの追加]をクリック

スクリーンショット 2025-10-19 095131.png

⑩ 検索バーで http を検索し、[HTTP]を選択し、以下の項目に入力する

スクリーンショット 2025-10-19 095200.png

具体的な値はこちらを参照
  • URl
    https://management.azure.com/subscriptions/{subscriptionId}/resourceGroups/{resourceGroupName}/providers/Microsoft.ApiManagement/service/{serviceName}/namedValues/{namedValue名}?api-version=2024-05-01
  • Method
    PATCH
  • Headers
    Content-Type: application/json
  • Body(以下)

{
  "properties": {
    "value": "True",
    "secret": false
  }
}

⑪ [詳細パラメータ]をクリックし、Authentication にチェックを入れる

スクリーンショット 2025-10-19 095224.png

⑫ パラメータを以下の画像のように入力

image.png

3. Monitorのアクショングループを作成

① 検索バーで[監視]を検索し、[アクショングループ]をクリック

スクリーンショット 2025-10-19 093402.png

② 以下の項目に任意の値を入力する

スクリーンショット 2025-10-19 093608.png

③ アクションのアクションタイプで[ロジックアプリ]を選択し、任意の名前を入力する

スクリーンショット 2025-10-19 093806.png

④ 作成したロジックアプリを選択し、他はデフォルトのまま作成する

image.png

4. 予算を作成

① 検索バーで[予算]を検索し、[追加]をクリック

image.png

② 以下の画面で任意の値を入力(テストするために今回は金額に10を入力しています)

image.png

③ 警告条件として画像のように入力し、アクショングループには先ほど作成したアクショングループを選択
④ アラートを受け取りたいメールを入力し、[作成]をクリック

image.png

5. テスト

Logic Apps

先ほど作成した Logic Apps の画面から手動でテストしてみましょう!

① Logic Apps の画面に移動し、[ロジックアプリデザイナー]をクリック

② [Run]をクリック

image.png

③ [Open run]をクリック

image.png

④ 以下の画面のように右上にチェックマークがついていれば成功です
image.png

⑤ APIM の画面で名前付きの値を確認すると、false から True になっていることが分かります

image.png

APIMのテスト画面で確認

今度は名前付きの値が True になっている時に、 APIM の画面からリクエストを送信し、エラーが返ってくることを確認します

① APIM の画面から Test を選択し、[Template parameters]と[Request body]に適切な値を入力

image.png

② APIMでリクエストを送信すると以下のレスポンスが返ってくれば成功

image.png

おまけ

予算の設定をした際に、メールに通知が来るように設定していましたが、数日後に以下のような通知を受け取ることができました。

これにより、Logic Apps が実行され、APIM の名前付きの値が変更され、自動的に LLM へのリクエストを遮断することが可能となっています。

image.png

まとめ

  • 利用できる上限の予算を設定して、それを超過すると自動的にリクエストを遮断することで意図しないコスト増大を防ぐことができる
  • APIM で認証やレート制限をしつつ、Budget 機能で予算を制御することで安心して LLM を利用する基盤を構築できる

終わりに

本記事では、Azure OpenAI を APIM 経由で利用し、予算超過時に自動でリクエストを遮断する仕組みを紹介しました。
AIの導入が進む一方で、「使いすぎによるコスト増加」や「統制の難しさ」が課題になりやすいですが、今回の記事で紹介した仕組みにより、安心して業務へ組み込める構成を実現できるのではないでしょうか。

AI基盤を設計する際の一つのアイデアとして、参考になれば幸いです!


  • Azure は、マイクロソフト 企業グループの商標です。
  • その他、記載されている会社名および商品・製品・サービス名は、各社の商標または登録商標です。
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?