源内 AI アプリリポジトリの Azure vLLM/OpenAI テンプレートを源内 Web に接続してみた
いわさです。
源内 AI アプリリポジトリの各クラウドテンプレートを ExApp としてデプロイするシリーズ、前回は Google Cloud 版(Lawsy-Custom-BQ)をデプロイしました。
今回は Azure テンプレート(azure/genai-azure)をデプロイし、源内 Web と接続してみました。
今回こちらを確認してみたので紹介します。
Azure テンプレートの概要
このテンプレートは 3 つの API 群を提供しており、それぞれ異なるユースケースとコンポーネント構成を持っています。
API 提供の仕組み

3 つの API 群すべてに共通する基盤が、APIM(API Management)と Application Gateway です。
APIM は Azure のフルマネージド API ゲートウェイサービスで、API の公開・認証・レート制限・監視などを一元管理できます。
このテンプレートでは APIM が外部向けの単一エンドポイントを提供し、接続元 IP 制限と API キー認証を行います。
APIM から Application Gateway へは VNet 内のプライベート IP 通信で HTTP リクエストし、Application Gateway の WAF ポリシーでリクエスト元の APIM を検証する仕組みになっています。
Application Gateway からバックエンド(OpenAI、Functions、VMSS)へは Private Endpoint 経由でアクセスします。
源内 Web 側は Lambda(VPC 内)から NAT Gateway 経由でインターネットに出て、APIM のパブリックエンドポイントにアクセスします。
3 つの API 機能
vLLM 対応モデル API
vLLM は LLM の推論を高速化するためのオープンソースエンジンです。
Docker イメージ(vllm/vllm-openai)を使えば、Hugging Face で公開されているモデルを OpenAI 互換 API として簡単にホスティングできます。
テンプレートのデフォルトでは Preferred Networks 社の PLaMo 翻訳モデル(pfnet/plamo-2-translate)が設定されています。
PLaMo は日英・英日翻訳に特化したモデルで、plamo-community-license の下で提供されています。
この API 群では、VMSS(Virtual Machine Scale Sets)上の GPU VM(A100)で vLLM コンテナを稼働させ、Application Gateway 経由で負荷分散します。
Azure Automation で定期的な起動 / 停止スケジュールも管理できます。
Azure OpenAI Direct API
Azure OpenAI Service は、OpenAI のモデル(GPT-4o 等)を Azure 上でホスティングし、REST API として提供するサービスです。
このテンプレートの「Direct API」は、Azure OpenAI の Chat Completions API と Responses API を APIM 経由でそのまま提供する API です。
リクエスト / レスポンスの変換は行わず、OpenAI 互換形式をそのままパススルーします。
Azure OpenAI Code Interpreter API
Code Interpreter は、Azure OpenAI が Python コードをサンドボックス環境で実行し、データ分析やグラフ生成を行う機能です。
このテンプレートでは Azure Functions で Code Interpreter のオーケストレーションを行い、ファイルのアップロード・分析実行・結果取得を一括処理する API として提供しています。
日本語グラフ描画用のフォントファイル(NotoSansJP)も自動でアップロードされます。
こちらについては公式ドキュメントの以下でも解説されています。
デプロイしてみる
リポジトリには azd(Azure Developer CLI)のプロジェクト定義一式が用意されています。
azure.yaml— azd プロジェクト定義。IaC プロバイダーに Bicep を指定し、インフラ定義の場所(infra/)とアプリの場所(app/)を宣言infra/— Bicep テンプレート群。main.bicepをエントリーポイントに、ネットワーク・APIM・Application Gateway・OpenAI・Functions 等のモジュールがcore/とapp/に分かれて格納infra/main.parameters.json— デプロイパラメータ。ユーザーが編集する唯一のファイルapp/— Azure Functions の Python コード(Code Interpreter のオーケストレーション処理)azure.yamlのhooks— デプロイ前後に自動実行されるシェルスクリプト(SSH 鍵生成、Functions key の APIM 登録、フォントファイルアップロード等)
この構成により、azd up 一発で「Bicep によるインフラ構築 → Functions へのアプリデプロイ → 後処理(フォントアップロード等)」まで完了します。
2 回目以降にインフラだけ変更したい場合は azd provision、アプリだけ更新したい場合は azd deploy を個別に実行できます。
パラメータの設定
infra/main.parameters.json の主な変更点です。
{
"deployVllmSupportModel": { "value": false },
"deployCodeInterpreter": { "value": true },
"deployOpenAiDirect": { "value": true },
"openaiCapacity": { "value": 50 }
}
openaiCapacity は gpt-4o の TPM(Tokens Per Minute、千トークン単位)のキャパシティです。
デフォルトの 140 だとサブスクリプションのクォータ上限(50K TPM)を超えてデプロイに失敗したので、50 に下げました。
また、apiAllowedSourceIps には源内 Web の NAT Gateway IP を追加する必要があります。
源内 Web 側の CloudFormation スタックから NAT Gateway のパブリック IP を確認して設定します。
デプロイの実行
azd auth login
azd up
deployCodeInterpreter が true の場合は azd up(インフラ + アプリ両方)を使います。
デプロイ完了まで 5 分程度でした(vLLM なしの場合)。
デプロイ後のリソース

