VoiceRAGをプロキシ環境で動かしてみた

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3764962/9396c872-1cd5-2cb8-832a-be9631786c93.png)

作成日：2025年1月25日(土)

## １．はじめに

2024年5月13日にOpenAIが[Spting Update](https://openai.com/index/spring-update/)で発表したAdvanced Voice Modeは、感情豊かな話し方と自然な発音を実現した衝撃的な技術革新でした。

この技術を自分のパソコンでも体験してみたいと考えていたところ、2024年10月2日に待望のRealtime APIを使用したVoiceRAGの記事が「[AI -Azure AI service Blog](https://techcommunity.microsoft.com/category/ai/blog/azure-ai-services-blog)」に掲載されました。Azure AI Searchの知識はありませんでしたが、試しにAzure AI Searchの設定なしで自宅のPCで動かしてみました。RAGは機能しませんでしたが、自然な発音での会話が実現できました（多少の音声の途切れはありますが）。

この成功を受けて会社のPCでも同じ手順を試してみましたが、残念ながら動作しませんでした。

会社のPCで動作しない原因を調査したところ、アプリケーションが社内プロキシサーバーを通過できないことが判明したため、対策を実施し、自宅と会社の両環境で利用できるようにしました。

この記事ではAzure-Sample/aisearch-openai-rag-audioの設定方法と、そのオリジナルをフォークしてプロクシを越えられるように修正した私のリポジトリpotofo/aisearch-openai-rag-audioについて紹介します。

## ２．VoiceRAGとは

VoiceRAGとは、音声データを活用した検索・質問応答システムです。音声ファイルから情報を抽出し、その内容に対して自然な会話形式で質問応答を行うことができます。Azure AI SearchとOpenAIを組み合わせることで、音声データの中から関連情報を効率的に検索し、ユーザーの質問に的確に回答することが可能になります。

## ３．aisearch-openai-rag-audioとは

Azure-Sample/aisearch-openai-rag-audioとは、音声インターフェイスを使用したRAG（Retrieval-Augmented Generation）アプリケーションの実装例を提供するリポジトリです。GPT-4のリアルタイムオーディオAPIを活用し、音声インターフェイスと検索機能を組み合わせた革新的なソリューションを実現しています。このプロジェクトについては、[ブログ記事](https://techcommunity.microsoft.com/blog/azure-ai-services-blog/voicerag-an-app-pattern-for-rag--voice-using-azure-ai-search-and-the-gpt-4o-real/4259116)で詳細な説明を確認でき、短い動画で実際の動作デモを見ることができます。
Azure-Sample/aisearch-openai-rag-audioではFrontend(RTClient)、Backend(RTMiddleTier)、Azure AI Searchの3層構造でRAGシステムを構築しています。

以下は本家のブログ記事にある構造図です。
![pablocastro_1-1727739495810.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3764962/0c048860-9690-27ee-2d2c-85a0472d9346.png)

https://github.com/Azure-Samples/aisearch-openai-rag-audio

https://techcommunity.microsoft.com/blog/azure-ai-services-blog/voicerag-an-app-pattern-for-rag--voice-using-azure-ai-search-and-the-gpt-4o-real/4259116

## ４．必要なもの

Azure-Sample/aisearch-openai-rag-audioは、AI Search系の環境変数を空に設定することで、RAG機能を使用せずgpt-4o-realtime-previewとの会話アプリとして動作させることができます。

Azure AI Serviceを完全に実装するには、ストレージアカウント、Azure Blob Storage、Azure OpenAI Serviceなど、複数のサービスの設定が必要となります。これは最初は複雑に感じるかもしれません。ただし、まずはAI Serviceの設定なしで起動することで、複雑な部分を回避でき、より簡単に始められますので、このアプローチをおすすめします。

| No | 区分 | 使いたいサービス | サービス/アプリ/モデル | 説明 |
| --- | --- | --- | --- | --- |
| 1 | Azure | Azure OpenAI Service | gpt-4o-realtime-preview | 2024年10月1日にOpenAI/Azure OpenAIで公開されたRealtime APIに対応するLLM（Large Language Model）です。OpenAIはこの後、応答タイミングをコントロールできるgpt-4o-realtime-preview-2024-12-17をローンチしていますが、Azure OpenAIではまだ提供されていません。 |
| 2 |  | Azure AI Search | → | ベクトル検索を提供するサービス |
| 3 |  |  | ストレージアカウント | Azure AI Searchに取り込ませるAzure Blob Storageを管理するアカウント<br>Azure AI SearchはSharePoint Online等の、他のデータソースからもデータが取り込めるます。今回は構造をできるだけ簡単にするため、Blob Storageを提供するために作成します。<br>Blob StorageはRest APIからもファイル転送できるので便利です。 |
| 4 |  |  | Azure Blob Storage | ストレージアカウントのリソース配下に作成できるストレージサービスの一つです。 |
| 5 |  |  | text-embedding-3-large | Azure AI Searchで知識源を取り込む際に使用するEmbeddingモデルのLLM |
| 6 | PC | aisearch-openai-rag-audio | Powershell | aisearch-openai-rag-audioのREADME.mdページにはpwshというPowershell7のコマンドを利用してプログラムを起動していますが、Powershell5でも問題なく動きますので、pwshコマンドだけのためにPowershellをインストールする必要はありません。 |
| 7 |  |  | Azure Developer CLI | aisearch-openai-rag-audioのREADME.mdページAzure App Serviceでデプロイする場合に必要とのことなのでserverでデプロイ(すなわちPCで起動)する場合には必要ありません。 |
| 8 |  |  | Node.js-20.12.2 | aisearch-openai-rag-audioのfrontend部分のGUIを起動するためのjavascript言語です。scripts/start.ps1<br>※.npmrcに起業プロキシの設定済みである必要があります。 |
| 9 |  |  | Pyrhon-3.12 | aisearch-openai-rag-audioのbackend部分の中継サーバ部分を起動するためのPython言語です。<br>※pip.iniに起業プロキシの設定済みである必要があります。 |
| 0 |  |  | Git | aisearch-openai-rag-audioをデプロイするのに必要です。
scripts/start.ps1の中で呼び出しているかもしれません。 |

※グレー部分のアプリは今回、使用しません。

## ５．前提条件

このガイドは、AzureポータルでストレージアカウントとBlobストレージを既に構築していることを前提としています。

私の会社ではストレージをSharePoint Onlineに移行済みで、理想的にはAI SearchでSharePoint Onlineを検索対象にしたいところです。しかし、個人環境ではSharePoint Onlineが使用できないため、Azure Blob Storageに保存したファイルをRAGの知識源として活用します。

AI Searchの仕組みとしては、Azure Blob Storageのファイルをインポートする際に、自動的にインデックス作成とベクトル化が行われます。

なお、Azure Blob Storageはストレージアカウントのサブリソースとして作成するため、まずストレージアカウントを作成し、その後でAzure Blob Storageを構築します。

以下が私が作成したストレージアカウントの設定内容です
設定は[Azureポータル]⇒[ストレージアカウント]で「＋作成」ボタンで行います。

| No | 項目 | 設定 |
| --- | --- | --- |
| 1 | サブスクリプション | Azure subscription |
| 2 | 　┗リソースグループ | Production-RG |
| 3 | ストレージアカウント名 | ptfstr |
| 4 | リージョン | (Asia Pacific) Japan East |
| 5 | プライマリーサービス | Azure Blob Storage またはAzure Data Lake Storage Gen 2 |
| 6 | パフォーマンス | Standard |
| 7 | 冗長性 | ローカル冗長ストレージ(LRS) |
| 8 | データ保護<br>┗BLOBの論理的な削除を有効にする | チェックを外す。<br>**チェックするとバックアップサービスが自動的に作成されストレージの世代管理がされるため、コストが掛ります。** |
| 9 | 　コンテナーの論理的な削除を有効にする | チェックを外す。 |
| 0 | 　ファイル共有の論理的な削除を有効にする | チェックを外す。 |

※ストレージアカウントはプライベートエンドポイントも作成できるので、インターネットに公開せずサービスを構築することも可能です。

以下が私が作成したAzure Blob Storageの設定内容です。
設定は[Azureポータル]⇒[ストレージアカウント]⇒[ptfstr]⇒[データストレージ]⇒[コンテナー]で「＋コンテナー」ボタンで行います。

私はptf-containerというコンテナーを作成しました。

美味しそうな内容で音声応答を試したいと考え、

ptf-containerにRoo CodeとFelo.aiを使用してバーガーキングのメニュー説明を作成し、アップロードしました（メニューの内容の正確性は未確認です）。
プロンプト：バーガーキングの全てのメニューを商品ごとに300文字で説明してください。

作成したメニューは私のGitHubのaisearch-openai-rag-audioフォークのdataフォルダに保存しています。

※ChatGPTでは出力トークンの制限により長文が途中で切れてしまうため、Roo Codeのチャットで内容を作成し、Felo.aiで校正を行いました。

https://github.com/potofo/aisearch-openai-rag-audio/blob/Support-Corporate-Proxy/data/burgerking.ja-JP.md

## ５．インストール手順

インストールの流れは①AI Searchをデプロイする、②AI Searchでインポートする、③

### 5-1 AI Searchをデプロイする

AzureポータルからAI Searchをデプロイします。
[Azureポータル]⇒[AI Search]
※50MBまでは無料で作成することができます。

![CreateAzureAIService.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3764962/923212ce-e96d-bb6f-3b34-d1b4830df976.png)

※デフォルトで作成するとStandard S1(160GB)の価格レベルに設定され$330.34/月が設定されてしまいますので、必ず「価格レベルの変更」を教えて変更しましょう。

![CreateAzureAIService_scale.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3764962/ceb5c9fa-f93a-d3be-ae29-78f4504aeebf.png)

### 5-2 AI Searchでインポートする

　作成したAI Searchに事前に作成しておいたAzure Blob Storageをインポートします。
　このとき、

　[Azureポータル]⇒[ptf-aisearch]⇒[概要]で「データのインポートとベクター化」を実行します。

### 5-2 AI Searchでインポートする

　作成したAI Searchに事前に作成しておいたAzure Blob Storageをインポートします。
　[Azureポータル]⇒[ptf-aisearch]⇒[概要]で「データのインポートとベクター化」を実行します。

| No | 工程 | 項目 | 設定 | 説明 |
| --- | --- | --- | --- | --- |
| 1 | データへの接続 | データ接続の設定 | Azure Blob Storage |  |
| 2 |  | Azure Blob Storageの構成 |  |  |
| 3 |  | 　サブスクリプション | Azure subscription |  |
| 4 |  | 　ストレージアカウント | ptfstr | 作成したストレージアカウントを指定 |
| 5 |  | 　BLOBコンテナー | ptf-container | 作成したBLOBコンテナーを指定 |
| 6 |  | 　BLOBフォルダ | ＜空＞ |  |
| 7 |  | 　解析モード | Markdown | 今回はバーキンのメニューをMarkdownにしていますので「Markdown」を選択します。 |
| 11 |  | 　　削除の追跡を有効にする | □ |  |
| 12 |  | 　　マネージドIDを使用して認証する | □ |  |
| 13 | テキストをベクトル化する | Kind | Azure OpenAI |  |
| 14 |  | サブスクリプション | Azure subscription |  |
| 15 |  | Azure OpenAI Service | ptf-eus2 |  |
| 16 |  | デプロイモデル | text-embedding-3-large |  |
| 17 |  | Azure OpenAIサービスに接続すると、アカウントに追加料金が発生… | ☑ |  |
| 18 | 詳細設定 | インデックスフィールド | ＜プレビューと編集＞で確認 |  |
| 19 |  | インデックス作成のスケジュール | 一度だけ |  |

Azure AI Searchでは作成したベクトルデータベースの検索を試すことができます。

![CreateAzureAIService_querytest.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3764962/d9b59f15-56e4-71d5-2a24-16dcca3dcbf8.png)

### 5-3 AI Searchのエンドポイント、APIキーを調べる

Azure AI Searchではエンドポイントの情報をエンドポイント、インデックスで管理し、エンドポイントにAPIキーが割り当てられています。
APIキーには管理キー(おそらく更新権限があるもの)とクエリキー(おそらく検索のみのもの)がります。

エンドポイントは概要ページ、インデックスは[検索管理]⇒[インデックス]、APIキーは[設定]⇒[キー]ページで確認する必要があり少し面倒です。
ここでは確認方法を解説します。

①エンドポイント
　エンドポイントは概要ページのURLとなります。
　[Azureポータル]⇒[AI Search]⇒<ptf-aisearch>⇒[概要]から参照できます。
　[https://ptf-aisearch.search.windows.net](https://ptf-aisearch.search.windows.net/)

 ![CreateAzureAIService_endpoint.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3764962/8d1bed24-48ac-c3ef-669e-4dfb6c765f6b.png)

②インデックス
　インデックスとはAI Searchでインポートしたときに作成されるデータベースのようなものです。
　[Azureポータル]⇒[AI Search]⇒<ptf-aisearch>⇒[検索管理]⇒[インデ ックス]から参照できます。 
　以下の例では「vector-1737766332330」がインデックスとなります。

 ![CreateAzureAIService_index.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3764962/0dff258d-d141-e242-7a49-ed54d3f0de5a.png)

③APIキー(クエリキー)
　APIキーとはAzure AI Serviceのエンドポイントに外部からアクセスするときに指定するパスワードのようなものです。
　[Azureポータル]⇒[AI Search]⇒[設定]⇒[キー]ページで確認できます。

 ![CreateAzureAIService_apikey.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3764962/e46215a2-452a-c54d-03c9-57c4a4834c6d.png)

取得したエンドポイント情報は以下の通りとなります。

| No | 項目 | 値 |
| --- | --- | --- |
| 1 | エンドポイント | https://ptf-aisearch.search.windows.net |
| 2 | インデックス | vector-1737766332330 |
| 3 | APIキー | xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx |

### 5-4 potofo/aisearch-openai-rag-audioのデプロイ

オリジナルのAzure-Sample/aisearch-openai-rag-audioは企業プロキシを越えられないため、今回は私が少しだけ修正を加えたpotofo/aisearch-openai-rag-audioをデプロイします。
「Support-Corporate-Proxy」ブランチにプロキシ対応のコードがありますので、ご利用ください。
初めてのpull requestなので旨くできたか分かりませんが、[**Support Corporate Proxy #74**](https://github.com/Azure-Samples/aisearch-openai-rag-audio/pull/74)で本家のAzure-Sample/aisearch-openai-rag-audioにpull requestも出しています。
```
portf@Ardbeg MINGW64 /k
$ git clone https://github.com/potofo/aisearch-openai-rag-audio.git
Cloning into 'aisearch-openai-rag-audio'...
remote: Enumerating objects: 747, done.
remote: Counting objects: 100% (363/363), done.
remote: Compressing objects: 100% (100/100), done.
remote: Total 747 (delta 288), reused 269 (delta 263), pack-reused 384 (from 2)
Receiving objects: 100% (747/747), 2.09 MiB | 10.78 MiB/s, done.
Resolving deltas: 100% (396/396), done.

portf@Ardbeg MINGW64 /k
$

portf@Ardbeg MINGW64 /k
$ cd aisearch-openai-rag-audio/

portf@Ardbeg MINGW64 /k/aisearch-openai-rag-audio (main)
$ git checkout Support-Corporate-Proxy
Switched to a new branch 'Support-Corporate-Proxy'
branch 'Support-Corporate-Proxy' set up to track 'origin/Support-Corporate-Proxy'.

portf@Ardbeg MINGW64 /k/aisearch-openai-rag-audio (Support-Corporate-Proxy)

```

![gitclone.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3764962/fc20172d-e363-ed16-8b85-812953e6be78.png)

![choose_branch.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3764962/d2ffd15a-9799-ee1f-f07d-e18e584b2c2a.png)

https://github.com/potofo/aisearch-openai-rag-audio.git

### 5-3 .envファイルを作成する

potofo/aisearch-openai-rag-audioの[README.md](https://github.com/potofo/aisearch-openai-rag-audio/blob/Support-Corporate-Proxy/README.md)の「**Development server」**の説明に従って.envファイルをapp\backend\.envに作成します。

エンドポイントはgpt-4o-realtime-previewのエンドポイントとAzure AI Serachのエンドポイントを設定します。
会社のプロキシはこのファイルのHTTPS_PROXYに設定してください。
HTTPS_PROXYは空欄にするとダイレクトで接続されます。

```
AZURE_OPENAI_ENDPOINT=wss://xxxxx.openai.azure.com/
AZURE_OPENAI_REALTIME_DEPLOYMENT=gpt-4o-realtime-preview
AZURE_OPENAI_REALTIME_VOICE_CHOICE=echo
AZURE_OPENAI_API_KEY=xxxxxxxxxxxxxxxxxxxxxxxxxxxx
HTTPS_PROXY=<your proxies ex. http://user:pass@192.168.1.2:3128>
AZURE_SEARCH_ENDPOINT=https://xxxxx.search.windows.net
AZURE_SEARCH_INDEX=vector-xxxxxxxxxx
AZURE_SEARCH_API_KEY=xxxxxxxxxxxxxxxxxxxxxxxxxxxx
```

### 5-4 aisearch-openai-rag-audioの実行

本家のREADME.mdにはPowershell7で実装されたpwshコマンドで実行するとありますがpowershell5でも動きますので、以下のように実行します。

私はvscodeのターミナルから実行しました。

```
PS Q:\OneDrive\Git\aisearch-openai-rag-audio> powershell .\scripts\start.ps1
```
vscodeのターミナルで「powershell .\scripts\start.ps1」を実行します。
![start_command_on_terminal.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3764962/cd5e998c-e70c-0b2c-0031-e671a90d5015.png)

start.ps1を実行するとPythonの依存パッケージのダウンロード、Node.jsの依存パッケージのダウンロードがされます。
※ここで何らかのエラーが発生する場合はpip.iniか.npmrcのプロキシの設定が間違っています。

以下のように「======== Running on http://localhost:8765 ========」が表示されれば成功です。
※「use proxies:」の後ろにプロキシ情報が表示される場合、aiohttp.proxyが利用されています。

```
Starting backend

INFO:voicerag:Running in development mode, loading from .env file
INFO:voicerag:use proxies: http://*****:*****@192.168.1.2:3128
INFO:voicerag:Realtime voice choice set to echo
======== Running on http://localhost:8765 ========
(Press CTRL+C to quit)
```

ブラウザで「http://localhost:8765」にアクセスすると以下の様な画面が表示されます。

![talk_to_data.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3764962/19491c07-642e-644c-21e2-0240ea599ee2.png)

この後、中央のマイク「🎙」のアイコンのボタンを押すとボタンが赤色の「会話停止」に変わりRealtime APIと会話できるようになります。

![talk_to_data_start.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3764962/13966430-ea34-1fe7-b4a0-c64b9b4c6184.png)

「ワッパーの具材を教えてください。」と質問するとAI Searchに登録した内容から答えてくれます。
参照したナレッジもきちんと表示してくれます。（会話終了してもナレッジは消えないバグがあるようです）
因みに「日本の総理大臣を教えてください。」と質問すると「日本の総理大臣に関する情報は見つかりませんでした」と回答されます。

## ６．関連URL
https://github.com/Azure-Samples/aisearch-openai-rag-audio/pull/74

## ７．参考
https://github.com/Azure-Samples/aisearch-openai-rag-audio

https://techcommunity.microsoft.com/blog/azure-ai-services-blog/voicerag-an-app-pattern-for-rag--voice-using-azure-ai-search-and-the-gpt-4o-real/4259116

https://zenn.dev/headwaters/articles/365944c0cd01f4