RAGベースのQ&A LINE Botのいちばん簡単な作り方

こんにちは。LINE API Expertのうえぞうです。
質問内容をベクターストアで検索し、その検索結果をChatGPTにまとめてもらって回答するみたいなユースケースが普及しつつありますので、この記事ではこの手法を活用したLINE Botの作り方を説明します。LINE Messaging APIやその利用手順については触れませんので、公式の手順書や他の記事を参考にしてください。

# できあがりのイメージ

こんな感じです。この記事の手順でこれができます。

<iframe width="560" height="315" src="https://www.youtube.com/embed/grYJhBmw3kg?si=0o8od5ZpbI_9wepf" title="YouTube video player" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share" allowfullscreen></iframe>


# 普通の作り方

AzureやAWS、GCPなどでそれぞれベクターサーチの仕組みを持っており、本来はそういったサービスを組み合わせて作ることになります。
ですが、このような普及しつつある技術が想定しているユースケースで使い物になるかどうかをちょっと試したいだけなのに、クラウドをあれこれ覚えなければいけないのは敷居が高いと思います。少なくとも私はそう思います。

なので、この記事では普通の作り方については触れません。

# いちばん簡単な作り方

ではどうだったらいちばん簡単なのか考えてみます。

- すべてローカルPC上で動作
- インストールはすべてPythonのパッケージマネージャー経由
- プログラムはあまり書かずにすぐ動く
- RAGに使用するデータは整形せずそのままアップロードできる

こんな感じでしょうか。これらを兼ね備えるOSSライブラリーとして、[VSSLite](https://github.com/uezo/vsslite)というものがありますので、今回はこれを使用したいと思います。

## VSSLiteのインストール

Python 3.10以上の環境にて、以下の通りpipコマンドでインストールします。VSSLiteが依存するLangChainなども併せてインストールされますので、そこそこ時間がかかります。

```sh
$ pip install vsslite
```

## ベクターサーチエンジンの起動

OpenAIのAPIキーを環境変数にセットして、先ほどインストールしたVSSLiteをモジュールモードで実行します。

```sh
$ export OPENAI_API_KEY=YOUR_API_KEY
$ python -m vsslite
```

http://127.0.0.1:8000/docs にアクセスしてAPIドキュメントが表示されれば成功です。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/53296/cafafeaa-eea1-1614-0048-c9cf8ecc3604.png)

## ファイルのアップロード

検索対象とするデータをVSSLiteに登録します。ここではOpenAIの利用規約を登録してみたいと思います。以下のページを開いて、「1. Registration and Access」から利用規約本文の末尾までをコピーし、カレントディレクトリに`openai_terms.txt`として保存します。

https://openai.com/policies/terms-of-use

続いて、VSSLiteのAPIを使用してこのファイルをアップロードします。以下のスクリプトを作成しましょう。

```python:upload.py
from vsslite import LangChainVSSLiteClient

# APIクライアントの生成
vss = LangChainVSSLiteClient("http://127.0.0.1:8000")

# openaiというネームスペースにアップロード
vss.upload("openai_terms.txt", namespace="openai")
```

実行します。

```sh
$ python upload.py
```

これでファイルアップロードは完了です。検索できるかAPIドキュメントの画面で調べてみましょう。以下のように`namespace`に「openai」、`q`に「年齢制限はありますか？」と入力してExecuteボタンを押します。以下のようにResponse bodyが表示され、`page_content`に年齢制限に関する文章の塊が抽出されていれば成功です✌️

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/53296/7deeee7d-2023-40c2-5a96-7770c3fa37cd.png)

## LINE Botの起動

ユーザーからの入力をLINE Botに繋げるには以下のような手順を踏むことが必要です。

- LINEアプリからのユーザー入力内容（発話内容）を取得
- 発話内容がOpenAIの利用規約に関する質問であることを判定
- OpenAIの質問の場合、質問内容でVSSLiteサーバーを検索
- 質問本文と検索結果をChatGPTにプロンプトとして与えて、これに基づく応答文を作成
- 応答文をLINEサーバーに送信する

