LangChain v0.2 で RAGを構築
「LangChain v0.2」でRAGを構築してみます。
前回
1. LangChainのセットアップ
(1) パッケージのインストール。
# パッケージのインストール
!pip install langchain
!pip install langchain-openai
!pip install langchain-chroma
(2) 環境変数の準備。
左端の鍵アイコンで「OPENAI_API_KEY」を設定してからセルを実行してください。
import os
from google.colab import userdata
# 環境変数の準備 (左端の鍵アイコンでOPENAI_API_KEYを設定)
os.environ["OPENAI_API_KEY"] = userdata.get("OPENAI_API_KEY")
2. VectorStore
(1) ドキュメントの準備。
from langchain_core.documents import Document
# ドキュメントの準備
documents = [
Document(
page_content="犬は忠誠心とフレンドリーさで知られる、素晴らしいパートナーです。",
metadata={"source": "mammal-pets-doc"},
),
Document(
page_content="猫は独立したペットであり、自分だけの空間を楽しむことがよくあります。",
metadata={"source": "mammal-pets-doc"},
),
Document(
page_content="金魚は比較的簡単な飼育で初心者にも人気のペットです。",
metadata={"source": "fish-pets-doc"},
),
Document(
page_content="オウムは人間の言葉を真似ることができる賢い鳥です。",
metadata={"source": "bird-pets-doc"},
),
Document(
page_content="ウサギは社会的な動物であり、飛び回るのに十分なスペースが必要です。",
metadata={"source": "mammal-pets-doc"},
),
]
Documentは、次の2つの属性を持ちます。
(2) VectorStoreの準備。
今回は、Chromaを利用します。
from langchain_chroma import Chroma
from langchain_openai import OpenAIEmbeddings
# VectorStoreの準備
vectorstore = Chroma.from_documents(
documents,
embedding=OpenAIEmbeddings(),
)
VectorStoreには、クエリを実行するメソッドが提供されています。
・similarity_search() : 文字列クエリとの類似性で検索
vectorstore.similarity_search("猫")
[Document(page_content='猫は独立したペットであり、自分だけの空間を楽しむことがよくあります。', metadata={'source': 'mammal-pets-doc'}),
Document(page_content='犬は忠誠心とフレンドリーさで知られる、素晴らしいパートナーです。', metadata={'source': 'mammal-pets-doc'}),
Document(page_content='金魚は比較的簡単な飼育で初心者にも人気のペットです。', metadata={'source': 'fish-pets-doc'}),
Document(page_content='オウムは人間の言葉を真似ることができる賢い鳥です。', metadata={'source': 'bird-pets-doc'})]
・asimilarity_search() : 非同期クエリで検索
await vectorstore.asimilarity_search("猫")
[Document(page_content='猫は独立したペットであり、自分だけの空間を楽しむことがよくあります。', metadata={'source': 'mammal-pets-doc'}),
Document(page_content='犬は忠誠心とフレンドリーさで知られる、素晴らしいパートナーです。', metadata={'source': 'mammal-pets-doc'}),
Document(page_content='金魚は比較的簡単な飼育で初心者にも人気のペットです。', metadata={'source': 'fish-pets-doc'}),
Document(page_content='オウムは人間の言葉を真似ることができる賢い鳥です。', metadata={'source': 'bird-pets-doc'})]
・similarity_search_with_score() : 文字列クエリとの類似性で検索 + スコアを返す
vectorstore.similarity_search_with_score("猫")
[(Document(page_content='猫は独立したペットであり、自分だけの空間を楽しむことがよくあります。', metadata={'source': 'mammal-pets-doc'}),
0.30265679955482483),
(Document(page_content='犬は忠誠心とフレンドリーさで知られる、素晴らしいパートナーです。', metadata={'source': 'mammal-pets-doc'}),
0.41133826971054077),
(Document(page_content='金魚は比較的簡単な飼育で初心者にも人気のペットです。', metadata={'source': 'fish-pets-doc'}),
0.4211256802082062),
(Document(page_content='オウムは人間の言葉を真似ることができる賢い鳥です。', metadata={'source': 'bird-pets-doc'}),
0.43402451276779175)]
・similarity_search_by_vector() : 埋め込みクエリとの類似性で検索
embedding = OpenAIEmbeddings().embed_query("猫")
vectorstore.similarity_search_by_vector(embedding)
[Document(page_content='猫は独立したペットであり、自分だけの空間を楽しむことがよくあります。', metadata={'source': 'mammal-pets-doc'}),
Document(page_content='犬は忠誠心とフレンドリーさで知られる、素晴らしいパートナーです。', metadata={'source': 'mammal-pets-doc'}),
Document(page_content='金魚は比較的簡単な飼育で初心者にも人気のペットです。', metadata={'source': 'fish-pets-doc'}),
Document(page_content='オウムは人間の言葉を真似ることができる賢い鳥です。', metadata={'source': 'bird-pets-doc'})]
3. Retriever
「VectorStore」はRunnableをサブクラス化しないため、LECLチェーンにすぐに統合することはできません。「Retriever」はRunnableであるため、標準セットのメソッド (同期および非同期の呼び出しやバッチ操作など) を実装し、LCELチェーンに組み込まれるように設計されています。
(1) Retrieverの準備と実行。
# Retrieverの準備
retriever = vectorstore.as_retriever(
search_type="similarity",
search_kwargs={"k": 1},
)
# Retrieverの実行
retriever.batch(["猫", "魚"])
[[Document(page_content='猫は独立したペットであり、自分だけの空間を楽しむことがよくあります。', metadata={'source': 'mammal-pets-doc'})],
[Document(page_content='金魚は比較的簡単な飼育で初心者にも人気のペットです。', metadata={'source': 'fish-pets-doc'})]]
「VectorStoreRetriever 」は、「similarity」(デフォルト)、「mmr」(最大周辺関連性)、「similarity_score_threshold」の検索タイプをサポートします。 後者を使用して、類似性スコアによって取得者によって出力されたドキュメントをしきい値に設定できます。
4. RAGチェーン
「Retriever」は、特定の質問と取得したコンテキストを組み合わせて LLM のプロンプトを生成するRAG アプリケーションなど、より複雑なアプリケーションに簡単に組み込むことができます。
(1) LLMの準備。
from langchain_openai import ChatOpenAI
# LLMの準備
llm = ChatOpenAI(model="gpt-4o")
(2) プロンプトテンプレートの準備。
from langchain_core.prompts import ChatPromptTemplate
from langchain_core.runnables import RunnablePassthrough
# プロンプトテンプレートの準備
message = """
提供されたコンテキストのみを使用して、この質問に答えてください。
{question}
Context:
{context}
"""
prompt = ChatPromptTemplate.from_messages([("human", message)])
(3) RAGチェーンの準備。
# RAGチェーンの準備
rag_chain = {"context": retriever, "question": RunnablePassthrough()} | prompt | llm
(4) 質問応答。
# 質問応答
response = rag_chain.invoke("猫について教えてください")
print(response.content)
猫は独立したペットであり、自分だけの空間を楽しむことがよくあります。