TECH BLOG
RAG評価フレームワーク「Ragas」の紹介
こんにちは、ARISE analyticsの和久田です。
私は業務でカスタマーサポート向けのAIエージェントの開発に携わっており、特にRAG部分の精度向上に取り組んでいます。その過程で、RAG評価フレームワークである「Ragas」を知りました。
本記事では、私が担当しているプロジェクトにRagasを導入した経験をもとに、Ragasの特徴や、実務で利用する際に気を付けるべきポイントについて紹介します。
はじめに:RAGとは
近年、生成AIの企業導入が加速する中で、RAG(Retrieval-Augmented Generation:検索拡張生成)は注目される技術の1つとなっています。
RAGは、LLMによるテキスト生成(Generation)に外部情報の検索(Retrieve)を組み合わせて回答精度を高める技術です。ユーザーの質問に対して、関連情報を検索し、その情報をプロンプトに埋め込み、回答を生成します。これにより、LLMに知識がなくても外部の正確な情報を基に回答できます。

RAGにおける評価の重要性
RAGは、LLMのハルシネーションを抑制するために導入される技術です。しかし、RAGを導入しただけでハルシネーションが完全に解決されるわけではありません。RAGで検索された内容が適切な情報でなければ、結果としてハルシネーションが発生してしまいます。また、適切な情報が検索できたとしても、LLMがその情報を適切に扱えなければ、質問に対して不適切な回答をしてしまう可能性があります。
このような不適切な回答は、実務における信頼性の低下や法的・倫理的リスクの増大、さらには社会的な混乱を招くおそれがあります。したがって実務では、ハルシネーションの少ない高性能なRAGが求められており、その性能を客観的に測定・評価することが重要です。
RAG評価の観点と手法
評価観点
RAG評価観点は、大きく次の2つの軸があります。
- 検索:入力に対して「正しく検索できているか」を評価する
- 生成:検索された情報を基に「適切に回答を生成できているか」を評価する
これらをより具体化すると、次のような評価観点に分解できます。
- 検索
- 質問に対してどの程度正しい情報が検索できているか
- 回答に必要な情報がどの程度網羅的に検索できているか
- 生成
- 回答内容は検索された情報にどれだけ忠実か
- 検索されていない情報を回答にどの程度含めてしまっているか
- 回答内容はどの程度正確か
- 回答内容は質問内容とどの程度関連しているか
ここで挙げたもの以外にも、ユースケースに応じて様々な評価観点が存在します。
手動評価と自動評価
上記の評価指標を人間が評価しようとすると、
- 評価者ごとに「正しさ」の基準がブレてしまう
- 評価に膨大な時間がかかってしまう
といった問題が発生します。
(参考:実際にプロジェクトで人手による評価を実施した際、1件のテストケースを先ほどの6つの評価観点で評価するのに約1時間かかりました。10件のテストケースに対しては、単純計算で10時間かかることになります。)
この課題を解決するために、BLEUやROUGEといった統計的手法や、LLMによる評価(LLM-as-a-judge)といった自動評価手法が存在します。
BLEUなどの統計的手法は、RAG評価で使用されることはありますが、文脈を正確に捉えた評価としては限界があります。一方、LLMによる評価では、BLEUなどに比べて文脈を捉えたより正確な評価が可能です。
本記事では、LLMによるRAG評価が可能なフレームワークである「Ragas」について紹介していきます。
RAG評価フレームワーク「Ragas」の概要
「Ragas」は、現在広く利用されているRAGの自動評価が可能なオープンソースのフレームワークです。主な特徴は次です。
- 評価指標の網羅性:先述したRAG評価における評価観点も含めて、様々な評価観点を網羅しています
- 評価の透明性:LLMによる評価時の判断根拠が取得可能です
先述した評価観点は、Ragasではそれぞれ次の評価指標として提供されています。
| 観点のカテゴリ | 評価観点 | Ragasで提供されている評価指標 |
| 検索 | 質問に対してどのくらい正しい情報が検索できたか | Context Precision |
| 検索 | 回答に必要な情報がどのくらい網羅的に検索できたか | Context Recall |
| 生成 | 回答内容は検索された情報に忠実か | Faithfulness |
| 生成 | 検索されていない情報を回答に含めていないか | Noise Sensitivity |
| 生成 | 回答内容は正確か | Answer Correctness |
| 生成 | 回答内容は質問内容と関連するか | Answer Relevancy |
※公式ドキュメントの情報が古かったり、バージョンによって記載内容が異なることがあります。最新バージョンである0.4.xで使用可能な評価指標はこちらに整理されています。
RagasによるRAG評価の流れ
ここからは、Ragasを使ってRAGを評価する流れを実装例とともに解説し、Ragasが内部でどのように判断してスコアを出しているかを理由付きで詳しく見ていきます。
今回は、au公式HPの情報を登録したシンプルなRAGシステムを用意しました。
このRAGシステムに対して、検索の評価指標であるContext PrecisionとContext Recallを用いてRagasによる自動評価を行います。
評価指標の説明
まず、Ragasの評価に必要なデータを整理します。
| user_input | ユーザーがRAGシステムに入力する質問文 |
| context | LLMが回答生成に使用する情報 |
| response | user_inputに対して、LLMが生成した回答 |
| reference | user_inputに対する回答の正解データ |
次に、Context PrecisionとContext Recallを説明します。
Context Precision
| 評価内容 | user_inputに対して有用なcontextが上位に検索できているか |
| 計算方法 |
1.LLMが、各contextがreferenceと関連するかを判定する 2.(関連あるcontextのprecision@kの合計) / (関連あるcontextの数)を計算する |
| 入出力データ |
・入力データ:user_input、context、reference ・出力データ:0~1。1に近いほど良い |
Context Recall
| 評価内容 | responseを生成するのに必要な情報が、検索されたcontextにどれだけ含まれているか |
| 計算方法 |
1.LLMが、referenceを主張ごとに分解する 2.LLMが、各主張がcontextに含まれているかを判定する 3.(contextに含まれる主張の数) / (主張の合計数)を計算する |
| 入出力データ |
・入力データ:user_input、context、reference ・出力データ:0~1。1に近いほど良い |
今回は、Context Precisionの計算方法1ステップ目と、Context Recallの計算方法2ステップ目のLLM判定結果を判定理由付きで詳細に確認します。
評価用テストケース
評価用テストケースは次を使用します。
| テストケースNo. | 質問内容 | 備考 |
| 1 | au PAYの一時停止の操作方法を知りたい | ベクトルDBに関連情報が存在する質問 |
| 2 | Pontaポイントの概要 | ベクトルDBに関連情報が存在しない質問 |
ベクトルDBに登録するデータはau公式HPにある次のページとします。
| テストケースNo. | 質問内容 | 備考 |
| 1 | au PAY/au PAYプリペイドカードの一時停止の操作方法に関するFAQ | https://www.au.com/support/faq/details/00/0000/000024/pg00002424/ |
| 2 | au PAYの利用上限額に関するFAQ | https://www.au.com/support/faq/details/00/0000/000002/pg00000236/ |
| 3 | au PAYプリペイドカードが利用可能なお店に関するFAQ | https://www.au.com/support/faq/details/00/0000/000001/pg00000123/ |
| 4 | au PAYプリペイドカード利用時の注意点に関するFAQ | https://www.au.com/support/faq/details/00/0000/000002/pg00000232/ |
| 5 | au PAYプリペイドカードとau PAYの違いに関するFAQ | https://www.au.com/support/faq/details/00/0000/000002/pg00000275/ |
(登録データは、テキスト化したものを固定文字数でチャンキングしてベクトルDBに登録します)
正解データは、au公式HPの「よくある質問」の内容を参考に作成しました。
評価コードの実装例
今回はバージョン0.4.3で実装します。バージョンによって仕様が異なるため注意してください。
まず、Ragasで評価を実施するための評価用データセットをcsvファイル形式で作成します。
| user_input | reference |
| Pontaポイントの概要 |
Pontaポイントについてですね。 Pontaポイントは全国のPonta提携店やネットサービスで、ご利用金額に応じて「ためる」・「つかう」ことができる共通ポイントです。 Pontaポイントの貯め方、使い方などの詳細は以下のページをご確認ください。 ▽Pontaポイント ※ポイントの加算/反映はサービスによってお時間がかかる場合があります また、au IDとPonta会員IDを連携することで、ポイントを利用できる場所が広がります。 ▽au IDとPonta会員IDを連携したい |
| au PAYの一時停止の操作方法を知りたい |
au PAY(コード支払い)の一時停止/一時停止解除手順についてですね。 一時停止/一時停止解除は、au PAY サイトからお手続きができます。 ■操作手順 ▽au PAY 利用設定 ※ご注意事項※ |
このcsvファイルをdatasetsフォルダ配下に格納し、読み込みます。
from ragas import Dataset
# csvファイルの読み込み
dataset_loaded = Dataset.load(
name="{csvファイル名}",
backend="local/csv",
root_dir="{datasetsフォルダからのパス}",
)
LLM評価器を設定します。今回は評価者LLMにGPT-5.1を使用します。
from dotenv import load_dotenv
from metrics_with_reason import ContextPrecisionWithReason, ContextRecallWithReason
from openai import AsyncOpenAI
from ragas.llms import llm_factory
# 環境変数の読み込み
load_dotenv()
# 評価者LLMの設定
client = AsyncOpenAI()
llm = llm_factory("gpt-5.1", client=client)
# Ragasの潜在的なバグがあり、モデル名に"."が含まれている場合は
# max_tokens → max_completion_tokensへの変換を手動で行う必要がある
llm.model_args["max_completion_tokens"] = llm.model_args.pop("max_tokens", 1024)
llm.model_args["temperature"] = 0.0
# 評価指標の設定
precision_metric = ContextPrecisionWithReason(llm=llm)
recall_metric = ContextRecallWithReason(llm=llm)
RagasでContext PrecisionとContext Recallを算出する際、内部で評価理由を取得していますが出力されていません。そのため、Ragasのメソッドをオーバーライドして評価値を出力するよう修正します。
class ContextPrecisionWithReason(ContextPrecision):
async def ascore(self, user_input, reference, retrieved_contexts) -> MetricResult:
#######################
# Ragasの既存の処理
#######################
for idx, context in enumerate(retrieved_contexts):
input_data = ContextPrecisionInput(
question=user_input, context=context, answer=reference
)
prompt_string = self.prompt.to_string(input_data)
result = await self.llm.agenerate(prompt_string, ContextPrecisionOutput)
verdicts.append(result.verdict)
# context_index, verdict, reasonを出力するよう追加実装
items.append(
{
"context_index": idx,
"verdict": result.verdict,
"reason": result.reason,
}
)
score = self._calculate_average_precision(verdicts)
reason_json = json.dumps(items, ensure_ascii=False)
return MetricResult(value=float(score), reason=reason_json)
class ContextRecallWithReason(ContextRecall):
async def ascore(self, user_input, retrieved_contexts, reference) -> MetricResult:
#######################
# Ragasの既存の処理
#######################
attributions = [c.attributed for c in result.classifications]
score = sum(attributions) / len(attributions) if attributions else np.nan
# statement, attributed, reasonを出力するよう追加実装
items = [
{
"statement": c.statement,
"attributed": c.attributed,
"reason": c.reason,
}
for c in result.classifications
]
reason_json = json.dumps(items, ensure_ascii=False)
return MetricResult(value=float(score), reason=reason_json)
RAGシステムを実装します。FAISSインデックスが作成されている前提のコードになります。
class RAGSystem:
def __init__(self, index_dir: str = "faiss_index"):
self.index_dir = index_dir
self.embeddings = OpenAIEmbeddings()
self.vectorstore = FAISS.load_local(
self.index_dir,
self.embeddings,
allow_dangerous_deserialization=True,
)
self.llm = ChatOpenAI(model="gpt-4.1", temperature=0)
# ベクトル検索結果を受け取り回答生成を行うチェーンの実装
template = """以下のコンテキスト情報を基に質問に答えてください。
コンテキスト情報: {context}
質問: {question}
回答:"""
prompt = ChatPromptTemplate.from_template(template)
self._prompt_llm_chain = prompt | self.llm
# RAGの実行
def query(self, query):
# ベクトル検索(検索件数は3件)
source_documents = self.vectorstore.similarity_search_with_score(query, k=3)
retrieved_contexts = [doc.page_content for doc, _ in source_documents]
context = "\n\n".join(retrieved_contexts)
# 回答生成
result = self._prompt_llm_chain.invoke({"context": context, "question": query})
answer = result.content
return answer, retrieved_contexts
評価を実行するための関数を定義し、評価を実行します。
from pydantic import BaseModel
# 自前のRAGシステムをインポート
from rag_system import RAGSystem
rag_system = RAGSystem()
# 評価結果の型定義
# ここで定義した項目をカラム名としたcsvファイルが自動で出力される
class EvalResult(BaseModel):
user_input: str
reference: str
context_precision_value: float
context_precision_reason: Optional[str] = None
context_recall_value: float
context_recall_reason: Optional[str] = None
# 評価実行関数の定義
@experiment(EvalResult)
async def run_evaluation(row):
response, retrieved_contexts = await asyncio.to_thread(
rag_system.query, row["user_input"]
)
precision_result = await precision_metric.ascore(
user_input=row["user_input"],
retrieved_contexts=retrieved_contexts,
reference=row["reference"],
)
recall_result = await recall_metric.ascore(
user_input=row["user_input"],
retrieved_contexts=retrieved_contexts,
reference=row["reference"],
)
return EvalResult(
**row,
context_precision_value=precision_result.value,
context_precision_reason=precision_result.reason,
context_recall_value=recall_result.value,
context_recall_reason=recall_result.reason,
)
# 評価の実行
await run_evaluation.arun(
dataset_loaded, name=f"{datetime.now().strftime('%Y%m%d%H%M%S')}"
)
評価結果
各質問内容に対して次のような結果になりました。
| テストケースNo. | 質問内容 | Context Precision | Context Recall |
| 1 | au PAYの一時停止の操作方法を知りたい | 1.00 | 0.83 |
| 2 | Pontaポイントの概要 | 0.00 | 0.00 |
テストケース1は、ベクトルDBに関連した情報が存在するためContext Precision、Context Recallともに最大値である1.00に近い値になっており、良い結果が得られています。
テストケース2は、ベクトルDBに関連した情報が存在しないためContext PrecisionとContext Recallがそれぞれ0.00になっています。
以下では、テストケース1に対してRagasでどのような評価が行われたか詳しく見ていきます。
ケース1 評価結果の詳細
Context Precisionの評価内
Context Precisionでは、user_input、context、referenceを確認して、「contextがuser_inputに対して有用か」を判断していきます。
下表はRagasが有用か判断した結果(理由付き)です。
| No. | context(最初の100字) | user_inputに対して有用か | Ragasが出力した判断理由 |
| 1 | 一時停止中は、au PAY 残高がもらえるキャンペーンの特典は受け取れなくなります。特典をお受け取りになった後に手続きください。 手順 目安時間:5分 ステップ数:4 ご準備ください au ID/パスワード… |
1 |
|
| 2 | 【au PAY/au PAY プリペイドカード】利用を一時停止したい/一時停止を解除したい au PAY アプリでの手続き方法 【au PAY/au PAY プリペイドカード】利用を一時停止したい/一時停止を解除したい au PAY アプリのアカウント画面で、一時停止/解除のお手続きができます。… |
1 | コンテキストは、「au PAY利用設定」ページへのアクセス、au IDでのログイン、スイッチの切り替え、スイッチの色の意味など、au PAYの一時停止と再開の手順を明確に説明している。回答はこれらの手順と詳細を直接使用しているため、コンテキストは明らかに回答を導くのに有用だった。 |
| 3 | 【au PAY】利用上限額はいくらですか? au PAY(コード支払い/ネット支払い/請求書支払い) 【au PAY】利用上限額はいくらですか? au PAY(コード支払い/ネット支払い/請求書支払い)の利用上限額は、… |
0 | コンテキストはau PAYとau PAYプリペイドカードの利用上限額のみを説明しており、一時停止の手順や方法については一切言及していない。提供された回答にある具体的な一時停止/解除の操作手順は、このコンテキストから導けない。 |
Context Precisionは、関連ないcontextが関連あるcontextよりも上位に検索されると評価値が下がります。今回のケースでは、関連ないcontextが3位、関連あるcontextが1位・2位のため評価値は下がりません。
Context Recallの評価内容
Context Recallでは、referenceを「主張」という細かい文章に区切り、「主張がcontextに含まれているか」を判断していきます。
下表はRagasが含まれているか判断した結果(理由付き)です。
| 主張 | 主張がcontextに含まれているか | Ragasが出力した判断理由 |
|
au PAY(コード支払い)の一時停止/一時停止解除手順についてですね。 |
1 | コンテキストは、コード支払いを含むau PAYの一時停止と再開方法を説明するヘルプ記事であるため、この導入文はコンテキストと一致しており、コンテキストに基づいている。 |
| 一時停止/一時停止解除は、au PAY サイトからお手続きができます。 | 1 | コンテキストには、au PAYサイト(「au PAY利用設定」ページ)で一時停止または解除の手続きができることが明示されており、この文と一致する。 |
| ■操作手順 | 1 | これは手順を紹介する見出しであり、コンテキストも手順として提示しているため、一貫性があり、コンテキストに基づいている。 |
| ①「au PAY利用設定」ページにアクセスし、au IDでログイン | 1 | コンテキストには「「au PAY 利用設定」ページにアクセスし、au IDでログインします。」と記載されており、この手順と一致する。 |
| ②「au PAY」のスイッチを押下し、一時停止/一時停止解除を切り替え | 1 | コンテキストには、同じページで[au PAY]または[プリペイドカード]のスイッチをタップして一時停止と解除を切り替えることができると説明されており、この手順に対応する。 |
| ③「設定」を選択 | 1 | コンテキストには、スイッチの状態を確認して[設定]をタップするよう指示されており、この手順と一致する。 |
| ▽au PAY 利用設定 | 1 | これはau PAY設定ページのリンクのラベルであり、コンテキストにも「au PAY 利用設定」ページとして言及されている。 |
| ≫ | 1 | これはリンクの前に付ける装飾記号であり、コンテキストを超える事実的な内容を追加していない。 |
| https://aupay.auone.jp/menu/lock_set.html?state=confirm&openExternalBrowser=1 | 0 | コンテキストには「au PAY 利用設定」ページが存在し、「こちら」と記載されているが、この具体的なURLは提供されていないため、正確なリンクはコンテキストに基づいていない。 |
| ※ご注意事項※ | 1 | これは注意事項の見出しであり、コンテキストにも注意セクションがあるため、注意見出しの存在は一貫性があり、コンテキストに基づいている。 |
| ・一時停止にする場合はスイッチをオフ(灰色)、解除する場合はオン(緑色)にしてください | 1 | コンテキストには「スイッチがオン(緑色)の場合は解除、オフ(灰色)の場合は一時停止されます。」と記載されており、この指示と一致する。 |
| ・「au PAY」を停止にした場合、au PAY プリペイドカードもご利用できなくなります | 0 | コンテキストには、一時停止中はau PAY(コード支払い)とau PAYプリペイドカードの両方が利用できなくなると記載されているが、au PAYのみを停止するとプリペイドカードも自動的に利用不可になるという因果関係は明示されていない。 |
実際に、referenceに記載されているURLはcontextに含まれないため、正しく評価できています。
最後の主張については、人間なら「含まれている」と判断するところですが、Ragasの判定は「含まれていない」でした。
原文では「一時停止中は~」と書かれており、「au PAYの一時停止中である」という前提が明記されていません。そのため、Ragasは「何が一時停止のときの話なのか」を正しく読み取れず、「含まれていない」と判断してしまったと思われます。
また、「≫」という記号単体で主張に分解するなど、主張への分解精度は課題があります。
Ragasを使って見えた『気づきポイント』
Ragasを実際に利用してみて得られた気づきポイントをまとめます。
Ragasの評価精度
Ragasは、人間の評価感覚と概ね近い評価を行えることが確認できました。ベクトルDBに関連情報が含まれる場合は高評価、含まれない場合は低評価となり、直感的に理解しやすい評価結果が得られます。
一方で、主語や前提条件が省略されているなどで情報構造が崩れているケースや、言い回しが少し異なるケースでは、人間の評価とRagasの評価がズレることもありました。
また、「≫」のような記号やURL自体など、人間から見ると意味の薄い要素も1つの主張として評価されるため、違和感のある評価を行う場合があります。
自動評価の実用性と費用対効果
Context PrecisionとContext RecallをLLMを使わず人手で評価した場合、1テストケースあたり約40分かかっていましたが、Ragasによる自動評価では1~2分程度まで短縮されました。コスト面でも、2ケースを2つの評価指標で評価した場合(GPT-5.1使用)の費用は約5円と低く、十分な費用対効果が得られると考えられます。
評価結果の扱い方
LLMによる評価であるため、評価のたびに結果がブレる可能性があります。より安定した評価を得るには、複数回評価を実行し、その平均値を取ることを推奨します。
また、評価値だけでなく、Ragasが提供する評価理由も確認し、評価が妥当かどうかを人間がレビューすることが重要です。
まとめ
本記事では、RAG評価フレームワーク「Ragas」について、その概要と具体的な使用例を紹介しました。 Ragasは、RAGの評価作業を大幅に効率化できる有用なフレームワークです。
一方で、RagasはLLMによる自動評価に基づくため、評価結果がブレたり、人間の評価感覚とズレてしまうところもあります。
そのため、自動評価結果をそのまま活用せず、評価値の根拠をしっかり確認したうえで、評価の妥当性を人間がレビューすることが重要です。