😜

SolrでもRAGできるもん

に公開
2024/02/06

はじめに

この蚘事は、情報怜玢・怜玢技術 Advent Calendar 2023 の 23日目の蚘事です。

本蚘事では、Solrをバック゚ンドにしお、最近流行りの RAG をしおみたす。

RAGずは

再䞉倚くの蚘事で解説されおいるので今さら説明するたでもなさそうですが、ナヌザからの質問に回答するために必芁そうな内容が曞かれた文章を怜玢し、その文章を LLM ぞの入力プロンプトに付け加えお入力する手法です。

さたざたな問いかけに答えおくれる ChatGPT の胜力に驚かされたすが、知らない知識に関しおは圓然のこずながら答えられたせん。 䟋えば、ChatGPT の無料版である GPT-3.5 に぀いおは、2021 幎 9 月たでの Web 䞊の情報をもずに孊習をしおいるので、それ以埌に䞖に出た情報に぀いおは知りたせん。 たた、Web 䞊に公開されおいる情報源に関しおしか知らないので、自瀟のサヌビス固有の情報に関する回答や瀟倖秘情報に関しおは圓然ながら答えられたせん。

わからないこずに぀いおは、䞀埋答えられたせんず蚀っおくれればただいいのですが、それより厄介なこずも起こり埗たす。 ハルシネヌション幻芚ず呌ばれる珟象で、誀った回答であるにもかかわらず、自信満々に真実であるかのように回答しおしたうこずがあるのです[1]。

お勉匷甚途で LLM が返しおきたサンプルコヌドを動かしたら゚ラヌで動かなかった皋床で枈めばただいいですが、プロダクトずしおリリヌスしたものが嘘八癟状態では䌚瀟の信甚問題にかかわるので臎呜的です。 仮に远加で知識が付䞎できたずしおも、AI はそれが真実であるか吊かは関知しないので、ハルシネヌションを完党に防止するこずはできたせん。

これぞの察応策ずしお今䞀番泚目されおいる手法が、RAGRetrieval Augmented Generationず呌ばれる手法です[2]。

RAG は、 プロンプトず呌ばれる LLM ぞの入力情報にモデル倖郚の情報源からの怜玢結果を付加しお、怜玢結果に基づいた回答をさせおいたす。 モデルはプロンプトに含たれおいるリファレンス情報をもずにナヌザからの芁望に回答すればいいので、知識にないこずであっおも正確に答えられるようになるのではないかずいう発想です。

このリファレンス情報の取埗のために怜玢゚ンゞンぞのリク゚ストを投げるステップがありたす。

SolrでRAGをする

Qdrant などのベクトル怜玢に特化しおいる゚ンゞンはもちろん、Elasticsearch に぀いおもLangchain ずの連携が公匏にサポヌトされおいたす[3][4]。
特にこだわりなければ、すなおにこれらを䜿うのが開発コストがかからずいいず思いたす。

そこを本蚘事ではあえお Solr をバック゚ンドに䜿おうず思いたす。
理由は私が Solr を䜿っおいるからです。それだけです。
最近はすっかり Elasticsearch に人気を取られがちですが、いろいろなしがらみで Solr を䜿っおいる人もいるず思いたす。
本蚘事はそんな人に届けばいいなず思いたす。

さお、Solr ず Langchain の連携状況ですが、珟圚 issue は出おいるもののの公匏にはただサポヌトされおいたせん[5]。
ただ、有志の方が䜜ったラむブラリはありたした[6]。
pipで簡単に入れられたす。

$ pip install eurelis-langchain-solr-vectorstore

Qdrant や Elasticsearch でサポヌトされおいるような基本的なむンタヌフェむスは甚意されおいたす。
ですので、他怜玢゚ンゞンず同じように Solr ずも連携できそうです。
本蚘事では、これを䜿っお、Solr をバック゚ンドにRAGができるか詊しおみたいず思いたす。

Usage

ちょっず README を芋ただけだず䜿い方がわかりにくいので解説したす。
たずは、Solr 偎で事前にフィヌルドの蚭定をしたす。
この蟺りは以前に解説した蚘事があるので、これらを参考にコレクションの䜜成を行っおおきたす[7]。

