お知らせ
過去にQiitaに投稿した内容のアーカイブです。
前回の投稿で、Amazon BedrockのEmbeddingsを試しました。 LLMと独自ナレッジを組み合わせたFAQに活用できそうです。
ベクトルデータベースのQdrantでは、単体のサーバーとして構築する方法だけでなく、メモリー上で動作させたりローカルファイルシステムで動作させることができます。
ローカルファイルとして動作するということは、 Lambda化できるのではないか!? と思い、挑戦しました。
手順
SAMプロジェクトを作成
sam init
コマンドを実行し、SAMプロジェクトを生成します。言語はPython 3.10、Zipでデプロイの方式を選択しました。hello_world/requirements.txt
に必要なライブラリーを追加します。バージョンは2023/9/30時点のものです。GA直後のため、今後バージョンアップするものと思われます。boto3==1.28.57
langchain==0.0.303
qdrant-clientQdrantのデータベースファイルを
hello_world
ディレクトリに格納します。 hello_worldディレクトリ内の配置はこのようになります。hello_world/
├── app.py
├── __init__.py
├── local_qdrant
│ ├── collection
│ │ └── ec2
│ │ └── storage.sqlite
│ └── meta.json
└── requirements.txtapp.pyにロジックを記述します。
1点ひねった部分があります。 Lambda上での動作時、ファイルシステムが/tmpを除いてリードオンリーになります。Qdrantに接続した際に
.lock
ファイルを作成しようとするのですが、作成できないのでエラーとなります。 エラーを回避するため、Qdrantのファイルを/tmpにコピーしています。shutil.copytree('./local_qdrant', '/tmp/local_qdrant')
app.py
import json
import boto3
import shutil
from langchain.chains import RetrievalQA
from langchain.embeddings import BedrockEmbeddings
from langchain.llms import Bedrock
from langchain.prompts import PromptTemplate
from langchain.vectorstores import Qdrant
from qdrant_client import QdrantClient
shutil.copytree('./local_qdrant', '/tmp/local_qdrant') # データベースファイルを/tmpにコピー
embeddings = BedrockEmbeddings(
client=boto3.client('bedrock-runtime'),
model_id='amazon.titan-embed-text-v1'
)
qdrant_client=QdrantClient(path='/tmp/local_qdrant') # /tmpのデータベースファイルを使用する
db = Qdrant(
client=qdrant_client,
collection_name='ec2',
embeddings=embeddings,
)
prompt_template = '''Human:
Text: {context}
Question: {question}
Answer the question based on the text provided. If the text doesn't contain the answer, reply that the answer is not available.
Assistant:
'''
PROMPT = PromptTemplate(
template=prompt_template, input_variables=['context', 'question']
)
llm = Bedrock(
client=boto3.client('bedrock-runtime'),
model_id="anthropic.claude-instant-v1",
verbose=True
)
chain_type_kwargs = {"prompt": PROMPT}
qa = RetrievalQA.from_chain_type(llm=llm,
chain_type="stuff",
retriever=db.as_retriever(),
chain_type_kwargs=chain_type_kwargs,
return_source_documents=True)
def lambda_handler(event, context):
answer = qa(event["input"])
print(answer)
return {
"statusCode": 200,
"body": answer["result"],
}template.yamlを編集
- メモリーを512MB以上にする
- タイムアウト時間を1分程度にする
- Bedrockへのアクセス権限を付与する
sam build
とsam deploy
を実行
以上です。これでベクトルDBを内部に保持したLambdaができました。
呼び出し
- テストイベント
{
"input": "EC2とは?"
}
- レスポンス
{
"statusCode": 200,
"body": " EC2 (Amazon Elastic Compute Cloud) は、Amazon が提供するクラウドコンピューティングサービスです。EC2はクラウド内で「コンピューティング」を可能にするサービスで、ユーザーはEC2のウェブサービスインターフェイスを使用して必要な機能やリソースを簡単に取得および設定できるとのことです。つまりEC2はAmazonのクラウド上で仮想サーバー(インスタンス)を作成、管理、使用できるサービスです。"
}
やったね!!