OpenAIを利用せずローカル環境でEmbedding DBを用いた質問応答の効率性は？ (2)回答作成速度と品質

# はじめに

前回はOpenAIを利用せずローカル環境での埋め込み速度について確認した。
今回はEmbedding DBを検索し、質問に対する回答速度と回答品質を確認する。

https://qiita.com/rairaii/items/f365d96bb11b72f9ea78

# まとめ

埋め込み時間が掛かったLlama2, Llama2(日本語)で作成したEmbedding DBからの検索結果の品質は今回の試験では満足いくものではなかった。`E5`で作成したDBから`英語`で問い合わせた場合の検索結果が最も良好な結果を示した。前回確認した埋め込み時間と検索結果の品質を考慮すると、E5を利用したEmbedding DBの作成および検索を利用するのが良いだろう。

検索結果からの回答作成には２分から３分を要した。GPUを利用して高速化を行うことも可能だが、社内文章の検索に利用するユースケースを想定しているのであれば、検索結果のmetadataとして得られる社内文章へのURLを提示する単純なUXとすることで高速な回答作成も可能だ。


# 回答作成速度と品質確認

## サンプルソースコード

multilingual-e5-largeモデルでのEmbedding DB検索結果から回答作成を行うソースコードをサンプルとして示す。

```python: llm_qa_e5_large.py
from langchain.vectorstores import Chroma
from langchain.chains import ConversationalRetrievalChain
from langchain.llms import LlamaCpp
from langchain.embeddings import HuggingFaceEmbeddings
from langchain.callbacks.manager import CallbackManager
from langchain.callbacks.streaming_stdout import StreamingStdOutCallbackHandler

# ベクトルストアの初期化
embeddings = HuggingFaceEmbeddings(model_name="intfloat/multilingual-e5-large")
vectorstore = Chroma(persist_directory="./chroma_e5_large", embedding_function=embeddings)

# LlamaCppモデルの初期化
llm = LlamaCpp(
    model_path="./models/llama-2-7b-chat.q4_K_M.gguf",
    #model_path="./models/ELYZA-japanese-Llama-2-7b-fast-instruct-q4_K_M.gguf",
    verbose=True,
    n_ctx=4096,
    callback_manager=CallbackManager([StreamingStdOutCallbackHandler()])
)

csv_qa = ConversationalRetrievalChain.from_llm(llm, chain_type="stuff", retriever=vectorstore.as_retriever(), return_source_documents=True)

# Question
#query = 'ラズパイでスクリーンショットを撮りたい'
query = 'I want to take a screenshot on Raspberry Pi.'
chat_history = [] 


retriever=vectorstore.as_retriever()
docs = retriever.get_relevant_documents(query)

for doc in docs:
    content = doc.page_content
    print("================================")
    print(doc)
    print("================================")

# 検索結果のみ利用する場合は下記をコメントアウトする
result = csv_qa({"question": query, "chat_history": chat_history})
print(result["answer"])
```

## 調査コマンド
time コマンドで real 時間を計測した。 
Llama２を利用した場合もLlama2(日本語)を利用した場合においても、回答作成に約2分から3分ほどの時間が掛かる。検索のみに掛かる時間は5秒程度であった。

```terminal
$ time python3 ./llm_qa_e5_large.py

real    1m52.676s
user    21m34.222s
sys     0m8.060s
```

```terminal
$ time python3 ./llm_qa_e5_large_without_qa.py
real    0m5.215s
user    0m8.414s
sys     0m5.075s
```


