Azure x C#でRAGを作ろう! – Alternative Architecture DOJO

皆さんこんにちは、オルターブースの星加です!
今回は、Azure OpenAIの学習も兼ねて、Azureを使用したRAGを構築してみました。
Azureを使用することで、サクッとRAGを作ることが出来るので、Azure上の操作を中心に、作り方をご紹介したいと思います。

Azureでは、RAGは次のように説明されています。

検索拡張生成 (RAG) は、2 つのテクニックを組み合わせた AI フレームワークです。まず、データベース、ドキュメント、Web などの外部ソースから関連情報を取得します。この情報が収集されると、それを用いて回答の生成の際に情報を提供し、その質を高めるために使用されます。このアプローチを使用すると、検索テクニックと生成テクニックの両方の長所が活用され、回答が正確で関連性が高いものであり、さらに入手可能な最新かつ特定の情報によってコンテキストが補強されていることが保証されます。この 2 つの機能により、RAG システムは純粋な生成モデルよりも情報に基づいた繊細な出力を生成できます。

azure.microsoft.com

学習したデータから回答を生成するのではなく、データを引用し回答を生成することで、より繊細な回答が可能になります。

では実際に、Azureリソースを使用して、RAGを構築しましょう。
今回は3つのリソースを使用した、シンプルなRAGにします。

  • Azure サブスクリプション
  • .NET 8.0
  • Visual Studio 2022

まずはRAGの構築に必要なリソースを準備しましょう。

1-1. リソースのデプロイ

以下のリソースを順にデプロイします。
記載されていない設定値は、デフォルトのままで大丈夫です。
各リソースの名前は任意ですが、パブリックURLに名前が含まれるものもあるので、個人の情報などは含まないようにしましょう。

  1. リソースグループ

    • 基本
      • リソースグループ名: 任意のリソースグループ名
      • リージョン: Japan East
  2. Azure OpenAI

    • 基本
      • リソースグループ: 1のリソースグループ名
      • リソース名: 任意のリソース名
      • リージョン: East US 2
      • 価格レベル: Standard S0
    • ネットワーク
      • タイプ: All networks, including the internet, can access this resource.
  3. Azure AI Search

    • 基本
      • リソースグループ: 1のリソースグループ名
      • リソース名: 任意のリソース名
      • リージョン: Japan East
      • 価格レベル: 基本
    • ネットワーク
      • エンドポイントの接続: パブリック
  4. ストレージアカウント

    • 基本
      • リソースグループ: 1のリソースグループ名
      • ストレージアカウント名: 任意のリソース名
      • リージョン: Japan East
      • パフォーマンス: Standard
      • 冗長性: ローカル冗長ストレージ (LRS)
    • ネットワーク
      • パブリックネットワークアクセス: 有効にする
      • パブリックネットワークアクセススコープ: すべてのネットワークから有効にする

1-2. モデルのデプロイ

検索前の下処理と、回答の生成に使用する2つのモデルをAzure OpenAIにデプロイします。

今回は gpt-4.1 を使用していますが、他のモデルを使用することもできます。

  1. 作成した Azure OpenAI リソースに移動し、「概要 > Explore Azure AI Foundry portal」を押します。

  2. Azure AI Foundry が開いたら、「デプロイ > モデルのデプロイ > 基本モデルをデプロイする」を押します。

  3. gpt-4.1 を選択し、「確認」を押します。

  4. リソースの場所が「Azure OpenAI」のリージョンと同様の East US 2 になっていることを確認し、「デプロイ」を押します。
    クォータが不足している時は、デプロイできない可能性があるので注意してください。

  5. 再度「デプロイ」を押し、モデルのデプロイに成功したことを確認します。

  6. 1-2-2 ~ 1-2-4 の手順を参考に text-embedding-3-large をデプロイします。
    両モデルともデプロイに成功したことを確認します。

1-3. データソースの準備

Azure Blob Storage に、RAGで使用するサンプルデータをアップロードします。
今回は、内閣官房情報通信技術(IT)総合戦略室の「アジャイル開発実践ガイドブック」を使用します。

以下リンクからダウンロードできます。
https://www.digital.go.jp/assets/contents/node/basic_page/field_ref_resources/e2a06143-ed29-4f1d-9c31-0f06fca67afc/150a60b4/20220422_resources_standard_guidelines_guidebook_01.pdf

  1. 作成した Azure OpenAI リソースに移動し、「ストレージ ブラウザー > BLOBコンテナー」を押します。

  2. 「コンテナ―の追加」を押し、画面右側に出てきたウィンドの「名前」に documents を入力し、「作成」を押します。

  3. 追加された「documents」を押します。

  4. 「アップロード」を押し、画面右側に出てきたウィンドにダウンロードした 20220422_resources_standard_guidelines_guidebook_01.pdf を添付し、「アップロード」を押します。

  5. PDFのアップロードに成功したことを確認します。