vLLM なしの場合、VMSS や Automation は作成されず、APIM + Application Gateway + Functions + OpenAI + VNet 関連リソースが作成されます。
vLLM のデプロイはクォータ不足で断念
vLLM 対応モデル API のデプロイには Standard_NC24ads_A100_v4(NVIDIA A100 GPU 搭載、24 vCPU)が必要です。
私の検証用 Azure サブスクリプションのクォータを確認したところ Limit が 0 でした。
az vm list-usage --location japaneast --output table
Name CurrentValue Limit
---------------------------------------- -------------- -------
Standard NCADS_A100_v4 Family vCPUs 0 0

Azure Portal からクォータ引き上げ申請を行いましたが、却下されました。
今回使用しているサブスクリプションが Visual Studio 特典のクレジットを利用しているものだったので、GPU 系のクォータ引き上げが認められなかったようです。
本番用途のサブスクリプションであれば通る可能性はあると思います。
源内 Web から使ってみる
APIM サブスクリプションキーの作成
デプロイ後、APIM の「GenAI Product」に対してサブスクリプションを作成し、API キーを取得します。
Azure Portal の APIM リソースから作成するか、Azure CLI で作成できます。
Code Interpreter(データ分析 AI)の登録
Code Interpreter は源内の標準 I/F(inputs.input_text 形式)をそのまま受け付ける設計なので、デフォルトのまま連携できます。
源内 Web の「チーム管理」→「アプリの作成」から以下の内容で登録します。
- API エンドポイントの URL:
https://apim-xxxxx.azure-api.net/code-interpreter/responses - API キー: APIM サブスクリプションキー
- API リクエストのデータ形式(JSON):
{
"input_text": {
"type": "textarea",
"title": "分析指示",
"required": true
},
"files": {
"type": "file",
"title": "分析対象ファイル",
"accept": ".xlsx,.csv",
"multiple": true
}
}
CSV ファイルをアップロードして「どういうデータなのか説明してください」と入力して実行してみました。

データの構造を分析して説明してくれました。

