見出し画像

LangChain の RetrievalQA を試す


「LangChain」の「RetrievalQA」を試したので、まとめました。

・LangChain v0.0.123

1. VectorDBQA と RetrivalQA

「LangChain」を活用する目的の1つに、専門知識を必要とする質問応答チャットボットの作成があります。

これを行う主な方法は、「Retrieval Augmented Generation」と呼ばれる手法です。ユーザーの質問を言語モデルに直接渡すだけでなく、システムが質問への回答に関連するドキュメントを検索し、元の質問と一緒に言語モデルに渡して、応答を生成します。

1-1. 既存のシステム

よく使われる検索手法は「セマンティック検索」です。この手法では、まずはじめにすべてのドキュメントを「埋め込み」(ベクトル表現) を計算し、ベクトルデータベースに格納します。そして、ユーザーの質問も同様に「埋め込み」を計算し、ユーザーの質問に埋め込み空間で最も近いドキュメントを取得します。

1-2. 既存のシステムの問題点

上記手法は非常にうまく機能しました。しかし、2つの問題点がありました。

1つ目は、ドキュメントの検索手法には、様々なバリエーションがあることです。セマンティック検索を超えることをやりたがっている人もたくさんいます。

2つ目は、LangChainの外部で「Retriever」を構築する人がいることです。たとえば、OpenAIは「ChatGPT Retrieval Plugin」をリリースしています。

「VectorDBQA」を中心に抽象化することで、チェーンの利用を制限し、他の検索手法を試したいユーザー、LangChain外の「Retriever」を作るユーザーにとって、使いにくいものにしてしまっていたのです。

1-3. 新システムの変更点

上記問題点を、以下の方法で解決しています。

(1) 「Retriever」の概念を導入。
「Index」は効率的な検索をサポートするデータ構造なのに対し、「Retriever」は「Index」で関連するドキュメントを検索し、ユーザーの質問に応答するコンポーネントになります。

(2) VectorDBチェーンを「Retriever」を使用するように変更。
「VectorDBQA」は「RetrievalQA」、「ChatVectorDBChain」は「ConversationalRetrievalChain」になりました。

(3) 非LangChain Retriever の最初のインスタンスである 「ChatGPT Retriever Plugin」 を追加。
OpenAIによってオープンソース化されたモジュールの「Retriever」です。

これは後方互換性があるため、既存のチェーンはこれまでと同様に動作しますが、「VectorDBチェーン」から「Retrievalチェーン」に早くアップデートすることが推奨されています。

2. Colabでの実行

Google Colabでの実行手順は、次のとおりです。

(1) パッケージのインストール。
「chromadb」はVectorDBのパッケージです。

# パッケージのインストール
!pip install langchain
!pip install openai
!pip install chromadb

(2) 環境変数の準備。
以下のコードの <OpenAI_APIのトークン> にはOpenAI APIのトークンを指定します。(有料)

import os
os.environ["OPENAI_API_KEY"] = "<OpenAI_APIのトークン>"

(3) ドキュメント「bocchi.txt」のアップロード。
「bocchi.txt」は以下で使ったものと同様になります。

(4) ドキュメントの読み込み。

from langchain.document_loaders import TextLoader

# ドキュメントの読み込み
loader = TextLoader("bocchi.txt")
documents = loader.load()

(5) VectorDBの生成。

from langchain.embeddings.openai import OpenAIEmbeddings
from langchain.vectorstores import Chroma
from langchain.text_splitter import CharacterTextSplitter

# VectorDBの生成
text_splitter = CharacterTextSplitter(chunk_size=700, chunk_overlap=0)
texts = text_splitter.split_documents(documents)
embeddings = OpenAIEmbeddings()
docsearch = Chroma.from_documents(texts, embeddings)

(6) RetrievalQAチェーンの生成。
as_retriever()で「Retriever」を取得して、RetrievalQAに設定しています。

from langchain.llms import OpenAI
from langchain.chains import RetrievalQA

# RetrievalQAチェーンの生成
qa = RetrievalQA.from_chain_type(
    llm=OpenAI(), 
    chain_type="stuff", 
    retriever=docsearch.as_retriever()
)

(7) 質問応答。

# 質問応答
qa.run("ぼっちちゃんの得意な楽器は?")
DEBUG:Chroma:time to pre process our knn query: 1.6689300537109375e-06
DEBUG:Chroma:time to run knn query: 0.0007779598236083984
' 後藤ひとりの得意な楽器はギターです。

関連


この記事が気に入ったらサポートをしてみませんか?