背景や目的
・以前RAGの実験をした時に、テキスト生成よりも検索精度の方に問題がありました。→RAGアプリの精度を確認してみた
・情報があるのに検索で漏れていて、それを防ぐために質問文から重要ワードをピックアップした上で、類似度比較の処理を入れた方が良いアイデアかもしれないと思いました。
・今回はそれを実験してみました。
今回の課題
という事で、確認したい事は、キーワード化して検索すると順位が上がるのかということです。
例:query =「金額入力画面の内容をEXCEL出力したい。」
→質問文で検索:【順位は2位以下】 △まあまあです。
→キーワードで検索:【順位は1位になります】 〇 これは良いです。
確認環境を用意
Google Colabo上で試験することにします。
(Google colabの使用については、ここでは扱わないです。)
・Colabo上notebook内セルにて、まずはPineconeをインストールします。
(Pineconeに関連するセットアップ情報等は以前の記事(→Pineconeを使いVectorStoreを構成してみた)を参照してください)
### pinecone install
!pip install pinecone-client
・次はopenaiをインストールします。
### open ai install
!pip install --upgrade openai
・検索実行用セル内の「query」で入力する質問文を設定して「shift+enter」で実行します。
###検索実行用セル
from pinecone import Pinecone, PodSpec
import json
from openai import OpenAI
pc = Pinecone(api_key='**************')
client = OpenAI(api_key = "sk-***********")
index = pc.Index("starter-index-test1")
##ベクター検索をする
query ='価格入力で、ファイル出力をしたいです。EXCELで出来ると良いのですが、サポートお願いします。'
response = client.embeddings.create(input=query,model="text-embedding-ada-002")
query_emb = response.data[0].embedding
index.query(vector=query_emb,top_k=50,include_values=False,include_metadata=True)・質問文からキーワードを抽出する用コードとその後キーワード利用検索処理コードは以下の通りで、「question」を設定して「shift+enter」で実行します。
from openai import OpenAI
import textwrap
openai_client = OpenAI(api_key = "sk-***********")
question = '金額入力画面の内容をEXCEL出力したい'
system_prompt = textwrap.dedent("""\
あなたは日本語文法の研究者です。以下コンテクストの文を分析します。
## コンテクスト ##
{}
""").format(question)
question2 = 'コンテクストの文から名詞を抽出し、その名詞を半角カンマで区切って最大5個まで回答して下さい。'
question2 += '抽出数が5個より多い場合は、文字数が多い順に回答して下さい。'
question2 += '名詞が無い場合は、Noneと回答して下さい。'
response_gpt = openai_client.chat.completions.create(
model="gpt-4o",
messages=[
{"role": "system", "content": system_prompt},
{"role": "user", "content": question2}
],
)
reply = response_gpt.choices[0].message.content
ret_word_tmp = reply.split(',')
print('ret_word_tmp',ret_word_tmp)
#キーワード利用検索処理
from pinecone import Pinecone, PodSpec
pc = Pinecone(api_key='******')
index = pc.Index("starter-index-test1")
llm_context = ''
context_candidates,work_list,use_context = [],[],[]
for search_word in ret_word_tmp:
print('search_word:',search_word)
res_openai = openai_client.embeddings.create(input=search_word,model="text-embedding-ada-002")
search_word_emb = res_openai.data[0].embedding
search_results = index.query(vector=search_word_emb,top_k=10,include_values=False,include_metadata=True)
work_list_tmp = []
for val in search_results['matches']:
if val['score'] >= 0.8:
context_candidates.append([val['id'],val['score'],val['metadata']['doc']])
work_list_tmp.append(val['id'])
work_list.append(work_list_tmp)
print('len(context_candidates):',len(context_candidates))
print('work_list:',work_list)
for candidate_list in use_context:
llm_context = llm_context + candidate_list[2] + '\n-----------------\n'
system_prompt = textwrap.dedent("""\
あなたは質問に回答するチャットbotです。
以下のコンテクストを参考にして質問に回答して下さい。
コンテクストの中に質問に対する答えがない場合や、わからない場合、不確かな情報で回答しないでください。
わからない場合は正直に「わかりませんでした」と答えてください。
## コンテクスト(開始) ##
{}
## コンテクスト(終了) ##
""").format(llm_context)
response_gpt = openai_client.chat.completions.create(
model="gpt-4o",
messages=[
{"role": "system", "content": system_prompt},
{"role": "user", "content": question}
],
)
answer = response_gpt.choices[0].message.content
print("回答:",answer)試験仕様
確認したいことは次のとおりです。
・試験1:ワード化検索すると順位が上がりますか?
せっかくなので、以下の追加試験もしたいと思います。
・試験2:無駄な表現が多いと、Scoreがどの程度変わるでしょうか?
・試験3:検索漏れは閾値の問題かどうかを再確認。
試験1:ワード化検索すると順位が上がりますか?
・以下のQAを検索でHITさせたく、質問文そのままとワード利用検索と両方試します。
DBでHITして欲しいQA情報(のQ):金額入力画面の内容をEXCEL出力したい。(ID=1606)
・入力用の質問文は以下の内容にします。
| 入力する質問文 |
|---|
| 価格入力で、ファイル出力をしたいです。EXCELで出来ると良いのですが、サポートお願いします。 |
・2通りそれぞれの期待値は下表の通りです。「ワードで検索」の方が良い事を期待しました。
| 期待値 | |
|---|---|
| 質問文で検索 | 2位以下くらい? |
| ワードで検索 | 質問文での結果より上位 |
・実行した結果は、下表の通りでした。
| 結果 | |
|---|---|
| 質問文で検索 | 3位 |
| ワードで検索 (途中で抽出されたワードは、’価格入力’, ‘ファイル出力’, ‘サポート’, ‘EXCEL’でした。) | 49位 |
・ああ、ワードで検索した方がダメでした。
→今回使用したVectorStore には 661 件の QA情報 が含まれており、その中で抽出したキーワード「EXCEL」が他で50 件、「サポート」の結果が 10 件あり、それが低い順位になった原因と思われます。結局、質問文をそのまま使うのが良さそうですね。
試験2:無駄な表現が多いと、Scoreがどの程度変わるでしょうか?
・検索でHITさせたい以下のQ(A)に、少しづつ言葉を追加してスコアがどう変化するか試します。
DBでHITして欲しいQA情報(のQ):金額入力画面の内容をEXCEL出力したい。
・まず、質問の最後に言葉を少し追加します。
| 1回目入力する質問文 |
|---|
| 金額入力画面の内容をEXCEL出力したいのですが、どうしたら良いですか? |
・質問文だけのScoreは0.8925でしたが、それより小さいなScoreになる事を予想し、実行しました。結果は下表の通りです。
| 1回目結果 | |
|---|---|
| Score | 0.8883 |
→結果は予想通りスコアが減少しました(0.8883 <0.8925)。
・2回目は、さらにEXCELの示し方を冗長にして文字数を増やしてみます。
| 2回目入力する質問文 |
|---|
| 金額入力画面の内容をファイルで出力したいです。形式はEXCELが良いのですが、どうすれば良いでしょうか? |
・スコアがさらに減る事を予想し、実行しました。結果は下表の通りです。
| 2回目結果 | |
|---|---|
| Score | 0.8845 |
→予想通り減少しました(0.8845 <0.8883)。
・最後に、文の最後に文字をもっと増やしてみます。
| 3回目入力する質問文 |
|---|
| 金額入力画面の内容をファイルで出力したいです。形式はEXCELにしたいです。以前にやった事があるのですが、忘れてしまいました。教えて下さい。 |
・さらに減少する事を予想し、実行しました。
| 3回目結果 | |
|---|---|
| Score | 0.8814 |
→最後も予想通り現象しました(0.8814 <0.8845)。
→無駄な表現が多いほどScoreは下がりました(0.8925>0.8883>0.8845>0.8814)。
試験3:検索漏れは閾値の問題かどうかを再確認。
・Scoreの閾値の重要性を再確認します。以前の実験時に、検索ヒットしないケースがあり、そのケースでScoreの値をチェックしてみます。
・以前に検索漏れした以下のQA(のQ)を利用します。
QAの質問:表紙の右下にある会社名、作成者、日付はどこから入力すればいいのか?
・まず、曖昧な言い方で試します。
| 入力する質問文 |
|---|
| サインはどこで入れるの? |
・実行結果は以下の通りでした。なお、検索結果として採用する閾値は0.8にしています。
| 結果 |
|---|
| 出現:しない Score: 0.796317577(0.8未満) |
・次は、少しだけ丁寧な表現に変えてみます。
| 入力する質問文 |
|---|
| 日付等はどこで入れるの? |
・以下が実行結果です。
| 結果 |
|---|
| 出現:した Score:0.829834163(0.8以上) |
・”QAの質問”に似たのでしょう。Scoreが上がり閾値を超え、検索結果で表示されました。
→この程度の文の違いで閾値が 0.03 変わるのをみると、閾値を広めに設定したくなりますね。実装者が制御可能なのは閾値なので、いずれにせよその重要性を理解しました。
まとめ
1.意中のデータを検索で上位に出力させるために、有効かと思ってワード化検索を実装しましたが、効果は確認できませんでした。
2.ワード化処理(それぞれ検索し重複データを優先的に得る処理)は、時間もかかるので、検索の前処理としては、以下の内容が良さそうです。
・検索処理で使う質問は、(ベクター値の類似度比較であれば)ユーザ入力文そのまま。
(Kendra等を使う場合は、追加考慮が要るかもしれません。詳細はここでは割愛します。)
・Scoreの閾値は低めに設定する。
・コンテキストで採用する件数も(同じ理由で)多めにとる。
・ただし、これらにより、コンテキストのデータ量が増えるので、価格のシミュレーションもしっかりしておくべき。
Vectorstore自体が良くなるといいなぁ。