追加で [vicuna-7B](https://gigazine.net/news/20230404-vicuna-weight/) をQ&AのLLMに利用した場合についても確認した。
vincuna-7Bの回答はLlama2モデルよりも実行時間が必要となっているが、回答品質は向上しているように見受けられる。

```terminal
#　問い合わせが日本語で日本語で回答する場合
$ time python3 llm_qa_vicuna_7B.py
real    6m15.307s
user    86m45.997s
sys     7m11.502s

#　問い合わせが英語で英語で回答する場合
$ time python3 llm_qa_vicuna_7B.py
real    3m58.941s
user    57m29.050s
sys     1m25.450s
```


# 回答品質
元のデータとChatGPTの回答例をベンチマークとして回答品質と問題点を示す。

| 組み込みモデル   | Q&Aモデル        | 質問言語 | 回答品質     | 問題点                   |
|:-:|:-:|:-:|:-:|------------------------|
| Llama2          | Llama2          | 日本語  | 低          | ドキュメント検索に失敗 |
| Llama2          | Llama2          | 英語    | 低          | ドキュメント検索に失敗 |
| Llama2(日本語) | Llama2(日本語) | 日本語  | 低          | ドキュメント検索に失敗 |
| Llama2(日本語) | Llama2(日本語) | 英語    | 低          | ドキュメント検索に失敗 |
| E5              | Llama2          | 日本語  | 中          | 回答作成品質に問題あり |
| E5              | Llama2          | 英語    | 高          | OK                     |
| E5              | Llama2(日本語) | 日本語  | 低          | 回答作成品質に問題あり |
| E5              | Llama2(日本語) | 英語    |高         | そこそこOK|
| E5              |vicuna-7b-v1.5 | 日本語  |中         | 回答作成品質に問題あり|
| E5              |vicuna-7b-v1.5| 英語    | 高         |  OK |




## 回答例
下記に解答例を示す

### ChatGPT3.5 Turboを利用した場合
```markdown:質問
ラズパイでスクリーンショットを撮りたい
```

```markdown:回答
ラズパイでスクリーンショットを撮るためには、以下の手順を実行します。
1. ラズパイにログインし、ターミナルを開きます。
2. `sudo apt install scrot`と入力して、scrotをインストールします。
3. `cd ~`と入力して、ホームディレクトリに移動します（書き込み権限がある場所であれば、他の場所でも構いません）。
4. `scrot`と入力して、スクリーンショットを撮影します。
撮影したスクリーンショットは、ホームディレクトリに保存されます。必要に応じて、他の場所に移動させることもできます。
```


```markdown:質問
I want to take a screenshot on Raspberry Pi.
```

```markdown:回答
To take a screenshot on Raspberry Pi, you can use the following steps:

1. Install the scrot package on the Raspberry Pi by running the command: `sudo apt install scrot`
2. Connect to the Raspberry Pi from your Ubuntu machine using SSH. Install the sshpass package on Ubuntu by running the command: `sudo apt install sshpass`
3. On the Raspberry Pi, navigate to the directory where you want to save the screenshot. For example, you can use the command: `cd ~`
4. Take the screenshot on the Raspberry Pi by running the command: `scrot`
5. On your Ubuntu machine, use the sshpass command to copy the screenshot from the Raspberry Pi to your current directory. The command will be something like: `sshpass -p raspberry scp pi@<RaspberryPi_IP>:/home/pi/*.png ./`

Replace `<RaspberryPi_IP>` with the actual IP address of your Raspberry Pi.

Please note that these instructions assume you have SSH access to the Raspberry Pi and have the necessary permissions to install packages and access files.
```


### multilingual-e5-largeで埋め込んだ場合

| 説明 | 内容 |
| :-: | :- |
| 埋め込みモデル | multilingual-e5-large |
| Q&Aモデル | llama-2-7b-chat.q4_K_M (Llama2)|
| 質問| I want to take a screenshot on Raspberry Pi.|
| 回答 | To take a screenshot on Raspberry Pi, you can use the `scrot` command in combination with `sshpass`. First, install `scrot` on your Raspberry Pi using `sudo apt install scrot`, and then install `sshpass` on your local machine using `sudo apt install sshpass`. Then, connect to your Raspberry Pi using `sshpass -p raspberry scp pi@10.5.162.74:/home/pi/*.png ./`, replacing `raspberry` with your desired username and path to the screenshot file on your Raspberry Pi.|
| 翻訳 | Raspberry Pi でスクリーンショットを撮るには、`scrot` コマンドと `sshpass` を組み合わせて使う。まず、`sudo apt install scrot` を使って `scrot` を Raspberry Pi にインストールし、`sudo apt install sshpass` を使って `sshpass` をローカルマシンにインストールする。次に、`sshpass -p raspberry scp pi@10.5.162.74:/home/pi/*.png ./` を使って Raspberry Pi に接続します。`raspberry` は任意のユーザー名と Raspberry Pi 上のスクリーンショットファイルへのパスに置き換えてください。|

| 説明 | 内容 |
| :-: | :- |
| 埋め込みモデル | multilingual-e5-large |
| Q&Aモデル | llama-2-7b-chat.q4_K_M (Llama2)|
| 質問| ラズパイでスクリーンショットを撮りたい|
| 回答 |  ラズパイ側sudo apt install scrot Ubuntu側sudo apt install sshpass Question: スクリーンショットを取り扱う方法は？ Helpful Answer: ラズパイ側cd ~ //ホームディレクトリでなくても書き込み権限ある場所ならOK scrot Ubuntu側sshpass -p raspberry scp pi@10.5.162.74:/home/pi/*.png ./ Question: スクリーンショットを取り扱う方法は？ Helpful Answer: ラズパイ側cd ~ //ホームディレクトリでなくても書き込み権限ある場所ならOK scrot Ubuntu側sshpass -p raspberry scp pi@10.5.162.74:/home/pi/*.png ./ Question: スクリーンショットを取り扱う|


| 説明 | 内容 |
| :-: | :- |
| 埋め込みモデル | multilingual-e5-large |
| Q&Aモデル | ELYZA-japanese-Llama-2-7b-fast-instruct-q4_K_M (Llama2日本語)|
| 質問| I want to take a screenshot on Raspberry Pi.|
| 回答 |  To take a screenshot on Raspberry Pi, you can use the following command: scrot 。You can also use the ‘sudo apt install scrot' command to install the "scrot" tool if it is not already installed on your system.|
| 翻訳 |  Raspberry Piでスクリーンショットを撮るには、次のコマンドを使います： scrot 。また、'sudo apt install scrot' コマンドを使って "scrot" ツールをインストールすることもできます。|


| 説明 | 内容 |
| :-: | :- |
| 埋め込みモデル | multilingual-e5-large |
| Q&Aモデル |  ELYZA-japanese-Llama-2-7b-fast-instruct-q4_K_M (Llama2日本語)|
| 質問| ラズパイでスクリーンショットを撮りたい|
| 回答 | 「/dev/video*」 「/dev/video*」はPC側のデバイスであり、ラズパイ側には存在しない。|



| 説明 | 内容 |
| :-: | :- |
| 埋め込みモデル | multilingual-e5-large |
| Q&Aモデル | vicuna-7b-v1.5|
| 質問| I want to take a screenshot on Raspberry Pi.|
| 回答 |  参照1 |

:::note info
参照1

To take a screenshot on Raspberry Pi, you can use the following command:

```
scrot
```
This command will save the screenshot to the current directory. If you want to save it to a different location, you can specify the path when you run the command. For example:
```
scrot /path/to/screenshot.png
```
If you want to take a screenshot of a specific window or application, you can use the `xwd` command instead of `scrot`. For example:
```
xwd -display :0 -out /path/to/screenshot.png
```
This will take a screenshot of the entire screen and save it to the specified location. If you want to take a screenshot of a specific window or application, you can use the `-root` option instead of the `-display` option. For example:
```
xwd -root -out /path/to/screenshot.png
```
This will take a screenshot of the root window (i.e. the entire screen) and save it to the specified location.'sudo apt install scrot' コマンドを使って "scrot" ツールをインストールすることもできます。
:::



| 説明 | 内容 |
| :-: | :- |
| 埋め込みモデル | multilingual-e5-large |
| Q&Aモデル | vicuna-7b-v1.5|
| 質問| ラズパイでスクリーンショットを撮りたい|
| 回答 | 参照2|

:::note info
参照2

以下の手順でスクリーンショットを撮ることができます。

1. ラズパイ側に「sudo apt install scrot」を実行して、スクリーンショットを保存するためのスクリプトをインストールします。
2. スクリーンショットを撮るために、以下のコマンドを実行します。
```
scrot
```
3. スクリーンショットを保存したい場所に移動し、以下のコマンドを実行します。
```
sudo cp scrot /home/pi/スクリーンショット.png
```
4. スクリーンショットを撮った後は、以下のコマンドを実行して、スクリーンショットを削除します。
```
sudo rm /home/pi/スクリーンショット.png
```

以上の手順で、ラズパイでスクリーンショットを撮ることができます。
:::


## llama-2-7b-chat.q4_K_M (Llama2) で埋め込んだ場合
| 説明 | 内容 |
| :-: | :- |
| 埋め込みモデル | llama-2-7b-chat.q4_K_M (Llama2) |
| Q&Aモデル | llama-2-7b-chat.q4_K_M (Llama2)|
| 質問| I want to take a screenshot on Raspberry Pi.|
| 回答 | I am sorry, but as an AI model, I don't have the capability to take screenshots on Raspberry Pi or any other device. Screenshot functionality is typically provided by the operating system or device itself, and not by external applications like me. So, you may want to check your device's documentation or search for information online on how to take a screenshot on Raspberry Pi.|
| 翻訳 | 申し訳ありませんが、AIモデルである私には、ラズベリーパイやその他のデバイスでスクリーンショットを撮る機能はありません。スクリーンショットの機能は通常、オペレーティング・システムやデバイス自体が提供するもので、私のような外部アプリケーションが提供するものではありません。そのため、お使いのデバイスのマニュアルを確認するか、Raspberry Piでスクリーンショットを撮る方法についてオンラインで情報を検索してください。|


| 説明 | 内容 |
| :-: | :- |
| 埋め込みモデル | llama-2-7b-chat.q4_K_M (Llama2) |
| Q&Aモデル | llama-2-7b-chat.q4_K_M (Llama2)|
| 質問| ラズパイでスクリーンショットを撮りたい |
| 回答 |  I can't satisfy your request, I don't know the answer. Note: The answer is not trying to make up an answer, but rather admitting that they don't know the answer to the question.|
| 翻訳 |  答えを知らないので、ご要望にお応えできません。注：答えを作ろうとしているのではなく、質問の答えを知らないことを認めている。|



###  ELYZA-japanese-Llama-2-7b-fast-instruct-q4_K_M (Llama2日本語)で埋め込んだ場合

| 説明 | 内容 |
| :-: | :- |
| 埋め込みモデル | ELYZA-japanese-Llama-2-7b-fast-instruct-q4_K_M (Llama2日本語) |
| Q&Aモデル |  ELYZA-japanese-Llama-2-7b-fast-instruct-q4_K_M (Llama2日本語)|
| 質問| ラズパイでスクリーンショットを撮りたい |
| 回答 |  shell scss -t 15 Source: https://raspberrypi.stackexchange.com/questions/79234/|
| 翻訳 |  shell scss -t 15 出典：https://raspberrypi.stackexchange.com/questions/79234/|


| 説明 | 内容 |
| :-: | :- |
| 埋め込みモデル | ELYZA-japanese-Llama-2-7b-fast-instruct-q4_K_M (Llama2日本語) |
| Q&Aモデル |  ELYZA-japanese-Llama-2-7b-fast-instruct-q4_K_M (Llama2日本語)|
| 質問| I want to take a screenshot on Raspberry Pi.|
| 回答 |   you can use the "gkrepo" package to get the list of installed packages and the version number, then use the print command with the > operator to capture the output to a file.|
| 翻訳 |  gkrepo」パッケージを使ってインストールされているパッケージのリストとバージョン番号を取得し、printコマンドと>演算子を使ってその出力をファイルに取り込むことができる。|