実用的で効果的なRAG（Retrieval-Augmented Generation）アプリケーション構築ガイドライン

# はじめに

この記事は、Retrieval-Augmented Generation (RAG) アプリケーションを実際に構築した経験をもとに執筆しています。単なるセットアップ手順の解説ではなく、実運用で RAG を効果的に活用するためのポイントに焦点を当てます。

他の視点があれば、ぜひコメントしてください！

本記事では、RAG の基本概念については既に理解していることを前提としています。もし基礎知識に不安がある場合は、まず関連リソースを確認してから読み進めることをおすすめします。本ガイドでは Azure AI Search を基盤としていますが、他の技術にも応用可能な原則について解説します。

実践的で分かりやすい構成とするために、各ステップを以下の2 つの要素を軸に構成しています。

- **概念とアプローチ**： 何をすべきか、なぜそれが重要なのかを解説
- **実際のシナリオ**： 実際の具体例や活用シーンを紹介

このガイドでは、RAG アプリケーションをただ作るだけでなく、実用的な価値を最大限に引き出す方法を学べます。それでは、始めましょう！🚀

# ステップ一覧
- [ステップ1：要件の明確化](#ステップ1要件の明確化)
- [ステップ2：入力データの評価](#ステップ2入力データの評価)
- [ステップ3：精度指標の定義](#ステップ3精度指標の定義)
- [ステップ4：アプリケーションアーキテクチャの設計とAzure AI Searchスキーマの設計](#ステップ4アプリケーションアーキテクチャの設計とazure-ai-searchスキーマの設計)
- [ステップ5：アプリケーションの実装](#ステップ5アプリケーションの実装)
- [ステップ6：データのAzure AI Searchへのインポート](#ステップ6データのazure-ai-searchへのインポート)
- [ステップ7：実行](#ステップ7実行)
- [ステップ8：結果の分析と最適化](#ステップ8結果の分析と最適化)


# ステップ1：要件の明確化

## 概念とアプローチ

実装に取りかかる前に、RAG アプリケーションの目的を明確にすることが重要です。明確なゴールを設定することで、実用的なソリューションを構築し、実際の価値を提供できます。

例えば、従業員が社内ドキュメントを見つけるのに苦労している場合、RAG システムは役立ちます。しかし、具体的にどのような機能が必要でしょうか？

- 関連するファイルを検索するだけでよいのか？
- それとも AI による要約も必要か？
- ユーザーは元のファイルにアクセスすべきか、それとも抽出されたコンテンツや AI 要約のみを提供するのか？

このように、要件を事前に明確にすることで、不要な開発を防ぎ、実際のニーズに合ったソリューションを構築できます。

## 実際のシナリオ

本ガイドでは、ユーザーのクエリとドキュメントの言語が一致していることを前提とし、以下の 3 つの要件を設定します。

1. 関連性の高いドキュメントから AI による要約を提供します。
2. 関連するドキュメントの詳細情報（ファイル名や保存場所など）を表示します。
3. ユーザーがリンクをクリックして、関連ドキュメントに直接アクセスできるようにします。

### 例

- **ユーザーのクエリ**
    - 「海外出張の費用精算の申請方法は？」
- **AI による要約**
  - 経費報告書に領収書、上司の承認フォーム、旅程表を添付して提出する。
  - 費用が会社のポリシーに準拠していることを確認する。
  - 領収書や支払い証明を添付し、経費精算システムまたは経理部門を通じて申請する。
  - 記録および監査のためにコピーを保管する。
  - **関連ファイル（関連度順）**：
    - 経費報告書_テンプレート.xlsx
    - 出張承認書.pdf
    - 旅行日程表_サンプル.docx

このように明確な要件を設定することで、単なる検索ツールではなく、実際にビジネス価値を提供する RAG アプリケーションを構築できます。

以下は、アプリケーションをイメージしやすくするための画像です。

![RAG_Application.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/596658/d4644b96-5f06-4ea5-b0ce-bd7ff6a32042.png)


# ステップ2：入力データの評価

## 概念とアプローチ

RAG の検索サービス（例：Azure AI Search）にデータを取り込む前に、入力データを評価することが重要です。これにより、効率的なデータ取り込みプロセスを設計し、予期しない課題を回避できます。

考慮すべき主なポイントは以下の通りです。

- **ファイルの種類とサイズ**
  - 対象となるドキュメントの種類（PDF、Word、Excel など）
  - 平均および最大ファイルサイズ（処理時間やストレージ容量の見積もりに必要）

- **チャンク分割とオーバーラップ戦略**
  - チャンク分割やオーバーラップのベストプラクティスを調査し、適切な方法を選択

- **データ抽出の要件**
  - 画像内の埋め込みテキストを抽出する必要があるか？必要な場合、光学文字認識 (OCR) を使用するか？
  - Vision モデルを利用して、画像そのものを分析する必要があるか？

- **抽出ツールの選択**
  - オープンソースのライブラリを利用するか？
  - クラウドベースのソリューション（例：Azure Document Intelligence）を利用するか？

- **前処理の必要性**
  - 未対応のフォーマットを変換する必要があるか？

## 実際のシナリオ

本ガイドでは、以下の前提で進めます。

- **ファイルの種類とサイズ**
  - ファイル数や、埋め込みモデルのTPM/RPMおよびトークンの制限を考慮することで、すべてのファイル内容をAzure AI Searchに処理するのに必要な時間を見積もることができます。これにより、アプリケーションのリリース日を決定するのに役立ちます。


| ドキュメントタイプ | 件数 | 平均サイズ | 最大サイズ |
| --- | --- | --- | --- |
| PDF | 1000 | 1MB | 10MB |
| Excel | 500 | 1MB | 10MB |
| Word | 100 | 1MB | 10MB |


- **チャンク分割とオーバーラップ戦略**
  - Excel ファイルは、各シート単位でトークンベースのチャンク分割を行う。ユースケースによっては、各行を別のチャンクとして扱うことも可能。

| ドキュメントタイプ | チャンクサイズ | オーバーラップサイズ | 補足 |
| --- | --- | --- | --- |
| PDF | 1ページ | 1/2ページ | 1ページが埋め込みモデルのトークン制限内に収まることを前提としています。 |
| Excel　| 1シートあたり5000トークン | 1000トークン | チャンクは1シートのデータのみを含み、複数のシートにはまたがりません。 |
| Word | チャンクあたり5000トークン | 1000トークン | Azure Document Intelligenceはページ番号を認識できないため、トークンを使って分割します。 |


- **データ抽出の要件**
  - OCR を使用して画像内のテキストを抽出する。

- **抽出ツールの選択**
  - コストが許容範囲内であるため、Azure Document Intelligence を使用する。

- **前処理の必要性**
  - 特別なフォーマットのファイルがないため、変換は不要。

事前に入力データをしっかり評価することで、スムーズなドキュメント処理を実現できます。

# ステップ3：精度指標の定義

## 概念とアプローチ

RAGシステムの要件定義とデータ準備が整った後、RAGシステムの精度をどのように評価するかを決定することが重要です。明確な指標がなければ、システムが良好に機能しているか、または改善が必要かを判断できません。

### 重要な考慮事項
- **「正しい」結果の定義**
  - 関連する文書が検索結果のトップ3またはトップ10に含まれるべきか？
  - 要約の正確性はどのように判断するか？
- **評価の粒度**
  - 文書単位で測定すべきか、それともページ、Excelシート単位で測定すべきか？
- **許容精度の基準**
  - 何パーセント以上の精度が実運用に十分と見なされるか？

## 実際のシナリオ

RAGシステムを評価するために、以下の精度基準を定義します：

- **関連する文書**: 検索結果のトップ10に期待される文書が含まれている場合、正しいと見なす。
- **要約**: 主要なポイントがカバーされている場合、正しいと見なす。
- **許容精度基準**:
  - 関連文書の取得精度：60%
  - 要約の精度：50%

精度評価を体系的に行うため、以下のようなExcelシートを活用します。この構造化されたアプローチにより、検索と要約の精度を評価するのに役立ちます。

https://gist.github.com/FlyRayTsou/75158d4fb1866306ac91511622756b8f


| 項目 | 説明 |
| --- | --- |
| ユーザーのクエリ | ユーザーが入力する質問 |
| 検索結果のファイル名 | 検索で取得された文書のファイル名 |
| 検索結果の位置 | PDFのページ番号やExcelのシート名など |
| 検索結果の内容 | 取得された特定の内容 |
| 期待されるファイル名 | 本来取得されるべきのファイル名 |
| 期待される位置 | 正しいコンテンツの位置 |
| 要約結果 | AI生成の要約 |
| 期待される要約 | 要約が正しいか判断するために必要なポイントを定義 |
| 検索結果の正確性 | はい/いいえ |
| 要約の正確性 | はい/いいえ |
| 要約の評価 | 誤りがある場合の分析と改善点 |

明確な精度指標を定義することで、RAGシステムが測定可能で信頼性が高く、継続的に改善可能であることを保証します。


# ステップ4：アプリケーションアーキテクチャの設計とAzure AI Searchスキーマの設計

## 概念とアプローチ

### アーキテクチャ
![アーキテクチャ.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/596658/6605f030-8301-4948-bd8c-09037a44e315.png)


RAGアプリケーションアーキテクチャは次のように構成されます：

| コンポーネント | 説明 |
|-----------|-------------|
| **検索サービス** | 例えば、Azure AI Search |
| **AIサービス** | 例えば、Azure OpenAI |
| **OCRサービス** | 例えば、Azure Document Intelligence |
| **フロントエンドサーバー** | ユーザーのクエリを受け入れ、検索結果や要約を表示します。 |
| **バックエンドサーバー** | クエリを処理し、Azure AI SearchやGPTおよび埋め込みモデルとやり取りします。 |
| **バッチ処理サーバー** | 文書のコンテンツを抽出し、埋め込みモデルとやり取りし、Azure AI Searchにデータを追加します。必要に応じて、文書は手動、定期的、自動でインポートされます。頻繁に更新が行われる場合、自動インジェストパイプラインが必要です。 |
| **ストレージ** | 文書が保存される場所（例：SharePoint、ローカルサーバー、またはその他のクラウドストレージ）。これは文書をどのように維持するかにも関係します。 |
| **データベース** | 初期段階では不要かもしれませんが、要件に応じて、OCRモデルから抽出したコンテンツを保存するためにデータベースを追加し、同じ文書を別のAzure AI Searchインデックスにアップロードする際のコスト削減に役立てることができます。また、ユーザーの検索履歴を保存するためにも使用できます。 |

### Azure AI Searchインデックススキーマの設計

Azure AI Searchをリレーショナルデータベースのように考えることができますが、実際には異なります。インデックスはテーブルのように、フィールドはカラムのように考えます。スキーマを設計する際、各フィールドのプロパティを設定する必要があります。

- **Retrievable**: 検索結果に返されるフィールドを決定します。運用中は必要なフィールドのみを取得し、開発中はデバッグのためにすべてのフィールドを有効にします。
- **Searchable**: テキスト検索用にインデックスされるフィールドを定義します。関連するフィールドのみを検索可能に設定します。
- **Filterable**: 特定のフィールドでフィルタリングを有効にします。検索結果を最適化するために役立ちます。
- ニーズにより、**Sortable**と**Facetable**のプロパティを設定する必要があります。

### 重要な考慮事項
- 検索結果の順番は、インデックスにあるデータが同じ場合、同じクエリに対して一貫性があります。
- インデックス作成後にSearchableやFilterableのプロパティを変更することはできません。そのため、設計段階での計画が重要です。
- 今後最適化の場合、他の検索アプローチ（例：ハイブリッド検索）を検討することも可能です。

## 実際のシナリオ
Azure OpenAI では、GPT モデルと埋め込みモデルの両方が必要になります。埋め込みモデルは、データインジェスト時にベクトル表現を生成し、それを Azure AI Search に保存します。また、クエリをベクトルに変換し、ベクトル検索を実行するためにも使用されます。

文書は SharePoint に保存され、保守担当者が最新のファイルに更新します。更新頻度が高い場合、自動インポートプロセスが毎日実行され、常に最新の状態が維持されます。

### Azure AI Searchインデックススキーマ

Azure AI Searchインデックスのフィールドの一例は以下の通りです：

| Field Name | Description | Retrievable | Searchable | Filterable |
|------------|-------------|-------------|------------|------------|
| `file_name` | ファイル名 | true | false | false |
| `chunk_content` | チャンク内容 | true | true | false |
| `chunk_content_vector` | チャンク内容のベクトル化結果 | true | true | false |
| `chunk_content_position` | 文書内の位置（ページ番号やシート名など） | true | false | false |
| `file_link` | エンドユーザーが参照するための元のファイルリンク | true | false | false |
| `document_category` | 文書のカテゴリーをカスタマイズするためのフィルター用フィールド | true | false | true |

以下の図は、先ほど述べたフィールドとは異なりますが、Azure AI Searchのインデックスフィールドの特性を簡単に理解するのに役立ちます。 この画像は、[Microsoft Dev Blogs](https://devblogs.microsoft.com/dotnet/vector-data-qdrant-ai-search-dotnet/)から引用しています。
![Example of Azure AI Search Index Fields.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/596658/8ab7f44e-ab60-41eb-8a5d-b5ec68c8d39d.png)


# ステップ5：アプリケーションの実装

多くの技術記事で RAG アプリケーションの実装コードが提供されているため、本記事では詳細な実装についてはカバーしません。


# ステップ6：データのAzure AI Searchへのインポート

## 概念とアプローチ

バッチ処理サーバーを実行してデータインジェストを処理します。エラーハンドリングを実装して、文書のアップロード失敗を管理することを考慮してください。文書のアップロードに失敗した場合、部分的なアップロードから回復するための戦略を決定し、データの整合性を確保します。

## 実際のシナリオ
エラーハンドリングの戦略：あるファイルがアップロード中に失敗し、その中の一部だけがインジェストされた場合、そのファイルに関連データをすべて削除して最初から再処理します。

# ステップ7：実行

## 概念とアプローチ
ステップ3で定義した精度指標をもとに、事前に準備した Excel シートを用いて評価を行います。手動での評価も可能ですが、自動化されたスクリプトを使用することも推奨されます。


## 実際のシナリオ
手動で実行する場合、以下の手順に従います：
1. RAGアプリケーションにサンプルクエリを入力します。
2. RAGアプリケーションから検索結果と要約出力を取得します。
3. これらの結果をExcelシートに記録します。
4. 期待される回答と比較します。
5. 記録されたデータに基づいて正解率を計算します。

# ステップ8：結果の分析と最適化

## 概念とアプローチ

正解率を算出した後、さらに最適化が必要か、またはフィードバックを集めるためにより多くのユーザーにアクセスを広げるべきかを判断できます。同時に、誤った結果を分析して原因を特定し、システムを最適化します。

## 実際のシナリオ
誤った結果が発生する主な原因には以下のようなものがあります。

### 検索結果の問題
- 無関係なドキュメントが多すぎる: 検索サービスに不要なノイズが多いと、関連性の高い結果が埋もれてしまう可能性があります。
- あいまいなクエリ: ユーザーが適切な質問の表現方法を理解できるよう、ガイドラインが必要な場合があります。
- チャンクサイズとオーバーラップサイズの調整: これらのパラメータを最適化することで検索精度が向上する可能性がありますが、データの再インジェストが必要となり、コストが発生する場合があります。

### 要約の問題
- プロンプトエンジニアリング: 生成 AI モデルに送信するプロンプトを洗練させることで、要約の品質を向上できます。固定テンプレートを用いた構造化プロンプトを使用すると、より良い結果が得られることが多いです。
- Azure OpenAI に渡す検索結果が多すぎる: 検索結果を過剰に Azure OpenAI に渡すと、回答の品質が低下することがあります。検索結果の精度が十分であれば、Azure OpenAI に渡す上位結果の数を適切に調整することで、要約の出力を改善できます。

# 結論
実用的な RAG アプリケーションを構築するには、技術的な実装だけでなく、以下の点を考慮することが重要です。
- **文書のメンテナンス** — データセットを最新かつ関連性のある状態に保ち、定期的に文書を更新します。
- **長期的な持続可能性** — 効果的なフィードバックループと継続的な改善プロセスを確立します。

使いやすさと反復的な改善に焦点を当てることで、RAGアプリケーションは時間とともに効果的で価値のあるものを維持できます。

# 参考
- 私が執筆した英語の記事：https://flytoleisure.medium.com/guideline-for-building-a-practical-and-effective-rag-retrieval-augmented-generation-application-f6cf50676e37