atomz technology logoatomz technologyBlog
記事一覧

RAGアプリの品質をどう評価するか ― 「いい感じ」でリリースを決めないためのLLM評価

·12 分で読めます
katsunari-nagai-80katsunari-nagai-80

はじめに

私は普段、企業向けにAIを使った業務改善のお手伝いをしています。 社内の規程や手引きをナレッジ化して質問に答えるFAQボットは、この1年でいちばん多く作ったものです。

デモをお見せすると、反応はだいたい良いです。

「おお、いい感じに答えますね」

そして、ほぼ必ずそのあとに聞かれます。

「この質問以外でも、同じように答えられるんですか?」

ここで難しいのが、私たちだけでは業務上の正解を判断できないことです。 そのため最終的な品質確認は、業務を理解している先方にお願いする必要があります。

ただ、「自由に触って確認してください」では、先方も何を、どこまで確認すればいいのか分かりません。 結果として、いくつか質問して「良さそうですね」で終わってしまいます。

そこで、こちらでテストの仕組みを作り、先方には現場でよくある質問と期待する回答を整理してもらう形にしました。 AIがそれらに回答し、先方には結果を確認してもらいます。

何を確認するかはこちらで設計し、何が正しいかは業務担当者に判断してもらう。

この形にすると、同じ質問を繰り返しテストできるため、プロンプトや検索設定を変えたときに、本当に品質が上がったのか、逆に悪くなった質問がないかを確認できます。

100問投げて、9割が期待どおりの回答なら本番に出す

これを最初に決めることで、「いい感じ」という感覚ではなく、基準を満たしたかどうかでリリースを判断できるようになります。

この記事では、そのための最低限の評価の仕組みを紹介します。

対象読者

  • RAGやFAQボットを作ったが、品質をどう説明していいか分からない方
  • 「評価基盤」を作りたいが、大掛かりに見えて手が出せていない方
  • 精度改善の打ち手が、なんとなくの当てずっぽうになっている方

題材:現場向けの社内FAQボット

この記事で扱うのは、こういうボットです

  • 社内の規程・手引き・過去のQ&Aをナレッジ化し、現場担当者の質問に答える
  • Difyのワークフロー型アプリ。ナレッジ検索 → LLMで回答生成というよくある構成
  • 利用者は業務のプロ。間違った答えは、使われないどころか信頼を失う

一般消費者向けのチャットボットなら「たまに外す」で済みますが、 業務の判断に使われるボットは、外し方によっては二度と開いてもらえません。

最初の壁 ―「改善したかどうかが分からない」

基準を決めたあと、最初にぶつかったのは意外なところでした。 改善したのかどうかが、自分でも分からないのです。

プロンプトを直す。モデルを変える。チャンク分割を見直す。 ここまでは誰でもやります。問題はそのあとで、変更の前後で何が良くなったのかを言えない。

理由は単純で、良くなった部分と悪くなった部分が同時に起きるからです。 「直したら、今度は根拠のないことまで答えるようになった」みたいなことが平気で起きる。

ソフトウェアなら当たり前にテストを書くのに、 LLMアプリになった途端、「触ってみて良さそう」で判断していたわけです。

なので、質問リストを固定することにしました。

図を描画中…

このループが回るようになると、はじめて「何を変えたら何がどう動いたか」を言葉にできます。

テストケースは数十問から始めていい

ここが最大の心理的ハードルだと思うので、先に潰しておきます。 網羅的なテストセットを作ってから始める必要はありません。

テストセットの作り方については、Anthropicが公開している Demystifying evals for AI agents の「Collect tasks for the initial eval dataset」がよく整理されていて、私もこの考え方を下敷きにしています。

Demystifying evals for AI agents — Anthropic

AIエージェントの評価をどう設計するか。タスクの集め方、3種類の採点者、長期運用の考え方まで整理された記事。

www.anthropic.com

記事の中では、はじめの一歩について次のように書かれています。

20-50 simple tasks drawn from real failures is a great start.

つまり、実際に起きた失敗から取った20〜50問で十分だと。 そして集め方も、新しく考えるのではなく既にやっていることを流用しろ、という整理になっています。