1-4. インデックスの作成

Azure Blob Storage にアップロードしたドキュメントのインデックスを作成します。

  1. 作成した Azure AI Search リソースに移動し、「データのインポートとベクター化」を押します。

  2. 「Azure Blob Storage」を押します。

  3. 「RAG」を押します。

  4. 以下の値をそれぞれ入力し、「次へ」を押します。

    • ストレージアカウント: ストレージアカウント のリソース名
    • BLOB コンテナー: documents

  5. 以下の値をそれぞれ入力し、「次へ」を押します。

    • Azure OpenAI Service: Azure OpenAI のリソース名
    • モデルデプロイ: text-embedding-3-learge
    • 認証の種類: API キー
    • 「Azure OpenAI サービスに接続すると…」にチェックを入れる

  6. これ以降はそのままの値で「次へ」を押し、「レビューと作成」まで進みます。

  7. 「オブジェクト名のプレフィックス」の値を控えておきます。
    今回の場合はrag-1757260738324です。
    値を控えたら「作成」を押します。

1-5. 動作テスト

実際にドキュメントを参照しLLMから回答を得られるか、動作テストを行います。

  1. Azure OpenAI リソースに移動し、「概要 > Explore Azure AI Foundry portal」を押し、Azure AI Foundry を開きます。

  2. 「チャット > データを追加する > データソースの追加」を押します。

  3. 以下の値をそれぞれ入力し、「次へ」を押します。

    • データソースの種類: Azure AI 検索
    • Azure AI Search Service: AI Search のリソース名
    • Azure AI Search 検索インデックス: 3-2-7 で控えた 「オブジェクト名のプレフィックス」の値

  4. 以下の値をそれぞれ入力し、「次へ」を押します。

    • 検索の種類: セマンティック
    • 既存のセマンティック検索の構成を選択する: 3-2-7 で控えた 「オブジェクト名のプレフィックス」の値の末尾に -semantic-configuration が付いたもの
      • 今回の場合は rag-1757260738324-semantic-configuration

  5. 「Azure リソース認証の種類」 を API キー にし、「次へ」を押します。

  6. 「確認して終了」まで来たら、「保存して終了」を押します。

  7. テキストボックスに、 スクラムマスターについて教えてください。 と入力し、テキストボックス右下のボタンからプロンプトを送信します。

  8. 「参照」から、実際にインデックスを作成したファイルを参照していることを確認します。

これで、RAGとして動作していることを確認できました!

チャットプレイグラウンドでの動作確認ができたので、コンソールからAIとやり取りできるアプリケーションを作成しましょう!

2-1. 環境の準備

Chat部のプログラムを作成する環境を準備しましょう。

  1. Visual Studio を起動し、新しいプロジェクトを作成します。

  2. コンソールアプリテンプレートを選択し、「次へ」を押します。

  3. プロジェクト名に、任意の値を入力します。
    今回はRagOnAzureにしました。
    入力したら、「次へ」を押します。

  4. フレームワークは「.NET 8.0」を選択し、「作成」を押します。

これで環境の準備が整いました。

2-2. パッケージのインストール

プロジェクトが作成出来たら、必要なパッケージをインストールします。
今回は以下のパッケージを使用します。

  • Azure.Identity
  • Azure.AI.OpenAI
  • Azure.Search.Documents
  • DotNetEnv
    パッケージのインストール方法について案内が不要な方は 2-3. .envファイルの作成 に進んでください。

  • 「プロジェクト > NuGet パッケージの管理」からパッケージマネージャを起動します。

  • 以下の手順で、パッケージをインストールします。

    1. 「参照」を押します。
    2. 検索ボックスに、パッケージ名を入力します。
    3. パッケージを選択し、インストールを押します。

  • 同様の手順で、パッケージを全てインストールします。

  • 「インストール済み」タブから、パッケージがインストールできたことを確認します。

2-3. .envファイルの作成

環境情報を入力する、.envファイルを作成します。

  1. プロジェクトを「右クリック > 追加 > 新しい項目の追加」を押します。

  2. .env と入力し、「作成」を押します。

  3. 以下を参考に、それぞれ値を控えておき、.envファイルに入力します。

Azure OpenAI
Azure OpenAIリソースを開き、「Keys and Endpoint」から以下の値をそれぞれ控えます。
① キー1
② エンドポイント

「概要」からAzure AI Foundryを開き、「デプロイ」から以下の値を控えます。
③ 名前

Azure AI Search
Azure AI Searchリソースを開き、「概要」から、以下の値を控えます。
④ URL

「キー」から、以下の値を控えます。
⑤ プライマリ管理者キー

「インデックス」から、以下の値を控えます。
⑥ インデックス名

控えた値を、.envに入力します。

AZURE_OPENAI_ENDPOINT = ②
AZURE_OPENAI_API_KEY = ①
AZURE_OPENAI_DEPLOYMENT_NAME = ③

