watsonxでPythonのRagasを使用してRAGパイプラインを評価

このチュートリアルでは、LangChainを使用したPythonでの検索拡張生成(RAG)評価のためのRagasフレームワークを使用します。

RAG自然言語処理 (NLP) の手法の一つで、情報検索と生成モデルを組み合わせて、より正確で関連性が高く、文脈を認識した応答を生成します。従来の言語生成タスクでは、OpenAI のGPT(Generative Pre-trained Transformer)や IBM Graniteモデル のような大規模言語モデル (LLM)が、入力プロンプトに基づいて応答を構築するために使用されます。これらの大規模言語モデルの一般的な現実世界でのユースケースはチャットボットです。これらのモデルは、文脈的に関連性のある応答や事実に即した応答、または最新の応答を生成するのが難しい場合があります。

RAGは、応答生成の前に検索ステップを組み込むことで、この制限に対処します。検索中に、プロンプトに関連する追加の文書の断片を(通常はベクトル・データベースに保存されている)大規模な文書コーパス内の関連文書といった知識ベースから取得します。最後に、取得したコンテキストで拡張された元のプロンプトに基づいて応答を生成するためにLLMを使用します。

RAG評価の概要

RAGの評価フレームワークや評価メトリクスは多岐にわたります。Ragas以外のフレームワークとしては、 IBMのUnitxtやOpenAIのEvalsなどがあります。他のフレームワークとは異なり、Ragasは別のLLMを審判として使用し、RAGパイプラインの性能を評価します。

RAGパイプラインの性能を測定するために利用できるメトリクスはいくつかあります。オープンソースのRagasフレームワークで今回使用するメトリクスは、以下の2つの部分に分割できます。

  • 生成評価
    • 忠実度は、生成されたすべての答えが、検索されたコンテキストから推測できるかどうかを測定します。
    • 回答の関連性は、質問に対して生成された回答の関連性を測定します。
  • 検索評価
    • コンテキストの精度は、グラウンド・トゥルースに関連するエンティティのコンテキスト内での順位を測定します。コンテキストの精度が高いということは、グラウンド・トゥルースに関連する項目が「ノイズ」よりも高い順位に置かれていることを意味します。
    • コンテキスト想起は、取得されたコンテキスト内で、LLMが生成したユーザー・クエリに対する回答がどの程度見つかるかを測定します。

これらのメトリクスは、RAGパイプラインがナレッジ・ベースから関連情報をどの程度適切に取得して応答を形成するかについての、主観的なプロキシーを意図したものです。データ、プロンプト、LLM に理想的なものは存在しないことに注意することが重要です。context_relevanceのスコアが低いコンテキストであっても、必ずしも不良コンテキストであるとは限りません。スコアが低いのは、ある程度の「ノイズ」や関連性の低い情報に起因しているか、あるいは単にタスク自体に複数の解釈が必要な可能性があるためです。また、ノイズは必ずしも悪いものとは限りません。私たち人間が質問に答える際も、理解可能な仕方で答えながらも、ある程度のノイズを作り出しています。

また、短い応答と長い応答のどちらかを優先するなど、RAGパイプラインの評価に影響を与えるバイアス(長さバイアスとも呼ばれる)もあります。このタイプのバイアスでは、内容ではなくその長さのために、ある回答が別の回答よりも高く評価される場合があります。

こうした理由から、複数の評価を実行することがベスト・プラクティスとなります。この演習は、LLMのプロンプト・テンプレート、メトリクス、評価のシーケンスなどを変更することで実施できます。また、RAGパイプライン用に独自のデータセットを作成している場合は、応答を生成するLLMと応答を批評するLLMにはそれぞれ異なるモデルを使用することが推奨されます。両方に同じモデルを使用すると、自己評価バイアスが生じる可能性が大きくなります。これらの評価メトリクスは主観的なものであるため、これらのフレームワークが出力した結果は人間の判断によって確認する必要があります。

このチュートリアルでは、RAGシステムの作成は行いません。代わりに、Ragasを使用して、以前に作成したRAGシステムのアウトプットを評価します。LangChainを使用してRAGシステムを構築する方法の詳細については、詳しいRAGチュートリアルを参照してください。

前提条件

watsonx.ai プロジェクトを作成するにはIBM® Cloudのアカウントが必要です。こちらから無料アカウントを登録してください