Begin with the manual checks you run during development—the behaviors you verify before each release and common tasks end users try.

私の場合も、ゼロから質問を考えたわけではありませんでした。 材料は最初から手元にありました。

  • リリース前に自分が毎回手で叩いて確認していた質問
  • 現場から「これ、間違って答えたよ」と上がってきた質問
  • 業務側が「こういうのを聞きたい」と最初のヒアリングで挙げていた質問

これをスプレッドシートに写すところから始めています。数十問です。 それでも、変更の前後を比べられるという一点だけで価値が出ます。

合っていることの確認より、言ってはいけないことを言っていないかの方が重要なのです。 規程の話をするボットが、根拠のない例外を1つ口にした瞬間に、そのボットは使えなくなります。

答えるべきでない質問も入れる

もうひとつ、意識して入れたのが範囲外の質問です。 ナレッジに載っていないこと、そのボットが答えるべきでないこと。全体の1〜2割ほど混ぜています。

これも先ほどの記事に、はっきり書かれています。

Test both the cases where a behavior should occur and where it shouldn't. One-sided evals create one-sided optimization.

答えられる質問だけで測っていると、答える方向にだけ最適化されます。 「分かりません」と言うべき場面で言えるかどうかは、業務用ボットではむしろ本丸です。

良い問題の条件

問題文を作るときの基準も、この記事の一文をそのまま使っています。

A good task is one where two domain experts would independently reach the same pass/fail verdict.

業務担当者2人が、別々に採点して同じ合否になるか。 ここが割れる問題は、仕様が曖昧なまま指標にノイズを混ぜているだけです。

自動化できる判定と、人に残す判定を分ける

FAQボットの評価をすべて自動化する必要はありません。

むしろ、業務上その回答が正しいかどうかは、最終的には人が確認するべきだと考えています。

その前に、機械で判断できるものだけを先に判定します。

コードで判定する

たとえば次のようなものです。

  • 回答が途中で切れていないか
  • 禁止要素が含まれていないか
  • 期待した文書を検索できているか
  • 棄権すべき質問で回答していないか

こうした判定は毎回同じ結果になるため、人が確認する必要はありません。

LLMで補助判定する

必要であれば、LLMを使って

  • 期待した結論になっているか
  • 必須要素が含まれているか

なども判定できます。

ただし、LLMによる採点にもAPIコストがかかるため、これは必須ではありません。

最終的な内容確認は人が行う

回答内容そのものが業務上正しいかどうかは、最終的には人が判断します。

ただし、毎回すべての回答を業務担当者に確認してもらう必要はありません。

最初のテストでは、業務担当者に全体を確認してもらい、 「どういう回答なら正しいのか」「どこまで言えていれば合格なのか」を開発側とすり合わせます。

一度この基準ができれば、2回目以降は開発側でもある程度判断できるようになります。

そのため、定常運用では

  • 明らかに合否を判断できるものは開発側で確認する
  • 業務知識が必要で判断できないものだけ、業務担当者に確認する

という形にしています。

つまり、最初に業務担当者と正解の基準を作り、その後は判断に迷うものだけ確認してもらう運用です。

これなら品質を担保しながら、業務担当者の確認負荷も大きく減らせます。

評価を継続して回すために見ること

評価の仕組みを作ったあとに重要なのは、毎回同じ条件で比較できる状態を保つことです。

LLMアプリの評価は、一度合格率を出して終わりではありません。 プロンプトやモデル、検索設定、ナレッジを変更するたびに同じ質問セットを実行し、前回との差分を確認します。

特に見るべきなのは、前回は正しく答えられていたのに、今回は答えられなくなった質問がないかです。

全体の合格率が上がっていても、一部の質問が悪化していることがあります。 そのため、合格率だけではなく、質問ごとの差分も確認するようにします。

また、不合格になった質問は原因を分類しておくと、次に何を直すべきか判断しやすくなります。

