🐡

RAGにおけるドキュメント検索精度向上について(実践編)

2023/12/20に公開

損害保険ジャパン株式会社 DX推進部の眞方です。この記事では、RAG(Retrieval Augmented Generative)の構築時に、ドキュメント検索精度の向上を目指して検索モデルの改善を行った際の手法、および結果について解説させていただきます。
概要を知りたい、という方は以前書いた前回の記事を読んでください。

はじめに

今回はRAGにおける検索モデルの改善を目的として、独自のデータを使用してfine-tuneを行いました。
RAG 全体像
RAGにおける検索(赤枠)の部分を改善する取り組みを行いました。

検索モデル

学習のためのライブラリとしては、sentence transformersを使用しました。また、モデルは日本語BERTを使用しています。

データ

今回RAGの対象となるドキュメントは、大きく次の2つが存在しています。

  1. 規定集
    保険商品の説明等が書かれているドキュメントです(詳細は前回の記事でも記載しています)。複数行のテキストで図表等が含まれており、質問文から規定集の検索はいわゆるasymmetric searchに該当します。
  2. FAQ
    過去の問い合わせ内容をQA形式で蓄積したものです。質問文から似ている質問文の検索を行っているので、symmetric searchに該当します。
    FAQ 検索例
    FAQを参照したLLMの回答例(2023年11月時点での内容です)

2のFAQデータに関しては、既存のFAQ照会システムで蓄積されたフィードバック(F/B)データが利用可能な状態であったため、今回はこのデータを用いて検索モデルのfine-tuneを行いました。規定集データに対しては、F/Bデータが存在しなかったためfine-tuneは実施せず、chunking等のドキュメント整形を実施しています。

# ドキュメント 種類 F/Bデータ 検索精度改善の手法
1 規定集 asymmetric search なし chunking等のドキュメント整形
2 FAQ symmetric search あり 検索モデルのfine-tune

評価

評価データとして、実際に過去にあった照会結果を活用しています。また評価指標としては、MRR(Mean Reciprocal Rank)を用いました。
参考までにBM25/OpenAI Embedding(ada、2023年11月時点)/e5-baseでの精度は以下の通りです。

手法 規定集検索スコア(MRR) FAQ検索スコア(MRR)
BM25 42.0 34.1
ada 43.7 37.5
e5-base(multi) 40.2 41.0

Fine-tune

Fine-tuneに関しては以下の2つの手法を試しました。

  1. Triplet Lossでの学習
    Metric Leaning系のタスクでよく使われているLossの一つで、anchorとなるテキスト(質問文)に対して、正解ドキュメントと不正解ドキュメントをそれぞれ用意することで1つの学習データが作成できます。正解ドキュメントは過去のF/B結果をそのまま使用し、不正解ドキュメントとしてはBM25でhard negativeを抽出した結果を使用しました。
  2. Re-rankingモデルのKD(Knowledge Distillation)
    e5の学習方法[1]を参考にRe-rankingモデルのKDを試しました。具体的には以下の手法で学習しています。

最終的な検索精度は以下の通りです。Re-rankingモデルを除くと、Triplet Lossで学習させたモデルが最もスコアが良かったです。Re-rankingモデルのKDでは、最後の蒸留部分(cの部分)をうまく実装できていない可能性がありそうです。

また、当然の結果ではあるのですが、規定集の検索スコアはそこまで高くなかったです。これはFAQ検索(symmetric search)に特化してfine-tuneを行っていること、そもそも規定集検索の学習用データがないことが原因として考えられます。

手法 規定集検索スコア(MRR) FAQ検索スコア(MRR)
Triplet Loss 37.0 56.9
(参考)Re-rankingモデル 28.5 59.5
Re-rankingモデルのKD 32.8 46.9

最終的に規定集の検索にはadaを、FAQの検索には今回Triplet Lossで学習させたモデルを使用したところ、実際のデータで80%程度のRecall@10は達成できています。コスト面やテキスト生成の精度面を考慮するともうちょっと改善を続けたいなという印象ですね。ここから先の改善は正直データがないと何とも難しいので、ユーザーからのF/Bデータをいかに貯めていくかが重要かなと考えています。

TripletLossでの学習コードサンプル
word_embedding_model = models.Transformer("cl-tohoku/bert-base-japanese-whole-word-masking")
pooling_layer = models.Pooling(word_embedding_model.get_word_embedding_dimension())
dense_layer = models.Dense(in_features=pooling_layer.get_sentence_embedding_dimension(), out_features=1024, activation_function=nn.Tanh)
model = SentenceTransformer(modules=[word_embedding_model, pooling_layer, dense_layer])

evaluator = evaluation.InformationRetrievalEvaluator(queries, corpus, relevant, mrr_at_k=[100])

train_dataset = SentencesDataset(train_examples, model)
train_dataloader = DataLoader(train_dataset, shuffle=True, batch_size=32)
train_loss = losses.TripletLoss(model)

