以前参画していた現場で、「Azure OpenAI Service」などを活用した社内向けRAGシステムのインフラ構築を担当しました。
今回のシステムは、GitHubで公開されているAzure-Samplesの「azure-search-openai-demo」をベースに構築しました。
0. システムの概要
RAGとは、LLMに社内文書などの検索結果を組み合わせて、回答精度を高める仕組みです。
生成AI単体では、社内独自のルールや業務資料までは把握できません。
そこで、社内ドキュメントを検索する基盤と組み合わせることで、実務で使いやすい回答を返せるようにします。
今回の環境では、Azure OpenAI Serviceだけではなく、複数のAzureサービスを組み合わせて、システム全体のインフラを構築しました。
1. Azure-SamplesのRAGサンプルをベースに構築
今回のRAGシステムは、GitHubで公開されている「Azure-Samples」の「azure-search-openai-demo」をベースにしました。
①「azure-search-openai-demo」について
「azure-search-openai-demo」は、Azure公式が作っています。
「Azure OpenAI Service」と「Azure AI Search」を使い、自社ドキュメントに対してチャット形式で質問できるようにするRAGアプリケーションのサンプルです。
Python製のバックエンド、チャット画面、「Azure AI Search」による検索、「Azure OpenAI Service」による回答生成、Azure上にリソースを作成するためのインフラ構成などが含まれています。
イメージとして、サンプルのままの状態ですと、以下のようになります。
②今回の使い方
ただし、現場ではサンプルをそのまま使ったわけではありません。
社内向けシステムとして利用できるように、ネットワーク、認証、権限管理、監視、デプロイ方法などを現場要件に合わせて調整しました。
このサンプルは、「Azure OpenAI Service」や「Azure AI Search」を組み合わせて、独自ドキュメントに対してChatGPTのように質問できるRAGアプリケーションです。
リポジトリ内には、アプリケーションコードだけでなく、Azure上に必要なリソースを作成するためのインフラ構成も含まれています。
そのため、単にアプリを動かすだけではなく、Azure上に必要なリソースを作成し、アプリケーションコードをデプロイする流れまで確認できる構成になっています。
実際の現場でも、この構成を土台にしました。
そのサンプルをそのまま社内環境に適用するのではなく、現場の要件に合わせてかなり手を入れました。
ゼロからRAGアプリケーションを作ったというより、Azure-Samplesの公式サンプルを土台にして、現場要件に合わせてインフラと運用まわりを作り込んだ形です。
<主に調整した部分>
・閉域網を前提にしたネットワーク構成
・Private EndpointとPrivate DNS Zoneの追加
・Managed IdentityとAzure RBACによる権限管理
・Application InsightsとLog Analytics Workspaceによる監視
・Bicepによるインフラ定義
・Azure App Serviceへのアプリコードデプロイ
・開発環境と本番環境へ展開できる構成整理
・Speech Serviceを使った音声入力、音声読み上げ対応
2. インフラ構築とアプリデプロイを分けて管理
今回の構築では、Azure Developer CLIを使って、インフラ構築とアプリケーションコードのデプロイを行いました。
ただし、一括で実行するのではなく、インフラ構築とアプリケーションデプロイは分けて実行しました。
大きな流れとしては、以下のようになります。
Bicepでインフラ構成を定義する
azd provision --previewでインフラ差分を確認する
azd provisionでAzureリソースを構築・更新する
azd deployでアプリケーションコードをApp Serviceへデプロイする
①インフラのプロビジョニング
まず、Bicepで定義したAzureリソースをプロビジョニングします。
変更前には、以下のコマンドを実行して差分を確認しました。
azd provision --preview
ここで、想定外のリソース作成、更新、削除が含まれていないかを確認します。
次のコマンドでAzureリソースを構築・更新します。azd provision
正しくリソースが構築されたか確認をします。
②アプリのデプロイ
その後、アプリケーションコードの変更は、次のコマンドでAzure App Serviceへデプロイします。
azd deploy
アプリが想定通りに動くか確認をします。
このように、インフラ構築とアプリコードのデプロイを分けることで、変更の影響範囲を確認しやすくなりました。
③構築とデプロイまとめ
特に本番環境では、インフラ変更とアプリ変更をまとめて反映すると、問題が起きたときに原因を切り分けづらくなります。
そのため、まずインフラ側の差分を確認してから反映し、その後にアプリコードをデプロイする流れにしました。
この運用にしたことで、「Private Endpoint」、「Private DNS Zone」、「Managed Identity」、「RBAC」などのインフラ変更を慎重に確認しながら進めることができました。
3. RAGアプリケーションを動かす構成
①App Service Plan
今回のアプリケーションは、「Azure App Service」上で動かす構成でした。
現場では、「Azure App Service」と「App Service Service Plan」を利用しました。
利用者がWebアプリケーションから質問すると、アプリケーション側でリクエストを受け付けます。
②「Azure AI Search」と「Azure OpenAI Service」
その後、「Azure AI Search」で社内ドキュメントを検索し、取得した検索結果を「Azure OpenAI Service」へ渡します。
「Azure OpenAI Service」は、その検索結果をもとに回答を生成します。
つまり、「Azure OpenAI Service」だけで回答を作るのではなく、「Azure AI Search」の検索結果を組み合わせることで、社内情報を踏まえた回答ができる構成にしました。
PDFなどのドキュメントについては、「Azure AI Document Intelligence」で解析し、検索しやすいデータとして取り込めるようにしました。
RAGというとAI部分に注目しがちですが、実際にはWebアプリ、検索、文書解析、ストレージ、DB、ネットワークがつながって、ようやくひとつのシステムとして動きます。
4. 音声の入力と読み上げ
今回の構成では、テキストで質問するだけではなく、音声系のサービスも利用しました。
音声を組み合わせることで、効率が上がる場合などがあるからということのようです。
①「Speech Service」
具体的には、Azure AI Speechを使い、「Speech to Text」と「Text to Speech」に対応する構成です。
利用者が音声で質問した内容は、「Speech to Text」でテキストに変換します。
そのテキストをもとに、通常のRAGと同じように「Azure AI Search」で社内ドキュメントを検索し、検索結果を「Azure OpenAI Service」へ渡します。
「Azure OpenAI Service」が回答を生成したあとは、その回答テキストを「Text to Speech」で音声に変換します。
①利用者が音声で質問する
②Speech to Textで音声をテキスト化する
③Azure AI Searchで社内ドキュメントを検索する
④Azure OpenAI Serviceで回答を生成する
⑤Text to Speechで回答を音声として返す
②音声の有用性
通常のRAGシステムは、チャット画面にテキストで質問し、テキストで回答を受け取る形が多いです。
そこに音声入力と音声読み上げを組み合わせることで、より会話に近い形で社内情報へアクセスできるようになります。
この部分も、単に「Azure OpenAI Service」を呼び出せば終わりではありません。
音声データの扱い、アプリケーション側の連携、ネットワーク、認証、権限管理なども含めて考える必要があります。
5. 閉域網を前提にしたAzureネットワーク構成
①ネットワークリソース
社内向けのRAGシステムだったため、閉域的なネットワーク構成となりました。
最初に対応したのは、「Azure Virtual Network」を中心としたネットワーク設計です。
主要なPaaSサービスへインターネット経由で直接アクセスする構成は避けました。
「Azure OpenAI Service」、「Azure AI Search」、「Storage Account」、「Cosmos DB」、「Document Intelligence」、「Speech Service」などは、「Private Endpoint」を利用し、「Virtual Network」内からアクセスする構成にしました。
また、「Private DNS Zone」もあわせて構成しました。
「Private Endpoint」を使う場合、名前解決の設計も必要になります。
②名前解決
通常のホスト名でアクセスしつつ、実際の通信はプライベートIPへ向くようにするためです。
このあたりは、知らないことも多かったですが、Azureのネットワークを実務で触ってみて、かなり理解が深まった部分でした。
単に「Private Endpoint」を作れば終わりではなく、どのサブネットに配置するのか、どの「Private DNS Zone」と紐づけるのか、アプリケーション側から名前解決できるのかまで確認する必要があります。
RAGシステムの構築ではありますが、実際にはAzureネットワークの理解がかなり求められる現場でした。
6. Managed IdentityとAzure RBACで権限を管理
①認証
認証やアクセス権については、「Managed Identity」や「Azure RBAC」を利用しました。
各サービスに対して必要最小限の権限だけを付与し、不要なキー管理や過剰な権限付与を避ける方針で進めました。
認証設定は、Azure Portalから後で手作業で追加したのではなく、azdのenv設定で管理しました。
具体的には、envファイル側で以下の設定を有効にします。AZURE_USE_AUTHENTICATION=true
これにより、アプリを開いてログインする際に、認証が求められます。
②権限
アプリケーションから「Azure AI Search」、「Storage Account」、「Cosmos DB」などへアクセスする際も、可能な範囲で「Managed Identity」を使う構成にしました。
また、リージョンごとのVMクォータ制限に引っかかることもありました。
「azd provision」をかける際に、「App Service」の権限でエラーが何度も出ました。
Azureでは、サブスクリプションやリージョンごとに利用できるvCPU数やVMサイズに上限があります。
そのため、Bicepやazd provisionの定義自体に問題がなくても、選択したリージョンで必要なリソースを確保できず、デプロイ時にエラーになるケースがあります。
最初はBicepの書き方やApp Service側の設定ミスかと思いましたが、実際にはリージョンごとのクォータや利用可能なSKUが原因になっていることもありました。
この場合は、利用するリージョンを変更するか、必要に応じてAzure側でクォータ引き上げ申請を行う必要があります。
③認証と権限まとめ
AI系のサービスを使う場合でも、インフラとしては通常の業務システムと同じように、認証、権限、ネットワーク制御をきちんと設計する必要があります。
生成AIだから特別というより、むしろ扱う情報が社内文書になる分、より慎重に設計する必要があると感じました。
7. 監視サービス
①使用したサービス
RAGシステムでは、確認すべきポイントが複数あります。
今回の構成では、「Application Insights」と「Log Analytics」を利用し、「App Service」上で動くアプリケーションのログ、エラー、パフォーマンス情報などを確認できるようにしました。
②障害調査
また、障害が起きたときに、アプリケーション側の問題なのか、Azureリソース側の設定なのか、ネットワークや権限まわりの問題なのかを切り分けられるように、ログの確認先を整理しました。
特に、Private EndpointやManaged Identity、RBACを組み合わせた構成では、エラーの原因がアプリ側だけとは限りません。
接続先の名前解決、権限不足、Azureサービスへのアクセス失敗なども考えられるため、Application InsightsとLog Analytics Workspaceで状況を追えるようにしたことは大きかったです。
監視基盤を用意しておくことで、原因調査がしやすくなりました。
8. Bicepで環境ごとのインフラを管理
①Bicepファイル
インフラ構築では、「Azure Portal」から手作業で設定するのではなく、Azure公式がお勧めする「Bicep」ファイルを使ってコードを管理しました。
リソースグループ、ネットワーク、AIサービス、検索サービス、監視、「Private Endpoint」、権限設定などをBicepで定義しました。
環境変数を切り替えることで、開発環境と本番環境へ同じ構成を展開できるようにしました。
手作業でポータルから設定すると、どうしても環境差分が出やすくなります。
開発環境では動いているのに、本番環境では設定が少し違って動かない、ということも起きやすくなります。
②インフラのコード管理
その点、Bicepで管理すると、構成をコードとして残せます。
レビューもしやすくなりますし、あとから「なぜこの設定になっているのか」も追いやすくなります。
また、後からエラー以前の状態に戻すなどの対応も可能です。
繰り返し、「azd provision」を行なってコードをアップしてインフラ構築を試したりするのにも効率的になります。
今回のように、「Private Endpoint」、「Private DNS Zone」、「Managed Identity」、「RBAC」などが絡む構成では、Bocepファイルを仕上げるのは大変ですが、特にIaCで管理するメリットをかなり感じました。
9. リソース名変更とPrivate Endpointの再構築も経験
①思わぬ仕様
今回の構築では、「Document Intelligence」のリソース名変更や、「Private Endpoint」の再構築も経験しました。
Azureでは、一度作成したリソース名を後から変更できないケースがあります。
その場合は、既存リソースの名前を変えるのではなく、新しいリソースを作成し、接続先を切り替える形で対応しました。
影響確認
ただ、単純にリソースを作り直せば終わりではありません。
「Private Endpoint」、「Private DNS Zone」、アプリケーション側の接続設定、Bicep定義、環境変数なども関係してきます。
そのため、影響範囲を確認しながら進める必要がありました。
この対応を通して、AzureのPaaSサービスとネットワークのつながりをかなり実践的に学ぶことができました。
特に、「Private Endpoint」を使っている環境では、リソースを差し替えるだけでも接続先などの影響確認が必要になります。
ここは、実際にやってみないと理解しづらい部分でした。
10. 生成AIシステムはAIだけでは成り立たない
①AIシステムの構成
「Azure OpenAI Service」を使ったRAGシステムというと、どうしてもAI部分に注目が集まりやすいです。
ただ、実際に構築してみると、AIはシステム全体の一部でしかありませんでした。
「Azure-Samples」の「azure-search-openai-demo」をベースにすれば、RAGアプリケーションの全体像はかなり掴みやすいです。
②要件反映の難しさ
一方で、社内向けのシステムとして運用できる形にするには、そこから先の作り込みが必要でした。
検索基盤、ストレージ、ネットワーク、監視、認証、権限管理、BicepによるIaC、「Azure Developer CLI」によるデプロイ管理‥
さらに今回の構成では、「Speech Service」を使った音声入力、音声読み上げなども含まれていました。
こうした要素がきちんとつながって、初めて社内で使えるRAGシステムになります。
特に実務的だったのは、「Azure Developer CLI」を使って、インフラ構築とアプリケーションデプロイを分けて管理したことです。
azd provision --previewで差分を確認し、azd provisionでインフラを反映し、azd deployでアプリコードを「App Service」へデプロイする。
この流れにしたことで、インフラ変更とアプリ変更の影響範囲を分けて確認できるようになりました。
③インフラ構築の奥深さ
今回の現場を通して、生成AIシステムの構築には、AIの知識だけでなくAzureインフラ全体の理解が必要だと実感しました。
「Private Endpoint」や「Private DNS」を使った閉域構成、「Managed Identity」と「Azure RBAC」による権限管理、BicepによるIaC、「Azure Developer CLI」によるデプロイ運用、「Speech Service」を含む音声機能もありました。
どれも、社内向けRAGシステムを実際に動かすうえで欠かせない要素でした。
今回学んだことを、今後のAzure案件や生成AI関連のインフラ構築にも活かしていきたいです。