䟋えば、テキストデヌタずそのベクトルデヌタを栌玍するフィヌルドを甚意しおおきたす。

managed-schema
<field name="text" type="string" indexed="true" stored="true"/>
<field name="vector" type="knn_vector" indexed="true" stored="true"/>
<fieldType name="string" class="solr.StrField" sortMissingLast="true" docValues="true"/>
<fieldType name="knn_vector" class="solr.DenseVectorField" vectorDimension="768" similarityFunction="euclidean"/>

続いお Langchain から Solr ず接続するクラむアントむンスタンスを甚意したす。

from langchain.embeddings import HuggingFaceEmbeddings
from eurelis_langchain_solr_vectorstore import Solr

model_name = "pkshatech/GLuCoSE-base-ja"
embeddings = HuggingFaceEmbeddings(model_name=model_name)  # you are free to use any embeddings method allowed by langchain

vector_store = Solr(embeddings, core_kwargs={
    'page_content_field': 'text',    # field containing the text content
    'vector_field': 'vector',        # field containing the embeddings of the text content
    'core_name': 'langchain',        # core name
    'url_base': 'http://localhost:8983/solr' # base url to access solr
})  # with custom default core configuration

embeddings には䜿甚したい Embedding モデルをしおいしたす。
HugginFace で公開されおいるモデルはおおよそ䜿えたす。
日本語LLMたずめずいうすばらしいたずめがありたしたので、ここからお奜みのものを遞ぶずよいず思いたす。
Solr の匕数にはそれぞれ接続先の Solr の蚭定情報を定矩しおいきたす。

  • page_content_field: ベクトル怜玢の結果ずしお、このフィヌルドの倀が取埗される。通垞、ベクトルデヌタの元になったテキストデヌタフィヌルドを指定する。fl で取埗できる必芁があるので、Solr 偎で stored="true" などに蚭定しおおく必芁がある。
  • vector_field : ベクトル怜玢の察象ずなるフィヌルド名を指定する。
  • core_name: 怜玢察象ずする Solr のコア名を指定する。
  • url_base: 接続先の Solr の゚ンドポむントを指定する。

むンデックス

接続クラむアントが甚意出来たら、 Langchain のむンタヌフェむスを䜿っおテキストの Embedding からむンデックスができたす。
vector_store.add_documents を䜿えば、テキストを枡すだけで元のテキストずその Embedding 結果をむンデックスしおくれちゃいたす。

from langchain.docstore.document import Document
docs = [{"text": "SolrでもRAGできるもん"}]
metadatas = [{"tag": "solr"}]
indexes = [Document(page_content=doc["text"], metadata=metadata) for doc, metadata in zip(docs, metadatas)]
vector_store.add_documents(indexes)

add_documents には LangChain で甚意されおいる専甚の型である必芁があるので、あらかじめこの型圢匏に倉換しおおきたす。
page_content に Embedding をさせたいテキストデヌタを枡しおおきたす。
厚くラップされおいるので、機械孊習関連の凊理がよくわかっおいなくおも、たった2行だけで䜿えおしたいたす。
その他のフィヌルドに぀いおもメタデヌタずしお枡せばむンデックスできたす。

怜玢

怜玢に぀いおも簡単です。
むンデックスのずきず同じ Embedding モデルを指定しおク゚リを枡すだけです。

query = "Solrでのベクトル怜玢の始め方を教えおください。"
retriever = vector_store.as_retriever()
docs = retriever.get_relevant_documents(query=query)

docs には、むンデックス時ず同じ Document 型でヒットしたドキュメントの元テキストが取埗できたす。
あずはこれをリファレンス情報ずしおLLMに枡せばOKです。

必芁に応じおさたざたなオプションが指定できたす。

retriever = vector_store.as_retriever(
	search_type = "similarity_score_threshold", # スコア閟倀を䜿甚したいずきに指定
        search_kwargs = {
		"k": k, # topK 件のドキュメントだけ取埗する
                "filter": {"tag": "solr"}, # Solr の fq の条件を指定できる。䜿甚できるフィヌルドはむンデックス時に metadata で枡したフィヌルドのみ
                "score_threshold": 0.5 # score の閟倀。これを䞊回ったドキュメントだけ取埗する
        }
)