フォントファイル(NotoSansJP)が事前にアップロードされているので、日本語のグラフも正しく描画されます。
Direct API(OpenAI チャット)の登録
Direct API はデフォルトだとリクエストボディをそのまま Azure OpenAI に透過する設計です。
源内 Web は外部 API に {"inputs": {...}} でラップしてリクエストを送るため、そのままでは Azure OpenAI が期待する OpenAI 形式({"model": "...", "messages": [...]})と合いません。
APIM ポリシーをカスタマイズして、inputs.input_text を OpenAI Chat Completions 形式に変換し、レスポンスも outputs 形式に変換する処理を追加しました。
infra/app/apim-api-aoai-direct.bicep のポリシーに以下のような <set-body> を追加します。
inbound で inputs.input_text と inputs.systemPrompt を受け取り、OpenAI の messages 配列に変換します。
<set-body>@{
var body = context.Request.Body.As<Newtonsoft.Json.Linq.JObject>(true);
var inputs = body["inputs"] as Newtonsoft.Json.Linq.JObject;
if (inputs != null && inputs["input_text"] != null) {
var inputText = (string)inputs["input_text"];
var systemPrompt = inputs["systemPrompt"] != null ? (string)inputs["systemPrompt"] : null;
var messages = new Newtonsoft.Json.Linq.JArray();
if (systemPrompt != null) {
messages.Add(new Newtonsoft.Json.Linq.JObject(
new Newtonsoft.Json.Linq.JProperty("role", "system"),
new Newtonsoft.Json.Linq.JProperty("content", systemPrompt)
));
}
messages.Add(new Newtonsoft.Json.Linq.JObject(
new Newtonsoft.Json.Linq.JProperty("role", "user"),
new Newtonsoft.Json.Linq.JProperty("content", inputText)
));
var result = new Newtonsoft.Json.Linq.JObject(
new Newtonsoft.Json.Linq.JProperty("model", "gpt-4o"),
new Newtonsoft.Json.Linq.JProperty("messages", messages)
);
return result.ToString();
}
return body.ToString();
}</set-body>
outbound で OpenAI のレスポンスを源内形式(outputs)に変換します。
<set-body>@{
var body = context.Response.Body.As<Newtonsoft.Json.Linq.JObject>(true);
var choices = body["choices"] as Newtonsoft.Json.Linq.JArray;
if (choices != null && choices.Count > 0) {
var message = choices[0]["message"];
var content = message != null ? (string)message["content"] : "";
var result = new Newtonsoft.Json.Linq.JObject(
new Newtonsoft.Json.Linq.JProperty("outputs", content)
);
return result.ToString();
}
return body.ToString();
}</set-body>
ポリシー変更後、azd provision で再デプロイすれば反映されます。
なお、README に APIM ポリシーのカスタマイズガイドへのリンクがあるので、他の変換パターンもそちらを参考にできます。
源内 Web での登録内容:
- API エンドポイントの URL:
https://apim-xxxxx.azure-api.net/openai/v1/chat/completions - API キー: APIM サブスクリプションキー
- API リクエストのデータ形式(JSON):
{
"input_text": {
"type": "textarea",
"title": "質問・指示",
"required": true
}
}
- システムプロンプトのキー名:
systemPrompt
システムプロンプトを設定すれば、同じエンドポイントで翻訳 AI、要約 AI など用途別のアプリを複数作成できます。
テキストを入力して実行してみました。

APIM ポリシーで変換しているので、源内の標準的なテキスト入力フォームからそのまま Azure OpenAI の gpt-4o を呼び出せています。
料金
vLLM あり(今回は未デプロイ)
vLLM テンプレートで使用する Standard_NC24ads_A100_v4 の料金目安です。
- オンデマンド: 約 $3.67/時(月額約 $2,680 / 約 40 万円)
- スポット: 約 $0.68/時(月額約 $490 / 約 7.3 万円)
テンプレートのデフォルトではスポット VM + 自動起動 / 停止スケジュール(8:00〜24:00)が設定されているので、16h/日稼働で月額約 $330(約 5 万円)程度になります。
加えて APIM、Application Gateway 等の周辺リソースも月数千円〜1 万円程度かかります。
vLLM なし(今回のデプロイ構成)
GPU VM が不要なので大幅にコストが下がります。
- API Management (Developer tier): 約 $50/月
- Application Gateway: 約 $25/月
- Azure OpenAI (50K TPM, 従量課金): 利用量に応じて
- Azure Functions (従量課金): 検証レベルならほぼ無料
- その他(VNet, Storage, Log Analytics 等): 数ドル/月
検証用途であれば月額 $80〜100 程度で運用できます。
さいごに
本日は源内 AI アプリリポジトリの Azure テンプレートをデプロイして源内 Web と接続してみました。
Code Interpreter は源内の標準 I/F に合わせた設計になっているので、デフォルトのままデプロイするだけで源内 Web から利用できます。
Direct API の方は OpenAI 互換形式をそのまま透過する設計なので、源内 Web から使うには APIM ポリシーのカスタマイズが必要でした。
APIM ポリシーで変換ロジックを書けば柔軟に対応できるので、用途に応じてカスタマイズする想定なのだと思います。
vLLM テンプレートは A100 GPU のクォータが必要で、今回は Visual Studio 特典サブスクリプションだったため申請が却下されてしまいデプロイできませんでした。
本番用途のサブスクリプションであれば通る可能性はあるので、別途試してみたいところです。
料金面では、vLLM なしであれば月額 $80〜100 程度でした。APIM と Application Gateway が使っていなくてもそこそこ料金がかかりますね。
こちらも前回の Google みたいに AWS への移植を試してみようかな。