手順

ステップ1. 環境を設定する

いくつかあるツールの中から選択することもできますが、このチュートリアルでは、Jupyter Notebookを使用するためにIBMアカウントを設定する方法について説明します。

  1. IBM Cloudアカウントを使用して、watsonx.aiにIBM Cloudアカウントを使用します。

  2. watsonx.aiプロジェクトを作成します。

    プロジェクトIDはプロジェクト内から取得できます。「管理」タブをクリックし、「全般」ページの「詳細」セクションからプロジェクトIDをコピーしてください。このチュートリアルではこのIDが必要になります。

  3. Jupyter Notebookを作成します。

    このステップでは、このチュートリアルのコードをコピーできるノートブック環境が開きます。あるいは、このノートブックをローカル・システムにダウンロードし、watsonx.aiプロジェクトにアセットとしてアップロードすることもできます。さらに詳しいGraniteチュートリアルを見るには、IBM Graniteコミュニティをご覧ください。このJupyter NotebookはGitHubでも入手できます。

ステップ2. watsonx.ai RuntimeのインスタンスとAPIキーを設定する

  1. watsonx.ai Runtimeサービス・インスタンスを作成します(適切なリージョンを選択し、無料インスタンスであるLiteプランを選択します)。

  2. APIキーを生成します。

  3. watsonx.aiランタイム・サービス・インスタンスを、watsonx.aiで作成したプロジェクトに関連付けます。

ステップ3. 関連ライブラリーをインストールしてインポートし、認証情報を設定する

このチュートリアルには、いくつかのライブラリとモジュールが必要です。以下に列挙されているコンポーネントを必ずインポートしてください。インストールされていない場合は、pipをクイックインストールすることで問題が解決されます。このチュートリアルはPython 3.11.9を使用して作成されました。

#installations
%pip install -q langchain_community
%pip install -q "ragas==0.2.1"
%pip install -q langchain_ibm
%pip install -q ibm_watson_machine_learning
%pip install -q ibm_watsonx_ai
%pip install -q langchain_core
%pip install -q nltk import os

from langchain_community.llms import WatsonxLLM as _WatsonxLLM
from langchain_ibm import WatsonxEmbeddings
from langchain.callbacks.manager import CallbackManagerForLLMRun
from langchain.schema import LLMResult
from ragas import evaluate
from ragas.llms import LangchainLLMWrapper
from ragas.metrics import answer_relevancy, context_precision, context_recall, faithfulness
from typing import List, Optional, Any
from datasets import load_dataset
from ibm_watson_machine_learning.metanames import GenTextParamsMetaNames as GenParams
from ibm_watsonx_ai.foundation_models.utils.enums import EmbeddingTypes

認証情報を設定します。APIキーとプロジェクトIDを文字列で入力します。プロビジョニングされたサービス・インスタンスに合わせて、watsonx URLとして一覧表示されているリージョンのいずれかを使用します。

  • ダラス: https://us-south.ml.cloud.ibm.com
  • ロンドン: https://eu-gb.ml.cloud.ibm.com
  • フランクフルト: https://eu-de.ml.cloud.ibm.com
  • 東京: https://jp-tok.ml.cloud.ibm.com
os.environ["WATSONX_APIKEY"] = <API_KEY>
os.environ["WATSONX_PROJECT_ID"] = <PROJECT_ID>
os.environ["WATSONX_URL"] = "https://us-south.ml.cloud.ibm.com"

ステップ4. データセットを読み込む

Ragas 評価には、複数の異なるプロンプトのRAGパイプライン実行を含むデータセットが必要です。データセットには、質問本文に加え、期待される回答(「グラウンド・トゥルース」と呼ばれます)、LLMが生成する回答、および各質問に回答する際にRAGパイプラインが取得するコンテキスト断片のリストを含める必要があります。独自にエンドツーエンドのデータセットを作成することもできますが、このチュートリアルで使用するデータセットはHugging Faceで入手できます。データセットをロードしましょう。

amnesty_qa = load_dataset(“explodinggradients/amnesty_qa”, “english_v2”)
amnesty_qa

アウトプット:

Repo card metadata block was not found. Setting CardData to empty.
DatasetDict({
    eval: Dataset({
        features: [‘question’, ‘ground_truth’, ‘answer’, ‘contexts’],
        num_rows: 20
    })
})