AZURE_AI_SEARCH_ENDPOINT = ④
AZURE_AI_SEARCH_API_KEY = ⑤
AZUIRE_AI_SEARCH_INDEX_NAME = ⑥

これで.envファイルの準備は完了です。

2-4. プログラムの作成

プログラムを作成する準備が整ったので、コードを書いていきましょう。

Program.cs に、以下のコードを入力します。

using Azure;
using Azure.AI.OpenAI;
using Azure.AI.OpenAI.Chat;
using OpenAI.Chat;

DotNetEnv.Env.Load("your-env-file-path-here"); // ここに.envファイルのパスを入力

// 環境変数から設定値を取得
string openAiEndpoint = DotNetEnv.Env.GetString("AZURE_OPENAI_ENDPOINT");
string openAiApiKey = DotNetEnv.Env.GetString("AZURE_OPENAI_API_KEY");
string openAiDeploymentName = DotNetEnv.Env.GetString("AZURE_OPENAI_DEPLOYMENT_NAME");

string aiSearchEndpoint = DotNetEnv.Env.GetString("AZURE_AI_SEARCH_ENDPOINT");
string aiSearchApiKey = DotNetEnv.Env.GetString("AZURE_AI_SEARCH_API_KEY");
string aiSearchIndexName = DotNetEnv.Env.GetString("AZUIRE_AI_SEARCH_INDEX_NAME");

// Azure OpenAIクライアントの作成
AzureOpenAIClient azureClient = new(new Uri(openAiEndpoint), new AzureKeyCredential(openAiApiKey));
ChatClient chatClient = azureClient.GetChatClient(openAiDeploymentName);

ChatCompletionOptions options = new()
{
    Temperature = 0.7f,
    TopP = 0.95f,
    FrequencyPenalty = 0.0f,
    PresencePenalty = 0.0f,
    MaxOutputTokenCount = 13107,
};

// ChatCompletionOptions.AddDataSource() は将来的に、SDKの仕様変更を受ける可能性がある
// その警告が出るため、今回は理解した上で警告を非表示にする
#pragma warning disable AOAI001

options.AddDataSource(new AzureSearchChatDataSource()
{
    Endpoint = new Uri(aiSearchEndpoint),
    IndexName = aiSearchIndexName,
    Authentication = DataSourceAuthentication.FromApiKey(aiSearchApiKey),
});

#pragma warning restore AOAI001

// チャットメッセージリストの初期化(システムメッセージのみ)
var messages = new List
{
    new SystemChatMessage("あなたはAIアシスタントです。"),
};

while (true)
{
    Console.Write("あなた: ");
    string? userInput = Console.ReadLine();

    // ユーザー入力が空またはnullの場合は再入力を促す
    if (string.IsNullOrWhiteSpace(userInput))
    {
        Console.WriteLine("質問を入力してください。");
        continue;
    }

    // "exit"が入力された場合はプログラムを終了
    if (userInput.Trim().ToLower() == "exit")
    {
        Console.WriteLine("チャットを終了します。");
        break;
    }

    // ユーザーメッセージを追加
    messages.Add(new UserChatMessage(userInput));

    try
    {
        Console.Write("AI: ");
        ChatCompletion completion = await chatClient.CompleteChatAsync(messages, options);

        if (completion?.Content?.Count > 0)
        {
            string response = completion.Content[0].Text;
            Console.WriteLine(response);

            // AIの応答をメッセージ履歴に追加(会話の継続性のため)
            messages.Add(new AssistantChatMessage(response));
        }
        else
        {
            Console.WriteLine("応答を取得できませんでした。");
        }
    }
    catch (Exception ex)
    {
        Console.WriteLine($"エラーが発生しました: {ex.Message}");
        Console.WriteLine("もう一度お試しください。");
    }

    Console.WriteLine();
}

このコード内で使用している、 ChatCompletionOptions.AddDataSource() というメソッドは将来的にSDKの仕様変更を受ける場合があるため警告が出ます。
それを把握した上で、警告を非表示している点に注意してください。

RAGの構築が完了したので、動作を確認しましょう!

画面上部の「」アイコンから、デバッグ実行します。

ターミナルが起動するので、 スクラムマスターについて教えてください。 と入力し、「Enter」キーを押します。
しばらく待つと、無事に回答が返ってくることを確認できました!

プログラムを終了する際は、exitと入力すると終了できます。

今回はAzureとC#を使用して、簡単なRAGを作成してみました!
Azureを活用することで、比較的簡単に作ることができました。
基本的な構成なので、ここから自由にカスタマイズすることが出来ると思います。
是非、自分好みのRAGにしてみてください!


サービス一覧
www.alterbooth.com
cloudpointer.tech
www.alterbooth.com




Source link

関連記事

コメント

この記事へのコメントはありません。