分類主な原因改善する場所
回答が途中で切れる出力上限・タイムアウト基盤設定
関係ない文書を取得する検索条件メタデータ・絞り込み
必要な文書を取得できない検索精度チャンク・検索方法
ナレッジに情報がない文書不足ナレッジ追加
根拠にない内容を回答する回答生成プロンプト
表現だけが気になる文体優先度を下げる

こうして原因を分けておくことで、すべてを「LLMの精度が悪い」でまとめずに済みます。

測定条件も残す

前回との比較をするために、実行時の条件も記録しておきます。

  • 使用したモデルとパラメータ
  • プロンプトのバージョン
  • ナレッジのバージョンや更新日
  • 検索設定
  • 今回変更した内容

条件が変わっているのに記録が残っていないと、なぜ結果が変わったのか分からなくなります。

評価の仕組みで大事なのは、単に合格率を出すことではありません。

変更によって何が良くなり、何が悪くなったのかを継続的に追える状態を作ることです。

まとめ

RAGアプリを「いい感じ」で評価するのではなく、リリース判断できる状態にするために、今回の仕組みでは次のことを意識しました。

  • 先に合格基準を決める。 「何問中、何割正しく答えられればリリースするか」を決めておくことで、感覚ではなく基準で判断できます。

  • テストケースは数十問から始める。 現場でよく聞かれる質問や、過去にうまく答えられなかった質問を使えば十分です。

  • 自動化できる判定は先に機械で確認する。 回答の打ち切り、禁止要素、参照文書などはコードで確認し、必要であればLLMによる補助判定も使います。

  • 回答内容の正しさは人が確認する。 最初は業務担当者と一緒に正解基準を作り、2回目以降は開発側で判断します。業務知識が必要で判断できないものだけ、業務担当者に確認します。

  • 合格率だけでなく、前回との差分を見る。 全体の数字が良くなっていても、一部の質問が悪化していることがあります。変更前後で何が良くなり、何が悪くなったのかを確認します。

  • 不合格の原因を分類する。 検索、プロンプト、ナレッジ不足、基盤設定などに分けることで、次にどこを直すべきかが分かります。

大事なのは、大掛かりな評価基盤を作ることではありません。

何をテストするかを決め、同じ質問で繰り返し評価し、結果を比較できる状態を作ること。

そして期待値としては、評価が保証してくれるのは「後退していないこと」までです。 評価の仕組みそのものが、次にどう改善すればよいかを教えてくれるわけではありません。

良くする方向は、不合格になった原因を分類し、その結果から自分たちで読み取る必要があります。

この型はFAQボットに限らず、社内文書を使ったRAGアプリ全般に応用できます。 「精度は上がってきたけど、リリースしていいか判断できない」という場面で、ひとつの参考になれば嬉しいです。


付録:ディレクトリ構成と1回まわす手順

スクリプトは3本だけです。

test/
├── tasks/tasks.csv          問題と合格条件。テストコード相当。実行ごとに書き換えない
├── src/run.py               質問セットを投げ、回答と検索結果を保存
├── src/grade.py             採点。コード判定+任意でLLM判定
├── src/report.py            集計と前回との比較
├── runs/{run_id}/
│   ├── config.json          実行条件。モデル・ナレッジ版・検索設定
│   ├── raw.jsonl            回答と検索結果の生ログ
│   └── graded.csv           採点結果。最終判定の列を人が埋める
└── reports/{run_id}_vs_{比較先}.md

1回まわす手順はこの5ステップです。

手順やること誰が
0疎通確認。1問だけ投げるスクリプト
1全問を実行スクリプト
2実行条件を config.json に記入人
3採点スクリプト
4判定を確認する。段階に応じて読む量が変わる人
5レポート生成・前回と比較スクリプト
# 0. 疎通確認
python src/run.py --run-id TEST --only T001
 
# 1. 全問を実行。--note には「何を変えたか」を書く
python src/run.py --run-id R03 --note "出力上限を引き上げ・rerank有効化"
 
# 3. 採点
python src/grade.py --run-id R03 --judge
 
# 5. レポート
python src/report.py --run-id R03 --compare R01

--note は地味ですが重要です。あとから数字が動いた理由を辿る、ほぼ唯一の手がかりになります。

Services

その他のサービスはatomz technology ↗で。