5
3

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

Last updated at Posted at 2023-09-30

前回の投稿で、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のクラウド上で仮想サーバー(インスタンス)を作成、管理、使用できるサービスです。"
}

やったね!!

5
3
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
5
3