はじめに
生成AIではハルシネーションなどの問題を軽減するためにRAGの仕組みを利用しているが、RAGの回答の品質を客観的に評価できる方法について考えたことはないですか?
運用しているうちに、
- ユーザーからの質問内容が変わってしまった
- ベクトルDBなどの検索部分のデータを増やしたら以前は検索で引っかかっていたデータが引っ掛からなくなってしまった
- 生成AIのモデルを変えた方がいいか迷っている
などなど、いろいろと本番運用する上でRAGを評価できるツールは必要になっていきます。
RAGの品質について、LLMを利用してIBM Watsonx.governanceでの測定を試したので、日本語のRAGを評価できたことやその手順を紹介します。
RAGでの主な評価指標
RAGの主な4つの指標を算出します
(https://www.ibm.com/docs/en/cloud-paks/cp-data/5.0.x?topic=models-metrics-computation-using-python-sdk#answer-quality を参照)
コンテキストの関連度( Context relevance )
- RAGの検索部分が対象
- 質問と検索結果であるコンテキストを評価
- コンテキストが質問とどの程度関連しているかを評価する
- スコアが高いほど、コンテキストがプロンプトの質問に関連性が高いことを示す
忠実性( Faithfulness )
- RAGの回答生成部分が対象
- コンテキストと生成AIの出力を評価
- モデル出力がモデルのコンテキストにどれだけ忠実であるかを測定する
- スコアが高いほど、幻覚性(ハルシネーション)が低い
回答の関連性( Answer relevance )
- RAGの全体が対象
- 質問と回答を評価
- モデルの回答が質問にどの程度関連しているかを測定する
- スコアが高いほど、質問に対して適切な回答を提供している
回答の類似性( Answer similarity )
- RAGの全体が対象
- 生成AIの出力した回答を(模範回答と比較して)評価
- 生成された回答が正解の回答や参照の回答とどの程度類似しているかを測定する
- スコアが高いほど、生成された回答がリファレンスの回答に類似している
試したこと
以下の2つのサンプルコードを参考にして、RAGにおける日本語の質問、検索結果、回答などをwatsonx.aiのLLMを用いて、watsonx.governanceで品質を評価してみました。
環境
前提条件
- watsonx.aiとwatsonx.governanceはSaaSを利用
- python 3.11
M1 Mac(arm64)では必要なライブラリibm-metrics-plugin
がインストールできなかったため、コンテナ環境--platform linux/x86_64
で実施しました。(2024年12月)
準備
必要なものは2つ
- IBM Cloud の
API Key
- watsonx.ai の
プロジェクトID
全体の流れ
- 必要なライブラリのインストール
- 日本語のトークナイザを作成
- 試してみるデータを準備
- watsonx.governanceへの認証
- スコアリング関数にwatsonx.aiのモデルを設定
- 計算する指標のConfigを構成
- 計算
- 結果の取得
実際に試してみます
1. 必要なライブラリのインストール
watsonx.ai や watsonx.governance を利用するためのライブラリをインストールします。
pip install -U "ibm-metrics-plugin~=3.0.9" | tail -n 1
pip install -U ibm-watson-openscale | tail -n 1
pip install -U ibm_watsonx_ai | tail -n 1
pip install -U ibm-watson-machine-learning | tail -n 1
自然言語処理のライブラリをインストールします。
pip install nltk
カスタムで日本語のトークナイザを用いるためにSpaCyのライブラリをインストールします。
(https://github.com/explosion/spaCy/issues/13528 と同様のエラーの事象が発生したので、numpyのバージョン指定してインストールしました。)
pip install numpy==1.26.4 spacy
2. 日本語のトークナイザを作成
多言語対応のサンプルコードのシナリオ2を参考に日本語のカスタムトークナイザ my_custom_tokenizer_ja
を作成。
language_code = "ja"
import spacy
import nltk
nltk.download('wordnet')
def get_language_model_sp(language='en'):
nlp = None
if language=='en':
nlp = spacy.load("en_core_web_sm")
if language=='ja':
nlp = spacy.load("ja_core_news_sm")
return nlp
class MyCustomTokenizer():
def __init__(self, language = 'en'):
self.language = language
self.tokenizer = None
def tokenize(self, input_text):
tokens = []
nlp = get_language_model_sp(self.language)
doc = nlp(input_text)
for token in doc:
tokens.append(str(token))
return tokens
def __call__(self, input_text):
return self.tokenize(input_text)
my_custom_tokenizer_ja = MyCustomTokenizer(language_code).tokenize
3. 試してみるデータを準備
RAGで取得できる、ユーザーからの質問、検索結果、生成AIの出力、をセットする。
また、回答の類似性(Answer similiarity)を測定するために模範回答もセットする。
(各データは環境に合わせてセットしてください。)
query1 = "ユーザからの質問"
context1 = "質問内容から検索結果"
answer1 = "質問と検索結果を元に生成AIが回答した内容"
ground_truth1 = "正解の回答内容"
uestions = [query1]
contexts = [context1]
answers = [answer1]
ground_truth = [ground_truth1]
サンプルコードに倣って、以下も実行します。
import pandas as pd
data = pd.DataFrame(contexts, columns=["context1"])
data["question"] = questions
data["answer"] = answers
data["ground_truth"] = ground_truth
data
4. watsonx.governanceへの認証
API Keyやwatsonx.aiのURLをセットします。
(API Keyの値は環境に合わせて設定してください。)
from ibm_watsonx_ai import APIClient
from ibm_watsonx_ai import Credentials
credentials = Credentials(
url = "https://us-south.ml.cloud.ibm.com",
api_key="xxxxxxxxxxxxxx",
)
watsonx.aiで東京リージョンを利用する場合は、以下に書き換えてください
url = "https://jp-tok.ml.cloud.ibm.com",
watsonx.aiのプロジェクトIDを変数にセットします。
project_id = "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx"
watsonx.governanceのAPIで認証します。
from ibm_cloud_sdk_core.authenticators import IAMAuthenticator
from ibm_watson_openscale import APIClient
from ibm_watson_openscale import *
from ibm_watson_openscale.supporting_classes.enums import *
from ibm_watson_openscale.supporting_classes import *
authenticator = IAMAuthenticator(
apikey=credentials['apikey']
)
client = APIClient(
authenticator=authenticator
)
print(client.version)
5. スコアリング関数にwatsonx.aiのモデルを設定
サンプルコードを参考にして、スコアリング関数を作成します。
サンプルコードからモデルをmistralai/mixtral-8x7b-instruct-v01
に変更しています。
日本語のRAGの指標の精度は、こちらのモデルの方が良かったです。(2024年12月)
from ibm_watson_machine_learning.metanames import GenTextParamsMetaNames as GenParams
from ibm_watson_machine_learning.foundation_models import Model
from ibm_watson_machine_learning.foundation_models.utils.enums import ModelTypes
import pandas as pd
generate_params = {
GenParams.MAX_NEW_TOKENS: 1000,
GenParams.MIN_NEW_TOKENS: 10,
GenParams.TEMPERATURE: 0.0
}
model = Model(
model_id="mistralai/mixtral-8x7b-instruct-v01",
params=generate_params,
credentials={
"apikey": credentials.get("apikey"),
"url": credentials.get("url")
},
project_id=project_id
)
def scoring_fn(data):
results = []
for prompt_text in data.iloc[:, 0].values.tolist():
model_response = model.generate_text(prompt=prompt_text)
results.append(model_response)
return pd.DataFrame({"generated_text": results})
6. 計算する指標のConfigを構成
watsonx.governanceにおいて計算する指標やスコアリング関数を構成する。
from ibm_metrics_plugin.metrics.llm.utils.constants import LLMTextMetricGroup, LLMCommonMetrics, LLMQAMetrics, LLMRAGMetrics, RetrievalQualityMetric
# Edit below values based on the input data
context_columns = ["context1"]
question_column = "question"
answer_column = "answer"
config_json = {
"configuration" : {
"record_level" : True,
"scoring_fn" : scoring_fn,
"context_columns" : context_columns,
"question_column" : question_column,
LLMTextMetricGroup.RAG.value: {
LLMCommonMetrics.FAITHFULNESS.value: {},
LLMCommonMetrics.ANSWER_RELEVANCE.value: {},
LLMQAMetrics.UNSUCCESSFUL_REQUESTS.value: {},
LLMCommonMetrics.CONTENT_ANALYSIS.value: {},
LLMRAGMetrics.RETRIEVAL_QUALITY.value: {},
LLMCommonMetrics.ANSWER_SIMILARITY.value: {},
}
}
}
ここで、以下のような設定を入れてしまうと日本語のカスタムトークナイザが機能しなくなるため、要注意です。
"language_code" : language_code
7. 計算
サンプルコードに倣って、以下を実行する。
df_input = pd.DataFrame(data, columns=context_columns+[question_column])
df_output = pd.DataFrame(data, columns=[answer_column])
df_reference = pd.DataFrame(data, columns=["ground_truth"])
サンプルコードに倣って、以下を実行するが、ここで日本語のカスタムトークナイザをセットする。
import json
metrics_result = client.llm_metrics.compute_metrics(
config_json,
sources=df_input,
predictions=df_output,
references=df_reference,
tokenizer = my_custom_tokenizer_ja,
)
実行完了まで少し時間がかかります。
8. 結果の取得
サンプルコードに倣って、以下を実行して結果を取得する。
final_results = client.llm_metrics.get_metrics_result(configuration=config_json, metrics_result=metrics_result)
print(json.dumps(final_results, indent=2))
サンプルコードに倣って、以下を実行して結果を表形式で出力する。
results_df = data.copy()
for metric_name, metric_data in final_results.items():
vals = {}
if "record_level_metrics" in metric_data:
for rm in metric_data["record_level_metrics"]:
for m, mv in rm.items():
if m != "record_id" and m!= "faithfulness_attributions" and m!= "context_relevances": # Excluding columns
if m in vals:
vals[m].append(mv)
else:
vals[m] = [mv]
if vals:
for k, v in vals.items():
results_df[k] = v
results_df
最後に
日本語のRAGの品質をLLMを用いて評価できることを試すことができました。
検索部分の評価を活用することで、質問を回答できるデータがベクトルDBにあるか、ベクトルDBにデータがある場合はデータの入れ方や検索方法などの工夫が必要になるかなど考慮できるようになります。
また、回答生成の評価を活用することで、ハルシネーションなど回避するためにプロンプトテンプレートや生成AIについて考慮できるようになります。
質問から回答への評価では、RAGの品質を客観的に評価できるようになります。
生成AIによってAIシステムの開発が容易になった反面、テストや運用や保守などのコストについて考えてみると、RAGを検証したり本番運用したりする際に、生成AIにRAGを評価させることで効率良くRAGの品質を評価し改善していく、というのが今後の生成AIの利用方法の1つになっていくかもしれないです。
watsonx.governanceでの評価においてwatsonx.aiのLLMで利用した場合は、watsonx.governanceとは別にwatsonx.aiの料金が発生するので注意してください。