46.6kデモを予約するログイン無料で始める

Milvus Lite、Llama3、LlamaIndexを使ったRAGの構築

Retrieval Augmented Generation (RAG)は、LLMの幻覚を軽減するための手法です。Milvus、Llama3、LlamaIndexを使ってチャットボットRAGを構築する方法を学びましょう。

大規模言語モデル(LLMs)は、人間のようなテキスト応答を生成する驚くべき能力を実証している。これらのモデルは、翻訳、要約、コード生成、情報検索など、様々な自然言語タスクを実行することができる。

これらすべてのタスクを実行するために、LLMは膨大な量のデータに対する事前学習プロセスを経る。この過程でLLMは、前の単語が与えられた文の中で次の単語を予測することにより、自然言語を学習する。トークン予測として知られるこの方法により、LLMは首尾一貫した、文脈に関連した応答を生成することができる。しかし、このモデルは事実を検証するのではなく、最も可能性の高い次の単語を予測することに重点を置いているため、その出力が不正確であったり、誤解を招いたりすることがある。一方、事前学習データセットが古い場合があり、LLMが最新のデータに関連する質問に答えることが難しくなる。

LLMの回答の真実性を評価するのは、回答の根拠となるテーマに関する専門知識を持っていない限り難しい。Retrieval Augmented Generation (RAG)は、この問題を軽減するために使用できる手法で、この記事で詳しく説明します。それでは早速、RAGの基本的な紹介から始めよう。

RAGを理解する

大規模言語モデル(LLM)は、様々な自然言語の問題に取り組む上で非常に強力であるため、AIにおいて最も議論されているトピックの一つであることは否定できない。しかし、LLMには、いわゆる知識カットオフ・デートを含む限界がある。このカットオフ・デートとは、LLMに使用される学習データの最新の日付を指す。

例えば、GPT-4ターボの知識カットオフ日は2023年12月である。ChatGPTにリアルタイム更新やそれ以降の情報を求めると、不正確な回答を受け取る危険性があります。この現象はLLM幻覚と呼ばれています。

幻覚は、LLMによって生成された応答が説得力があり、首尾一貫しているように見えるにもかかわらず、その真実性が完全にずれている場合に発生します。LLMによって生成された幻覚を検出することは非常に困難であり、依然として活発な研究分野である。

生成されたテキストの品質を評価するために当惑度のような指標を計算することはできるが、このアプローチは核心的な問題に直接対処していない。そこで、RAGのような概念が登場する。

RAGはLLMの幻覚を軽減するように設計されている。プロセスは簡単で、まずLLMにクエリーを送信する。そのクエリを直接LLMに送信する代わりに、私たちはまず、LLMがより正確な答えを提供するのに役立つ関連コンテキストを特定する。

次に、LLMに元のクエリと、LLMがクエリに答えるのに役立つ最も関連性の高いコンテキストの2つの入力を提供する。最後に、LLMは提供されたコンテキストを考慮して応答を生成する。

この方法により、LLMはクエリに対して単にランダムな出力を生成するのではなく、文脈を考慮した適切な回答を生成することが保証される。

RAGの構成要素

その名前が示すように、RAGは3つの主要なコンポーネントから構成されている。まず、検索コンポーネントについて説明しよう。

検索コンポーネント

RAGにおける検索コンポーネントの主な目的は、与えられたユーザクエリに基づいて有望なコンテキスト候補を特定することである。最初のステップは、入力クエリをvector embeddingsと呼ばれる数値表現に変換することです。ベクトル埋め込みの次元数は、使用する埋め込みモデルによって異なります。HuggingFaceやSentenceTransformersのような、オープンソースでフリーの埋め込みモデルが多数あります。

これらの埋め込みは、元のテキストの意味的な意味を保持し、似た意味を持つ2つのテキストの埋め込みが、ベクトル空間において互いに近接して配置されることを保証します。その結果、任意の2つのベクトルのユークリッド距離(L2)を計算することで、任意の2つのベクトル間の類似度を計算することができます。以下は、これらのベクトルが2次元ベクトル空間でどのように配置されているかの例である。

