AzureOpenAIのAPIを企業内公開するためのAPI ManagementとApplication Gatewayの活用

## はじめに

BIPROGYでは各社員ベースで生成AIを用いた業務改善を進められることを目的にAzureOpenAIのAPIを社内公開しています。グループ社員なら誰でも **簡単な申請** で **最新のo1モデルをはじめ** Azure OpenAIのAPIを使うことができます。

企業内で大人数でAzureOpenAIを使うためにはAzureOpenAIの既存機能だけでは実現できない要件もあるため、弊社では **API ManagementやApplication Gateway** を組み合わせて提供しています。

今回はAzureOpenAIのAPIを社内公開するために、API ManagementやApplication Gatewayを用いてどのような工夫をしているかをご紹介します。

## 構成図

多少簡略化していますが、以下のような構成をとっています。

![APIMとAGWによるAOAI管理構成](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3640132/d5e36313-262e-91aa-6de8-b74d0989dc2a.png)

フロントにはAPI Managementを設置し、ユーザはここにアクセスします。ユーザ認証が通った後はバックエンドのApplication Gatewayに転送され、その後指定したモデルが使えるAzureOpenAIに適宜ルーティングされる形です。

## 社内公開するための要件

AzureOpenAIのAPIを社内公開するにあたり、ざっくり以下のような要件がありました。

1. 最新モデル含めて **複数モデル** を公開したい
2. ユーザごとの **利用上限（流量制限）** を設定したい
3. ユーザごとの **コスト** を見える化したい
4. 不正利用など **セキュリティ** 対策をしたい

:::note warn
「データが学習に用いられない」等、AzureOpenAIのみでクリアできる要件は割愛しています。
:::

「責任あるAI」であるAzureOpenAIですが、企業内で大規模に使うとなるとAzureOpenAI単体では実現できない要件も出てきてしまいます。

## AzureOpenAIを単体利用することの課題

前述の要件を踏まえて、AzureOpenAIを単体で利用しようとすると以下のような課題があります。

### リージョンごとに提供モデルが違い使い分けが煩雑

AzureOpenAIではリージョンにより、利用できるモデルが異なります。

https://learn.microsoft.com/ja-jp/azure/ai-services/openai/concepts/models?tabs=python-secure#standard-deployment-model-availability

とくにpreviewの最新モデルは提供リージョンが絞られていることが多いです。2024/10/17現在ですと、最新のo1モデルはeastus2とswedencentralのみで提供されています。

基本はJapan Eastリージョンを使いたいが、XXモデルを使うためにはEast USリージョンが必要。East USリージョンを作ったはいいが、今度はYYモデルがSweden Centralしか対応していない、と、いったように複数リージョンの使い分けが必要になるケースは多いです。

AzureOpenAIのAPIのurlはリソースごとに変わるため、複数のリージョンを使う場合はAPIリクエストで指定するurlも複数になってしまいます。

![複数モデルの使い分けは煩雑](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3640132/5fb81591-de2f-0325-a333-ecc91a5224b2.png)

### キーの共有で漏洩リスクが高い

AzureOpenAIの認証はapi-keyによる認証とマネージドIDによる認証の2つが用意されています。

api-keyはAzureOpenAIのリソース作成時に2つ（メインとサブ）が発行されます。大人数で利用する場合にはこのキーをユーザ全員で共有することになってしまいます。また、前述したように複数モデルを使うために複数リソースがある場合は、さらにリソースごとにapi-keyも別になります。

このようにユーザが共有されたキーをいくつも持っている状態はとても漏洩リスクが高いです。

また、マネージドIDによる認証の場合はもう少し選択肢は増えます。Azureやユーザや、EntraIDのアプリケーション登録を利用すればキーの共有は避けられそうですが、それでも大人数になってくると管理はかなり複雑になりそうです。

### ユーザごとの分析が難しい

AzureOpenAI側でユーザを識別することができないため、ユーザごとの使用状況を分析することができません。もちろんユーザごとの流量制限や課金額の管理もできません。

呼び出し元のIPアドレスなどで分析できるかもしれませんが、企業ユースだとプロキシなどで全員同じIPアドレスになることもあると思いますし、複数のクライアントから呼び出す場合もあります。

## API ManagementとApplication Gatewayによる解決策

これに対してAPI ManagementとApplication Gatewayを組み合わせると以下のような構成になります。（実際の構成を簡略化したものになります）

![APIMとAGWによるAOAI管理構成](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3640132/d5e36313-262e-91aa-6de8-b74d0989dc2a.png)

### 解決策① API Managementのサブスクリプション機能でユーザごとの認証を実現

API Managementにはサブスクリプションという機能があります。

:::note warn
紛らわしいですが、Azureの利用、管理、課金するための単位の「Azureサブスクリプション」とは別物です。
:::

API Managementの中にユーザごとのキー（サブスクリプションキー）を作成することができ、ユーザはこのキーを用いてAPI Managementに認証できます。

![APIMのサブスクリプションを用いた認証](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3640132/19e3bfb2-ac29-b2b7-cebc-38475167e309.png)

