AI / MLAWSJavaScriptLangChain.jsLLMNode.jsSaaS / FaaS

LangChainからAmazon Bedrock Knowledge Baseでインデックスを生成したPineconeインデックスにアクセスする

以前BerdockのKnowledge Baseを使ってEmbeddingしたデータのインデックスを作っていた。Pineconeをベクターストアに使用し、LangChainから利用することに興味があったため、実験を行った。結果は成功し、S3のデータを取得できた。次にはRAGのようなものを作成するために、BedrockのSDKを追加し、Chainを組んでいく予定。また、BedrockChatモデルを使った場合も試してみたが、調整が必要であることがわかった。

広告ここから
広告ここまで

以前BerdockのKnowledge Baseを使ってEmbeddingしたデータのインデックスなどを作りました。その際にPineconeをベクターストアに使ったのですが、このインデックスをLangChainから利用したらどうなるか気になったので試してみました。

OpenAI APIとPineconeで検索だけ動かしてみる

ベクターストア周りはLangChainのPineconeインテグレーションをそのまま利用します。シンプルにOpenAI APIを利用する形でまず組んでみました。

    const pinecone = new Pinecone({
        apiKey: env.pinecone.API_KEY,
        environment: env.pinecone.ENV
    });
    
    const pineconeIndex = pinecone.Index(env.pinecone.PINECONE_INDEX);

    const vectorStore = await PineconeStore.fromExistingIndex(
        new OpenAIEmbeddings({
            openAIApiKey: env.openai.apiKey
        }),
        { pineconeIndex }
      );
      const results = await vectorStore.similaritySearch("subscription", 1);
      console.log(results);

結果がこちら。Knowledge Base経由でEmbddingしていたS3のデータを取れているのがなんとなく伺えます。

[
  {
    "metadata": {
      "metadata": "{\"source\":\"s3://DUMMY_BUCKET_NAME/app-flow/stripe-product-pricing/stripe-price/c7f15f4e-906f-4217-9a42-9675341a9773/-1259199976-2023-12-11T14:11:13\"}",
      "question1": "{\"id\":\"price_1KJALKL6R1kGwUF47gErXS96\",\"object\":\"price\",\"active\":true,\"billing_scheme\":\"per_unit\",\"created\":1642484094,\"currency\":\"jpy\",\"custom_unit_amount\":null,\"livemode\":false,\"lookup_key\":\"membership\",\"metadata\":{},\"nickname\":\"monthly membership\",\"product\":\"prod_Kz8cjSg54JYbjd\",\"recurring\":{\"aggregate_usage\":null,\"interval\":\"month\",\"interval_count\":1,\"trial_period_days\":null,\"usage_type\":\"licensed\"},\"tax_behavior\":\"unspecified\",\"tiers_mode\":null,\"transform_quantity\":null,\"type\":\"recurring\",\"unit_amount\":1000,\"unit_amount_decimal\":\"1000\"} {\"id\":\"price_1KJALKL6R1kGwUF4NejvgEUz\",\"object\":\"price\",\"active\":true,\"billing_scheme\":\"per_unit\",\"created\":1642484094,\"currency\":\"jpy\",\"custom_unit_amount\":null,\"livemode\":false,\"lookup_key\":null,\"metadata\":{},\"nickname\":\"simple"
    }
  }
]

ChainでRAGのようなものを作ってみる

データは取れそうなので、RAGを目指してChainを組んでいきます。

Bedrockのモデルを利用できるようにSDKを追加する

LangChainが内部的に利用するランタイムをインストールしましょう。

npm i '@aws-sdk/client-bedrock-runtime'

LLMのモデルで実装してみる

まずはLLMs側でワンショットのChainを作ってみます。Embeddingで生成するベクトルデータを揃えた方がよいかもと思ったので、ここでEmbeddingに利用するモデルをBedrockに切り替えています。

jsonApp.get('load', async c => {

    const pinecone = new Pinecone({
        apiKey: env.pinecone.API_KEY,
        environment: env.pinecone.ENV
    });
    
    const pineconeIndex = pinecone.Index(env.pinecone.PINECONE_INDEX);
    const embeddings = new BedrockEmbeddings({
      region: env.aws.region,
      credentials: {
        accessKeyId: env.aws.credentials.accessKeyId,
        secretAccessKey: env.aws.credentials.secretAccessKey,
      },
      model: "amazon.titan-embed-text-v1", // Default value
    });

    const vectorStore = await PineconeStore.fromExistingIndex(
        embeddings,
        { pineconeIndex }
      );
      const model = new OpenAI({
        openAIApiKey: env.openai.apiKey
      });
      const chain = VectorDBQAChain.fromLLM(model, vectorStore, {
        k: 1,
        returnSourceDocuments: true,
      });
      const response = await chain.call({ query: "Stripeでのサブスクリプションの作り方" });
      console.log(response);
      return c.json(response)
})

生成された文章がこちら。returnSourceDocumentsを含めているからか、参照したデータまで見れるのがよいですね。ただし回答の精度については、「I don’t know」が混ざっているあたり、要調整に見えます。