データはDatasetDictとしてロードされ、今回使用するリソースは"eval"スプリット内に存在します。

dataset = amnesty_qa[“eval”]
dataset

アウトプット

Dataset({
    features: [‘question’, ‘ground_truth’, ‘answer’, ‘contexts’],
    num_rows: 20
})

データをPandasデータフレームにロードします。このデータセットのエントリの例については、 HuggingFace のドキュメンテーションを参照してください。

df = dataset.to_pandas()        

RAG評価用のデータセットはさまざまな方法で作成できます。今回のデータセット作成の主な要素は、LLMに提供する外部のナレッジ・ベースでした。このナレッジ・ベースは、スクレイピングされたウェブページ、基本的なテキスト・ファイル、インポートされたドキュメントなどから取得できます。今回はアムネスティ・インターナショナルから収集したレポートを使用しています。データセットのコンテンツは、エンドツーエンドか、またはRagasのTestsetGeneratorなどの合成データ生成アプローチを使用して作成することができます。TestsetGeneratorを使用するには、ロード済みドキュメント、生成用LLM、検証用LLM、および埋め込みモデルが必要です。

エンドツーエンドのアプローチには、いくつかのステップが含まれます。このデータセットの作成にエンドツーエンドのアプローチを採用すると仮定します。これは、質問列に保存されている質問をLLMまたは人間が作成したということを意味します。各質問に対するグラウンド・トゥルースは、ユーザーが手動で作成する場合や、適切なプロンプト・テンプレートを使用してLLMで生成する場合があります。これらの回答は理想的な回答とみなされ、ground_truth列に保管されます。最後に、回答列に表示されている回答は、RAGパイプラインを使用して生成したものです。RAGパイプラインを構築する際に、外部のナレッジベースがベクトル化されています。その後、RAGシステムにクエリを実行する際に、LLMが各回答の生成に使用した関連テキストのチャンクが、Top-k検索アルゴリズムなどの類似性アルゴリズムを使用してベクトル・ストアから取得されています。これらのデータセットはコンテキスト列に保管されています。

ステップ5. 評価と埋め込みのためのモデルを設定する

このチュートリアルでは、IBM Graniteモデルを審査員として使用します。

RagasはデフォルトではOpen AIモデルを使用します。WatsonxLLMはIBM watsonx基盤モデルAIのラッパーです。Ragas互換の WatsonxLLMラッパーは現在開発中で、まだ利用できません。現時点では、Graniteモデルと合わせてRagasを使用するには、ラッパーのプロパティを変更する必要があります。

class WatsonxLLM(_WatsonxLLM):
    temperature: float = 0.05
    “””
    A workaround for interface incompatibility: Ragas expected all LLMs to
    have a `temperature` property whereas WatsonxLLM does not define it.
    “””

    def _generate(
        self,
        prompts: List[str],
        stop: Optional[List[str]] = None,
        run_manager: Optional[CallbackManagerForLLMRun] = None,
        stream: Optional[bool] = None,
        **kwargs: Any,
    ) -> LLMResult:
        “””
        A workaround for interface incompatibility: Ragas expected the
        `token_usage` property of the LLM result be of a particular shape.
        WatsonX returns it in a slightly different shape.
        “””
        result: LLMResult = super()._generate(prompts, stop, run_manager, stream, **kwargs)
        if not result.llm_output or “token_usage” not in result.llm_output:
            return result
        usage = result.llm_output[“token_usage”]
        if not isinstance(usage, dict):
            return result
        result.llm_output[“token_usage”] = {
            “prompt_tokens”: usage[“input_token_count”],
            “completion_tokens”: usage[“generated_token_count”],
            “total_tokens”: usage[“input_token_count”] + usage[“generated_token_count”],
        }
    return result

このチュートリアルでは、類似した結果を出すために、IBM Granite-3.0-8B-Instructモデルの使用を推奨しています。任意のAIモデルを自由に使用して、このベンチマークと比較し、アプリケーションに最適なモデルを選択してください。watsonxを通じて入手可能な基盤モデルは、こちらからご覧いただけます。LLMアプリケーションにおけるこれらのモデルの目的は、実行するアクションと生成する応答を決定する推論エンジンの役割を果たすことです。RagasでWatsonxLLMラッパーを使用するには、 LangchainLLMWrapperを使用する必要があります。