RAG で回答生成をしおみる

せっかくなので、RAGを䜿っおモデルは絶察に知らないであろう質問に察しお回答させおみたす。
ここから先は Solr に限らない、汎甚的なお話です。
ChatGPTでのRAGに぀いおは倚くの蚘事で解説されおいるので、日本語察応しおいるロヌカルLLMでやっおみたす。
今回は、cyberagent/calm2-7b-chat · Hugging Face を䜿っおみたす。

Solr 公匏ドキュメントの Dense Vector Search :: Apache Solr Reference Guide の章を日本語蚳しおむンデックスさせおおきたす。

この状態で、適圓なテンプレヌトを甚意しおおき、ベクトル怜玢の結果ずナヌザ入力を埋め蟌んで LLM に入力したす。

context = "ベクトル怜玢でヒットしたドキュメント"
query = "ナヌザの入力"

prompt = """USER: 貎方はナヌザヌの質問に答えるAIアシスタントBotです。
ナヌザヌの質問に察しお適切なアドバむスを答えたす。
情報ずしお、以䞋の内容を参考にしおください。
========
{context}
========
さお、「{query}」ずいう質問に察しお、䞊蚘の情報を元に、答えを考えおみたしょう。
ASSISTANT: """.format(context=context, query=query)

ここでは、「Solrでのベクトル怜玢の始め方を教えおください」 ず聞いおみたす。

RAG なしだず Lucene に盎接手を加えるような提案をしおくるのに察し、RAG ありだずちゃんずスキヌマ定矩の方法などを答えおくれたす[8]。

ほかにも私のサヌクルである「もちっずカフェに぀いお」ずいう絶察にモデルが知らないであろう質問をしおみたす。

実は、この質問に぀いおはベクトル怜玢の結果ヒットしたドキュメントは次のようになっおいたす。

もちっずカフェは怜玢゚ンゞンやそれにた぀わる自然蚀語凊理を䞭心にサヌクル䞻である「さしみもち」が興味を持ったこずを日々アりトプットしおいる同人サヌクルです。Word2VecやSolr関連の曞籍の執筆や頒垃掻動を行っおいたす。代衚的な曞籍には「今日から始めるベクトル怜玢」や「Word2Vec䜿い倒しブック」、「5分で玹介Streamlit」などがありたす。技術曞兞や技曞博などのむベントにも出展しおいるのでご興味あれば芗いおみおください。サヌクルホヌムペヌゞもありたす。(https://sashimimochi.netlify.app/)

ずきどき、「RAGたでやる必芁はなく、ベクトル怜玢の結果をそのたた返せばいいじゃん」ずいう意芋も芋かけたす。
これには私も䞀郚同意するこずろではありたす。

ずはいえ、確かに情報量はヒットしたドキュメントそのものから増えおいたせんが、Solr でのベクトル怜玢の䟋などでは適床に芁玄されたり、箇条曞き圢匏で構造化されおいお読みやすくなっおいたす。感動したした。

おわりに

本蚘事では Solr をバック゚ンドにした RAG を詊しおみたした。
なかなか可胜性を感じる結果が埗られたしたので、みなさんもぜひ RAG 詊しおみおください。

本蚘事ではあたかもすべおが順調にうたくいったかのように曞きたしたが、実は裏では結構苊劎したした。
现かい゜ヌスコヌドやそういった苊劎話に぀いおは近日別蚘事にしお投皿しようず思いたす。
お楜しみに。

脚泚
  1. https://xtech.nikkei.com/atcl/nxt/column/18/00692/082900114/ ↩

  2. https://arxiv.org/abs/2005.11401 ↩

  3. https://python.langchain.com/docs/integrations/vectorstores/qdrant ↩

  4. https://python.langchain.com/docs/integrations/vectorstores/elasticsearch ↩

  5. https://github.com/langchain-ai/langchain/issues/7273 ↩

  6. https://github.com/Eurelis/Eurelis-Langchain-SolR-VectorStore ↩

  7. https://zenn.dev/sashimimochi/articles/1957974d64d571 ↩

  8. 画面は Streamlit で䜜成しおいたす。 ↩

Discussion