また、ChatGPTのWeb画面では生成された文章が逐次表示されるのに対してLINE Botではリプライトークンは1回の送信にしか使用できず、通常であれば全文生成されるのを待ってから返信する必要があります。これは長い待ち時間になるため、良いユーザー体験とは言えません。そこで、ある程度の塊ができたら一旦応答メッセージを送信して、続きはユーザー側から取りに来てもらうような作りが望ましいと考えます。

VSSLiteでは、上記のような手順をフルカバーしていることはもちろん、ユーザー体験上の課題についてもクイックリプライで続きを読み込めるような工夫が最初からされています。

そのため、前置きが長くなりましたが、作るスクリプトは以下の通りです。

```python:line.py
import os
from vsslite.chatgpt_processor import VSSQAFunction
from vsslite.line import LineBotServer

# OpenAI利用規約のQ&AのためのFunctionを定義
from vsslite.chatgpt_processor import VSSQAFunction
openai_qa_func = VSSQAFunction(
    name="get_openai_terms_of_use",
    description="Get information about terms of use of OpenAI services including ChatGPT.",
    parameters={"type": "object", "properties": {}},
    vss_url="http://127.0.0.1:8000",
    namespace="openai",
    answer_lang="Japanese",
    verbose=True
)

# LINE Botサーバーの起動
app = LineBotServer(
    channel_access_token=YOUR_CHANNEL_ACCESS_TOKEN,
    channel_secret=YOUR_CHANNEL_SECRET,
    endpoint_path="/linebot",
    functions=[openai_qa_func]
).app
```

`VSSQAFunction`は、発話内容に特定のQ&Aの意図があることをChatGPTに判定してもらうための定義と、判定された場合にVSSLiteによる検索を実行して検索結果を返す処理を担う部品です。`LineBotServer`にこれを渡して起動することで、利用規約のQ&A LINE Botとしての役割を果たすようになります。以下の通り8002番ポートで起動しましょう。

```sh
$ uvicorn line:app --host 0.0.0.0 --port 8002
```

## LINE Messaging APIとの接続

ngrokなどのトンネリングツールを使って前の手順で立ち上げたLINE Botサーバーにインターネット経由でアクセスできるようにしましょう。ngrokを使う場合は以下の通りです。

```sh
$ ngrok http 8002

ngrok by @inconshreveable                                       (Ctrl+C to quit)
                                                                              
Session Status                online                                            
Account                       Your Name (Plan: Pro)                             
Update                        update available (version 2.3.41, Ctrl-U to update
Version                       2.3.35                                            
Region                        United States (us)                                
Web Interface                 http://127.0.0.1:4041                             
Forwarding                    http://87fff2ed3ff1.ngrok.app -> http://localhost:
Forwarding                    https://87fff2ed3ff1.ngrok.app -> http://localhost
                                                                                
Connections                   ttl     opn     rt1     rt5     p50     p90       
                              0       0       0.00    0.00    0.00    0.00  
```

この場合、https://87fff2ed3ff1.ngrok.app/linebot をLINE DevelopersでWebhook URLとして設定します。

以上で準備は完了です。

# 動作確認

以下のような質問をLINEアプリで投げかけてみましょう。VSSLite検索エンジンを動かしている方のターミナルには検索クエリーが入ってきたことのログが表示されるとともに、しばらくするとLINEアプリの方にも返信が返ってきます。

- ChatGPTに年齢制限はありますか？
- ChatGPTの支払いの通貨は？
- ChatGPTで生成した文章の著作権は誰のもの？

冒頭の動画のように引用付きで応答メッセージが得られれば成功です。

このように、ChatGPT APIの使い方やベクターサーチの使い方、各種クラウドのアーキテクチャー、その構築手順についての知識がなくても簡単にRAG(Retrieval Augmented Generation)ベースのLINE Botが作れたと思います。

その中身の具体的なやり方が知りたい方はVSSLiteのソースコードを読んでみてください。それでは、Enjoy creating LINE Bot🥳