{
  "text": " Stripeのサブスクリプションを作るには、まずStripeのウェブサイトにアクセスし、アカウントを作成します。その後、ダッシュボードから「サブスクリプション」を選択し、必要な情報を入力してプランを作成します。作成したプランをウェブサイトに組み込んで、顧客がサブスクリプションを購入できるようにします。\n\nI don't know.",
  "sourceDocuments": [
    {
      "metadata": {
        "metadata": "{\"source\":\"s3://DUMMY_BUCKET_NAME/app-flow/stripe-product-pricing/3300a769-6250-4833-80c5-d93af6ce2d16/-1264520871-2023-12-01T06:56:56\"}",
        "question1": "{\"id\":\"prod_KugwwcPLrFjsBW\",\"object\":\"product\",\"active\":true,\"attributes\":[],\"created\":1641458563,\"default_price\":\"price_1KErYWL6R1kGwUF40RAg2a4Y\",\"description\":\"(created by Stripe CLI)\",\"images\":[],\"livemode\":false,\"metadata\":{\"industry\":\"pvAeqLVP\"},\"name\":\"SubscriptionTestProduct\",\"package_dimensions\":null,\"shippable\":null,\"statement_descriptor\":null,\"tax_code\":null,\"type\":\"service\",\"unit_label\":null,\"updated\":1652121707,\"url\":null} {\"id\":\"prod_KmSIFB9LJUXdU3\",\"object\":\"product\",\"active\":true,\"attributes\":[],\"created\":1639558988,\"default_price\":\"price_1K6tOCL6R1kGwUF4NC25BLww\",\"description\":null,\"images\":[],\"livemode\":false,\"metadata\":{},\"name\":\"たべものパッケージ\",\"package_dimensions\":null,\"shippable\":null,\"statement_descriptor\":null,\"tax_code\":\"txcd_40060003\",\"type\":\"service\",\"unit_label\":null,\"updated\":1696839595,\"url\":null} {\""
      }
    }
  ]
}

BedrockChatモデルを使ってみた場合

別のモデルも試してみましょう。今度はLLMsではなくChat Modelで、Bedrockのみを使ってみます。


    const pinecone = new Pinecone({
        apiKey: env.pinecone.API_KEY,
        environment: env.pinecone.ENV
    });
    
    const pineconeIndex = pinecone.Index(env.pinecone.PINECONE_INDEX);
    const embeddings = new BedrockEmbeddings({
      region: env.aws.region,
      credentials: {
        accessKeyId: env.aws.credentials.accessKeyId,
        secretAccessKey: env.aws.credentials.secretAccessKey,
      },
      model: "amazon.titan-embed-text-v1", // Default value
    });

    const vectorStore = await PineconeStore.fromExistingIndex(
        embeddings,
        { pineconeIndex }
    );
    const model = new BedrockChat({
        model: "anthropic.claude-v2",
        region: env.aws.region,
        credentials: {
          accessKeyId: env.aws.credentials.accessKeyId,
          secretAccessKey: env.aws.credentials.secretAccessKey,
        },
    });
    const chain = VectorDBQAChain.fromLLM(model, vectorStore, {
        k: 5,
        returnSourceDocuments: true,
    });
    const response = await chain.invoke({
        query:"Stripeでのサブスクリプションの作り方"
    });

こちらの回答は次のようになりました。文章が途切れていたり、Embeddingしたデータを利用した回答ができていないなど、調整がかなり必要そうな気配を感じます。

{
  "text": " すみません、Stripeでのサブスクリプションの作り方について詳しく知りません。Stripeは決済サービスのプラットフォ",
  "sourceDocuments": [
    {
      "metadata": {
        "metadata": "{\"source\":\"s3://DUMMY_BUCKET_NAME/app-flow/stripe-product-pricing/3300a769-6250-4833-80c5-d93af6ce2d16/-1264520871-2023-12-01T06:56:56\"}",
        "question1": "{\"id\":\"prod_KugwwcPLrFjsBW\",\"object\":\"product\",\"active\":true,\"attributes\":[],\"created\":1641458563,\"default_price\":\"price_1KErYWL6R1kGwUF40RAg2a4Y\",\"description\":\"(created by Stripe CLI)\",\"images\":[],\"livemode\":false,\"metadata\":{\"industry\":\"pvAeqLVP\"},\"name\":\"SubscriptionTestProduct\",\"package_dimensions\":null,\"shippable\":null,\"statement_descriptor\":null,\"tax_code\":null,\"type\":\"service\",\"unit_label\":null,\"updated\":1652121707,\"url\":null} {\"id\":\"prod_KmSIFB9LJUXdU3\",\"object\":\"product\",\"active\":true,\"attributes\":[],\"created\":1639558988,\"default_price\":\"price_1K6tOCL6R1kGwUF4NC25BLww\",\"description\":null,\"images\":[],\"livemode\":false,\"metadata\":{},\"name\":\"たべものパッケージ\",\"package_dimensions\":null,\"shippable\":null,\"statement_descriptor\":null,\"tax_code\":\"txcd_40060003\",\"type\":\"service\",\"unit_label\":null,\"updated\":1696839595,\"url\":null} {\""
      }
    },
    {

感想

同じようなプロンプトをいれたのですが、期待した回答は得られませんでした。LangChainのChainに相当する部分がBedrockのAgentやKnowledge Base内部で実装されていると考えると、LangChainで同じようなChainに作れるのではという予測をしています。が、そこまでするくらいならLangChainからBedrockのAgentを呼び出すようなChainを作ってみるのも一つかもしれません。

ヒントになるのは、RetrievalQAChainな気がしますので、日を改めてこちらと連携したものも作ってみようと思います。

ブックマークや限定記事(予定)など

WP Kyotoサポーター募集中

WordPressやフロントエンドアプリのホスティング、Algolia・AWSなどのサービス利用料を支援する「WP Kyotoサポーター」を募集しています。
月額または年額の有料プランを契約すると、ブックマーク機能などのサポーター限定機能がご利用いただけます。

14日間のトライアルも用意しておりますので、「このサイトよく見るな」という方はぜひご検討ください。

広告ここから
広告ここまで

Related Category posts