RAGを０から理解する


# 最初に

Retrieval-Augmented Generation (RAG)を
「ChatGPTが文書の内容をもとに回答する」
ぐらいの解像度でしか理解していない私が一からRAGを調べていきます。

この記事では、RAGの構成図とその処理の流れまでをWebで調べた内容をもとに整理していきます！！


いや、本当になんで今更？という感じですが、お付き合いいただければと思います！！

# 前提

前提というより、これを書き始める前の私のレベルです（笑）

- 機械学習、ニューラルネットワークをほんのり理解している
- LLMを実装したことがない（Pythonはかじったことがある）

# RAGとは

いくつかのテック企業の説明分を引用します。
要するに外部のデータベースを参考にLLMが回答するということですね

AWS
>検索拡張生成 (RAG) は、大規模な言語モデルの出力を最適化するプロセスです。そのため、応答を生成する前に、トレーニングデータソース以外の信頼できる知識ベースを参照します。

https://aws.amazon.com/jp/what-is/retrieval-augmented-generation/

IBM
>RAGは、外部の知識ベースから事実を検索して、最新の正確な情報に基づいて大規模言語モデル（LLM）に回答を生成させることで、ユーザーの洞察をLLMの生成プロセスに組み込むというAIフレームワークです。

https://www.ibm.com/blogs/solutions/jp-ja/retrieval-augmented-generation-rag/

NVIDIA
>検索拡張生成 (RAG) は、世界の一般知識で有名な大規模言語モデル (LLM) の機能と、ドキュメント、SQL データベース、社内ビジネス アプリケーションなど、ビジネスに固有の情報源が組み合わされたソフトウェア アーキテクチャです。

https://www.nvidia.com/ja-jp/glossary/retrieval-augmented-generation/


## Fine Tuningとの違い

まずFine Tuningについて、ITmediaでは以下のように説明されています
>機械学習（厳密にはニューラルネットワーク）におけるファインチューニング（Fine-tuning：微調整）とは、あるデータセットを使って事前学習（Pre-training）した訓練済みモデルの一部もしくは全体を、別のデータセットを使って再トレーニングすることで、新しいタスク向けに機械学習モデルのパラメーターを微調整すること
https://atmarkit.itmedia.co.jp/ait/articles/2301/26/news019.html


AIモデル（パラメータ）を変更することがFine Tuningですね



# RAGの技術要素

ここではNaive RAGの攻勢を参考にどのような技術要素があるのかを整理していきます
Naive以外にAdvanced RAGやModula RAGなどもあるみたいですが、一旦パスで！（現時点ではきびしい笑）
参考：https://note.com/ainest/n/n5c6145abb8ca

（個人的な感想ですが、`Naive RAG`で検索するといっぱい論文のまとめサイトがでてきますね）

概略図ですが、RAGのシステム構成は下図のようにまとめられます

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2152468/05d15f42-535b-ab70-6c47-b4eb037140ee.png)


参考：
https://myscale.com/blog/ja/naive-rag-vs-advanced-rag/


# 処理の流れ

### ① ドキュメントをチャンクに分割

そもそもチャンクとはを調べてみました。
>chunk（チャンク）とは、データや情報を扱いやすくするために分割された（断片的な）小さな単位のこと
https://3chome.net/rag-chunk-embedding/


長い文章ではこの後扱いにくいので、細かく区切る必要があるみたいです
以下のライブラリが使われるようです。
- LangChain
- Llama Index
- SimplerLLM


どのライブラリを使うかで区切られ方が変わるなら、RAGの性能（回答の正確性）に影響をあたえるんでしょうか。

調べてみると、ライブラリもそうですが、区切り方・区切る文字の長さも影響を与えそうです
参考：https://fintan.jp/page/10301/ 「チャンキング戦略」

チャンクの分割方法を最適化する手法も2024年の論文で出てきているみたいです

論文：https://arxiv.org/pdf/2401.18059
解説記事：https://zenn.dev/knowledgesense/articles/71e3d2d2ff3858


### ② チャンクをベクトル化

分割した単語をベクトルにします。
ベクトルとは言っても高校で習った2次元・3次元ではなく、数千を超えるような次元なんだとか・・・

ちなみに、AIが学習するときも単語ではなく、単語をベクトル化したもので学習しているみたいです

このベクトル化自体も学習が必要なAIで、一から作ると膨大な時間がかかるので、OpenAIやAWSなどが提供している学習済みのものを使います
（以下、一例）
- OpenAI 
- Amazon Titan Embeddings 


### ③ ベクトルをベクトルDBに保存

②の処理を毎回実施すると時間がかかるので、計算結果をDBに保管しておきます。
このとき、ベクトル専用のデータベースがあるので、それを使います
例えば、次のようなものがあります
- pgvector
- Chroma DB


Vector Databaseの比較では以下のSpeaker Deckの資料が参考になりました！
https://speakerdeck.com/knishioka/llmapurikesiyondeshi-yong-suruvector-databasenobi-jiao?slide=17

特に参考になりそうな点は以下3点です
- ベンチマークテストはANN Benchmarksのようなサイトがしている
- 使うライブラリによって利用可能なDBが限定されている
- 利用シーンの特定ニーズも視野にいれて比較検討する



### ④ ユーザーからのクエリをベクトル化

②と同じようにユーザーからのクエリもベクトル化します！

### ⑤ クエリのベクトルと類似したものをベクトルDBから検索

ベクトル同士は類似度を出すことができるので、DBからクエリと似ているものを抽出します




### ⑥ 検索結果とクエリを合わせてLLMに渡す

⑤で見つけたクエリと関連のあるチャンクと、クエリを合わせます
正直、このあたりがどういう挙動になっているかは、実際のプログラムを触っていないので、不透明です。。。

LLMはいろいろなものが出てきていますが、以下のようなものがあります（代表的なものしか知らないです。。。）
- GPT4
- LLAMA
- Gemini

### ⑦ 出力

LLMの回答結果を出力します


# 最後に

Webで調べていくと本当に詳細にまとめられた記事が多くて本当に参考になりました。

そのような記事がたくさんある一方で、もうありきたりの記事かもしれませんが、自分でまとめることはやはり頭の整理になるなと実感した次第です。。。

次は自分で簡易的なRAGを実装していきたいと思います！！！