🦜
任意のWebページをEmbeddingしてVertexAI Searchで検索する
はじめに
この記事ではLangChainとVertexAIを使ってLLMから応答を得る記事です。
今回は任意のWebページをEmbeddingしてLLMに渡し、QAを実行する内容となっています。
手順
任意のWebページをEmbeddingしてVertexAI Searchで検索するまでの手順を以下に記載します。
おおまかな流れ
- Vertex AI Searchのエンドポイントを構築する
- インデックス処理を実行してベクターストアを構築する
- LLMを使って応答を得る
事前準備
スクリプトを実行するにあたってはいくつかのパッケージをインストールする必要があります。具体的には以下の内容です。
# Basic python packages
urllib3==1.26.18
unstructured==0.6.6
tabulate==0.9.0
pytesseract==0.3.10
tiktoken==0.4.0
langchain-google-vertexai==0.0.3
langchain==0.1.0
# Load Web Page Documents
beautifulsoup4==4.12.2
html2text==2020.1.16
また、コンテナで動かす場合は以下のdockerfileを参考にしてください。
FROM python:3.9-slim as builder
ENV APP_HOME /app
WORKDIR $APP_HOME
COPY . ./
RUN pip install --no-cache-dir --upgrade pip && pip install --no-cache-dir -r requirements.txt
CMD ["python","app.py"]
Vertex AI Searchのエンドポイントを構築する流れ
- Vertex AI Search のインデックスを作成
- 事前にコンソールで作成して
INDEX_ID
をコピーしておく
- 事前にコンソールで作成して
- Vertex AI Search のインデックスをエンドポイントにデプロイ
なお、エンドポイントの作成は一度だけ実行します。
from google.cloud import aiplatform
PROJECT_ID = os.environ.get("PROJECT_ID", "")
LOCATION = os.environ.get("PROJECT_ID", "asia-northeast1")
# VertexAIのIndex IDを指定する
INDEX_ID = ""
# INDEX_ID = "projects/〜/locations/asia-northeast1/indexes/〜"
aiplatform.init(project=PROJECT_ID, location=LOCATION)
# Endpointを作成する
index_endpoint = aiplatform.MatchingEngineIndexEndpoint.create(
project=PROJECT_ID,
location=LOCATION,
display_name="index-endpoint-ai",
description="search-endpoint",
public_endpoint_enabled=False,
)
# IndexをEndpointにデプロイする
index = aiplatform.MatchingEngineIndex(index_name=INDEX_ID, location=LOCATION)
deployed_index = index_endpoint.deploy_index(
index=index,
deployed_index_id="deployed_index_id",
display_name="display-name-ai-index",
machine_type="e2-standard-2",
min_replica_count=1,
max_replica_count=1,
)
インデックス処理を実行してベクターストアを構築する流れ
- 特定のURLからWebページを取得する
- 取得したWebページをhtmlパース
- htmlパースしたテキストを分割する
- ベクターストアに格納する
import os
from google.cloud import aiplatform
from langchain.text_splitter import RecursiveCharacterTextSplitter
from langchain_community.document_loaders.recursive_url_loader import RecursiveUrlLoader
from langchain_google_vertexai.embeddings import VertexAIEmbeddings
from langchain_community.vectorstores import MatchingEngine
from langchain_community.document_transformers import Html2TextTransformer
PROJECT_ID = os.environ.get("PROJECT_ID", "")
LOCATION = os.environ.get("PROJECT_ID", "asia-northeast1")
# VertexAIのIndex IDを指定する
INDEX_ID = ""
# VertexAIのENDPOINT IDを指定する
ENDPOINT_ID = ""
# embedding データの保存先
GCS_BUCKET_NAME = ""
use_embedding_model_name = "textembedding-gecko@003"
loader = RecursiveUrlLoader("https://docs.aws.amazon.com/ja_jp/lambda/latest/dg/configuration-function-zip.html")
documents = loader.load()
# pip install --user html2text
html2text = Html2TextTransformer()
docs_transformed = html2text.transform_documents(documents)
# split the documents into chunks
text_splitter = RecursiveCharacterTextSplitter(
chunk_size=1000,
chunk_overlap=50,
separators=["\n\n", ".", "!", "?", ",", " ", "。"],
)
doc_splits = text_splitter.split_documents(docs_transformed)
aiplatform.init(project=PROJECT_ID, location=LOCATION)
vector_store = MatchingEngine.from_components(
embedding=VertexAIEmbeddings(model_name=use_embedding_model_name),
project_id=PROJECT_ID,
region=LOCATION,
gcs_bucket_name=GCS_BUCKET_NAME,
index_id=INDEX_ID,
endpoint_id=ENDPOINT_ID,
)
vector_store.add_documents(doc_splits)
LLMを使って応答を得る流れ
- Matching Engine を起動する
- ベクターストアオブジェクトを呼び出す
- ベクターストアを検索する(近傍値=3)
- RetrievalQAを実行してLLMから応答を得る
import json
from google.cloud import aiplatform
from langchain_google_vertexai import VertexAI
from langchain_google_vertexai.embeddings import VertexAIEmbeddings
from langchain_community.vectorstores import MatchingEngine
from langchain.chains import RetrievalQA
PROJECT_ID = os.environ.get("PROJECT_ID", "")
LOCATION = os.environ.get("PROJECT_ID", "asia-northeast1")
# VertexAIのIndex IDを指定する
INDEX_ID = ""
# VertexAIのENDPOINT IDを指定する
ENDPOINT_ID = ""
# embedding データの保存先
GCS_BUCKET_NAME = ""
use_embedding_model_name = "textembedding-gecko@003"
use_chat_model_name = "text-bison-32k"
aiplatform.init(project=PROJECT_ID, location=LOCATION)
vector_store = MatchingEngine.from_components(
embedding=VertexAIEmbeddings(model_name=use_embedding_model_name),
project_id=PROJECT_ID,
region=LOCATION,
gcs_bucket_name=GCS_BUCKET_NAME,
index_id=INDEX_ID,
endpoint_id=ENDPOINT_ID,
)
NUMBER_OF_RESULTS = 3
query = """
命令セットアーキテクチャを変更する前に確認することは何ですか?
"""
retriever = vector_store.as_retriever(
search_type="similarity",
search_kwargs={"k":NUMBER_OF_RESULTS})
chat = VertexAI(model_name=use_chat_model_name, temperature=0)
qa_chain = RetrievalQA.from_chain_type(llm=chat, chain_type="stuff", retriever=retriever)
result = qa_chain.run(query)
print(result)
まとめ
3工程で簡単にRAG構成を作成できました。しかし、課題がいくつか残っています。
具体的には以下のとおりです。
- ベクトル化したWebページの保存と管理
- 複数のWebページをベクトルデータベースに格納した時のドキュメント検索
などなどです。
現在検討中なので何かわかったらまた記事にしようと思います。
Discussion