自社のチャットボットでOpenAI + LlamaIndex を用いてFAQを実現できるか検証してみた
はじめに
ジーニーCHAT開発部の鶴瀬です。
ジーニーはチャット型Web接客プラットフォーム「GENIEE CHAT[1]」を提供しています。
今回の試みは、このWeb接客型プラットフォームにOpenAI + LlamaIndexを利用して、顧客が持つドメイン知識を学習し予測モデルに組みこみ、エンドユーザーからの任意の質問に対してチャットボットが回答してもらうというものです。
概要
クライアント(チャットボット)からの任意の質問に対する回答を返すための、OpenAI + LlamaIndexを利用したAPIサーバーの構築。
実現方法
アーキテクチャ
管理画面
管理画面では、Index API Serverでインデックスを作成するのに必要な学習データ(URL)、インデックス名、説明を設定します。
インデックスを作成するのに必要なデータが設定できたらIndex API ServerにPOSTリクエストします。
Index API Server(Python FastAPI)
今回の肝です。Index API Serverでは管理画面で設定されたデータを用いてインデックスを作成します。
インデックスの作成にはOpenAI APIのLLamaIndexを利用します。詳細は後述で。
作成したインデックスはS3に保存します。インデックスに関する情報(インデックス・学習データなど)はDynamoDBに保存します。
S3
ストレージですね。作成したインデックスの生データを保存します。
DynamoDB
管理画面で設定したインデックスの情報を保存します。
実装
SuggestAPIの実装について書いていきます。
以下はインデックスを実際に作成し、s3にアップロードの処理を行うRepository層のコードです。
from llama_index import GPTSimpleVectorIndex, SimpleWebPageReader
from app.infra.s3 import S3Client
class LLamaIndexRepository:
def __init__(self, settings):
self.s3_client = S3Client(settings)
def upload_index(self, key: str, urls: list[str]):
index_string = self._create_index_string(urls)
self.s3_client.upload_object(index_string, key)
def _create_index_string(self, urls: list[str]):
vector_index = self._get_vector_index(urls)
index_string = vector_index.save_to_string()
return index_string
@staticmethod
def _get_vector_index(urls: list[str]):
documents = SimpleWebPageReader(html_to_text=True).load_data(urls)
vector_index = GPTSimpleVectorIndex.from_documents(documents)
return vector_index
コンストラクタ
def __init__(self, settings):
self.s3_client = S3Client(settings)
コンストラクタでは、infra層で生成したs3のクライアントを呼び出して、s3のクライアントをインスタンス変数として扱うようにしています。
upload_index
def upload_index(self, key: str, urls: list[str]):
index_string = self._create_index_string(urls)
self.s3_client.upload_object(index_string, key)
service層から呼び出されるメソッドです。インデックス作成のメソッドを呼び出し、作成したインデックスをs3にアップロードします。
_create_index_string
def _create_index_string(self, urls: list[str]):
vector_index = self._get_vector_index(urls)
index_string = vector_index.save_to_string()
return index_string
実際にインデックスの作成を行うメソッド(_get_vector_index
)を呼び出しています。
作成したインデックスを文字列に変換しています。
_get_vector_index
@staticmethod
def _get_vector_index(urls: list[str]):
documents = SimpleWebPageReader(html_to_text=True).load_data(urls)
vector_index = GPTSimpleVectorIndex.from_documents(documents)
return vector_index
ドキュメントの作成
documents = SimpleWebPageReader(html_to_text=True).load_data(urls)
SimpleWebPageReader
に学習データのURLのリストを与えます。
インデックスの作成
vector_index = GPTSimpleVectorIndex.from_documents(documents)
GPTSimpleVectorIndex
にdocuments
を与えることによって埋め込みベクトルの作成ができます。
Discussion