メインコンテンツまでスキップ

Amazon BedrockのEmbeddingsで作成したベクトルDBをLambda単体で使用する手順

· 約4分
moritalous
お知らせ

過去にQiitaに投稿した内容のアーカイブです。

前回の投稿で、Amazon BedrockのEmbeddingsを試しました。 LLMと独自ナレッジを組み合わせたFAQに活用できそうです。

ベクトルデータベースのQdrantでは、単体のサーバーとして構築する方法だけでなく、メモリー上で動作させたりローカルファイルシステムで動作させることができます。

ローカルファイルとして動作するということは、 Lambda化できるのではないか!? と思い、挑戦しました。

手順

  1. SAMプロジェクトを作成 sam initコマンドを実行し、SAMプロジェクトを生成します。言語はPython 3.10、Zipでデプロイの方式を選択しました。

  2. hello_world/requirements.txtに必要なライブラリーを追加します。バージョンは2023/9/30時点のものです。GA直後のため、今後バージョンアップするものと思われます。

    boto3==1.28.57
    langchain==0.0.303
    qdrant-client
  3. Qdrantのデータベースファイルをhello_worldディレクトリに格納します。 hello_worldディレクトリ内の配置はこのようになります。

    hello_world/
    ├── app.py
    ├── __init__.py
    ├── local_qdrant
    │ ├── collection
    │ │ └── ec2
    │ │ └── storage.sqlite
    │ └── meta.json
    └── requirements.txt
  4. app.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"],
    }
  5. template.yamlを編集

    1. メモリーを512MB以上にする
    2. タイムアウト時間を1分程度にする
    3. Bedrockへのアクセス権限を付与する
  6. sam buildsam deployを実行

以上です。これでベクトルDBを内部に保持したLambdaができました。

呼び出し

  • テストイベント
{
"input": "EC2とは?"
}
  • レスポンス
{
"statusCode": 200,
"body": " EC2 (Amazon Elastic Compute Cloud) は、Amazon が提供するクラウドコンピューティングサービスです。EC2はクラウド内で「コンピューティング」を可能にするサービスで、ユーザーはEC2のウェブサービスインターフェイスを使用して必要な機能やリソースを簡単に取得および設定できるとのことです。つまりEC2はAmazonのクラウド上で仮想サーバー(インスタンス)を作成、管理、使用できるサービスです。"
}

やったね!!