サブスクリプションキーによる認証がOKであればバックエンド（この場合はAzureOpenAI）に転送します。API Managementには事前にAzureOpenAIへのアクセス権のあるマネージドIDを登録しておけば、これで実質的に **ユーザごとに別のキー** を用いてAzureOpenAIを利用できるようになり漏洩時のリスクを低減できます。

### 解決策② API Managementのポリシーとプランの組み合わせでユーザごとの流量制限をする

API Managementにはポリシーという、APIの動作を変更せずに、要求や応答を変換、制御、セキュリティ保護するためのルールセットがあります。このポリシーの1つにユーザ（サブスクリプション）ごとの **リクエスト数の制限** を設定できるポリシーがあり、これを使えば流量制限ができます。

https://learn.microsoft.com/ja-jp/azure/api-management/rate-limit-by-key-policy

以下のように書くと、60秒ごとの10回までのアクセスに制限できます。

```xml
<policies>
    <inbound>
        <base />
        <rate-limit-by-key calls="10"
              renewal-period="60"
              increment-condition="@(context.Response.StatusCode == 200)"
              counter-key="@(context.Request.IpAddress)"
              remaining-calls-variable-name="remainingCallsPerIP"/>
    </inbound>
    <outbound>
        <base />
    </outbound>
</policies>
```

また、API Managementには「プラン」という`Unlimited`や`Standard`といったプランをユーザに紐づけられる機能があります。このプランのポリシーに上述のアクセス制限を書いておくと、以下のようにユーザごとに個別の流量制限を設定できます。

![プランとポリシーによる流量制限](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3640132/c046b198-2d98-c54b-77c9-e52dc5cac331.png)

### 解決策③ サブスクリプションIDとレスポンス内のtoken使用量でユーザごとの使用量を把握

サブスクリプションを用いて認証すると`ApimSubscriptionId`という項目でサブスクリプションIDがheaderに付与されます。

LLMからのレスポンスにはmodel, token使用量が含まれるためLog Analytics上では以下のようにサブスクリプションIDとともに合わせてみることができます。

![logにサブスクリプションIDが表示される](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3640132/e2dc705e-420a-771b-962a-bec262309fca.png)

クエリを書き換えることでユーザが一定の期間においてどのモデルを合計何token使ったか、という情報もまとめられるようになりここから金額も算出できます。

### 解決策④ Application Gatewayのルーティングを使って単一のbase-urlから複数LLMの使い分け

モデルごとに複数のAzureOpenAIがあってもApplication Gatewayがあれば最適なルーティングを設定できます。

たとえばgpt-4oとo1-miniで提供リージョンが別々で2つのAzureOpenAIを作成しているとします。Application Gatewayでurlが`/openai/deployments/o1-mini/~`のときはRegion1のAzureOpenAIへ、`/openai/deployments/gpt-4o/~`のときはRegion2へというようにルーティングできます。

この場合でもあくまでユーザはAPI Managementに向けてリクエストを転送すればよいのでどのモデルを使うときでも同じbase-url(この場合はAPI Managementのurl)を指定すればOKです。認証もAPI Managementで実施されるので同じapi-keyが使えます。

![Application GatewayでAzureOpenAIへルーティング](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3640132/2d93f6af-865d-85aa-5376-7c79f66a3ebd.png)

### (補足)API ManagementのGenAIゲートウェイ機能

上述したようにAPI Managementはそれ自体がAzureOpenAIと組み合わせることで相乗効果を発揮するようなサービスになっています。

ただ、それに追加される形で2024年のMicrosoft BuildにおいてAzureOpenAI連携機能 = **GenAIゲートウェイ機能** が公開されました。

https://learn.microsoft.com/ja-jp/azure/api-management/genai-gateway-capabilities

このGenAIゲートウェイ機能には以下のようなものが含まれます。

- AzureOpenAIのAPIを簡単にインポートできる機能
- ユーザごとの制限をtoken数ベースで設定できる機能
- tokenの使用量メトリクスをApplication Insightsに送信できる機能
- AzureOpenAIへのロードバランサー/サーキットブレーカー機能
- セマンティックキャッシュ（類似度の高いプロンプトに対してはキャッシュからレスポンスを変える）機能

これらはいずれも登場したばかりの機能で、まだ機能的には十分とは言えませんが適宜組み合わせることでより管理がしやすくなります。

ちなみに弊社の環境ではこれら機能も評価していますが、いくつかの理由で現状は使用していません。このあたりの内容に関しては後日別の記事で記載できればと思っていますのでご期待ください。

## まとめ

いかがでしたでしょうか。生成AIの活用の幅はさまざまです。社内にAPIを呼び出せるエンジニアが多い場合はAPIそのものを公開し、各社員の手で活用事例の模索をしてほしいというのはよくあるケースと思います。

そんなケースの参考になれば幸いです。

## We Are Hiring

BIPROGYでは一緒に働く仲間を募集しています。ご興味ある方は下記をご参照ください。

https://www.biprogy.com/recruit/recruiting/