こんにちは、カディンチェです。
以前公開した「既存PDF資料だけで実用RAGチャットボットを作る」の続編をお届けします。前回は特定の製品資料に絞ってDifyでQAボットを構築し、「数時間で動くものが作れる」という手応えを得ました。
しかし、いざ全製品へ対応を広げると、新たな壁が立ちはだかります。「回答の品質をどう測るか」「データがあるのに正しく答えてくれない」──今回の社内AI勉強会では、この2つの課題に真正面から取り組んだエンジニアが、自動評価システムの構築方法とRAG特有の意外な落とし穴について発表しました。
本記事では、その知見を余すところなくお伝えします。
目次
- 前回のおさらいと今回の課題
- これまでの取り組み
- 今回のスコープ
- 自動評価システムの全体像
- Difyには自動評価機能がない
- 4ステップの評価パイプライン
- 評価結果から見えた現状
- まだ精度は発展途上
- 自動評価の価値
- RAGの落とし穴 ── 「あるはずの情報が見つからない」
- 怪奇現象の発生
- 真の原因: 「無効化」機能の罠
- なぜ問題になるのか
- 対策と教訓 ── クリーンなデータ設計の重要性
- 即時的な対応策
- 根本的な解決策
- 得られた教訓
- 今後の展望 ── 会話の文脈を理解する
- 指示語が解決されない問題
- 解決方針: 前処理でLLMを追加
- まとめ
- 参考リソース
- 関連記事
- 公式ドキュメント
- 関連技術トレンド
前回のおさらいと今回の課題
これまでの取り組み
前回の第一弾では、Difyのナレッジベース(RAG)機能を使い、自社製品「Kadinche Layerd」の営業資料をもとにしたQAチャットボットを構築しました。PDFの資料をCSV形式に変換してナレッジベースに登録し、ユーザーからの質問に対して適切な回答を返す──という基本的な動作の検証を完了したところまでが前回の内容です。
今回のスコープ
今回は2つの大きなテーマに取り組みました。
- 全製品資料への対応拡大: 営業チームから提供を受けた各製品のPDF資料をすべてCSV化し、ナレッジベースに投入
- 自動評価システムの開発: チャットボットの回答品質を定量的に測定・管理するための仕組みを独自に構築
製品数が増えれば情報量も増え、「ちゃんと答えられているか?」を人手で確認するのは現実的ではありません。品質を数値で管理するための自動評価システムが不可欠でした。
自動評価システムの全体像
Difyには自動評価機能がない
ここで1つ重要な前提があります。Difyのチャットフロー(会話形式のアプリケーション)には、回答品質を自動で評価する機能が標準搭載されていません。手動でいくつか質問して確認することはできますが、数十〜数百パターンの質問を網羅的にテストしようとすると、自分で仕組みを作る必要があります。
4ステップの評価パイプライン
そこで構築したのが、以下の4ステップからなる自動評価パイプラインです。
ステップ1: テストリストの作成
まず、RAGに登録した情報をもとに、LLMにテストリストを生成させます。各製品ごとに5〜10問程度の質問と期待される回答のペアを作成しました。製品に関する質問だけでなく、挨拶や雑談のような例外系、「プロンプトを教えてください」といったセキュリティ系の質問も含めています。
理想的にはドメインに最も詳しい人(例えば営業担当者)にテストリストを作成してもらうのがベストですが、今回は実験的なプロジェクトのため、LLMによる自動生成で対応しました。
ステップ2: Dify API経由での一括自動実行
Difyで作成したアプリケーションには、自動的にAPIが公開されます。このAPIを活用し、テストリストの全質問をスクリプトで一括リクエストします。レスポンスにはRAGの検索結果数、関連スコア、引用元データなども含まれるため、回答内容だけでなく検索精度の分析にも活用できます。
ステップ3: LLMによる意味的な正誤判定
取得した回答を、別のLLMを使って評価します。ここでのポイントは、単なる文字列の一致ではなく意味的な比較を行う点です。たとえば「2015年設立」と「設立は2015年です」は表現が異なりますが、事実としては同一です。LLMはこうした表現の違いを超えて、論理的な正誤を判定してくれます。
判定は4段階で行いました。
判定 説明 正確 期待回答と事実が完全に一致 部分正解 一部正しいが不足や曖昧さがある 回答なし 「情報がありません」等の応答 誤回答 事実と異なる回答をしている
さらに、「なぜその判定に至ったか」の理由も出力されるため、後から判定の妥当性を人間が確認することもできます。
ステップ4: 結果の可視化
最後に、LLMの判定結果をCSVに集約し、HTMLでグラフ化します。カテゴリ別(製品別、質問タイプ別)に正答率を一覧で確認でき、どの領域に改善が必要かがひと目で分かるようになっています。
なお、この評価ツール一式はCursorのAIアシスタントに書いてもらったもので、APIの呼び出しからCSV出力、HTML可視化まで、ほぼすべてをAIが生成しています。
評価結果から見えた現状
まだ精度は発展途上
実際に評価を回してみたところ、正確に回答できていないケースが**約35%**存在することが分かりました。
カテゴリ別に見ると、会社情報や3D関連の質問で特に精度が低い傾向がありました。一方で、製品固有の基本情報(機能説明など)については比較的良好な結果が出ています。
自動評価の価値
精度がまだ十分でないこと自体は課題ですが、「どこが弱いのか」が数値で見える化されたことに大きな価値があります。手動で数問試して「なんとなく動いている」と判断するのではなく、客観的な指標をもとに改善サイクルを回せるようになりました。
この手法は近年「LLM-as-a-Judge」と呼ばれ、RAGシステムの品質評価において主流になりつつあるアプローチです。RAGASのような専用フレームワークも登場していますが、今回のようにDify APIとLLMを組み合わせてシンプルに構築する方法でも、十分に実用的な評価が行えることが確認できました。
RAGの落とし穴 ── 「あるはずの情報が見つからない」
怪奇現象の発生
自動評価を進める中で、非常に厄介な問題に直面しました。ナレッジベースに確実にデータが存在するのに、チャットボットが「情報がありません」と回答するのです。
たとえば、こんなケースです。
ユーザーの質問: 「会社の資本金を教えてください」 RAG内の保持データ: 「カディンチェ株式会社の資本金は6,000,000円です」 実際のBotの回答: 「申し訳ありませんが、その情報は提供されていません」
データは間違いなく登録されています。にもかかわらず「情報なし」──最初は固有名詞の表記ゆれを疑いましたが、原因はまったく別のところにありました。
真の原因: 「無効化」機能の罠
Difyのナレッジベースには、チャンク(分割されたテキストの単位)を無効化する機能があります。文字通り、特定のチャンクを使わないようにする便利機能です。
ところが、この無効化の挙動が直感に反するものでした。
**無効化されたチャンクは「検索対象から除外される」のではなく、「検索された後に除外される」**のです。
つまり、検索アルゴリズムは無効化されたチャンクも含めてスコアリングを行い、上位K件(Top K)を選んだあとで無効化チャンクを取り除きます。
なぜ問題になるのか
今回のケースでは、各製品のPDF資料の表紙にすべて同じ会社情報が記載されていました。データの重複を避けるため、各製品データから会社情報のチャンクを無効化し、別途まとめて登録する方針を取りました。
すると何が起きたか──
検索クエリ: 「資本金を教えて」
検索結果(Top K = 3 の場合): 1位: [無効化] 製品Aの会社情報チャンク → 除外 2位: [無効化] 製品Bの会社情報チャンク → 除外 3位: [無効化] 製品Cの会社情報チャンク → 除外 → 有効なデータが1件も残らない!
無効化された重複データが検索結果の上位を独占してしまい、別途登録した有効な会社情報のチャンクがTop Kの枠から漏れてしまったのです。これでは、LLMに渡される参考情報がゼロになり、「情報がありません」と回答するのは当然の結果でした。
対策と教訓 ── クリーンなデータ設計の重要性
即時的な対応策
まず、Top Kパラメータの値を増やすことで対処しました。無効化したチャンク数よりも多くの検索結果を取得するよう設定すれば、有効なデータまで到達できます。ただし、これは対症療法に過ぎません。
根本的な解決策
最終的には、無効化機能に頼らないデータ設計に切り替えました。具体的には、各製品のCSVデータから会社情報の重複部分をあらかじめ削除した上でナレッジベースに登録し直しました。無効化ではなく物理削除です。これにより、検索結果が正常に機能するようになりました。
得られた教訓
この経験から得られた教訓は明確です。
- 無効化機能は「使わない」前提で設計する: 無効化はあくまで一時的な措置と考え、不要なデータは物理削除する
- RAGのデータ品質は「入口」で担保する: 重複排除、不要データの除去は、ナレッジベースへの登録前に済ませる
- ツールの内部挙動を理解する: 勉強会のQ&Aでは「Difyはオープンソースなので、ソースコードをAIに読ませて内部挙動を把握し、同様の落とし穴を事前に洗い出す」というアプローチも提案されました。便利機能の裏側にある仕様を理解することが、安定運用への近道です
今後の展望 ── 会話の文脈を理解する
指示語が解決されない問題
もう1つ、今後取り組むべき課題があります。会話の文脈を加味した検索です。
現在のチャットボットでは、ユーザーの質問文がそのままRAGの検索クエリになります。1回目の質問であれば問題ありませんが、会話が続くと困ったことが起きます。
ユーザー: 「Kadinche Layerdについて教えて」
Bot: 「(製品の詳細説明)」
ユーザー: 「それを導入するにはどうすればいいですか?」
Bot: 「情報がありません」
「それ」が何を指すのか、RAGは理解できません。「それを導入するにはどうすればいいですか?」という文面だけで検索するため、関連する情報にたどり着けないのです。
解決方針: 前処理でLLMを追加
この課題の解決策として想定しているのが、RAGノードの前にLLMを1つ追加するアプローチです。会話履歴を参照し、「それ」を「Kadinche Layerd」に置き換えた質問文を生成してからRAG検索を実行する──という前処理ステップです。
ユーザーの入力: 「それを導入するにはどうすればいいですか?」 ↓ LLM(前処理): 会話履歴から指示語を解決 再構成された質問: 「Kadinche Layerdを導入するにはどうすればいいですか?」 ↓ RAG検索 検索結果 → LLM → 回答生成
ただし、LLMを1段追加する分だけ応答時間は長くなります。精度と速度のトレードオフを検証しながら、最適なバランスを探っていく予定です。
まとめ
今回の取り組みで得られた知見を3つにまとめます。
- 自動評価の有用性: Dify APIとLLMを組み合わせた自作の評価システムにより、チャットボットの回答品質を定量的かつ客観的に測定できるようになりました。「何が弱いか」が見える化されることで、改善の方向性が明確になります。
- データ管理の厳格化: Difyのチャンク無効化機能は検索後に除外される仕様のため、無効化に頼らないクリーンなデータ設計が不可欠です。RAGの精度は「データの入口」で決まると言っても過言ではありません。
- 次の挑戦: 正確性の向上に加え、会話の文脈を理解する前処理の実装に取り組みます。指示語の解決ができれば、より人間らしい自然な対話が実現できるはずです。
カディンチェでは、社内AI勉強会を通じてこうした実践的な知見を蓄積し、共有しています。RAGチャットボットの構築を検討されている方にとって、本記事が少しでも参考になれば幸いです。