watsonx_llm = LangchainLLMWrapper(
    langchain_llm = WatsonxLLM(
        model_id = “ibm/granite-3-8b-instruct”,
        url = os.getenv(“WATSONX_URL”),
        apikey = os.getenv(“WATSONX_APIKEY”),
        project_id = os.getenv(“WATSONX_PROJECT_ID”),
        params = {
            GenParams.MAX_NEW_TOKENS: 200,
            GenParams.MIN_NEW_TOKENS: 1,
            GenParams.STOP_SEQUENCES: [“<|endoftext|>“],
            GenParams.TEMPERATURE: 0.2,
            GenParams.TOP_K: 50,
            GenParams.TOP_P: 1,
        }
    )
)

評価モデルとしてGraniteモデルを使用します。回答は既にデータセットの回答列に保管されているため、モデルを使用して回答を生成することはありません。

今回使用している埋め込みモデルは、watsonx.ai LangChainラッパーを介した IBM Slateモデルです。埋め込みモデルが指定されていない場合、RagasはデフォルトでOpenAIの埋め込みを使用します。埋め込みモデルは、別個の列からのデータを埋め込んでその間の距離を測定するために使用するので、評価には不可欠です。

watsonx_embeddings = WatsonxEmbeddings(
    model_id = EmbeddingTypes.IBM_SLATE_30M_ENG.value,
    url = os.getenv(“WATSONX_URL”),
    apikey = os.getenv(“WATSONX_APIKEY”),
    project_id = os.getenv(“WATSONX_PROJECT_ID”)
)

ステップ6. Ragasで評価を生成する

データセットに対してRagas評価を実行することができるようになりました。ここで、データセット、評価用メトリクス、LLM、埋め込みモデルをパラメーターとして渡します。

警告メッセージが表示された場合は、そのメッセージを無視し、評価を完了し、結果を表示できるようにします。

result = evaluate(
    amnesty_qa[“eval”],
    metrics=[
        context_precision,
        faithfulness,
        answer_relevancy,
        context_recall,
    ],
    llm=watsonx_llm,
    embeddings=watsonx_embeddings)
print(result)

アウトプット:

{‘context_precision’: 0.9444, ‘faithfulness’: 0.6000, ‘answer_relevancy’: 0.6917, ‘context_recall’: 0.8333}

以上です。RAGパイプラインの1回目の評価が完了しました。前述したように、複数回の評価を実行したり、さまざまなモデルを試したり、パラメーターを変更することもできます。評価の回数を重ねるほど、RAGを使用したLLMシステムの精度と有効性をより包括的に評価できるようになります。

まとめ

このチュートリアルでは、Ragasを使用してRAGパイプラインを評価しました。アウトプットには、context_precision 、faithfulness 、answer_relevancy、context_recall のメトリクスが含まれていました。評価に使用したLLMはIBM Graniteモデルで、埋め込みモデルにはwatsonx.ai埋め込みAPIを介してアクセスしたIBM Slateモデルを使用しました。

今回実行した評価は、将来の生成AIワークフローにも適用してRAGシステムの性能を評価し、改善することができます。

メトリクスと評価プロセスの詳細について、Ragasのドキュメンテーションページを確認することをお勧めします。

関連ソリューション
IBM watsonx.ai

AI開発者向けの次世代エンタープライズ・スタジオであるIBM watsonx.aiを使用して、生成AI、基盤モデル、機械学習機能をトレーニング、検証、チューニング、導入しましょう。わずかなデータとわずかな時間でAIアプリケーションを構築できます。

watsonx.aiをご覧ください。
人工知能ソリューション

業界をリードするIBMのAI専門知識とソリューション製品群を使用すれば、ビジネスにAIを活用できます。

AIソリューションはこちら
AIサービス

AIの導入で重要なワークフローと業務を再構築し、エクスペリエンス、リアルタイムの意思決定とビジネス価値を最大化します。

AIサービスはこちら
次のステップ

AI開発ライフサイクル全体にわたる機能にワンストップでアクセスできます。使いやすいインターフェース、ワークフロー、業界標準のAPIやSDKを利用して、強力なAIソリューションを構築できます。

watsonx.aiの詳細はこちら デモを予約