図1- 2次元ベクトル空間における埋め込み](https://assets.zilliz.com/Figure_1_Embeddings_in_2_D_vector_space_6522ce6d91.png)

図1:2次元ベクトル空間における埋め込み

上記のベクトルの埋め込み概念を理解すれば、有望なコンテクストを見つける方法は簡単である。クエリの埋め込みとコンテキストの埋め込みとの距離を計算すればよい。

この2つの埋め込み間の距離計算は、比較するコンテキストが数個しかない場合は何とかなります。しかし、数百万のコンテキストがある場合はどうなるでしょうか?計算コストは法外に高くなり、ローカルマシンはすべての埋め込みを保存できない可能性が高い。したがって、このタスクを効率的に処理するために、Milvusのようなスケーラブルで高性能なベクトルデータベースが必要になります。

図2- ベクトル検索の実行方法](https://assets.zilliz.com/Figure_2_How_to_perform_a_vector_search_f38e8533a2.png)

図2: ベクトル検索の実行方法

Milvusは高度なインデックス作成アルゴリズムを持っており、何十億もの文脈埋め込みを保存し、大規模なベクトル類似度計算を実行するのに非常に効率的です。また、一般的なAIフレームワークと簡単に統合できるため、RAGベースのLLMアプリケーションの開発が容易になります。次のセクションで、実際に使ってみましょう。

補強コンポーネント

ベクトルデータベースの助けを借りてベクトル類似性検索を実行した後、補強コン ポーネントに移る。この段階では、前のステップで検索された最も関連性の高い上位k個のコンテキストが、ユーザークエリと組み合わされ、完全なプロンプトを形成し、これがLLMの入力となる。

このプロンプトはLLMへの入力となる。しかし、プロンプトの基本的なテンプレートは通常次のようになる:

最後の質問に答えるために、以下の文脈を使用してください。


{コンテキスト}


質問{質問}


役に立った回答

これでオーグメンテーション・コンポーネントは終了です。

生成コンポーネント

RAGの3番目の最後のコンポーネントは生成コンポーネントである。この段階では、GPT、Llama、Mistral、Claude、othersなどの選択したLLMが、ユーザークエリと最も関連性の高いコンテクストの両方を含むプロンプトに基づいて応答を生成する。

このセットアップにより、我々のLLMは、学習データからの知識のみに頼るのではなく、提供されたコンテキストに基づいて、ユーザークエリに対する回答を生成する。このアプローチは、LLMによる幻覚のリスクを軽減するのに役立つ。

以下は、これまで説明してきたRAGの完全なコンポーネントとワークフローを視覚化したものである:

図3- RAGのワークフロー](https://assets.zilliz.com/Figure_3_RAG_workflow_d13d98fb43.png)

図3:RAGのワークフロー

Milvus Lite、Llama 3、LlamaIndexの紹介

以下のセクションでは、MilvusとLlamaIndexのような人気のあるAIフレームワークを使って、RAGを搭載したLLMアプリケーションを構築します。実用的な実装に入る前に、このプロジェクトで使用するツールについて説明します。

Milvus Lite

Milvusはオープンソースのベクトルデータベースで、10億スケールのベクトル埋め込みを保存し、効率的なベクトル検索を実行することができます。以下のデモでは、Milvusを使ってコンテキストの埋め込みを保存し、クエリとコンテキストの埋め込み間の類似検索を行います。

Milvusは様々な方法でインストール、インスタンス化できますが、最も簡単な方法はMilvus Liteを使う方法です。Milvus LiteはMilvusの軽量版であり、MilvusをAIプロジェクトに組み込みたい人に強く推奨される。例えば、様々なチャンキング戦略やテキストドキュメントの埋め込みモデルを試してみたい場合など、ラピッドプロトタイピングに使用することができます。

Milvus Liteのインストールは非常に簡単である。以下のpipコマンドを実行するだけです:

pip install "pymilvus>=2.4.2 "をインストールする。

これで、PythonでMilvusをインスタンス化できる。注意すべき点は、Milvus Liteは100万個までのベクトル埋め込みを保存する場合に最適であるということです。

より多くの埋め込みを保存し、本番環境で使用したい場合は、DockerコンテナにMilvusをインストールして実行するか、Kubernetesクラスタ経由でデプロイしてください。このインストールガイドでは、DockerとKubernetesへのMilvusのインストール方法を説明します。

ラマ3

ベクターデータベースに加えて、RAGシステムのもう一つの重要なコンポーネントはLLMそのものである。いくつかのオープンソースのLLMが市場で入手可能であり、LlamaとMistralは最も人気のあるオプションの2つである。この記事では、Meta社が開発したLlama3モデルをLLMとして使用する。Llama3モデルは、以前のLlama2モデルよりも7倍大きなデータセットで事前にトレーニングされており、パフォーマンスの向上に繋がっています。

Llama3モデルには、80億パラメータと700億パラメータの2種類のサイズがあります。下の画像に示すように、どちらのモデルもベンチマークデータセットにおいて、同程度のサイズの他のLLMと比較して競争力のある性能を実証しています。

図4-ベンチマークデータセットにおけるLlama3の性能 出典](https://assets.zilliz.com/Figure_4_Llama3_performance_on_benchmark_datasets_Source_316a03eea7.png)

図4:ベンチマークデータセットにおけるLlama3の性能。出典.

この記事では、80億パラメータのLlama3モデルを使用します。デフォルトでは、80億パラメータモデルは約32GBのVRAMを必要とし、フリーのGPUで利用可能な一般的なVRAMを上回ります。しかし、4ビット量子化を行うことで、モデルのサイズを約4GBのVRAMに減らすことができます。

Llama3モデルをロードして4ビット量子化を適用する方法は複数あります。最初の方法は、Hugging Faceライブラリとbitsandbytesライブラリを組み合わせる方法です。2番目の方法は、Ollamaをインストールし、そこに直接モデルをロードします。デフォルトでは、Ollama上のLLMはすでに4ビットに量子化されています。

Ollamaオプションを使用します。Ollamaを使えば、様々なLLMをローカル・マシンで簡単に実行できる。Llama3をダウンロードするには、まずOllamaをインストールする必要があります。最新のインストール手順については 彼らのドキュメント を参照してください。

Ollamaをインストールしたら、LLMをダウンロードすることができます。ここではLlama3を使うので、ターミナルで以下のコマンドを実行する:

ollama run llama3

LlamaIndex

LlamaIndexは、RAGパイプラインをオーケストレーションするための非常に便利なフレームワークです。前のサブセクションで、RAGアプリケーションのためにベクターデータベースとLLMをインストールしました。今、欠けているのは、完全に機能するRAGシステムを構築するために、これら2つのコンポーネントを接続するフレームワークです。そこでLlamaIndexの出番となる。

LlamaIndexは、様々なソースからの入力データを前処理し、ベクトル埋め込みに変換し、埋め込みをベクトルデータベースに格納し、関連するコンテキストを取得し、LLMに送信し、LLMからの応答を出力するための使いやすいメソッドを提供します。

LlamaIndexはpipコマンドでインストールできる。以下は、このプロジェクトでLlamaIndexを使用するために必要なコマンドである。実装の詳細については次のセクションで説明する。

pip install llama
pip install llama-index-vector-stores-milvus llama-index-llms-ollama llama-index-embeddings-huggingface

Milvus Lite、LLama3、LlamaIndexでチャットボットRAGを作る

Milvus Lite、LLama3、LlamaIndexを使ってRAGシステムを実装してみよう。今回のユースケースでは、論文の内容に関する質問に答えるためのチャットボットRAGシステムを構築したいとします。具体的には、有名なTransformerアーキテクチャを紹介した「Attention is All You Need」論文に関する質問にLLMが答えるようにしたい。どのような研究論文を使っても構いません。

この論文で紹介されているコードはすべて このノートブックに掲載されているので、それに従ってください。まず、必要なライブラリをすべてインポートしましょう:

pip install arxiv

import arxiv
from llama_index.core import SimpleDirectoryReader
from llama_index.vector_stores.milvus import MilvusVectorStore
from llama_index.core import VectorStoreIndex, Settings
from llama_index.llms.ollama import Ollama
from llama_index.embeddings.huggingface import HuggingFaceEmbedding
from pymilvus import MilvusClient

最初のステップは、PDF研究論文をローカルマシンにダウンロードすることである。Arxivの公式Pythonライブラリを使ってダウンロードすることができる。

dir_name = "./Documents/pdf_data/"

arxiv_client = arxiv.Client()
paper = next(arxiv.Client().results(arxiv.Search(id_list=["1706.03762"])))

# 指定したディレクトリにカスタムファイル名でPDFをダウンロードします。
paper.download_pdf(dirpath=dir_name, filename="attention.pdf")

上のコードでは、"Attention is All You Need "の論文のIDにアクセスして、ローカルディレクトリにダウンロードしました。お気づきのように、Arxivの各研究論文のURLにはIDが記載されているので、そのIDを上記のコードにコピーするだけで、好きな研究論文をダウンロードすることができる。

次に、MilvusベクトルデータベースとLlama3モデルをインスタンス化します。生の入力テキストをベクトル埋め込み表現に変換する埋め込みモデルとして、HuggingFaceからロードできるBGEベースモデルを使います。

vector_store = MilvusVectorStore(
    uri="./milvus_rag_demo.db", dim=768, overwrite=True
)

embedding_model = HuggingFaceEmbedding(model_name="BAAI/bge-base-en-v1.5")
llm = Ollama(model="llama3",temperature=0.1, request_timeout=480.0)

ご覧のように、BGEの基本モデルが提供する埋め込み次元である768サイズのベクトル埋め込みを持つMilvusベクトルデータベースをインスタンス化しました。

それでは、ダウンロードしたPDF論文を埋め込みモデルで処理できるように取り込んでみましょう。LlamaIndexを使えば、SimpleDirectoryReaderオブジェクトを呼び出すだけです:

pdf_document = SimpleDirectoryReader(
    input_files=[f"{dir_name}attention.pdf"].
).load_data()
print("入力文書の数:", len(pdf_document))

# または、ディレクトリ内に複数の PDF がある場合は、このコマンドを実行します。
pdf_document = SimpleDirectoryReader(
        dir_name, recursive=True
).load_data()

"""
出力:
入力文書数15
"""

私たちの論文は15ページで構成されているので、入力文書の数は15である。

LLMと埋め込みモデルをRAGパイプライン全体で使用できるようにバインドするには、LlamaIndexのSettingsクラスを使用する必要があります。このクラスでは、PDFデータのチャンクサイズとオーバーラップをカスタマイズすることもできます。

設定.llm = llm
設定.embed_model = embedding_model


設定.chunk_size = 128
設定.chunk_overlap = 64

次に、PDFデータをMilvusベクトルデータベースに取り込みましょう。以下のコマンドで、PDFデータはチャンクに分割され、各チャンクはBGEベースモデルを用いてベクトル埋め込みに変換されます。最後に、チャンク埋め込みはMilvusベクトルデータベースに格納されます。

index = VectorStoreIndex.from_documents(pdf_document)
print("Number of nodes:", len(index.docstore.docs))

query_engine = index.as_query_engine()

"""
出力:
ノード数: 196
"""

見ての通り、196個のチャンク埋め込みがベクターデータベース内にあります。また、 index で as_query_engine メソッドを呼び出すことで、ベクターデータベース内のデータに対して質問を行うことができます。

以上で、LlamaIndexを使ったRAGパイプラインが完成した。これで、論文に関連した質問をすることができます。例えば、「シングルヘッドアテンションではなく、マルチヘッドアテンションの利点は何か?次のコマンドを実行することでそれができる:

query = "シングルヘッドアテンションではなく、マルチヘッドアテンションの利点は何ですか?"

result = query_engine.query(query)
print(result)
"""
出力:
マルチヘッド注意は、モデルが異なる位置にある異なる表現部分空間からの情報に共同で注意することを可能にする。単一の注意ヘッドでは、平均化がこれを阻害する。
"""

研究論文から提供された情報に基づいて、高度に文脈に沿った回答が得られます!同じロジックで、RAGを使えば、研究論文の複雑なトピックに関するどんな質問も簡単にできます。

RAGパイプラインの最適化

RAGパイプラインを本番環境に導入することは、プロトタイピングよりも困難です。共通の問題の一つは、RAGシステムによって生成された応答の品質を評価することです。幸い、RagasやTruLens-Evalのようないくつかのオープンソースツールが、RAGシステムの応答品質を評価するために利用可能です。

Ragasを使用すると、RAGシステムの2つの重要なコンポーネント、検索と生成を評価することができます。検索コンポーネントの品質を評価するために、RagasはLLMが回答を生成するために使用するコンテキストの精度を評価する方法を提供します。一方、生成コンポーネントの評価には、忠実度や回答の関連性といったメトリクスが一般的に採用されています。これらのメトリクスの詳細は 関連ドキュメント をご覧ください。

図5- Ragasを用いたRAG評価メトリクス](https://assets.zilliz.com/Figure_5_Figure_RAG_evaluation_metrics_using_Ragas_3f71b3f768.png)

図5: Ragasを使用した図RAG評価メトリクス_(英語)

これらの評価指標を評価することは、RAGの応答品質の悪化に気づいた場合の重要な第一歩です。これらの評価に基づいてRAGの結果が悪いことを確認した場合、それを改善するための措置を講じる必要があります。しかし、データの質を評価することから始めることが重要です。

私たちは自問しなければならない:ベクターデータベースに、質問に効果的に答えるための適切なデータがあるか?データを適切なチャンクサイズに分割できているか?チャンクに分割する前にデータをクリーニングする必要があるか?

データの品質に問題がないと確信が持てたら、例えば、LLMを置き換えたり、より性能の高い代替モデルを組み込んだりして、RAGパイプラインを強化することができる。

RAGの観測可能性、評価、最適化のための技術やツールについて詳しくは、以下のブログをお読みになることをお勧めします:

  • 本番への道:LLMアプリケーションの評価と観測可能性](https://zilliz.com/blog/path-to-production-llm-system-evaluations-and-observability)

  • RAGアプリケーションの評価方法 ](https://zilliz.com/learn/How-To-Evaluate-RAG-Applications)

結論

Ollama、LlamaIndex、HuggingFaceのような様々なAIフレームワークの導入により、RAGパイプラインの構築はかつてないほどシンプルになった。Milvusを使えば、大量のコンテキスト埋め込みを効率的に保存し、様々なAIフレームワークとシームレスに統合することができる。その結果、わずか数行のコードでRAGパイプラインを構築することができる。

この記事で紹介するRAGのユースケースは、あなたが実装できる無数のアプリケーションの一つに過ぎません。Milvus Liteを追加することで、pip installコマンド1つで、ベクターデータベースを素早くセットアップし、複数のRAGユースケースを簡単にプロトタイプ化できる。ご自身のRAGシステムを構築するために、ぜひお試しください!

その他のリソース

  • リランカーによるRAGの最適化:その役割とトレードオフ](https://zilliz.com/learn/optimize-rag-with-rerankers-the-role-and-tradeoffs)

  • ハイブリッド検索:テキストと画像の組み合わせによる検索機能の強化 ](https://zilliz.com/learn/hybrid-search-combining-text-and-image)

  • ジェネレーティブAIリソースハブ|Zilliz](https://zilliz.com/learn/generative-ai)

  • 検索拡張生成(RAG)の探求:チャンキング、LLM、評価](https://zilliz.com/blog/exploring-rag-chunking-llms-and-evaluations)

  • 検索拡張生成(RAG)のためのチャンキング戦略ガイド](https://zilliz.com/learn/guide-to-chunking-strategies-for-rag)

  • LLMの課題をマスターする:RAGの探求 ](https://zilliz.com/learn/RAG-handbook)

  • RAGはロングコンテクストLLMに殺されるのか ](https://zilliz.com/blog/will-retrieval-augmented-generation-RAG-be-killed-by-long-context-LLMs)

  • 引用による検索拡張生成](https://zilliz.com/blog/retrieval-augmented-generation-with-citations)