model.fit(train_objectives=[(train_dataloader, train_loss)], evaluator=evaluator, epochs=10, save_best_model=True)

RAGの精度は上がったのか?

さて、結局のところRAGの精度は上がったのでしょうか?ここで質問文を投げてから回答を生成する一連のプロセスに対して評価をしてみたいと思います。

RAGをどう評価するか

RAG全体の評価項目としては、「最終的に出力された自然文が正しいかどうか」と「ハルシネーションが発生していないかどうか」を現時点では見ています。テキスト生成の定量的な評価指標としては、機械翻訳で使われているようなBLEU、ROUGEが挙げられます。また、Open-Domain QAの評価では、正解との意味的類似度を測るようなBERTScore等も使われていますが、サービスとして展開するにあたってはより直接的に精度を評価したいと考えたため、プロンプトを作成した上でGPT4での評価を実施しました。
評価するLLM自体が正しいのか?という疑問はあると思います("Who Watches the Watchmen?"みたいな話ですね)。今回、人手での評価結果とGPTの評価結果を比較したところ、平均値では大きな乖離が見られなかったため、評価のコスト等を鑑み暫定的にGPTでの自動評価を採用しています。
余談ですが、Deepmindの記事[2]では、最初はLLMを人手で評価していたものの評価にばらつきがあったり、時間が非常にかかるということもあって

  • 評価ガイドラインを策定(ばらつきの削減)
  • 難しいタスクはエキスパート(人手)に任せつつ、それ以外はLLMで評価自動化(時間の削減)

を試しているとの記載がありました。最近ではLLMのテストフレームワークも整備されつつあると思うので、今後知見が溜まっていくことに期待したいですね。

評価結果

前置きが長くなりましたが評価結果は以下の通りです。

手法 平均回答スコア ハルシネーション発生率
GPT3.5-turbo 1.65 28.3%
GPT3.5-turbo + 検索精度向上 1.73 24.4%
GPT4-turbo + 検索精度向上 2.02 10.0%
(参考)GPT3.5-turbo + Correct Document 1.87 -
(参考)GPT4-turbo + Correct Document 2.29 -

GPT3.5-turboでは検索精度向上の効果はあまり見えないのですが、GPT4-turboを使用することで回答スコアが上がっていることがわかります。一方で完全に正しいドキュメントを渡して、かつGPT4-turboを使った状態でも、平均回答スコアが2.29にとどまっており、prompt tuning/chainingやGPTのfine-tuning等、テキスト生成部分の改善の必要性があると感じています。

まとめ

RAG全体での改善の必要性

ここまでは比較的検索部分の改善にフォーカスしており、実際に検索モデルのfine-tuneによって検索精度の向上は実現することができました。一方で、この後はやはりキスト生成部分にも手を入れて、RAGシステム全体で改善していく必要性があるなと考えています。prompt tuningに関しても自動化を試みている例[5]などがあるので、こういった知見は取り入れていきたいですね。また、RAGシステム全体を見て精度面を改善していく場合、評価をどのように効率化/自動化していくかについては依然として課題があります。

データ蓄積の重要性・難しさ

当たり前ではありますが、何をするにもデータがないとどうしようもないです。FAQのF/Bデータを用いてのfine-tuningが検索精度の向上に寄与しているように、今後データが溜まればテキスト生成部分に関しても同様の結果が得られるかもしれません。そのためには、いち早くシステムをローンチさせて、ユーザーのF/Bデータを溜めていかないと、、、となりますよね。
一方で、中途半端な状態でシステムを出した場合、ユーザーにとっては「間違っているかもしれない、そこそこ長い文章を見せられる」という、かなり疲れる状態が発生してしまいます。F/Bの入力どころか、ユーザーエンゲージメントが即座に低下してしまいそうですよね。結局今はHuman-in-the-Loopでやるしかないので、生成AIの凄さは認めつつ現実的なユースケースを探す動きも重要だと思われます。


いかがでしたでしょうか?今回の記事では、RAGの精度改善を目的に検索精度を向上させる取り組み内容を紹介しました。LLMのビジネス応用における難しさ、面白さを少しでも感じていただけると幸いです。
損害保険ジャパン株式会社では引き続きエンジニアを採用しております。カジュアル面談も実施しておりますので、興味のある方はぜひご検討ください!

https://www.green-japan.com/company/9215

脚注
  1. https://github.com/microsoft/unilm/tree/master/simlm ↩︎ ↩︎

  2. https://blog.research.google/2023/11/responsible-ai-at-google-research_16.html ↩︎

  3. https://storage.googleapis.com/deepmind-media/gemini/gemini_1_report.pdf ↩︎

  4. https://github.com/explodinggradients/ragas/blob/main/src/ragas/metrics/_faithfulness.py ↩︎

  5. https://tech.preferred.jp/ja/blog/prompt-tuning/ ↩︎

損害保険ジャパン DX推進部

Discussion