API Managementで IPアドレスごとにトークンの使用を制限する。

## はじめに

### 自己紹介
AzureのクラウドエンジニアとしてAzure OpenAIを使用した環境の構築などを行っています。
2024年12月でエンジニア経験がちょうど1年たちました。

### つくるもの
Azure API Managementを使用して、
IPアドレスごとにAzure OpenAI API トークンの使用を制限する。

エンタープライズでAzure OpenAIの利用する際に「部署ごとにトークンの利用数を制限したい」といったリクエストが今後出てくるのではと考えています。
Azure API ManagementでIPアドレスをキーとしてトークン制限を行うポリシーが設定できるということで、実際にやってみました。

### 対象読者
・Azure OpenAIとAPI Managementを連携して使いたい人
・Azure OpenAIの言語モデルトークンの使用量をIPアドレスで制限したい人

### Azure OpenAIとは
Azure OpenAIは、MicrosoftのクラウドプラットフォームAzure上でOpenAIのAIモデルを利用できるサービスです。

### Azure API Managementとは
Azure API Managementは、APIの公開、管理、保護、分析を効率化するMicrosoftのクラウドサービスです。APIの動作を制御するためにポリシーを設定することができます。

## 環境準備
ポリシー設定前にAzure API ManagementやAzure OpenAIを構築します。
ここは本題ではなく、公式ドキュメントあるため簡単に流れだけ紹介します。

### １．Azure OpenAIのデプロイと、モデルのデプロイ
こちらの公式ドキュメントを参考にAzure OpenAIと言語モデルをデプロイしました。
https://learn.microsoft.com/ja-jp/azure/ai-services/openai/how-to/create-resource?pivots=web-portal




2024/12/13現在、このトークン制限のポリシーを使用できるのは以下の6つのモデルだけのようです。今回はgpt-4をデプロイしました。
- gpt-3.5
- gpt-4
- gpt-3.5-turbo-instruct
- text-embedding-3-large
- text-embedding-3-small
- text-embedding-ada-002

### ２．Azure API Managementのデプロイ
Azure API Managementをデプロイします。
https://learn.microsoft.com/ja-jp/azure/api-management/get-started-create-service-instance
![apim.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3930091/c1114452-07f2-bc3e-5f38-d54becd65c11.png)


### ３．Azure API ManagementにAzure OpenAIのAPIをインポート
以下のURLを参考に作成したAzure API ManagementにAzure OpenAIのAPIをインポートしていきます。
https://learn.microsoft.com/ja-jp/azure/api-management/azure-openai-api-from-specification

APIs＞Add API＞Azure OpenAI Serviceを選択
![APIM-AOAI.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3930091/24b68d06-6159-b02b-9ed3-4fdb176264c4.png)

やろうとしていたトークンによる制限がまさかのポリシータブで簡単に設定できるようになっていました。先ほど作成したAzure OpenAIインスタンスを選択し、簡単に作成することができました。
![APIM-AOAI2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3930091/bb1deb7a-4c74-6514-e529-1355911f5d3c.png)

APIのインポートが完了しました。リクエストURLに記載する必要のあるdeployment-id,api-versionのvalueを入力します。
![APIM-AOAI3.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3930091/1cc5ceb0-4d7e-2610-dbcc-e08bfda24361.png)

### ４．APIのテスト
APIから応答がちゃんと帰ってくるかテストします。

`Creates a completion for the chat messege`の操作を選択　＞　テスト タブをひらきます。会話を構成するメッセージのリストを送ると、言語モデルが適切なレスポンスを返してくれる操作です。
![APIM-AOAI4.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3930091/7d583989-53c9-779c-4357-3bad1eb48952.png)

適当なHTTPリクエストを入力し、HTTPステータス 200 OKが返ってくることを確認しました。
![testok.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3930091/d4adc20b-1434-0080-85b2-7f57df45ea46.png)


## ポリシーの適用確認
### １．ポリシー設定を確認

現状どのようなポリシーが設定されているかを確認します。
APIインポートのときにポリシータブで設定した内容は
インポートしたAPI ＞ All operations ＞ Policies　に設定されていました。
すべてのAPIの操作に対してIPアドレスごとのトークン制限がかかるようになっています。
![policy.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3930091/d9d4c097-0a08-a0e8-b7b8-abf83a2c3253.png)

設定されていたポリシーはこちら。
```
<policies>
    <inbound>
        <set-backend-service id="apim-generated-policy" backend-id="xxxxx-openai-endpoint" />
        <azure-openai-token-limit tokens-per-minute="100" counter-key="@(context.Request.IpAddress)" estimate-prompt-tokens="true" />
        <authentication-managed-identity resource="https://cognitiveservices.azure.com/" />
        <base />
    </inbound>
    <backend>
        <base />
    </backend>
    <outbound>
        <base />
    </outbound>
    <on-error>
        <base />
    </on-error>
</policies>
```

#### ポリシーの意味を調べてみました。
- set-backend-service
API Management がリクエストをどのバックエンドサービスに送信するかを設定します。
- azure-openai-token-limit
Azure OpenAI サービスへのリクエスト数を制限します。
tokens-per-minute="100" は、1分間あたり最大100トークンのリクエストを許可することを意味します。
  
- counter-key="@(context.Request.IpAddress)"
IPアドレスごとに制限をかけることができます。
  
- estimate-prompt-tokens="true" 
プロンプトトークン数を推定して、トークン制限に反映させる設定です。


（補足）
>各操作のInbound processing/Outbound processingにポリシーを設定することもできるようです。
![policy2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3930091/899b063f-e5b9-35da-4bd1-60b239a9a753.png)

>Add Policyをおすと、IP制限や呼び出し制限などの設定できるポリシーを確認できます。わかりやすいですね。
![policy3.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3930091/3c38e23f-b49c-eb3d-a083-0933ab28814a.png)




### ２．IPアドレスごとにトークン制限がかかるか確認

異なるIPアドレスからリクエストを送って制限のかかり方を確認します。

22~から始まるIPアドレスからtoken limitがかかるまでリクエストを送ります。
![tokenlimit2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3930091/4f3f5a15-646a-9ba1-b12b-a06852ea03ba.png)

13~から始まる別のIPアドレスからリクエストを直後に送り、そちらのIPでは200OKが返ってくるのを確認できました。
![tokenlimit.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3930091/37ac9fa0-249d-a572-309b-d740477e79ac.png)

（もっといいテスト方法がありそう。。。）

## おわりに
API Managementは機能が多くてまだわからない部分の方が多いですがゴリゴリ触って理解を深めていきたいです。