From e532a6cf390b7be835dab34666ec2dd68d5e83db Mon Sep 17 00:00:00 2001 From: Rubab Khan Date: Tue, 4 Feb 2025 16:21:38 -0800 Subject: [PATCH 1/2] Added and updated notebooks --- ...d_retreiveandgenerate_and_streamapi.ipynb} | 147 +- .../05_document_level_kb_ingestion.ipynb | 1121 ++++++++++++ .../autogenerated-metadata-filters.ipynb | 1591 +++++++++++++++++ .../re-ranking_using_kb.ipynb | 1574 ++++++++++++++++ .../structured-rag-using-kb.ipynb | 711 ++++++++ .../text-images-rag-using-kb.ipynb | 1172 ++++++++++++ 6 files changed, 6290 insertions(+), 26 deletions(-) rename 01-rag-concepts/{02_managed_rag_custom_prompting_and_no_of_results.ipynb => 02_managed_retreiveandgenerate_and_streamapi.ipynb} (87%) create mode 100644 01-rag-concepts/05_document_level_kb_ingestion.ipynb create mode 100644 02-optimizing-accuracy-retrieved-results/autogenerated-metadata-filters.ipynb create mode 100644 02-optimizing-accuracy-retrieved-results/re-ranking_using_kb.ipynb create mode 100644 05-structured-rag/structured-rag-using-kb.ipynb create mode 100644 06-multi-modal-rag/text-images-rag-using-kb/text-images-rag-using-kb.ipynb diff --git a/01-rag-concepts/02_managed_rag_custom_prompting_and_no_of_results.ipynb b/01-rag-concepts/02_managed_retreiveandgenerate_and_streamapi.ipynb similarity index 87% rename from 01-rag-concepts/02_managed_rag_custom_prompting_and_no_of_results.ipynb rename to 01-rag-concepts/02_managed_retreiveandgenerate_and_streamapi.ipynb index 1c4ec6d..47136df 100644 --- a/01-rag-concepts/02_managed_rag_custom_prompting_and_no_of_results.ipynb +++ b/01-rag-concepts/02_managed_retreiveandgenerate_and_streamapi.ipynb @@ -11,8 +11,10 @@ "This module contains:\n", "1. [Overview](#1-Overview)\n", "2. [Pre-requisites](#2-Pre-requisites)\n", - "3. [How to leverage maximum number of results](#3-how-to-leverage-the-maximum-number-of-results-feature)\n", - "4. [How to use custom prompting](#4-how-to-use-the-custom-prompting-feature)" + "3. [Understanding RetrieveAndGenerate API](#understanding-retrieveandgenerate-api)\n", + "4. [Sreaming response using RetrieveAndGenerate API](#streaming-response-with-retrieveandgenerate-api)\n", + "5. [Adjust 'maximum number of results' retrieval parameter](#3-how-to-leverage-the-maximum-number-of-results-feature)\n", + "6. [How to use custom prompting](#4-how-to-use-the-custom-prompting-feature)" ] }, { @@ -107,6 +109,7 @@ "import json\n", "import boto3\n", "import pprint\n", + "import sys\n", "from botocore.exceptions import ClientError\n", "from botocore.client import Config\n", "\n", @@ -134,8 +137,8 @@ }, "outputs": [], "source": [ - "%store -r kb_id\n", - "# kb_id = \"<>\" # Replace with your knowledge base id here." + "# %store -r kb_id\n", + "kb_id = \"<>\" # Replace with your knowledge base id here." ] }, { @@ -159,7 +162,7 @@ { "cell_type": "code", "execution_count": null, - "id": "ca915234", + "id": "bf0243f5", "metadata": {}, "outputs": [], "source": [ @@ -174,9 +177,17 @@ "$search_results$\n", "\n", "$output_format_instructions$\n", - "\"\"\"\n", - "\n", - "def retrieve_and_generate(query, kb_id, model_arn, max_results, prompt_template = default_prompt):\n", + "\"\"\"" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "ca915234", + "metadata": {}, + "outputs": [], + "source": [ + "def retrieve_and_generate(query, kb_id, model_arn, max_results=5, prompt_template = default_prompt):\n", " response = bedrock_agent_client.retrieve_and_generate(\n", " input={\n", " 'text': query\n", @@ -202,24 +213,10 @@ " return response\n" ] }, - { - "cell_type": "markdown", - "id": "a58b7808", - "metadata": {}, - "source": [ - "### How to leverage the maximum number of results feature\n", - "\n", - "In some use cases; the FM responses might be lacking enough context to provide relevant answers or relying that it couldn't find the requested info. Which could be fixed by modifying the maximum number of retrieved results.\n", - "\n", - "In the following example, we are going to run the following query with a few number of results (5):\n", - "\\\n", - "```Provide a list of risks for Octank financial in bulleted points.```\n" - ] - }, { "cell_type": "code", "execution_count": null, - "id": "e2918161", + "id": "ccd657e6", "metadata": {}, "outputs": [], "source": [ @@ -241,6 +238,104 @@ " pprint.pp(contexts)\n" ] }, + { + "cell_type": "markdown", + "id": "5f1d6784", + "metadata": {}, + "source": [ + "### Test RetrieveAndGenerate API" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "dbefffdd", + "metadata": {}, + "outputs": [], + "source": [ + "query = \"\"\"Provide a list of risks for Octank financial in numbered list without description.\"\"\"\n", + "\n", + "results = retrieve_and_generate(query = query, kb_id = kb_id, model_arn = model_arn)\n", + "\n", + "print_generation_results(results)" + ] + }, + { + "cell_type": "markdown", + "id": "f6d8439e", + "metadata": {}, + "source": [ + "### Streaming response with RetrieveAndGenerate API\n", + "\n", + "Using new [streaming API](https://docs.aws.amazon.com/bedrock/latest/APIReference/API_agent-runtime_RetrieveAndGenerateStream.html) customers can use `retrieve_and_generate_stream` API from Amazon Bedrock Knowledge Bases to receive the response as it is being generated by the Foundation Model (FM), rather than waiting for the complete response. This will help customers to reduce the time to first token in case of latency sensitive applications." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "86a3a94a", + "metadata": {}, + "outputs": [], + "source": [ + "def retrieve_and_generate_stream(query, kb_id, model_arn, max_results=5, prompt_template = default_prompt):\n", + " response = bedrock_agent_client.retrieve_and_generate_stream(\n", + " input={\n", + " 'text': query\n", + " },\n", + " retrieveAndGenerateConfiguration={\n", + " 'type': 'KNOWLEDGE_BASE',\n", + " 'knowledgeBaseConfiguration': {\n", + " 'knowledgeBaseId': kb_id,\n", + " 'modelArn': model_arn, \n", + " 'retrievalConfiguration': {\n", + " 'vectorSearchConfiguration': {\n", + " 'numberOfResults': max_results # will fetch top N documents which closely match the query\n", + " }\n", + " },\n", + " 'generationConfiguration': {\n", + " 'promptTemplate': {\n", + " 'textPromptTemplate': prompt_template\n", + " }\n", + " }\n", + " }\n", + " }\n", + " )\n", + "\n", + " for event in response['stream']:\n", + " if 'output' in event:\n", + " chunk = event['output']\n", + " sys.stdout.write(chunk['text'])\n", + " sys.stdout.flush()\n", + "\n", + " \n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "a55d95ce", + "metadata": {}, + "outputs": [], + "source": [ + "query = \"\"\"Provide a list of risks for Octank financial in numbered list without description.\"\"\"\n", + "\n", + "retrieve_and_generate_stream(query = query, kb_id = kb_id, model_arn = model_arn)" + ] + }, + { + "cell_type": "markdown", + "id": "a58b7808", + "metadata": {}, + "source": [ + "### Adjust 'maximum number of results' retrieval parameter\n", + "\n", + "In some use cases; the FM responses might be lacking enough context to provide relevant answers or relying that it couldn't find the requested info. Which could be fixed by modifying the maximum number of retrieved results.\n", + "\n", + "In the following example, we are going to run the following query with a few number of results (3):\n", + "\\\n", + "```Provide a list of risks for Octank financial in bulleted points.```\n" + ] + }, { "cell_type": "code", "execution_count": null, @@ -990,9 +1085,9 @@ ], "instance_type": "ml.t3.medium", "kernelspec": { - "display_name": "Python 3 (Data Science 3.0)", + "display_name": "Python 3", "language": "python", - "name": "python3__SAGEMAKER_INTERNAL__arn:aws:sagemaker:us-west-2:236514542706:image/sagemaker-data-science-310-v1" + "name": "python3" }, "language_info": { "codemirror_mode": { @@ -1004,7 +1099,7 @@ "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", - "version": "3.10.6" + "version": "3.10.13" } }, "nbformat": 4, diff --git a/01-rag-concepts/05_document_level_kb_ingestion.ipynb b/01-rag-concepts/05_document_level_kb_ingestion.ipynb new file mode 100644 index 0000000..1b10e47 --- /dev/null +++ b/01-rag-concepts/05_document_level_kb_ingestion.ipynb @@ -0,0 +1,1121 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Near real-time ingestion using Document level API (DLA) - End to end example \n", + "\n", + "With Document Level API (DLA), customers can now efficiently and cost-effectively ingest, update, or delete data directly from Amazon Bedrock Knowledge Bases using a single API call, without the need to perform a full sync with the data source periodically or after every change.\n", + "\n", + "To read more about DLA, see the [documentation](https://docs.aws.amazon.com/bedrock/latest/userguide/kb-direct-ingestion-add.html)\n", + "\n", + "\n", + "#### Pre-requisites: \n", + "\n", + "- You have already created a Amazon Bedrock Knowledge base by running [01_create_ingest_documents_test_kb_multi_ds.ipynb](/knowledge-bases/01-rag-concepts/01_create_ingest_documents_test_kb_multi_ds.ipynb)\n", + "- Note down the KB id\n", + "\n", + "#### Test Knowledge base: \n", + "- Ingest document into Knowledge base using DLA.\n", + "- Start querying knowledge base for information\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "\n", + "
\n", + "Note: Please make sure to enable `Anthropic Claude 3 Sonnet` and, `Titan Text Embeddings V2` model access in Amazon Bedrock Console.\n", + "
-------------------------------------------------------------------------------------------------------------------------------------------------------
\n", + " \n", + "Please run the notebook cell by cell instead of using \"Run All Cells\" option.\n", + "
\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### 0 - Setup\n", + "Before running the rest of this notebook, you'll need to run the cells below to (ensure necessary libraries are installed and) connect to Bedrock.\n", + "\n", + "Please ignore any pip dependency error (if you see any while installing libraries)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "%pip install --force-reinstall -q -r ../../requirements.txt --quiet\n", + "%pip install --upgrade boto3" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# restart kernel\n", + "from IPython.core.display import HTML\n", + "HTML(\"\")" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "import boto3\n", + "print(boto3.__version__)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "%load_ext autoreload\n", + "%autoreload 2" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "import warnings\n", + "warnings.filterwarnings('ignore')" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "import os\n", + "import sys\n", + "import time\n", + "import boto3\n", + "import logging\n", + "import pprint\n", + "import json\n", + "import uuid\n", + "\n", + "# Set the path to import module\n", + "from pathlib import Path\n", + "current_path = Path().resolve()\n", + "current_path = current_path.parent\n", + "if str(current_path) not in sys.path:\n", + " sys.path.append(str(current_path))\n", + "# Print sys.path to verify\n", + "# print(sys.path)\n", + "\n", + "from utils.knowledge_base import BedrockKnowledgeBase\n", + "from utils.knowledge_base_operators import create_document_config, ingest_documents_dla\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "#Clients\n", + "s3_client = boto3.client('s3')\n", + "sts_client = boto3.client('sts')\n", + "session = boto3.session.Session()\n", + "region = session.region_name\n", + "account_id = sts_client.get_caller_identity()[\"Account\"]\n", + "bedrock_agent_client = boto3.client('bedrock-agent')\n", + "bedrock_agent_runtime_client = boto3.client('bedrock-agent-runtime') \n", + "logging.basicConfig(format='[%(asctime)s] p%(process)s {%(filename)s:%(lineno)d} %(levelname)s - %(message)s', level=logging.INFO)\n", + "logger = logging.getLogger(__name__)\n", + "region, account_id" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Ingest document directly into Knowledge base using Document Level API (INLINE)\n", + "\n", + "To ingest documents directly into a knowledge base, send an [IngestKnowledgeBaseDocuments](https://docs.aws.amazon.com/bedrock/latest/APIReference/API_agent_IngestKnowledgeBaseDocuments.html) request by specifying the knowledge base ID and data source \n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# %store -r kb_id\n", + "\n", + "kb_id = \"\" \n", + "ds_id_list = bedrock_agent_client.list_data_sources( knowledgeBaseId=kb_id, maxResults=100)['dataSourceSummaries']\n", + "ds_id = ds_id_list[0]['dataSourceId']\n", + "\n", + "kb_id, ds_id" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "\n", + "Currently You can use DLA only if your knowledge base is connected to one of the following data source types:\n", + "\n", + " - Amazon S3\n", + " - Custom " + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Based on various configurations, there can be different types of ingest patterns as shown below. To read more about these patteren refer to API documentation [here](https://boto3.amazonaws.com/v1/documentation/api/latest/reference/services/bedrock-agent/client/ingest_knowledge_base_documents.html)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# You can choose between different Ingest patterns (based on Data source type i.e. s3 or Custom) using DLA\n", + "\n", + "print(\"Different DLA ingest pattern:\")\n", + "# For S3 Data source type\n", + "print(\"1. Data Source Type: S3 - Metadata: INLINE\")\n", + "print(\"2. Data Source Type: S3 - Metadata: S3_Location\")\n", + "\n", + "# For CUSTOM Data source type\n", + "print(\"3. Data Source Type: CUSTOM - Document source type: INLINE - conetent type: TEXT - Metadata: INLINE\")\n", + "print(\"4. Data Source Type: CUSTOM - Document source type: INLINE - conetent type: TEXT - Metadata: S3_Location\")\n", + "print(\"5. Data Source Type: CUSTOM - Document source type: INLINE - conetent type: BYTE - Metadata: INLINE\")\n", + "print(\"6. Data Source Type: CUSTOM - Document source type: INLINE - conetent type: BYTE - Metadata: S3_Location\")\n", + "print(\"7. Data Source Type: CUSTOM - Document source type: S3_LOCATION - Metadata: INLINE\")\n", + "print(\"8. Data Source Type: CUSTOM - Document source type: S3_LOCATION - Metadata: S3_Location\")\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "For using DLA, you have to define the knowledgeBaseId, dataSourceId, and the documents (A list of objects, each of which contains information about the documents to add).\n", + "\n", + "- We have created a custom function named `create_document_config` , which will define the list of documents based on the ingest pattern you chose. this function accepts the following arguments:\n", + "\n", + " - data_source_type: Either 'CUSTOM' or 'S3'.\n", + " - document_id: The ID for a custom document.\n", + " - s3_uri: The S3 URI for S3 data source.\n", + " - inline_content: The inline content configuration for custom data source.\n", + " - Metadata: Metadata information that can be a list of inline attributes or an S3 location.\n", + "\n", + "For this notebook - we have implemented only four ingest patterns i.e. pattern 1,2,3 & 4. But you can extent it to pattern 5, 6, 7 & 8.\n", + "\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "\n", + "
\n", + "Note: While using DLA, the dataSourceType specified in the content for each document must match the type of the data source that you specify otherwise ingestion will throw an error. \n", + "
    - if your KB data source is S3, then choose S3 as data source type while using DLA API
\n", + "
    - if your KB data source is CUSTOM, then choose CUSTOM as data source type while using DLA API
" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# Provide below information based on your ingest pattern\n", + "#---------------------------------------------------------------------------------------\n", + "# FOR INGEST PATTERN CHOICE = 1, i.e. Data Source Type: S3 - Metadata: INLINE\n", + "# **************************************************************************************\n", + "# S3 uri of the data to be ingetsed\n", + "document_s3_uri = 's3://standard-kb-7104855/octank_financial_10K (1).pdf'\n", + "\n", + "# INLINE Metadata details\n", + "metdata_1 = {'key': 'company', 'value': { 'stringValue': 'octank', 'type': 'STRING'}}\n", + "metdata_2 = {'key': 'document', 'value': { 'stringValue': '10k', 'type': 'STRING'}}\n", + "metadata_list =[metdata_1, metdata_2]\n", + "\n", + "inline_metadata ={'inlineAttributes':metadata_list}\n", + "\n", + "# Create document configuration for this ingest pattern\n", + "s3_doc_inline_metadata = create_document_config(\n", + " data_source_type='S3',\n", + " s3_uri=document_s3_uri,\n", + " metadata= inline_metadata\n", + ")\n", + "\n", + "# #---------------------------------------------------------------------------------------\n", + "# # FOR INGEST PATTERN CHOICE = 2, i.e. Data Source Type: S3 - Metadata: S3_Location\n", + "# # **************************************************************************************\n", + "# document_s3_uri = '' \n", + "# metadata_s3_uri = '' \n", + "# metadata_s3_accountid = '' \n", + "\n", + "# # if your metada is stored at S3_location\n", + "# metadata_s3_uri = '' \n", + "# metadata_s3_accountid = '' \n", + "# s3_metadata = {'uri': metadata_s3_uri, 'bucketOwnerAccountId': metadata_s3_accountid }\n", + "\n", + "# s3_doc_s3_metadata = create_document_config(\n", + "# data_source_type='S3',\n", + "# s3_uri='s3://standard-kb-7104855/octank_financial_10K (1).pdf',\n", + "# metadata= s3_metadata\n", + "# )\n", + "\n", + "\n", + "## ---------------------------------------------------------------------------------------\n", + "## FOR INGEST PATTERN CHOICE = 3, i.e. Data Source Type: CUSTOM - Document source type: INLINE - conetent type: TEXT - Metadata: INLINE\n", + "## **************************************************************************************\n", + "\n", + "## Example : USE DLA to ingest a custom document with TEXT inline content and inline metadata\n", + "\n", + "# document_content = '''This is sample document content'''\n", + "# document_id = ''\n", + "\n", + "# # if your Metadata is INLINE\n", + "# metdata_1 = {'key': 'company', 'value': { 'stringValue': 'octank', 'type': 'STRING'}}\n", + "# metdata_2 = {'key': 'document', 'value': { 'stringValue': '10k', 'type': 'STRING'}}\n", + "# metadata_list =[metdata_1, metdata_2]\n", + "\n", + "# inline_metadata ={'inlineAttributes': metadata_list}\n", + "\n", + "# custom_inline_text_inline_metadata = create_document_config(\n", + "# data_source_type='CUSTOM',\n", + "# document_id=document_id,\n", + "# inline_content={\n", + "# 'type': 'TEXT',\n", + "# 'data': document_content\n", + "# },\n", + "# metadata= inline_metadata\n", + "# )\n", + "\n", + "##---------------------------------------------------------------------------------------\n", + "## FOR INGEST PATTERN CHOICE = 4, i.e. Data Source Type: CUSTOM - Document source type: INLINE - conetent type: TEXT - Metadata: S3_Location\n", + "## **************************************************************************************\n", + "\n", + "## Example : USE DLA to ingest a custom document with TEXT inline content and S3 metadata\n", + "\n", + "# document_content = '''This is sample document content'''\n", + "# document_id = ''\n", + "\n", + "# # if your metada is stored at S3_location\n", + "# metadata_s3_uri = '' \n", + "# metadata_s3_accountid = '' \n", + "# s3_metadata = {'uri': metadata_s3_uri, 'bucketOwnerAccountId': metadata_s3_accountid }\n", + "\n", + "# custom_inline_text_s3_metadata = create_document_config(\n", + "# data_source_type='CUSTOM',\n", + "# document_id=document_id,\n", + "# inline_content={\n", + "# 'type': 'TEXT',\n", + "# 'data': document_content\n", + "# },\n", + "# metadata=s3_metadata\n", + "#)\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "After the document list has been configured, you can call the `ingest_documents_dla` (another custom function) function to ingest the documents into Knowledge base which will call [ingest_knowledge_base_documents](https://boto3.amazonaws.com/v1/documentation/api/latest/reference/services/bedrock-agent/client/ingest_knowledge_base_documents.html) API.\n", + "\n", + "- This function accepts the following arguments:\n", + "\n", + " - knowledge_base_id: The ID of the knowledge base.\n", + " - data_source_id: The ID of the data source.\n", + " - documents: A list of document configurations to ingest." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# Ingest the documents using DLA\n", + "response = ingest_documents_dla(\n", + " knowledge_base_id=kb_id,\n", + " data_source_id=ds_id,\n", + " documents=[ s3_doc_inline_metadata] # Based on the ingest pattern, this can be changed to [s3_doc_s3_metadata], [custom_inline_text_inline_metadata] or [custom_inline_text_s3_metadata]\n", + ")\n", + "\n", + "print(response)\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Check the status of the documents ingested via DLA" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "## To fetch the status of documents\n", + "# response = bedrock_agent_client.list_knowledge_base_documents(\n", + "# dataSourceId=ds_id,\n", + "# knowledgeBaseId=kb_id,\n", + "# )\n", + "# print(response)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### 2.2 Test the Knowledge Base\n", + "Now the Knowlegde Base is available we can test it out using the [**retrieve**](https://boto3.amazonaws.com/v1/documentation/api/latest/reference/services/bedrock-agent-runtime/client/retrieve.html) and [**retrieve_and_generate**](https://boto3.amazonaws.com/v1/documentation/api/latest/reference/services/bedrock-agent-runtime/client/retrieve_and_generate.html) functions. \n", + "\n", + "#### Testing Knowledge Base with Retrieve and Generate API\n", + "\n", + "Let's first test the knowledge base using the retrieve and generate API. With this API, Bedrock takes care of retrieving the necessary references from the knowledge base and generating the final answer using a foundation model from Bedrock.\n", + "\n", + "query = `Provide a summary of consolidated statements of cash flows of Octank Financial for the fiscal years ended December 31, 2019.`\n", + "\n", + "The right response for this query as per ground truth QA pair is:\n", + "```\n", + "The cash flow statement for Octank Financial in the year ended December 31, 2019 reveals the following:\n", + "- Cash generated from operating activities amounted to $710 million, which can be attributed to a $700 million profit and non-cash charges such as depreciation and amortization.\n", + "- Cash outflow from investing activities totaled $240 million, with major expenditures being the acquisition of property, plant, and equipment ($200 million) and marketable securities ($60 million), partially offset by the sale of property, plant, and equipment ($40 million) and maturing marketable securities ($20 million).\n", + "- Financing activities resulted in a cash inflow of $350 million, stemming from the issuance of common stock ($200 million) and long-term debt ($300 million), while common stock repurchases ($50 million) and long-term debt payments ($100 million) reduced the cash inflow.\n", + "Overall, Octank Financial experienced a net cash enhancement of $120 million in 2019, bringing their total cash and cash equivalents to $210 million." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "query = \"Provide a summary of consolidated statements of cash flows of Octank Financial for the fiscal years ended December 31, 2019?\"" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "foundation_model = \"anthropic.claude-3-sonnet-20240229-v1:0\"\n", + "\n", + "response = bedrock_agent_runtime_client.retrieve_and_generate(\n", + " input={\n", + " \"text\": query\n", + " },\n", + " retrieveAndGenerateConfiguration={\n", + " \"type\": \"KNOWLEDGE_BASE\",\n", + " \"knowledgeBaseConfiguration\": {\n", + " 'knowledgeBaseId': kb_id,\n", + " \"modelArn\": \"arn:aws:bedrock:{}::foundation-model/{}\".format(region, foundation_model),\n", + " \"retrievalConfiguration\": {\n", + " \"vectorSearchConfiguration\": {\n", + " \"numberOfResults\":5\n", + " } \n", + " }\n", + " }\n", + " }\n", + ")\n", + "\n", + "print(response['output']['text'],end='\\n'*2)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "As you can see, with the retrieve and generate API we get the final response directly and we don't see the different sources used to generate this response. Let's now retrieve the source information from the knowledge base with the retrieve API.\n", + "\n", + "#### Testing Knowledge Base with Retrieve API\n", + "If you need an extra layer of control, you can retrieve the chuncks that best match your query using the retrieve API. In this setup, we can configure the desired number of results and control the final answer with your own application logic. The API then provides you with the matching content, its S3 location, the similarity score and the chunk metadata." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "response_ret = bedrock_agent_runtime_client.retrieve(\n", + " knowledgeBaseId=kb_id, \n", + " nextToken='string',\n", + " retrievalConfiguration={\n", + " \"vectorSearchConfiguration\": {\n", + " \"numberOfResults\":5,\n", + " } \n", + " },\n", + " retrievalQuery={\n", + " \"text\": \"How many new positions were opened across Amazon's fulfillment and delivery network?\"\n", + " }\n", + ")\n", + "\n", + "def response_print(retrieve_resp):\n", + "#structure 'retrievalResults': list of contents. Each list has content, location, score, metadata\n", + " for num,chunk in enumerate(response_ret['retrievalResults'],1):\n", + " print(f'Chunk {num}: ',chunk['content']['text'],end='\\n'*2)\n", + " print(f'Chunk {num} Location: ',chunk['location'],end='\\n'*2)\n", + " print(f'Chunk {num} Score: ',chunk['score'],end='\\n'*2)\n", + " print(f'Chunk {num} Metadata: ',chunk['metadata'],end='\\n'*2)\n", + "\n", + "response_print(response_ret)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Clean up\n", + "Please make sure to uncomment and run the below section to delete all the resources." + ] + } + ], + "metadata": { + "availableInstances": [ + { + "_defaultOrder": 0, + "_isFastLaunch": true, + "category": "General purpose", + "gpuNum": 0, + "hideHardwareSpecs": false, + "memoryGiB": 4, + "name": "ml.t3.medium", + "vcpuNum": 2 + }, + { + "_defaultOrder": 1, + "_isFastLaunch": false, + "category": "General purpose", + "gpuNum": 0, + "hideHardwareSpecs": false, + "memoryGiB": 8, + "name": "ml.t3.large", + "vcpuNum": 2 + }, + { + "_defaultOrder": 2, + "_isFastLaunch": false, + "category": "General purpose", + "gpuNum": 0, + "hideHardwareSpecs": false, + "memoryGiB": 16, + "name": "ml.t3.xlarge", + "vcpuNum": 4 + }, + { + "_defaultOrder": 3, + "_isFastLaunch": false, + "category": "General purpose", + "gpuNum": 0, + "hideHardwareSpecs": false, + "memoryGiB": 32, + "name": "ml.t3.2xlarge", + "vcpuNum": 8 + }, + { + "_defaultOrder": 4, + "_isFastLaunch": true, + "category": "General purpose", + "gpuNum": 0, + "hideHardwareSpecs": false, + "memoryGiB": 8, + "name": "ml.m5.large", + "vcpuNum": 2 + }, + { + "_defaultOrder": 5, + "_isFastLaunch": false, + "category": "General purpose", + "gpuNum": 0, + "hideHardwareSpecs": false, + "memoryGiB": 16, + "name": "ml.m5.xlarge", + "vcpuNum": 4 + }, + { + "_defaultOrder": 6, + "_isFastLaunch": false, + "category": "General purpose", + "gpuNum": 0, + "hideHardwareSpecs": false, + "memoryGiB": 32, + "name": "ml.m5.2xlarge", + "vcpuNum": 8 + }, + { + "_defaultOrder": 7, + "_isFastLaunch": false, + "category": "General purpose", + "gpuNum": 0, + "hideHardwareSpecs": false, + "memoryGiB": 64, + "name": "ml.m5.4xlarge", + "vcpuNum": 16 + }, + { + "_defaultOrder": 8, + "_isFastLaunch": false, + "category": "General purpose", + "gpuNum": 0, + "hideHardwareSpecs": false, + "memoryGiB": 128, + "name": "ml.m5.8xlarge", + "vcpuNum": 32 + }, + { + "_defaultOrder": 9, + "_isFastLaunch": false, + "category": "General purpose", + "gpuNum": 0, + "hideHardwareSpecs": false, + "memoryGiB": 192, + "name": "ml.m5.12xlarge", + "vcpuNum": 48 + }, + { + "_defaultOrder": 10, + "_isFastLaunch": false, + "category": "General purpose", + "gpuNum": 0, + "hideHardwareSpecs": false, + "memoryGiB": 256, + "name": "ml.m5.16xlarge", + "vcpuNum": 64 + }, + { + "_defaultOrder": 11, + "_isFastLaunch": false, + "category": "General purpose", + "gpuNum": 0, + "hideHardwareSpecs": false, + "memoryGiB": 384, + "name": "ml.m5.24xlarge", + "vcpuNum": 96 + }, + { + "_defaultOrder": 12, + "_isFastLaunch": false, + "category": "General purpose", + "gpuNum": 0, + "hideHardwareSpecs": false, + "memoryGiB": 8, + "name": "ml.m5d.large", + "vcpuNum": 2 + }, + { + "_defaultOrder": 13, + "_isFastLaunch": false, + "category": "General purpose", + "gpuNum": 0, + "hideHardwareSpecs": false, + "memoryGiB": 16, + "name": "ml.m5d.xlarge", + "vcpuNum": 4 + }, + { + "_defaultOrder": 14, + "_isFastLaunch": false, + "category": "General purpose", + "gpuNum": 0, + "hideHardwareSpecs": false, + "memoryGiB": 32, + "name": "ml.m5d.2xlarge", + "vcpuNum": 8 + }, + { + "_defaultOrder": 15, + "_isFastLaunch": false, + "category": "General purpose", + "gpuNum": 0, + "hideHardwareSpecs": false, + "memoryGiB": 64, + "name": "ml.m5d.4xlarge", + "vcpuNum": 16 + }, + { + "_defaultOrder": 16, + "_isFastLaunch": false, + "category": "General purpose", + "gpuNum": 0, + "hideHardwareSpecs": false, + "memoryGiB": 128, + "name": "ml.m5d.8xlarge", + "vcpuNum": 32 + }, + { + "_defaultOrder": 17, + "_isFastLaunch": false, + "category": "General purpose", + "gpuNum": 0, + "hideHardwareSpecs": false, + "memoryGiB": 192, + "name": "ml.m5d.12xlarge", + "vcpuNum": 48 + }, + { + "_defaultOrder": 18, + "_isFastLaunch": false, + "category": "General purpose", + "gpuNum": 0, + "hideHardwareSpecs": false, + "memoryGiB": 256, + "name": "ml.m5d.16xlarge", + "vcpuNum": 64 + }, + { + "_defaultOrder": 19, + "_isFastLaunch": false, + "category": "General purpose", + "gpuNum": 0, + "hideHardwareSpecs": false, + "memoryGiB": 384, + "name": "ml.m5d.24xlarge", + "vcpuNum": 96 + }, + { + "_defaultOrder": 20, + "_isFastLaunch": false, + "category": "General purpose", + "gpuNum": 0, + "hideHardwareSpecs": true, + "memoryGiB": 0, + "name": "ml.geospatial.interactive", + "supportedImageNames": [ + "sagemaker-geospatial-v1-0" + ], + "vcpuNum": 0 + }, + { + "_defaultOrder": 21, + "_isFastLaunch": true, + "category": "Compute optimized", + "gpuNum": 0, + "hideHardwareSpecs": false, + "memoryGiB": 4, + "name": "ml.c5.large", + "vcpuNum": 2 + }, + { + "_defaultOrder": 22, + "_isFastLaunch": false, + "category": "Compute optimized", + "gpuNum": 0, + "hideHardwareSpecs": false, + "memoryGiB": 8, + "name": "ml.c5.xlarge", + "vcpuNum": 4 + }, + { + "_defaultOrder": 23, + "_isFastLaunch": false, + "category": "Compute optimized", + "gpuNum": 0, + "hideHardwareSpecs": false, + "memoryGiB": 16, + "name": "ml.c5.2xlarge", + "vcpuNum": 8 + }, + { + "_defaultOrder": 24, + "_isFastLaunch": false, + "category": "Compute optimized", + "gpuNum": 0, + "hideHardwareSpecs": false, + "memoryGiB": 32, + "name": "ml.c5.4xlarge", + "vcpuNum": 16 + }, + { + "_defaultOrder": 25, + "_isFastLaunch": false, + "category": "Compute optimized", + "gpuNum": 0, + "hideHardwareSpecs": false, + "memoryGiB": 72, + "name": "ml.c5.9xlarge", + "vcpuNum": 36 + }, + { + "_defaultOrder": 26, + "_isFastLaunch": false, + "category": "Compute optimized", + "gpuNum": 0, + "hideHardwareSpecs": false, + "memoryGiB": 96, + "name": "ml.c5.12xlarge", + "vcpuNum": 48 + }, + { + "_defaultOrder": 27, + "_isFastLaunch": false, + "category": "Compute optimized", + "gpuNum": 0, + "hideHardwareSpecs": false, + "memoryGiB": 144, + "name": "ml.c5.18xlarge", + "vcpuNum": 72 + }, + { + "_defaultOrder": 28, + "_isFastLaunch": false, + "category": "Compute optimized", + "gpuNum": 0, + "hideHardwareSpecs": false, + "memoryGiB": 192, + "name": "ml.c5.24xlarge", + "vcpuNum": 96 + }, + { + "_defaultOrder": 29, + "_isFastLaunch": true, + "category": "Accelerated computing", + "gpuNum": 1, + "hideHardwareSpecs": false, + "memoryGiB": 16, + "name": "ml.g4dn.xlarge", + "vcpuNum": 4 + }, + { + "_defaultOrder": 30, + "_isFastLaunch": false, + "category": "Accelerated computing", + "gpuNum": 1, + "hideHardwareSpecs": false, + "memoryGiB": 32, + "name": "ml.g4dn.2xlarge", + "vcpuNum": 8 + }, + { + "_defaultOrder": 31, + "_isFastLaunch": false, + "category": "Accelerated computing", + "gpuNum": 1, + "hideHardwareSpecs": false, + "memoryGiB": 64, + "name": "ml.g4dn.4xlarge", + "vcpuNum": 16 + }, + { + "_defaultOrder": 32, + "_isFastLaunch": false, + "category": "Accelerated computing", + "gpuNum": 1, + "hideHardwareSpecs": false, + "memoryGiB": 128, + "name": "ml.g4dn.8xlarge", + "vcpuNum": 32 + }, + { + "_defaultOrder": 33, + "_isFastLaunch": false, + "category": "Accelerated computing", + "gpuNum": 4, + "hideHardwareSpecs": false, + "memoryGiB": 192, + "name": "ml.g4dn.12xlarge", + "vcpuNum": 48 + }, + { + "_defaultOrder": 34, + "_isFastLaunch": false, + "category": "Accelerated computing", + "gpuNum": 1, + "hideHardwareSpecs": false, + "memoryGiB": 256, + "name": "ml.g4dn.16xlarge", + "vcpuNum": 64 + }, + { + "_defaultOrder": 35, + "_isFastLaunch": false, + "category": "Accelerated computing", + "gpuNum": 1, + "hideHardwareSpecs": false, + "memoryGiB": 61, + "name": "ml.p3.2xlarge", + "vcpuNum": 8 + }, + { + "_defaultOrder": 36, + "_isFastLaunch": false, + "category": "Accelerated computing", + "gpuNum": 4, + "hideHardwareSpecs": false, + "memoryGiB": 244, + "name": "ml.p3.8xlarge", + "vcpuNum": 32 + }, + { + "_defaultOrder": 37, + "_isFastLaunch": false, + "category": "Accelerated computing", + "gpuNum": 8, + "hideHardwareSpecs": false, + "memoryGiB": 488, + "name": "ml.p3.16xlarge", + "vcpuNum": 64 + }, + { + "_defaultOrder": 38, + "_isFastLaunch": false, + "category": "Accelerated computing", + "gpuNum": 8, + "hideHardwareSpecs": false, + "memoryGiB": 768, + "name": "ml.p3dn.24xlarge", + "vcpuNum": 96 + }, + { + "_defaultOrder": 39, + "_isFastLaunch": false, + "category": "Memory Optimized", + "gpuNum": 0, + "hideHardwareSpecs": false, + "memoryGiB": 16, + "name": "ml.r5.large", + "vcpuNum": 2 + }, + { + "_defaultOrder": 40, + "_isFastLaunch": false, + "category": "Memory Optimized", + "gpuNum": 0, + "hideHardwareSpecs": false, + "memoryGiB": 32, + "name": "ml.r5.xlarge", + "vcpuNum": 4 + }, + { + "_defaultOrder": 41, + "_isFastLaunch": false, + "category": "Memory Optimized", + "gpuNum": 0, + "hideHardwareSpecs": false, + "memoryGiB": 64, + "name": "ml.r5.2xlarge", + "vcpuNum": 8 + }, + { + "_defaultOrder": 42, + "_isFastLaunch": false, + "category": "Memory Optimized", + "gpuNum": 0, + "hideHardwareSpecs": false, + "memoryGiB": 128, + "name": "ml.r5.4xlarge", + "vcpuNum": 16 + }, + { + "_defaultOrder": 43, + "_isFastLaunch": false, + "category": "Memory Optimized", + "gpuNum": 0, + "hideHardwareSpecs": false, + "memoryGiB": 256, + "name": "ml.r5.8xlarge", + "vcpuNum": 32 + }, + { + "_defaultOrder": 44, + "_isFastLaunch": false, + "category": "Memory Optimized", + "gpuNum": 0, + "hideHardwareSpecs": false, + "memoryGiB": 384, + "name": "ml.r5.12xlarge", + "vcpuNum": 48 + }, + { + "_defaultOrder": 45, + "_isFastLaunch": false, + "category": "Memory Optimized", + "gpuNum": 0, + "hideHardwareSpecs": false, + "memoryGiB": 512, + "name": "ml.r5.16xlarge", + "vcpuNum": 64 + }, + { + "_defaultOrder": 46, + "_isFastLaunch": false, + "category": "Memory Optimized", + "gpuNum": 0, + "hideHardwareSpecs": false, + "memoryGiB": 768, + "name": "ml.r5.24xlarge", + "vcpuNum": 96 + }, + { + "_defaultOrder": 47, + "_isFastLaunch": false, + "category": "Accelerated computing", + "gpuNum": 1, + "hideHardwareSpecs": false, + "memoryGiB": 16, + "name": "ml.g5.xlarge", + "vcpuNum": 4 + }, + { + "_defaultOrder": 48, + "_isFastLaunch": false, + "category": "Accelerated computing", + "gpuNum": 1, + "hideHardwareSpecs": false, + "memoryGiB": 32, + "name": "ml.g5.2xlarge", + "vcpuNum": 8 + }, + { + "_defaultOrder": 49, + "_isFastLaunch": false, + "category": "Accelerated computing", + "gpuNum": 1, + "hideHardwareSpecs": false, + "memoryGiB": 64, + "name": "ml.g5.4xlarge", + "vcpuNum": 16 + }, + { + "_defaultOrder": 50, + "_isFastLaunch": false, + "category": "Accelerated computing", + "gpuNum": 1, + "hideHardwareSpecs": false, + "memoryGiB": 128, + "name": "ml.g5.8xlarge", + "vcpuNum": 32 + }, + { + "_defaultOrder": 51, + "_isFastLaunch": false, + "category": "Accelerated computing", + "gpuNum": 1, + "hideHardwareSpecs": false, + "memoryGiB": 256, + "name": "ml.g5.16xlarge", + "vcpuNum": 64 + }, + { + "_defaultOrder": 52, + "_isFastLaunch": false, + "category": "Accelerated computing", + "gpuNum": 4, + "hideHardwareSpecs": false, + "memoryGiB": 192, + "name": "ml.g5.12xlarge", + "vcpuNum": 48 + }, + { + "_defaultOrder": 53, + "_isFastLaunch": false, + "category": "Accelerated computing", + "gpuNum": 4, + "hideHardwareSpecs": false, + "memoryGiB": 384, + "name": "ml.g5.24xlarge", + "vcpuNum": 96 + }, + { + "_defaultOrder": 54, + "_isFastLaunch": false, + "category": "Accelerated computing", + "gpuNum": 8, + "hideHardwareSpecs": false, + "memoryGiB": 768, + "name": "ml.g5.48xlarge", + "vcpuNum": 192 + }, + { + "_defaultOrder": 55, + "_isFastLaunch": false, + "category": "Accelerated computing", + "gpuNum": 8, + "hideHardwareSpecs": false, + "memoryGiB": 1152, + "name": "ml.p4d.24xlarge", + "vcpuNum": 96 + }, + { + "_defaultOrder": 56, + "_isFastLaunch": false, + "category": "Accelerated computing", + "gpuNum": 8, + "hideHardwareSpecs": false, + "memoryGiB": 1152, + "name": "ml.p4de.24xlarge", + "vcpuNum": 96 + }, + { + "_defaultOrder": 57, + "_isFastLaunch": false, + "category": "Accelerated computing", + "gpuNum": 0, + "hideHardwareSpecs": false, + "memoryGiB": 32, + "name": "ml.trn1.2xlarge", + "vcpuNum": 8 + }, + { + "_defaultOrder": 58, + "_isFastLaunch": false, + "category": "Accelerated computing", + "gpuNum": 0, + "hideHardwareSpecs": false, + "memoryGiB": 512, + "name": "ml.trn1.32xlarge", + "vcpuNum": 128 + }, + { + "_defaultOrder": 59, + "_isFastLaunch": false, + "category": "Accelerated computing", + "gpuNum": 0, + "hideHardwareSpecs": false, + "memoryGiB": 512, + "name": "ml.trn1n.32xlarge", + "vcpuNum": 128 + } + ], + "instance_type": "ml.t3.medium", + "kernelspec": { + "display_name": "Python 3", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.10.13" + } + }, + "nbformat": 4, + "nbformat_minor": 4 +} diff --git a/02-optimizing-accuracy-retrieved-results/autogenerated-metadata-filters.ipynb b/02-optimizing-accuracy-retrieved-results/autogenerated-metadata-filters.ipynb new file mode 100644 index 0000000..4c9d823 --- /dev/null +++ b/02-optimizing-accuracy-retrieved-results/autogenerated-metadata-filters.ipynb @@ -0,0 +1,1591 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "id": "15c08f81", + "metadata": {}, + "source": [ + "# Autogenerated filters\n", + "\n", + "## Overview\n", + "\n", + "This notebook demonstrates the **Autogenerated Filters** feature of Amazon Bedrock Knowledge Bases, which enhances search capabilities through automatic metadata filtering. By leveraging Amazon Bedrock's foundation models, the Autogenerated Filters feature dynamically interprets user queries and generates appropriate metadata filters based on the defined metadata schema for the Knowledge Base. This improves the quality and relevance of search results without requiring explicit filter specifications.\n", + "\n", + "The Autogenerated Filters feature is enabled through the `implicitFilterConfiguration` parameter within the `vectorSearchConfiguration` of the `retrievalConfiguration` in the `Retrieve` and `RetrieveAndGenerate` API calls. These APIs analyze the user's query, identify relevant metadata attributes based on the specified `implicitFilterConfiguration`, and apply these filters to narrow down the search results.\n", + "\n", + "For example, if a user searches for \"marketing reports from last year,\" the Autogenerated Filters feature can automatically recognize that \"last year\" refers to a specific time period and apply a filter based on the date metadata field. Similarly, if the query mentions a specific product or department, the system can apply filters based on the corresponding metadata fields.\n", + "\n", + "Let's explore how to implement and utilize Autogenerated Filters with Amazon Bedrock Knowledge Bases for an example use case." + ] + }, + { + "cell_type": "markdown", + "id": "ece99ba7", + "metadata": {}, + "source": [ + "## 1. Setup\n", + "Before running the rest of this notebook, you'll need to run the cells below to (ensure necessary libraries are installed and) connect to Bedrock.\n", + "\n", + "Please ignore any pip dependency error (if you see any while installing libraries)" + ] + }, + { + "cell_type": "code", + "execution_count": 1, + "id": "dc89fe3a", + "metadata": {}, + "outputs": [], + "source": [ + "%pip install --force-reinstall -q -r utils/requirements.txt --quiet" + ] + }, + { + "cell_type": "code", + "execution_count": 2, + "id": "57056c5d", + "metadata": {}, + "outputs": [], + "source": [ + "%pip install --upgrade boto3" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "165e5495", + "metadata": {}, + "outputs": [], + "source": [ + "# restart kernel\n", + "from IPython.core.display import HTML\n", + "HTML(\"\")" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "7c1c0eb1", + "metadata": {}, + "outputs": [], + "source": [ + "import boto3\n", + "print(boto3.__version__)" + ] + }, + { + "cell_type": "code", + "execution_count": 5, + "id": "7173b4bf", + "metadata": {}, + "outputs": [], + "source": [ + "import warnings\n", + "warnings.filterwarnings('ignore')" + ] + }, + { + "cell_type": "code", + "execution_count": 6, + "id": "84241929", + "metadata": {}, + "outputs": [], + "source": [ + "import os\n", + "import sys\n", + "import time\n", + "import boto3\n", + "import logging\n", + "import pprint\n", + "import json\n", + "\n", + "# Set the path to import module\n", + "from pathlib import Path\n", + "current_path = Path().resolve()\n", + "current_path = current_path.parent\n", + "if str(current_path) not in sys.path:\n", + " sys.path.append(str(current_path))\n", + "# Print sys.path to verify\n", + "# print(sys.path)\n", + "\n", + "from utils.knowledge_base import BedrockKnowledgeBase" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "cda1c18f", + "metadata": {}, + "outputs": [], + "source": [ + "#Clients\n", + "s3_client = boto3.client('s3')\n", + "sts_client = boto3.client('sts')\n", + "session = boto3.session.Session()\n", + "region = session.region_name\n", + "account_id = sts_client.get_caller_identity()[\"Account\"]\n", + "bedrock_agent_client = boto3.client('bedrock-agent')\n", + "bedrock_agent_runtime_client = boto3.client('bedrock-agent-runtime') \n", + "logging.basicConfig(format='[%(asctime)s] p%(process)s {%(filename)s:%(lineno)d} %(levelname)s - %(message)s', level=logging.INFO)\n", + "logger = logging.getLogger(__name__)\n", + "region, account_id" + ] + }, + { + "cell_type": "code", + "execution_count": 8, + "id": "5d74b5be", + "metadata": {}, + "outputs": [], + "source": [ + "import time\n", + "\n", + "# Get the current timestamp\n", + "current_time = time.time()\n", + "\n", + "# Format the timestamp as a string\n", + "timestamp_str = time.strftime(\"%Y%m%d%H%M%S\", time.localtime(current_time))[-7:]\n", + "# Create the suffix using the timestamp\n", + "suffix = f\"{timestamp_str}\"\n", + "knowledge_base_name = 'autogenerated-filters-kb'\n", + "knowledge_base_description = \"Knowledge Base autogenerated metadata filtering.\"\n", + "bucket_name = f'{knowledge_base_name}-{suffix}'\n", + "foundation_model = \"anthropic.claude-3-sonnet-20240229-v1:0\"" + ] + }, + { + "cell_type": "markdown", + "id": "e5142d7f", + "metadata": {}, + "source": [ + "## 2 - Create knowledge bases with fixed chunking strategy\n", + "Let's start by creating a [Knowledge Base for Amazon Bedrock](https://aws.amazon.com/bedrock/knowledge-bases/) to store video games data in csv format. Knowledge Bases allow you to integrate with different vector databases including [Amazon OpenSearch Serverless](https://aws.amazon.com/opensearch-service/features/serverless/), [Amazon Aurora](https://aws.amazon.com/rds/aurora/), [Pinecone](http://app.pinecone.io/bedrock-integration), [Redis Enterprise]() and [MongoDB Atlas](). For this example, we will integrate the knowledge base with Amazon OpenSearch Serverless. To do so, we will use the helper class `BedrockKnowledgeBase` which will create the knowledge base and all of its pre-requisites:\n", + "1. IAM roles and policies\n", + "2. S3 bucket\n", + "3. Amazon OpenSearch Serverless encryption, network and data access policies\n", + "4. Amazon OpenSearch Serverless collection\n", + "5. Amazon OpenSearch Serverless vector index\n", + "6. Knowledge base\n", + "7. Knowledge base data source" + ] + }, + { + "cell_type": "markdown", + "id": "8283567d", + "metadata": {}, + "source": [ + "We will create a knowledge base using fixed chunking strategy. \n", + "\n", + "You can chhose different chunking strategies by changing the below parameter values: \n", + "```\n", + "\"chunkingStrategy\": \"FIXED_SIZE | NONE | HIERARCHICAL | SEMANTIC\"\n", + "```" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "258fbb58", + "metadata": {}, + "outputs": [], + "source": [ + "knowledge_base_metadata = BedrockKnowledgeBase(\n", + " kb_name=f'{knowledge_base_name}-{suffix}',\n", + " kb_description=knowledge_base_description,\n", + " data_bucket_name=bucket_name, \n", + " chunking_strategy = \"FIXED_SIZE\", \n", + " suffix = suffix\n", + ")" + ] + }, + { + "cell_type": "markdown", + "id": "c79183c7", + "metadata": {}, + "source": [ + "### 2.1 Download Amazon 2019, 2020, 2021, 2022, & 2023 annual reports and upload it to Amazon S3\n", + "\n", + "Now that we have created the knowledge base, let's populate it with the `sec-10-k reports` dataset to KB. This data is being downloaded from [here](https://ir.aboutamazon.com/annual-reports-proxies-and-shareholder-letters/default.aspx). This data is about Amazon's annual reports, proxies and shareholder letters." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "c758da68", + "metadata": {}, + "outputs": [], + "source": [ + "import os\n", + "\n", + "def create_directory(directory_name): \n", + " if not os.path.exists(directory_name):\n", + " os.makedirs(directory_name)\n", + " print(f\"Directory '{directory_name}' created successfully.\")\n", + " else:\n", + " print(f\"Directory '{directory_name}' already exists.\")\n", + "\n", + "# Call the function to create the directory\n", + "create_directory(\"sec-10-k\")" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "a2bf67c7", + "metadata": {}, + "outputs": [], + "source": [ + "import requests\n", + "\n", + "def download_file(url, filename):\n", + " # Send a GET request to the URL\n", + " response = requests.get(url)\n", + " \n", + " # Check if the request was successful\n", + " if response.status_code == 200:\n", + " # Open the file in write-binary mode\n", + " with open(filename, 'wb') as file:\n", + " # Write the content of the response to the file\n", + " file.write(response.content)\n", + " print(f\"File downloaded successfully: {filename}\")\n", + " else:\n", + " print(f\"Failed to download file. Status code: {response.status_code}\")\n", + "\n", + "# URL of the files to download\n", + "urls = [\"https://s2.q4cdn.com/299287126/files/doc_financials/2024/ar/Amazon-com-Inc-2023-Annual-Report.pdf\",\n", + " \"https://s2.q4cdn.com/299287126/files/doc_financials/2023/ar/Amazon-2022-Annual-Report.pdf\",\n", + " \"https://s2.q4cdn.com/299287126/files/doc_financials/2022/ar/Amazon-2021-Annual-Report.pdf\",\n", + " \"https://s2.q4cdn.com/299287126/files/doc_financials/2021/ar/Amazon-2020-Annual-Report.pdf\",\n", + " \"https://s2.q4cdn.com/299287126/files/doc_financials/2020/ar/2019-Annual-Report.pdf\"]\n", + "\n", + "\n", + "for url in urls:\n", + " # Name for the downloaded file\n", + " filename = url.split('/')[-1]\n", + "\n", + " # Path to save the downloaded file\n", + " filepath = f\"./sec-10-k/{filename}\"\n", + "\n", + " # Call the function to download the file\n", + " download_file(url, filepath)" + ] + }, + { + "cell_type": "markdown", + "id": "70b83f68", + "metadata": {}, + "source": [ + "Let's upload the annual reports data available in the `sec-10-k` folder to s3." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "40e12fc8", + "metadata": {}, + "outputs": [], + "source": [ + "def upload_directory(path, bucket_name):\n", + " for root,dirs,files in os.walk(path):\n", + " for file in files:\n", + " if not file.startswith('.DS_Store'):\n", + " file_to_upload = os.path.join(root,file)\n", + " print(f\"uploading file {file_to_upload} to {bucket_name}\")\n", + " s3_client.upload_file(file_to_upload,bucket_name,file)\n", + "\n", + "upload_directory(\"sec-10-k\", bucket_name)" + ] + }, + { + "cell_type": "markdown", + "id": "71fc40a4", + "metadata": {}, + "source": [ + "#### 2.3 Prepare metadata for ingestion\n" + ] + }, + { + "cell_type": "code", + "execution_count": 13, + "id": "65939633", + "metadata": {}, + "outputs": [], + "source": [ + "import json\n", + "import re\n", + "\n", + "def generate_matadata(data_dir):\n", + " \n", + " # Loop through all PDF files in the directory\n", + " for filename in os.listdir(data_dir):\n", + " if not filename.startswith('.DS_Store'):\n", + " # Define the metadata dictionary\n", + " metadata ={}\n", + " \n", + " filename= f'{data_dir}/{filename}'\n", + " print(filename)\n", + " \n", + " # Create metadata\n", + " metadata[\"company\"] = \"Amazon\"\n", + " metadata[\"ticker\"] = \"AMZN\"\n", + " metadata[\"year\"] = re.search(r'\\d+', filename.split('/')[-1]).group(0)\n", + "\n", + " # Create a JSON object\n", + " json_data = {\"metadataAttributes\": metadata}\n", + "\n", + " # print(json_data)\n", + "\n", + " # Write the JSON object to a file\n", + " with open(f\"{filename.replace('.pdf', '.pdf.metadata.json')}\", \"w\") as f:\n", + " json.dump(json_data, f)\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "a41bbeb3", + "metadata": {}, + "outputs": [], + "source": [ + "data_dir = './sec-10-k'\n", + "generate_matadata(data_dir)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "2c913820", + "metadata": {}, + "outputs": [], + "source": [ + "# upload metadata file to S3\n", + "upload_directory(\"sec-10-k\", bucket_name)" + ] + }, + { + "cell_type": "markdown", + "id": "c524cd79", + "metadata": {}, + "source": [ + "Now start the ingestion job. Since, we are using the same documents as used for fixed chunking, we are skipping the step to upload documents to s3 bucket. " + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "6c35f597", + "metadata": {}, + "outputs": [], + "source": [ + "# ensure that the kb is available\n", + "time.sleep(30)\n", + "# sync knowledge base\n", + "knowledge_base_metadata.start_ingestion_job()" + ] + }, + { + "cell_type": "markdown", + "id": "3cf820bc", + "metadata": {}, + "source": [ + "Finally we save the Knowledge Base Id to test the solution at a later stage. " + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "f3c28c47", + "metadata": {}, + "outputs": [], + "source": [ + "kb_id_metadata = knowledge_base_metadata.get_knowledge_base_id()" + ] + }, + { + "cell_type": "markdown", + "id": "73deb547", + "metadata": {}, + "source": [ + "### 2.4 Enable Cloudwatch logs for Debugging our Autogenerated filters\n", + "\n", + "Below we're creating some helper functions to enable the cloudwatch logs for debugging." + ] + }, + { + "cell_type": "markdown", + "id": "702425bd", + "metadata": {}, + "source": [ + "#### Helper functions for CloudWatch Logs\n", + "\n", + "The helper functions facilitate the analysis of autogenerated filter generation by querying and processing CloudWatch logs. They provide insights into how user queries are leveraged to generate metadata filters. \n", + "\n", + "These functions allow you to examine the actual filters being generated, verify their consistency across different user query variations, and ensure they align with your expectations and query logic. If any filters are inconsistent or generated unexpectedly, you can use these functions to troubleshoot and understand the reasons behind it." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "7063db1b", + "metadata": {}, + "outputs": [], + "source": [ + "import boto3\n", + "from botocore.exceptions import ClientError\n", + "\n", + "def create_cloudwatch_log_group_for_bedrock(log_group_name):\n", + " logs_client = boto3.client('logs')\n", + " try:\n", + " logs_client.create_log_group(logGroupName=log_group_name)\n", + " print(f\"Successfully created CloudWatch log group: {log_group_name}\")\n", + " return True\n", + " except ClientError as e:\n", + " if e.response['Error']['Code'] == 'ResourceAlreadyExistsException':\n", + " print(f\"Log group {log_group_name} already exists.\")\n", + " return True\n", + " else:\n", + " print(f\"Error creating log group: {e}\")\n", + " return False\n", + "\n", + "def enable_bedrock_invokemodel_logs(cw_log_group_name):\n", + " bedrock_client = boto3.client('bedrock')\n", + " log_group_name = cw_log_group_name\n", + " \n", + " if not create_cloudwatch_log_group_for_bedrock(log_group_name):\n", + " print(\"Failed to create or confirm log group. Aborting log enablement.\")\n", + " return False\n", + "\n", + " try:\n", + " get_kb_response = bedrock_agent_client.get_knowledge_base(knowledgeBaseId = kb_id_metadata)\n", + " role_arn = get_kb_response['knowledgeBase']['roleArn']\n", + " kb_role_name = role_arn.split('/')[-1]\n", + "\n", + " sts_client = boto3.client('sts')\n", + " account_id = sts_client.get_caller_identity()[\"Account\"]\n", + " role_name = kb_role_name \n", + " role_arn = f\"arn:aws:iam::{account_id}:role/{role_name}\"\n", + "\n", + " # Get all available model types\n", + " response = bedrock_client.list_foundation_models()\n", + " all_model_types = list(set([model['modelName'] for model in response['modelSummaries']]))\n", + "\n", + " response = bedrock_client.put_model_invocation_logging_configuration(\n", + " loggingConfig={\n", + " 'cloudWatchConfig': {\n", + " 'logGroupName': log_group_name,\n", + " 'roleArn': role_arn\n", + " },\n", + " 'textDataDeliveryEnabled': True,\n", + " 'imageDataDeliveryEnabled': True,\n", + " 'embeddingDataDeliveryEnabled': True,\n", + " 'videoDataDeliveryEnabled': True\n", + " }\n", + " )\n", + " \n", + " print(f\"Successfully enabled InvokeModel logging for Bedrock with log group: {log_group_name}\")\n", + " return True\n", + " except ClientError as e:\n", + " print(f\"Error enabling InvokeModel logging: {e}\")\n", + " return False\n", + "\n", + "def delete_bedrock_invokemodel_log_group(log_group_name):\n", + " log_group_name = \"/aws/bedrock/invokemodel\"\n", + " logs_client = boto3.client('logs')\n", + " try:\n", + " # First, disable the logging configuration in Bedrock\n", + " bedrock_client = boto3.client('bedrock')\n", + " bedrock_client.delete_model_invocation_logging_configuration()\n", + " print(\"Successfully disabled InvokeModel logging for Bedrock\")\n", + "\n", + " # Then, delete the log group\n", + " logs_client.delete_log_group(logGroupName=log_group_name)\n", + " print(f\"Successfully deleted CloudWatch log group: {log_group_name}\")\n", + " return True\n", + " except ClientError as e:\n", + " if e.response['Error']['Code'] == 'ResourceNotFoundException':\n", + " print(f\"Log group {log_group_name} does not exist.\")\n", + " return True\n", + " else:\n", + " print(f\"Error deleting log group or disabling logging: {e}\")\n", + " return False\n", + "\n", + "\n", + "# Call the function\n", + "cw_log_group_name = \"/aws/bedrock/invokemodel\"\n", + "\n", + "if enable_bedrock_invokemodel_logs(cw_log_group_name):\n", + " print(\"Bedrock InvokeModel logging has been set up successfully.\")\n", + " log_group_name = cw_log_group_name\n", + "else:\n", + " print(\"Failed to set up Bedrock InvokeModel logging.\")\n", + "\n", + "\n", + "print(\"Logroup name: \", log_group_name)" + ] + }, + { + "cell_type": "code", + "execution_count": 19, + "id": "ef626f37", + "metadata": {}, + "outputs": [], + "source": [ + "import time\n", + "from datetime import datetime, timezone\n", + "from datetime import timedelta\n", + "import boto3\n", + "import json\n", + "\n", + "cw_client = boto3.client('logs', region_name=region)\n", + "\n", + "def query_model_invocation_log(query_string):\n", + " # Start query\n", + " startTime=int((datetime.now(timezone.utc) - timedelta(minutes=60)).timestamp())\n", + " start_query_response = cw_client.start_query(\n", + " logGroupName=log_group_name,\n", + " startTime=int((datetime.now(timezone.utc) - timedelta(minutes=60)).timestamp()),\n", + " endTime=int(datetime.now(timezone.utc).timestamp()),\n", + " queryString=query_string,\n", + " )\n", + " query_id = start_query_response['queryId']\n", + " # Wait for the query to complete\n", + " response = None\n", + " while response == None or response['status'] == 'Running':\n", + " print('Waiting for query to complete ...')\n", + " time.sleep(1)\n", + " response = cw_client.get_query_results(\n", + " queryId=query_id\n", + " )\n", + "\n", + " # Print the results\n", + " print(f\"Query status: {response['status']}\")\n", + " return response\n", + "\n", + "def print_filter_generation_output(user_query):\n", + " print(user_query)\n", + " # Construct CloudWatch Logs Insights query\n", + " # This query:\n", + " # 1. Selects timestamp and message fields\n", + " # 2. Filters for filter generation task messages\n", + " # 3. Matches the user's query\n", + " # 4. Orders results by most recent first\n", + " response = query_model_invocation_log(\n", + " f\"\"\"\n", + " fields @timestamp, @message\n", + " | filter @message like /Your task is to structure the user's query to match the request schema provided below./\n", + " | filter input.inputBodyJson.messages.0.content.0.text like /{user_query}/\n", + " | sort @timestamp desc\n", + " \"\"\")\n", + " print(response)\n", + " results = response['results']\n", + " if (len(results) == 0):\n", + " print(\"No results found\")\n", + " return\n", + " \n", + " result= results[0][1]['value']\n", + " result_dict = json.loads(result)\n", + " print(f\"Generated filter:\")\n", + " filter_gen_output = result_dict['output']['outputBodyJson']['output']['message']['content'][0]['text']\n", + " print(filter_gen_output)" + ] + }, + { + "cell_type": "markdown", + "id": "f9e2880b", + "metadata": {}, + "source": [ + "### 2.5 Update Knowledge Bases execution role" + ] + }, + { + "cell_type": "code", + "execution_count": 20, + "id": "54d82518", + "metadata": {}, + "outputs": [], + "source": [ + "# Before using autogenerated filters - update the knowledge base execution IAM role with right permissions\n", + "\n", + "iam = boto3.resource('iam')\n", + "client = boto3.client('iam')\n", + "\n", + "def get_attached_policies(role_name):\n", + " response = client.list_attached_role_policies(RoleName=role_name)\n", + " attached_policies = response['AttachedPolicies']\n", + " return attached_policies\n", + "\n", + "# get the knowledge base IAM role name\n", + "get_kb_response = bedrock_agent_client.get_knowledge_base(knowledgeBaseId = kb_id_metadata)\n", + "role_arn = get_kb_response['knowledgeBase']['roleArn']\n", + "role_name = role_arn.split('/')[-1]\n", + "\n", + "# get attached policies\n", + "attached_policies = get_attached_policies(role_name)\n", + "attached_policies\n", + "\n", + "def update_kb_execution_role(attached_policies, region_name):\n", + " \n", + " for policy in attached_policies:\n", + "\n", + " print(policy['PolicyArn'])\n", + " policy_name = policy['PolicyName']\n", + " policy_arn = policy['PolicyArn']\n", + "\n", + " if 'FoundationModel' in policy_arn:\n", + " print('Updating FoundationModel policy: ',policy_arn)\n", + " policy = iam.Policy(policy_arn)\n", + " version = policy.default_version\n", + " policyJson = version.document\n", + " policyJson['Statement'][0]['Resource'].append('arn:aws:bedrock:{}::foundation-model/anthropic.claude-3-sonnet-20240229-v1:0'.format(region)) \n", + " policyJson['Statement'][0]['Resource'].append('arn:aws:bedrock:{}::foundation-model/anthropic.claude-3-5-sonnet-20240620-v1:0'.format(region)) \n", + " \n", + " client.detach_role_policy(RoleName=role_name,\n", + " PolicyArn=policy_arn)\n", + " \n", + " response = client.delete_policy(\n", + " PolicyArn=policy_arn\n", + " )\n", + " print(response)\n", + " \n", + " response = client.create_policy(\n", + " PolicyName= policy_name,\n", + " PolicyDocument=json.dumps(policyJson)\n", + " )\n", + " print(response)\n", + " \n", + " client.attach_role_policy(\n", + " RoleName=role_name,\n", + " PolicyArn=policy_arn\n", + " )" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "540f149e", + "metadata": {}, + "outputs": [], + "source": [ + "update_kb_execution_role(attached_policies, region)\n", + "time.sleep(30)" + ] + }, + { + "cell_type": "markdown", + "id": "4890486e", + "metadata": {}, + "source": [ + "### 2.6 Query the Knowledge Base with Retrieve and Generate API - with metadata (using Autogenerated filters)\n", + "\n", + "Rather creating filters manually, We'll use auto generated filters by Amazon Bedrock Knowledge Bases." + ] + }, + { + "cell_type": "code", + "execution_count": 29, + "id": "b0f62917", + "metadata": {}, + "outputs": [], + "source": [ + "query = \"How many prime members does Amazon have after 2021?\"" + ] + }, + { + "cell_type": "markdown", + "id": "ffc3f298", + "metadata": {}, + "source": [ + "#### 2.6.1 Test - RetreiveAndGenerate API with Autogenerated filters\n", + "\n", + "Let's first test how the `RetrieveAndGenerate` API processes autogenerated filters with a sample user query. As a refresher, the `RetrieveAndGenerate` API is one of the APIs provided by Amazon Bedrock Knowledge Bases. This API queries the knowledge base to retrieve the desired number of document chunks based on a similarity search. It then integrates these retrieved chunks with a LLM to generate an answer to the user's question.\n", + "\n" + ] + }, + { + "cell_type": "markdown", + "id": "0bd75983", + "metadata": {}, + "source": [ + "In the code below, we are configuring the `RetrieveAndGenerate` API to use autogenerated filters based on specific metadata attributes. \n", + "\n", + "The `implicitFilterConfiguration` is a configuration object that defines the metadata attributes that can be used as filters for the similarity search during the retrieval process of the `RetrieveAndGenerate` API. \n", + "\n", + "This configuration specifies which metadata fields can potentially be used for filtering the retrieved document chunks. In this case, we included three fields:\n", + "\n", + "1. `year`: A number representing the year the document is about.\n", + "2. `company`: A string representing the company name the document describes.\n", + "3. `ticker`: A string representing the stock ticker symbol of the company.\n", + "\n", + "Each metadata attribute is defined as an object with the following properties:\n", + "\n", + "- `key`: The name of the metadata attribute.\n", + "- `type`: The data type of the metadata attribute (e.g., NUMBER, STRING).\n", + "- `description`: A human-readable description of the metadata attribute, including any potential values it may take.\n", + "\n", + "The `implicitFilterConfiguration` also specifies the model ARN for the foundation model used to generate filter expressions relevant to the user's query. In this case, it's set to `anthropic.claude-3-5-sonnet-20240620-v1:0`." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "b87ae715", + "metadata": {}, + "outputs": [], + "source": [ + "foundation_model = \"anthropic.claude-3-sonnet-20240229-v1:0\"\n", + "\n", + "response = bedrock_agent_runtime_client.retrieve_and_generate(\n", + " input={\n", + " \"text\": query\n", + " },\n", + " retrieveAndGenerateConfiguration={\n", + " \"type\": \"KNOWLEDGE_BASE\",\n", + " \"knowledgeBaseConfiguration\": {\n", + " 'knowledgeBaseId': kb_id_metadata,\n", + " \"modelArn\": \"arn:aws:bedrock:{}::foundation-model/{}\".format(region, foundation_model),\n", + " \"retrievalConfiguration\": {\n", + " \"vectorSearchConfiguration\": {\n", + " \"numberOfResults\":10,\n", + " # \"filter\": { \"equals\": { \"key\": \"x-amz-bedrock-kb-data-source-id\", \"value\": ds_id }},\n", + " \"implicitFilterConfiguration\": {\n", + " \"metadataAttributes\":[\n", + " {\n", + " \"key\": \"year\",\n", + " \"type\": \"NUMBER\",\n", + " \"description\": \"The year in which the document is about.\"\n", + " },\n", + " {\n", + " \"key\": \"company\",\n", + " \"type\": \"STRING\",\n", + " \"description\": \"The company name the document is describing. Possible values include ['Amazon']\"\n", + " },\n", + " {\n", + " \"key\": \"ticker\",\n", + " \"type\": \"STRING\",\n", + " \"description\": \"The ticker name of the company. Possible values include ['AMZN']\"\n", + " }\n", + " ],\n", + " \"modelArn\": \"arn:aws:bedrock:{}::foundation-model/anthropic.claude-3-5-sonnet-20240620-v1:0\".format(region)\n", + " },\n", + " } \n", + " }\n", + " }\n", + " }\n", + ")\n", + "\n", + "print(response['output']['text'],end='\\n'*2)" + ] + }, + { + "cell_type": "markdown", + "id": "15aa23eb", + "metadata": {}, + "source": [ + "Now, let's check the CloudWatch logs for the autogenerated filter generated for the given user query.\n", + "\n", + "The `RetrieveAndGenerate` API, with the autogenerated filter configuration, processes the user query and generates a structured filter expression based on the metadata attributes. This filter expression is represented as a JSON object containing logical operations (`and`, `or`) and comparison statements (`eq`, `gt`, `lt`, etc.). The comparison statements specify the metadata attributes and their corresponding values to filter the documents.\n", + "\n", + "Behind the scenes, the model determines the logical operations and values that constitute the filter expressions. It does this by analyzing the user query and the configured metadata attributes. The model identifies the relevant metadata attributes and their values mentioned in the query, and then constructs the filter expression accordingly, using appropriate logical operations and comparison statements." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "69ee8a26", + "metadata": {}, + "outputs": [], + "source": [ + "# check cloudwatch logs for the implict filter generated\n", + "time.sleep(60)\n", + "print_filter_generation_output(query)" + ] + }, + { + "cell_type": "markdown", + "id": "392a53df", + "metadata": {}, + "source": [ + "#### 2.6.2 Test - Retrieve API with autogenerated filters" + ] + }, + { + "cell_type": "markdown", + "id": "b1041117", + "metadata": {}, + "source": [ + "Next, we will test the autogenerated filter configuration with the `Retreive` API, another API provided by Knowledge bases for Amazon Bedrock which converts user queries into embeddings, searches the knowledge base, and returns the relevant results, giving you more control to build custom workflows on top of the semantic search results. The output of the Retrieve API includes the the retrieved text chunks, the location type and URI of the source data, as well as the scores of the retrievals.\n", + "\n", + "As we can see, some of the chunks returned by the `Retrieve` API includes associated metadata that has been filtered based on our autogenerated filters. \n", + "\n", + "1. Relevant Year: Notice that the chunks have a `year` metadata field set to greater than 2021, matching our query about \"Amazon's prime members after 2021\".\n", + "\n", + "2. Company Information: The `company` field in the metadata consistently shows \"Amazon\", which aligns with our query about a specific company .\n", + "\n", + "3. Stock Ticker Information: The `ticker` field consistently shows \"AMZN\", which aligns with our query about a specific stock.\n", + "\n", + "This demonstrates how the autogenerated filters are effectively narrowing down the search results based on the query's implied criteria, even without explicit filter specifications. The system has interpreted the user query about revenue in 2023 and automatically applied filters to return the most relevant information from the knowledge base." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "03479cfd", + "metadata": {}, + "outputs": [], + "source": [ + "response_ret_with_implicit_fiters = bedrock_agent_runtime_client.retrieve(\n", + " knowledgeBaseId=kb_id_metadata, \n", + " nextToken='string',\n", + " retrievalConfiguration={\n", + " \"vectorSearchConfiguration\": {\n", + " \"numberOfResults\":10,\n", + " \"implicitFilterConfiguration\": {\n", + " \"metadataAttributes\":[\n", + " {\n", + " \"key\": \"year\",\n", + " \"type\": \"NUMBER\",\n", + " \"description\": \"The year in which the document is about.\"\n", + " },\n", + " {\n", + " \"key\": \"company\",\n", + " \"type\": \"STRING\",\n", + " \"description\": \"The company name the document is describing. Possible values include ['Amazon']\"\n", + " },\n", + " {\n", + " \"key\": \"ticker\",\n", + " \"type\": \"STRING\",\n", + " \"description\": \"The ticker name of the company. Possible values include ['AMZN']\"\n", + " }\n", + " ],\n", + " \"modelArn\": \"arn:aws:bedrock:{}::foundation-model/anthropic.claude-3-5-sonnet-20240620-v1:0\".format(region)\n", + " },\n", + " } \n", + " },\n", + " retrievalQuery={\n", + " \"text\": query\n", + " }\n", + ")\n", + "\n", + "def response_print(retrieve_resp):\n", + "#structure 'retrievalResults': list of contents. Each list has content, location, score, metadata\n", + " for num,chunk in enumerate(retrieve_resp['retrievalResults'],1):\n", + " print(f'Chunk {num}: ',chunk['content']['text'],end='\\n'*2)\n", + " print(f'Chunk {num} Location: ',chunk['location'],end='\\n'*2)\n", + " print(f'Chunk {num} Score: ',chunk['score'],end='\\n'*2)\n", + " print(f'Chunk {num} Metadata: ',chunk['metadata'],end='\\n'*2)\n", + "\n", + "response_print(response_ret_with_implicit_fiters)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "7d4a64e1", + "metadata": {}, + "outputs": [], + "source": [ + "# check cloudwatch logs for the implict filter generated\n", + "time.sleep(20)\n", + "print_filter_generation_output(query)" + ] + }, + { + "cell_type": "markdown", + "id": "5577ab01-5239-4a19-9042-a263e8a3de6b", + "metadata": {}, + "source": [ + "### 2.7 Clean up\n", + "Please make sure to uncomment and run below cells to delete the resources created in this notebook." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "33f8a07a", + "metadata": {}, + "outputs": [], + "source": [ + "# delete local directory\n", + "import shutil\n", + "\n", + "dir_path = \"sec-10-k\" # Replace with the actual path\n", + "\n", + "try:\n", + " shutil.rmtree(dir_path)\n", + " print(f\"Directory '{dir_path}' and its contents have been deleted successfully.\")\n", + "except FileNotFoundError:\n", + " print(f\"Directory '{dir_path}' not found.\")\n", + "except Exception as e:\n", + " print(f\"An error occurred: {e}\")" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "e761a7d9", + "metadata": {}, + "outputs": [], + "source": [ + "# Delete log group name\n", + "delete_bedrock_invokemodel_log_group(log_group_name)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "9ab05eb1-76c9-47b7-8d28-16ee720966d9", + "metadata": { + "tags": [] + }, + "outputs": [], + "source": [ + "## Empty and delete S3 Bucket\n", + "\n", + "objects = s3_client.list_objects(Bucket=bucket_name) \n", + "if 'Contents' in objects:\n", + " for obj in objects['Contents']:\n", + " s3_client.delete_object(Bucket=bucket_name, Key=obj['Key']) \n", + "s3_client.delete_bucket(Bucket=bucket_name)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "a0cab3a2-e121-4d65-9254-4d318cf428f1", + "metadata": { + "tags": [] + }, + "outputs": [], + "source": [ + "print(\"===============================Knowledge base==============================\")\n", + "knowledge_base_metadata.delete_kb(delete_s3_bucket=True, delete_iam_roles_and_policies=True)" + ] + } + ], + "metadata": { + "availableInstances": [ + { + "_defaultOrder": 0, + "_isFastLaunch": true, + "category": "General purpose", + "gpuNum": 0, + "hideHardwareSpecs": false, + "memoryGiB": 4, + "name": "ml.t3.medium", + "vcpuNum": 2 + }, + { + "_defaultOrder": 1, + "_isFastLaunch": false, + "category": "General purpose", + "gpuNum": 0, + "hideHardwareSpecs": false, + "memoryGiB": 8, + "name": "ml.t3.large", + "vcpuNum": 2 + }, + { + "_defaultOrder": 2, + "_isFastLaunch": false, + "category": "General purpose", + "gpuNum": 0, + "hideHardwareSpecs": false, + "memoryGiB": 16, + "name": "ml.t3.xlarge", + "vcpuNum": 4 + }, + { + "_defaultOrder": 3, + "_isFastLaunch": false, + "category": "General purpose", + "gpuNum": 0, + "hideHardwareSpecs": false, + "memoryGiB": 32, + "name": "ml.t3.2xlarge", + "vcpuNum": 8 + }, + { + "_defaultOrder": 4, + "_isFastLaunch": true, + "category": "General purpose", + "gpuNum": 0, + "hideHardwareSpecs": false, + "memoryGiB": 8, + "name": "ml.m5.large", + "vcpuNum": 2 + }, + { + "_defaultOrder": 5, + "_isFastLaunch": false, + "category": "General purpose", + "gpuNum": 0, + "hideHardwareSpecs": false, + "memoryGiB": 16, + "name": "ml.m5.xlarge", + "vcpuNum": 4 + }, + { + "_defaultOrder": 6, + "_isFastLaunch": false, + "category": "General purpose", + "gpuNum": 0, + "hideHardwareSpecs": false, + "memoryGiB": 32, + "name": "ml.m5.2xlarge", + "vcpuNum": 8 + }, + { + "_defaultOrder": 7, + "_isFastLaunch": false, + "category": "General purpose", + "gpuNum": 0, + "hideHardwareSpecs": false, + "memoryGiB": 64, + "name": "ml.m5.4xlarge", + "vcpuNum": 16 + }, + { + "_defaultOrder": 8, + "_isFastLaunch": false, + "category": "General purpose", + "gpuNum": 0, + "hideHardwareSpecs": false, + "memoryGiB": 128, + "name": "ml.m5.8xlarge", + "vcpuNum": 32 + }, + { + "_defaultOrder": 9, + "_isFastLaunch": false, + "category": "General purpose", + "gpuNum": 0, + "hideHardwareSpecs": false, + "memoryGiB": 192, + "name": "ml.m5.12xlarge", + "vcpuNum": 48 + }, + { + "_defaultOrder": 10, + "_isFastLaunch": false, + "category": "General purpose", + "gpuNum": 0, + "hideHardwareSpecs": false, + "memoryGiB": 256, + "name": "ml.m5.16xlarge", + "vcpuNum": 64 + }, + { + "_defaultOrder": 11, + "_isFastLaunch": false, + "category": "General purpose", + "gpuNum": 0, + "hideHardwareSpecs": false, + "memoryGiB": 384, + "name": "ml.m5.24xlarge", + "vcpuNum": 96 + }, + { + "_defaultOrder": 12, + "_isFastLaunch": false, + "category": "General purpose", + "gpuNum": 0, + "hideHardwareSpecs": false, + "memoryGiB": 8, + "name": "ml.m5d.large", + "vcpuNum": 2 + }, + { + "_defaultOrder": 13, + "_isFastLaunch": false, + "category": "General purpose", + "gpuNum": 0, + "hideHardwareSpecs": false, + "memoryGiB": 16, + "name": "ml.m5d.xlarge", + "vcpuNum": 4 + }, + { + "_defaultOrder": 14, + "_isFastLaunch": false, + "category": "General purpose", + "gpuNum": 0, + "hideHardwareSpecs": false, + "memoryGiB": 32, + "name": "ml.m5d.2xlarge", + "vcpuNum": 8 + }, + { + "_defaultOrder": 15, + "_isFastLaunch": false, + "category": "General purpose", + "gpuNum": 0, + "hideHardwareSpecs": false, + "memoryGiB": 64, + "name": "ml.m5d.4xlarge", + "vcpuNum": 16 + }, + { + "_defaultOrder": 16, + "_isFastLaunch": false, + "category": "General purpose", + "gpuNum": 0, + "hideHardwareSpecs": false, + "memoryGiB": 128, + "name": "ml.m5d.8xlarge", + "vcpuNum": 32 + }, + { + "_defaultOrder": 17, + "_isFastLaunch": false, + "category": "General purpose", + "gpuNum": 0, + "hideHardwareSpecs": false, + "memoryGiB": 192, + "name": "ml.m5d.12xlarge", + "vcpuNum": 48 + }, + { + "_defaultOrder": 18, + "_isFastLaunch": false, + "category": "General purpose", + "gpuNum": 0, + "hideHardwareSpecs": false, + "memoryGiB": 256, + "name": "ml.m5d.16xlarge", + "vcpuNum": 64 + }, + { + "_defaultOrder": 19, + "_isFastLaunch": false, + "category": "General purpose", + "gpuNum": 0, + "hideHardwareSpecs": false, + "memoryGiB": 384, + "name": "ml.m5d.24xlarge", + "vcpuNum": 96 + }, + { + "_defaultOrder": 20, + "_isFastLaunch": false, + "category": "General purpose", + "gpuNum": 0, + "hideHardwareSpecs": true, + "memoryGiB": 0, + "name": "ml.geospatial.interactive", + "supportedImageNames": [ + "sagemaker-geospatial-v1-0" + ], + "vcpuNum": 0 + }, + { + "_defaultOrder": 21, + "_isFastLaunch": true, + "category": "Compute optimized", + "gpuNum": 0, + "hideHardwareSpecs": false, + "memoryGiB": 4, + "name": "ml.c5.large", + "vcpuNum": 2 + }, + { + "_defaultOrder": 22, + "_isFastLaunch": false, + "category": "Compute optimized", + "gpuNum": 0, + "hideHardwareSpecs": false, + "memoryGiB": 8, + "name": "ml.c5.xlarge", + "vcpuNum": 4 + }, + { + "_defaultOrder": 23, + "_isFastLaunch": false, + "category": "Compute optimized", + "gpuNum": 0, + "hideHardwareSpecs": false, + "memoryGiB": 16, + "name": "ml.c5.2xlarge", + "vcpuNum": 8 + }, + { + "_defaultOrder": 24, + "_isFastLaunch": false, + "category": "Compute optimized", + "gpuNum": 0, + "hideHardwareSpecs": false, + "memoryGiB": 32, + "name": "ml.c5.4xlarge", + "vcpuNum": 16 + }, + { + "_defaultOrder": 25, + "_isFastLaunch": false, + "category": "Compute optimized", + "gpuNum": 0, + "hideHardwareSpecs": false, + "memoryGiB": 72, + "name": "ml.c5.9xlarge", + "vcpuNum": 36 + }, + { + "_defaultOrder": 26, + "_isFastLaunch": false, + "category": "Compute optimized", + "gpuNum": 0, + "hideHardwareSpecs": false, + "memoryGiB": 96, + "name": "ml.c5.12xlarge", + "vcpuNum": 48 + }, + { + "_defaultOrder": 27, + "_isFastLaunch": false, + "category": "Compute optimized", + "gpuNum": 0, + "hideHardwareSpecs": false, + "memoryGiB": 144, + "name": "ml.c5.18xlarge", + "vcpuNum": 72 + }, + { + "_defaultOrder": 28, + "_isFastLaunch": false, + "category": "Compute optimized", + "gpuNum": 0, + "hideHardwareSpecs": false, + "memoryGiB": 192, + "name": "ml.c5.24xlarge", + "vcpuNum": 96 + }, + { + "_defaultOrder": 29, + "_isFastLaunch": true, + "category": "Accelerated computing", + "gpuNum": 1, + "hideHardwareSpecs": false, + "memoryGiB": 16, + "name": "ml.g4dn.xlarge", + "vcpuNum": 4 + }, + { + "_defaultOrder": 30, + "_isFastLaunch": false, + "category": "Accelerated computing", + "gpuNum": 1, + "hideHardwareSpecs": false, + "memoryGiB": 32, + "name": "ml.g4dn.2xlarge", + "vcpuNum": 8 + }, + { + "_defaultOrder": 31, + "_isFastLaunch": false, + "category": "Accelerated computing", + "gpuNum": 1, + "hideHardwareSpecs": false, + "memoryGiB": 64, + "name": "ml.g4dn.4xlarge", + "vcpuNum": 16 + }, + { + "_defaultOrder": 32, + "_isFastLaunch": false, + "category": "Accelerated computing", + "gpuNum": 1, + "hideHardwareSpecs": false, + "memoryGiB": 128, + "name": "ml.g4dn.8xlarge", + "vcpuNum": 32 + }, + { + "_defaultOrder": 33, + "_isFastLaunch": false, + "category": "Accelerated computing", + "gpuNum": 4, + "hideHardwareSpecs": false, + "memoryGiB": 192, + "name": "ml.g4dn.12xlarge", + "vcpuNum": 48 + }, + { + "_defaultOrder": 34, + "_isFastLaunch": false, + "category": "Accelerated computing", + "gpuNum": 1, + "hideHardwareSpecs": false, + "memoryGiB": 256, + "name": "ml.g4dn.16xlarge", + "vcpuNum": 64 + }, + { + "_defaultOrder": 35, + "_isFastLaunch": false, + "category": "Accelerated computing", + "gpuNum": 1, + "hideHardwareSpecs": false, + "memoryGiB": 61, + "name": "ml.p3.2xlarge", + "vcpuNum": 8 + }, + { + "_defaultOrder": 36, + "_isFastLaunch": false, + "category": "Accelerated computing", + "gpuNum": 4, + "hideHardwareSpecs": false, + "memoryGiB": 244, + "name": "ml.p3.8xlarge", + "vcpuNum": 32 + }, + { + "_defaultOrder": 37, + "_isFastLaunch": false, + "category": "Accelerated computing", + "gpuNum": 8, + "hideHardwareSpecs": false, + "memoryGiB": 488, + "name": "ml.p3.16xlarge", + "vcpuNum": 64 + }, + { + "_defaultOrder": 38, + "_isFastLaunch": false, + "category": "Accelerated computing", + "gpuNum": 8, + "hideHardwareSpecs": false, + "memoryGiB": 768, + "name": "ml.p3dn.24xlarge", + "vcpuNum": 96 + }, + { + "_defaultOrder": 39, + "_isFastLaunch": false, + "category": "Memory Optimized", + "gpuNum": 0, + "hideHardwareSpecs": false, + "memoryGiB": 16, + "name": "ml.r5.large", + "vcpuNum": 2 + }, + { + "_defaultOrder": 40, + "_isFastLaunch": false, + "category": "Memory Optimized", + "gpuNum": 0, + "hideHardwareSpecs": false, + "memoryGiB": 32, + "name": "ml.r5.xlarge", + "vcpuNum": 4 + }, + { + "_defaultOrder": 41, + "_isFastLaunch": false, + "category": "Memory Optimized", + "gpuNum": 0, + "hideHardwareSpecs": false, + "memoryGiB": 64, + "name": "ml.r5.2xlarge", + "vcpuNum": 8 + }, + { + "_defaultOrder": 42, + "_isFastLaunch": false, + "category": "Memory Optimized", + "gpuNum": 0, + "hideHardwareSpecs": false, + "memoryGiB": 128, + "name": "ml.r5.4xlarge", + "vcpuNum": 16 + }, + { + "_defaultOrder": 43, + "_isFastLaunch": false, + "category": "Memory Optimized", + "gpuNum": 0, + "hideHardwareSpecs": false, + "memoryGiB": 256, + "name": "ml.r5.8xlarge", + "vcpuNum": 32 + }, + { + "_defaultOrder": 44, + "_isFastLaunch": false, + "category": "Memory Optimized", + "gpuNum": 0, + "hideHardwareSpecs": false, + "memoryGiB": 384, + "name": "ml.r5.12xlarge", + "vcpuNum": 48 + }, + { + "_defaultOrder": 45, + "_isFastLaunch": false, + "category": "Memory Optimized", + "gpuNum": 0, + "hideHardwareSpecs": false, + "memoryGiB": 512, + "name": "ml.r5.16xlarge", + "vcpuNum": 64 + }, + { + "_defaultOrder": 46, + "_isFastLaunch": false, + "category": "Memory Optimized", + "gpuNum": 0, + "hideHardwareSpecs": false, + "memoryGiB": 768, + "name": "ml.r5.24xlarge", + "vcpuNum": 96 + }, + { + "_defaultOrder": 47, + "_isFastLaunch": false, + "category": "Accelerated computing", + "gpuNum": 1, + "hideHardwareSpecs": false, + "memoryGiB": 16, + "name": "ml.g5.xlarge", + "vcpuNum": 4 + }, + { + "_defaultOrder": 48, + "_isFastLaunch": false, + "category": "Accelerated computing", + "gpuNum": 1, + "hideHardwareSpecs": false, + "memoryGiB": 32, + "name": "ml.g5.2xlarge", + "vcpuNum": 8 + }, + { + "_defaultOrder": 49, + "_isFastLaunch": false, + "category": "Accelerated computing", + "gpuNum": 1, + "hideHardwareSpecs": false, + "memoryGiB": 64, + "name": "ml.g5.4xlarge", + "vcpuNum": 16 + }, + { + "_defaultOrder": 50, + "_isFastLaunch": false, + "category": "Accelerated computing", + "gpuNum": 1, + "hideHardwareSpecs": false, + "memoryGiB": 128, + "name": "ml.g5.8xlarge", + "vcpuNum": 32 + }, + { + "_defaultOrder": 51, + "_isFastLaunch": false, + "category": "Accelerated computing", + "gpuNum": 1, + "hideHardwareSpecs": false, + "memoryGiB": 256, + "name": "ml.g5.16xlarge", + "vcpuNum": 64 + }, + { + "_defaultOrder": 52, + "_isFastLaunch": false, + "category": "Accelerated computing", + "gpuNum": 4, + "hideHardwareSpecs": false, + "memoryGiB": 192, + "name": "ml.g5.12xlarge", + "vcpuNum": 48 + }, + { + "_defaultOrder": 53, + "_isFastLaunch": false, + "category": "Accelerated computing", + "gpuNum": 4, + "hideHardwareSpecs": false, + "memoryGiB": 384, + "name": "ml.g5.24xlarge", + "vcpuNum": 96 + }, + { + "_defaultOrder": 54, + "_isFastLaunch": false, + "category": "Accelerated computing", + "gpuNum": 8, + "hideHardwareSpecs": false, + "memoryGiB": 768, + "name": "ml.g5.48xlarge", + "vcpuNum": 192 + }, + { + "_defaultOrder": 55, + "_isFastLaunch": false, + "category": "Accelerated computing", + "gpuNum": 8, + "hideHardwareSpecs": false, + "memoryGiB": 1152, + "name": "ml.p4d.24xlarge", + "vcpuNum": 96 + }, + { + "_defaultOrder": 56, + "_isFastLaunch": false, + "category": "Accelerated computing", + "gpuNum": 8, + "hideHardwareSpecs": false, + "memoryGiB": 1152, + "name": "ml.p4de.24xlarge", + "vcpuNum": 96 + }, + { + "_defaultOrder": 57, + "_isFastLaunch": false, + "category": "Accelerated computing", + "gpuNum": 0, + "hideHardwareSpecs": false, + "memoryGiB": 32, + "name": "ml.trn1.2xlarge", + "vcpuNum": 8 + }, + { + "_defaultOrder": 58, + "_isFastLaunch": false, + "category": "Accelerated computing", + "gpuNum": 0, + "hideHardwareSpecs": false, + "memoryGiB": 512, + "name": "ml.trn1.32xlarge", + "vcpuNum": 128 + }, + { + "_defaultOrder": 59, + "_isFastLaunch": false, + "category": "Accelerated computing", + "gpuNum": 0, + "hideHardwareSpecs": false, + "memoryGiB": 512, + "name": "ml.trn1n.32xlarge", + "vcpuNum": 128 + } + ], + "instance_type": "ml.t3.medium", + "kernelspec": { + "display_name": "Python 3 (ipykernel)", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.10.13" + } + }, + "nbformat": 4, + "nbformat_minor": 5 +} diff --git a/02-optimizing-accuracy-retrieved-results/re-ranking_using_kb.ipynb b/02-optimizing-accuracy-retrieved-results/re-ranking_using_kb.ipynb new file mode 100644 index 0000000..32c1ba7 --- /dev/null +++ b/02-optimizing-accuracy-retrieved-results/re-ranking_using_kb.ipynb @@ -0,0 +1,1574 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "id": "15c08f81", + "metadata": {}, + "source": [ + "# Re-ranking\n", + "\n", + "Amazon Bedrock provides access to reranker models that you can use when querying to improve the relevance of the retrieved results. reranker model calculates the relevance of chunks to a query and reorders the results based on the scores that it calculates. By using a reranker model, you can return responses that are better suited to answering the query. \n", + "\n", + "Reranker models are trained to identify relevance signals based on a query and then use those signals to rank documents. Because of this, the models can provide more relevant, more accurate results.\n", + "\n", + "If you're using `Amazon Bedrock Knowledge Bases` for building your Retrieval Augmented Generation (RAG) application, use a reranker model while calling the `Retrieve` or `RetrieveAndGenerate operation`. The results from reranking override the default ranking that Amazon Bedrock Knowledge Bases determines.\n", + "\n", + "This notebook demonstrates the use of **reranking model** with Amazon Bedrock Knowledge Bases, through the Rerank API which will help to further improve the accuracy and relevance of RAG applications. With a reranker model, you can retrieve fewer, but more relevant, results. By feeding these results to the foundation model that you use to generate a response, you can also decrease cost and latency.\n", + "\n", + "Let's explore how to implement and utilize reranking models with Amazon Bedrock Knowledge Bases for an example use case." + ] + }, + { + "cell_type": "markdown", + "id": "ece99ba7", + "metadata": {}, + "source": [ + "## 1. Setup\n", + "Before running the rest of this notebook, you'll need to run the cells below to (ensure necessary libraries are installed and) connect to Bedrock.\n", + "\n", + "Please ignore any pip dependency error (if you see any while installing libraries)" + ] + }, + { + "cell_type": "code", + "execution_count": 1, + "id": "dc89fe3a", + "metadata": {}, + "outputs": [], + "source": [ + "%pip install --force-reinstall -q -r utils/requirements.txt --quiet" + ] + }, + { + "cell_type": "code", + "execution_count": 2, + "id": "57056c5d", + "metadata": {}, + "outputs": [], + "source": [ + "%pip install --upgrade boto3" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "165e5495", + "metadata": {}, + "outputs": [], + "source": [ + "# restart kernel\n", + "from IPython.core.display import HTML\n", + "HTML(\"\")" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "7c1c0eb1", + "metadata": {}, + "outputs": [], + "source": [ + "import boto3\n", + "print(boto3.__version__)" + ] + }, + { + "cell_type": "code", + "execution_count": 3, + "id": "7173b4bf", + "metadata": {}, + "outputs": [], + "source": [ + "import warnings\n", + "warnings.filterwarnings('ignore')" + ] + }, + { + "cell_type": "code", + "execution_count": 4, + "id": "84241929", + "metadata": {}, + "outputs": [], + "source": [ + "import os\n", + "import sys\n", + "import time\n", + "import boto3\n", + "import logging\n", + "import pprint\n", + "import json\n", + "\n", + "# Set the path to import module\n", + "from pathlib import Path\n", + "current_path = Path().resolve()\n", + "current_path = current_path.parent\n", + "if str(current_path) not in sys.path:\n", + " sys.path.append(str(current_path))\n", + "# Print sys.path to verify\n", + "# print(sys.path)\n", + "\n", + "from utils.knowledge_base import BedrockKnowledgeBase" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "cda1c18f", + "metadata": {}, + "outputs": [], + "source": [ + "#Clients\n", + "s3_client = boto3.client('s3')\n", + "sts_client = boto3.client('sts')\n", + "session = boto3.session.Session(region_name = 'us-west-2')\n", + "region = session.region_name\n", + "account_id = sts_client.get_caller_identity()[\"Account\"]\n", + "bedrock_agent_client = boto3.client('bedrock-agent')\n", + "bedrock_agent_runtime_client = boto3.client('bedrock-agent-runtime') \n", + "logging.basicConfig(format='[%(asctime)s] p%(process)s {%(filename)s:%(lineno)d} %(levelname)s - %(message)s', level=logging.INFO)\n", + "logger = logging.getLogger(__name__)\n", + "region, account_id" + ] + }, + { + "cell_type": "code", + "execution_count": 8, + "id": "5d74b5be", + "metadata": {}, + "outputs": [], + "source": [ + "import time\n", + "\n", + "# Get the current timestamp\n", + "current_time = time.time()\n", + "\n", + "# Format the timestamp as a string\n", + "timestamp_str = time.strftime(\"%Y%m%d%H%M%S\", time.localtime(current_time))[-7:]\n", + "# Create the suffix using the timestamp\n", + "suffix = f\"{timestamp_str}\"\n", + "knowledge_base_name = 'reranking-kb'\n", + "knowledge_base_description = \"Knowledge Base for re-ranking.\"\n", + "bucket_name = f'{knowledge_base_name}-{suffix}'\n", + "foundation_model = \"anthropic.claude-3-sonnet-20240229-v1:0\"" + ] + }, + { + "cell_type": "markdown", + "id": "e5142d7f", + "metadata": {}, + "source": [ + "## 2 - Create knowledge bases with fixed chunking strategy\n", + "Let's start by creating a [Knowledge Base for Amazon Bedrock](https://aws.amazon.com/bedrock/knowledge-bases/) to store video games data in csv format. Knowledge Bases allow you to integrate with different vector databases including [Amazon OpenSearch Serverless](https://aws.amazon.com/opensearch-service/features/serverless/), [Amazon Aurora](https://aws.amazon.com/rds/aurora/), [Pinecone](http://app.pinecone.io/bedrock-integration), [Redis Enterprise]() and [MongoDB Atlas](). For this example, we will integrate the knowledge base with Amazon OpenSearch Serverless. To do so, we will use the helper class `BedrockKnowledgeBase` which will create the knowledge base and all of its pre-requisites:\n", + "1. IAM roles and policies\n", + "2. S3 bucket\n", + "3. Amazon OpenSearch Serverless encryption, network and data access policies\n", + "4. Amazon OpenSearch Serverless collection\n", + "5. Amazon OpenSearch Serverless vector index\n", + "6. Knowledge base\n", + "7. Knowledge base data source" + ] + }, + { + "cell_type": "markdown", + "id": "8283567d", + "metadata": {}, + "source": [ + "We will create a knowledge base using fixed chunking strategy. \n", + "\n", + "You can chhose different chunking strategies by changing the below parameter values: \n", + "```\n", + "\"chunkingStrategy\": \"FIXED_SIZE | NONE | HIERARCHICAL | SEMANTIC\"\n", + "```" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "258fbb58", + "metadata": {}, + "outputs": [], + "source": [ + "knowledge_base_metadata = BedrockKnowledgeBase(\n", + " kb_name=f'{knowledge_base_name}-{suffix}',\n", + " kb_description=knowledge_base_description,\n", + " data_bucket_name=bucket_name, \n", + " chunking_strategy = \"FIXED_SIZE\", \n", + " suffix = suffix\n", + ")" + ] + }, + { + "cell_type": "markdown", + "id": "c79183c7", + "metadata": {}, + "source": [ + "### 2.1 Download Amazon 2019, 2020, 2021, 2022, & 2023 annual reports and upload it to Amazon S3\n", + "\n", + "Now that we have created the knowledge base, let's populate it with the `sec-10-k reports` dataset to KB. This data is being downloaded from [here](https://ir.aboutamazon.com/annual-reports-proxies-and-shareholder-letters/default.aspx). This data is about Amazon's annual reports, proxies and shareholder letters." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "c758da68", + "metadata": {}, + "outputs": [], + "source": [ + "import os\n", + "\n", + "def create_directory(directory_name): \n", + " if not os.path.exists(directory_name):\n", + " os.makedirs(directory_name)\n", + " print(f\"Directory '{directory_name}' created successfully.\")\n", + " else:\n", + " print(f\"Directory '{directory_name}' already exists.\")\n", + "\n", + "# Call the function to create the directory\n", + "create_directory(\"sec-10-k\")" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "a2bf67c7", + "metadata": {}, + "outputs": [], + "source": [ + "import requests\n", + "\n", + "def download_file(url, filename):\n", + " # Send a GET request to the URL\n", + " response = requests.get(url)\n", + " \n", + " # Check if the request was successful\n", + " if response.status_code == 200:\n", + " # Open the file in write-binary mode\n", + " with open(filename, 'wb') as file:\n", + " # Write the content of the response to the file\n", + " file.write(response.content)\n", + " print(f\"File downloaded successfully: {filename}\")\n", + " else:\n", + " print(f\"Failed to download file. Status code: {response.status_code}\")\n", + "\n", + "# URL of the files to download\n", + "urls = [\"https://s2.q4cdn.com/299287126/files/doc_financials/2024/ar/Amazon-com-Inc-2023-Annual-Report.pdf\",\n", + " \"https://s2.q4cdn.com/299287126/files/doc_financials/2023/ar/Amazon-2022-Annual-Report.pdf\",\n", + " \"https://s2.q4cdn.com/299287126/files/doc_financials/2022/ar/Amazon-2021-Annual-Report.pdf\",\n", + " \"https://s2.q4cdn.com/299287126/files/doc_financials/2021/ar/Amazon-2020-Annual-Report.pdf\",\n", + " \"https://s2.q4cdn.com/299287126/files/doc_financials/2020/ar/2019-Annual-Report.pdf\"]\n", + "\n", + "\n", + "for url in urls:\n", + " # Name for the downloaded file\n", + " filename = url.split('/')[-1]\n", + "\n", + " # Path to save the downloaded file\n", + " filepath = f\"./sec-10-k/{filename}\"\n", + "\n", + " # Call the function to download the file\n", + " download_file(url, filepath)" + ] + }, + { + "cell_type": "markdown", + "id": "70b83f68", + "metadata": {}, + "source": [ + "Let's upload the annual reports data available in the `sec-10-k` folder to s3." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "40e12fc8", + "metadata": {}, + "outputs": [], + "source": [ + "def upload_directory(path, bucket_name):\n", + " for root,dirs,files in os.walk(path):\n", + " for file in files:\n", + " if not file.startswith('.DS_Store'):\n", + " file_to_upload = os.path.join(root,file)\n", + " print(f\"uploading file {file_to_upload} to {bucket_name}\")\n", + " s3_client.upload_file(file_to_upload,bucket_name,file)\n", + "\n", + "# upload metadata file to S3\n", + "upload_directory(\"sec-10-k\", bucket_name)" + ] + }, + { + "cell_type": "markdown", + "id": "b70a4b4b", + "metadata": {}, + "source": [ + "Now start the ingestion job. Since, we are using the same documents as used for fixed chunking, we are skipping the step to upload documents to s3 bucket. " + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "241a6ab9", + "metadata": {}, + "outputs": [], + "source": [ + "# ensure that the kb is available\n", + "time.sleep(30)\n", + "# sync knowledge base\n", + "knowledge_base_metadata.start_ingestion_job()" + ] + }, + { + "cell_type": "markdown", + "id": "bad55ab6", + "metadata": {}, + "source": [ + "Finally we save the Knowledge Base Id to test the solution at a later stage. " + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "677c97ce", + "metadata": {}, + "outputs": [], + "source": [ + "kb_id = knowledge_base_metadata.get_knowledge_base_id()" + ] + }, + { + "cell_type": "markdown", + "id": "fcc80032", + "metadata": {}, + "source": [ + "## 3. Evaluate the relevance of query responses with and without Re-ranking (using Ragas)" + ] + }, + { + "cell_type": "markdown", + "id": "1cea8edf", + "metadata": {}, + "source": [ + "Define models for generation, evaluation and re-ranking" + ] + }, + { + "cell_type": "code", + "execution_count": 14, + "id": "bfa5a6bb", + "metadata": {}, + "outputs": [], + "source": [ + "from langchain.llms.bedrock import Bedrock\n", + "from langchain_aws import ChatBedrock\n", + "from langchain_aws import BedrockEmbeddings\n", + "\n", + "bedrock_client = boto3.client('bedrock-runtime')\n", + "\n", + "TEXT_GENERATION_MODEL_ID = \"anthropic.claude-3-haiku-20240307-v1:0\"\n", + "EVALUATION_MODEL_ID = \"anthropic.claude-3-sonnet-20240229-v1:0\"\n", + "EMBEDDING_MODEL_ID = \"amazon.titan-embed-text-v2:0\"\n", + "\n", + "# Reranker model: there are two reranker models available at launch\n", + "AMAZON_RERANKER_MODEL_ID = \"amazon.rerank-v1:0\"\n", + "COHERE_RERANKER_MODEL_ID = \"cohere.rerank-v3-5:0\"\n", + "\n", + "\n", + "llm_for_evaluation = ChatBedrock(model_id=\"anthropic.claude-3-sonnet-20240229-v1:0\", client=bedrock_client)\n", + "bedrock_embeddings = BedrockEmbeddings(model_id=\"amazon.titan-embed-text-v2:0\", client=bedrock_client)\n" + ] + }, + { + "cell_type": "markdown", + "id": "1c336de9", + "metadata": {}, + "source": [ + "#### 3.1 Update Knowledge Bases execution role" + ] + }, + { + "cell_type": "code", + "execution_count": 17, + "id": "aeac148b", + "metadata": {}, + "outputs": [], + "source": [ + "# Before using autogenerated filters - update the knowledge base execution IAM role with right permissions\n", + "\n", + "iam = boto3.resource('iam')\n", + "client = boto3.client('iam')\n", + "\n", + "def get_attached_policies(role_name):\n", + " response = client.list_attached_role_policies(RoleName=role_name)\n", + " attached_policies = response['AttachedPolicies']\n", + " return attached_policies\n", + "\n", + "# get the knowledge base IAM role name\n", + "get_kb_response = bedrock_agent_client.get_knowledge_base(knowledgeBaseId = kb_id)\n", + "role_arn = get_kb_response['knowledgeBase']['roleArn']\n", + "role_name = role_arn.split('/')[-1]\n", + "\n", + "# get attached policies\n", + "attached_policies = get_attached_policies(role_name)\n", + "attached_policies\n", + "\n", + "def update_kb_execution_role(attached_policies, region_name):\n", + " \n", + " for policy in attached_policies:\n", + "\n", + " print(policy['PolicyArn'])\n", + " policy_name = policy['PolicyName']\n", + " policy_arn = policy['PolicyArn']\n", + "\n", + " if 'FoundationModel' in policy_arn:\n", + " print('Updating FoundationModel policy: ',policy_arn)\n", + " policy = iam.Policy(policy_arn)\n", + " version = policy.default_version\n", + " policyJson = version.document\n", + " policyJson['Statement'][0]['Resource'].append(f'arn:aws:bedrock:{region}::foundation-model/{TEXT_GENERATION_MODEL_ID}')\n", + " policyJson['Statement'][0]['Resource'].append(f'arn:aws:bedrock:{region}::foundation-model/{EVALUATION_MODEL_ID}') \n", + " policyJson['Statement'][0]['Resource'].append(f'arn:aws:bedrock:{region}::foundation-model/{AMAZON_RERANKER_MODEL_ID}') \n", + " policyJson['Statement'][0]['Resource'].append(f'arn:aws:bedrock:{region}::foundation-model/{COHERE_RERANKER_MODEL_ID}') \n", + " \n", + " client.detach_role_policy(RoleName=role_name,\n", + " PolicyArn=policy_arn)\n", + " \n", + " response = client.delete_policy(\n", + " PolicyArn=policy_arn\n", + " )\n", + " print(response)\n", + " \n", + " response = client.create_policy(\n", + " PolicyName= policy_name,\n", + " PolicyDocument=json.dumps(policyJson)\n", + " )\n", + " print(response)\n", + " \n", + " client.attach_role_policy(\n", + " RoleName=role_name,\n", + " PolicyArn=policy_arn\n", + " )" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "b3521cb4", + "metadata": {}, + "outputs": [], + "source": [ + "update_kb_execution_role(attached_policies, region)\n", + "# time.sleep(30)" + ] + }, + { + "cell_type": "markdown", + "id": "529118c5", + "metadata": {}, + "source": [ + "#### 3.2 Customize retrieve and generate configuraion" + ] + }, + { + "cell_type": "code", + "execution_count": 19, + "id": "df68891d", + "metadata": {}, + "outputs": [], + "source": [ + "def retrieve_and_generate(query, reranker_model=None, kb_id=None, TEXT_GENERATION_MODEL_ID=None, metadata_filters=None):\n", + " \n", + " # Prepare retrieval configuration\n", + " retrieval_config = {\n", + " \"vectorSearchConfiguration\": {\n", + " \"numberOfResults\": 30 if reranker_model else 3\n", + " }\n", + " }\n", + "\n", + " if reranker_model:\n", + " retrieval_config[\"vectorSearchConfiguration\"][\"rerankingConfiguration\"] = {\n", + " \"type\": \"BEDROCK_RERANKING_MODEL\",\n", + " \"bedrockRerankingConfiguration\": {\n", + " \"modelConfiguration\": {\n", + " \"modelArn\": f'arn:aws:bedrock:{region}::foundation-model/{reranker_model}',\n", + " },\n", + " \"numberOfRerankedResults\": 3\n", + " }\n", + " }\n", + "\n", + " if metadata_filters:\n", + " retrieval_config[\"vectorSearchConfiguration\"][\"rerankingConfiguration\"][\"bedrockRerankingConfiguration\"][\"metadataConfiguration\"] = {\n", + " \"selectionMode\" : \"SELECTIVE\",\n", + " \"selectiveModeConfiguration\" : {\n", + " \"fieldsToInclude\": [{\n", + " \"fieldName\": \"year\",\n", + " }]\n", + " }\n", + " }\n", + " \n", + "\n", + " # Call the retrieve and generate API\n", + " start = time.time()\n", + " response = bedrock_agent_runtime_client.retrieve_and_generate(\n", + " input={'text': query},\n", + " retrieveAndGenerateConfiguration={\n", + " 'type': 'KNOWLEDGE_BASE',\n", + " 'knowledgeBaseConfiguration': {\n", + " 'knowledgeBaseId': kb_id,\n", + " 'modelArn': f'arn:aws:bedrock:{region}::foundation-model/{TEXT_GENERATION_MODEL_ID}',\n", + " 'retrievalConfiguration': retrieval_config,\n", + " },\n", + " }\n", + " )\n", + " time_spent = time.time() - start\n", + "\n", + " print(f\"[Response] : {response['output']['text']}\\n\")\n", + " print(f\"[Invocation time] : {time_spent}\\n\")\n", + "\n", + " return response\n" + ] + }, + { + "cell_type": "markdown", + "id": "fdc724b4", + "metadata": {}, + "source": [ + "#### 3.3 Prepare dataset for evaluation" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "b086554a", + "metadata": {}, + "outputs": [], + "source": [ + "from datasets import Dataset\n", + "from ragas import evaluate\n", + "from ragas.metrics import (\n", + " context_relevancy,\n", + " context_recall,\n", + " context_precision,\n", + " context_entity_recall,\n", + " answer_correctness,\n", + ")\n", + "\n", + "#specify the metrics here\n", + "metrics = [\n", + " context_relevancy,\n", + " context_recall,\n", + " context_precision,\n", + " context_entity_recall,\n", + " answer_correctness,\n", + "]\n", + "\n", + "questions = [\n", + " \"How many jobs did Amazon create in 2020, and what was its total global workforce after this expansion?\",\n", + " \"How does the 2023 net sales mix reflect Amazon's global priorities and strategic investments across segments?\",\n", + " \"How did foreign exchange rate fluctuations impact Amazon's net sales and the corresponding segment's performance in 2023?\",\n", + " \"What is the cumulative growth contribution of AWS and Advertising segments to Amazon's 2022 consolidated revenue?\",\n", + " \"How did Amazon's investments in technology infrastructure and fulfillment operations affect its cash flows and operating expenses in 2022?\",\n", + " \"What types of securities does Amazon invest its excess cash in 2019 and how are these investments classified in the balance sheet?\"\n", + "]\n", + "ground_truths = [\n", + " \"Amazon added 500,000 jobs in 2020, bringing its total workforce to approximately 1.3 million employees worldwide.\",\n", + " \"Amazon's 2023 net sales mix highlights its global priorities, with North America contributing 61%, International 23%, and AWS 16% of total sales. Year-over-year growth in each segment—12% for North America, 11% for International, and 13% for AWS—was driven by increased unit sales, advertising services, and subscription offerings. These trends reflect Amazon's balanced approach to expanding its core markets, strengthening its international presence, and investing in AWS's innovative cloud services to sustain long-term growth.\",\n", + " \"In 2023, foreign exchange rate fluctuations had a mixed impact on Amazon's financial performance. While these changes reduced consolidated net sales by $71 million, they positively influenced the International segment, increasing its net sales by $88 million. This highlights the nuanced effects of currency fluctuations, where gains in specific regions, such as the International segment, helped offset broader challenges at the consolidated level.\",\n", + " \"In 2022, AWS achieved a 29% year-over-year revenue growth, increasing from $62.2 billion in 2021 to $80.1 billion. Similarly, the Advertising segment experienced a 25% year-over-year growth, reaching $31 billion in revenue for the year. Together, these segments contributed significantly to Amazon's total consolidated revenue of $434 billion. AWS accounted for 19.59%, while Advertising contributed 7.14%, resulting in a cumulative contribution of approximately 26.73%.\",\n", + " \"In 2022, Amazon's substantial investments in technology infrastructure and fulfillment operations significantly impacted its cash flows and operating expenses. The company allocated $58.3 billion in cash capital expenditures to support AWS growth and expand its fulfillment network, resulting in a 31% increase in technology and content expenses due to higher payroll costs for technical teams and infrastructure spending on servers, networking equipment, and data centers. Fulfillment costs rose by 12%, driven by increased product sales volume, inventory levels, and wage rate incentives. These investments led to a decline in free cash flow to $(11,569) million, compared to $(9,069) million in 2021. Despite the higher costs, these expenditures were crucial for scaling operations, enhancing the customer experience, and sustaining long-term growth, particularly in AWS and global fulfillment capacity, highlighting Amazon's commitment to maintaining its competitive edge in a rapidly evolving market.\",\n", + " \"Amazon typically invests its excess cash in AAA-rated money market funds and investment-grade short- to intermediate-term fixed income securities, which are classified as either Cash and cash equivalents or Marketable securities on its consolidated balance sheets. In 2019, Amazon's marketable securities portfolio included a variety of assets such as money market funds, equity securities, foreign government and agency securities, U.S. government and agency securities, corporate debt securities, asset-backed securities, and other fixed income securities. These marketable securities were categorized as either Level 1 or Level 2 securities on the balance sheet.\"\n", + "]" + ] + }, + { + "cell_type": "code", + "execution_count": 21, + "id": "4ff26dda", + "metadata": {}, + "outputs": [], + "source": [ + "def prepare_eval_dataset(questions, ground_truths, kb_id=None, TEXT_GENERATION_MODEL_ID=None, reranker_model=None, metadata_filters = None):\n", + " answers = []\n", + " contexts = []\n", + " \n", + " for query in questions:\n", + " response = retrieve_and_generate(\n", + " query,\n", + " reranker_model=reranker_model,\n", + " kb_id=kb_id,\n", + " TEXT_GENERATION_MODEL_ID=TEXT_GENERATION_MODEL_ID,\n", + " metadata_filters=metadata_filters\n", + " )\n", + " \n", + " answers.append(response[\"output\"][\"text\"])\n", + " \n", + " context_group = []\n", + " for citation in response[\"citations\"]:\n", + " context_group.extend([\n", + " ref[\"content\"][\"text\"]\n", + " for ref in citation[\"retrievedReferences\"]\n", + " if \"content\" in ref and \"text\" in ref[\"content\"]\n", + " ])\n", + " contexts.append(context_group)\n", + " time.sleep(15)\n", + "\n", + " # Create dictionary\n", + " data = {\n", + " \"question\": questions,\n", + " \"answer\": answers,\n", + " \"contexts\": contexts,\n", + " \"ground_truth\": ground_truths\n", + " }\n", + "\n", + " # Convert dict to dataset\n", + " dataset = Dataset.from_dict(data)\n", + " return dataset\n" + ] + }, + { + "cell_type": "markdown", + "id": "9c51b09a", + "metadata": {}, + "source": [ + "#### 3.4 Evaluate dataset - without re-ranker" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "84dc3d78", + "metadata": {}, + "outputs": [], + "source": [ + "without_reranker_dataset = prepare_eval_dataset(questions, ground_truths, kb_id, TEXT_GENERATION_MODEL_ID, reranker_model=None)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "f9250cce", + "metadata": {}, + "outputs": [], + "source": [ + "without_reranker_result = evaluate(\n", + " dataset=without_reranker_dataset,\n", + " metrics=metrics,\n", + " llm=llm_for_evaluation,\n", + " embeddings=bedrock_embeddings,\n", + ")\n", + "\n", + "without_reranker_result_df = without_reranker_result.to_pandas()" + ] + }, + { + "cell_type": "markdown", + "id": "61243e2d", + "metadata": {}, + "source": [ + "#### 3.5 Evaluate dataset - with re-ranker" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "92591600", + "metadata": {}, + "outputs": [], + "source": [ + "with_reranker_dataset = prepare_eval_dataset(questions, ground_truths, kb_id, TEXT_GENERATION_MODEL_ID, reranker_model=AMAZON_RERANKER_MODEL_ID)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "d9e78450", + "metadata": {}, + "outputs": [], + "source": [ + "with_reranker_result = evaluate(\n", + "dataset=with_reranker_dataset,\n", + "metrics=metrics,\n", + "llm=llm_for_evaluation,\n", + "embeddings=bedrock_embeddings,\n", + ")\n", + "\n", + "with_reranker_result_df = with_reranker_result.to_pandas()" + ] + }, + { + "cell_type": "markdown", + "id": "a2f2f965", + "metadata": {}, + "source": [ + "#### 3.4 Evaluate dataset - with re-ranker + metadata configuration" + ] + }, + { + "cell_type": "markdown", + "id": "29c85464", + "metadata": {}, + "source": [ + "##### 3.4.1 Prepare metadata for ingestion\n" + ] + }, + { + "cell_type": "code", + "execution_count": 25, + "id": "17fe7e6c", + "metadata": {}, + "outputs": [], + "source": [ + "import json\n", + "import re\n", + "\n", + "def generate_matadata(data_dir):\n", + " \n", + " # Loop through all PDF files in the directory\n", + " for filename in os.listdir(data_dir):\n", + " if not filename.startswith('.DS_Store'):\n", + " # Define the metadata dictionary\n", + " metadata ={}\n", + " \n", + " filename= f'{data_dir}/{filename}'\n", + " print(filename)\n", + " \n", + " # Create metadata\n", + " metadata[\"company\"] = \"Amazon\"\n", + " metadata[\"ticker\"] = \"AMZN\"\n", + " metadata[\"year\"] = re.search(r'\\d+', filename.split('/')[-1]).group(0)\n", + "\n", + " # Create a JSON object\n", + " json_data = {\"metadataAttributes\": metadata}\n", + "\n", + " # print(json_data)\n", + "\n", + " # Write the JSON object to a file\n", + " with open(f\"{filename.replace('.pdf', '.pdf.metadata.json')}\", \"w\") as f:\n", + " json.dump(json_data, f)\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "69a16a17", + "metadata": {}, + "outputs": [], + "source": [ + "data_dir = './sec-10-k'\n", + "generate_matadata(data_dir)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "4ca6d8c0", + "metadata": {}, + "outputs": [], + "source": [ + "# upload metadata file to S3\n", + "upload_directory(\"sec-10-k\", bucket_name)" + ] + }, + { + "cell_type": "markdown", + "id": "c503656e", + "metadata": {}, + "source": [ + "##### 3.4.2 Ingest metadata into Knowledge Bases\n" + ] + }, + { + "cell_type": "markdown", + "id": "576f6fe6", + "metadata": {}, + "source": [ + "Now start the ingestion job. Since, we are using the same documents as used for fixed chunking, we are skipping the step to upload documents to s3 bucket. " + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "bdfb5938", + "metadata": {}, + "outputs": [], + "source": [ + "# ensure that the kb is available\n", + "time.sleep(30)\n", + "# sync knowledge base\n", + "knowledge_base_metadata.start_ingestion_job()" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "12589fe6", + "metadata": {}, + "outputs": [], + "source": [ + "with_reranker_metadata_filters_dataset = prepare_eval_dataset(questions, ground_truths, kb_id, TEXT_GENERATION_MODEL_ID, reranker_model=AMAZON_RERANKER_MODEL_ID, metadata_filters=True)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "21463f6f", + "metadata": {}, + "outputs": [], + "source": [ + "with_reranker_metadata_filters_result = evaluate(\n", + "dataset=with_reranker_metadata_filters_dataset,\n", + "metrics=metrics,\n", + "llm=llm_for_evaluation,\n", + "embeddings=bedrock_embeddings,\n", + ")\n", + "\n", + "with_reranker_metadata_filters_result_df = with_reranker_result.to_pandas()" + ] + }, + { + "cell_type": "markdown", + "id": "c44ec665", + "metadata": {}, + "source": [ + "#### 3.5 Prepare Comparison data frame" + ] + }, + { + "cell_type": "code", + "execution_count": 31, + "id": "f5ca9fc4", + "metadata": {}, + "outputs": [], + "source": [ + "import pandas as pd\n", + "\n", + "# Create the side-by-side DataFrame\n", + "comparison_df = pd.DataFrame({\n", + " 'question': without_reranker_result_df['question'],\n", + " 'without_reranker_answer': without_reranker_result_df['answer'],\n", + " 'with_reranker_answer': with_reranker_result_df['answer'],\n", + " 'with_reranker_metadata_answer': with_reranker_metadata_filters_result_df['answer'],\n", + " \n", + " 'without_reranker_answer_correctness': without_reranker_result_df['answer_correctness'],\n", + " 'with_reranker_answer_correctness': with_reranker_result_df['answer_correctness'],\n", + " 'with_reranker_metadata_correctness': with_reranker_metadata_filters_result_df['answer_correctness'],\n", + " })" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "30363097", + "metadata": {}, + "outputs": [], + "source": [ + "pd.options.display.max_colwidth = 1000\n", + "comparison_df" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "a3e83ab3", + "metadata": {}, + "outputs": [], + "source": [ + "# Calculate average correctness\n", + "without_reranker_avg_correctness = without_reranker_result_df['answer_correctness'].mean()\n", + "with_reranker_avg_correctness = with_reranker_result_df['answer_correctness'].mean()\n", + "with_reranker_metadata_avg_correctness = with_reranker_metadata_filters_result_df['answer_correctness'].mean()\n", + "\n", + "print(f\"\\nAverage Correctness without Reranker: {without_reranker_avg_correctness:.4f}\")\n", + "print(f\"Average Correctness with Reranker: {with_reranker_avg_correctness:.4f}\")\n", + "print(f\"Average Correctness with Reranker and metadata filter: {with_reranker_metadata_avg_correctness:.4f}\")" + ] + }, + { + "cell_type": "markdown", + "id": "5577ab01-5239-4a19-9042-a263e8a3de6b", + "metadata": {}, + "source": [ + "### 2.7 Clean up\n", + "Please make sure to uncomment and run below cells to delete the resources created in this notebook." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "33f8a07a", + "metadata": {}, + "outputs": [], + "source": [ + "# delete local directory\n", + "import shutil\n", + "\n", + "dir_path = \"sec-10-k\" # Replace with the actual path\n", + "\n", + "try:\n", + " shutil.rmtree(dir_path)\n", + " print(f\"Directory '{dir_path}' and its contents have been deleted successfully.\")\n", + "except FileNotFoundError:\n", + " print(f\"Directory '{dir_path}' not found.\")\n", + "except Exception as e:\n", + " print(f\"An error occurred: {e}\")" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "9ab05eb1-76c9-47b7-8d28-16ee720966d9", + "metadata": { + "tags": [] + }, + "outputs": [], + "source": [ + "## Empty and delete S3 Bucket\n", + "\n", + "objects = s3_client.list_objects(Bucket=bucket_name) \n", + "if 'Contents' in objects:\n", + " for obj in objects['Contents']:\n", + " s3_client.delete_object(Bucket=bucket_name, Key=obj['Key']) \n", + "s3_client.delete_bucket(Bucket=bucket_name)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "a0cab3a2-e121-4d65-9254-4d318cf428f1", + "metadata": { + "tags": [] + }, + "outputs": [], + "source": [ + "print(\"===============================Knowledge base==============================\")\n", + "knowledge_base_metadata.delete_kb(delete_s3_bucket=True, delete_iam_roles_and_policies=True)" + ] + } + ], + "metadata": { + "availableInstances": [ + { + "_defaultOrder": 0, + "_isFastLaunch": true, + "category": "General purpose", + "gpuNum": 0, + "hideHardwareSpecs": false, + "memoryGiB": 4, + "name": "ml.t3.medium", + "vcpuNum": 2 + }, + { + "_defaultOrder": 1, + "_isFastLaunch": false, + "category": "General purpose", + "gpuNum": 0, + "hideHardwareSpecs": false, + "memoryGiB": 8, + "name": "ml.t3.large", + "vcpuNum": 2 + }, + { + "_defaultOrder": 2, + "_isFastLaunch": false, + "category": "General purpose", + "gpuNum": 0, + "hideHardwareSpecs": false, + "memoryGiB": 16, + "name": "ml.t3.xlarge", + "vcpuNum": 4 + }, + { + "_defaultOrder": 3, + "_isFastLaunch": false, + "category": "General purpose", + "gpuNum": 0, + "hideHardwareSpecs": false, + "memoryGiB": 32, + "name": "ml.t3.2xlarge", + "vcpuNum": 8 + }, + { + "_defaultOrder": 4, + "_isFastLaunch": true, + "category": "General purpose", + "gpuNum": 0, + "hideHardwareSpecs": false, + "memoryGiB": 8, + "name": "ml.m5.large", + "vcpuNum": 2 + }, + { + "_defaultOrder": 5, + "_isFastLaunch": false, + "category": "General purpose", + "gpuNum": 0, + "hideHardwareSpecs": false, + "memoryGiB": 16, + "name": "ml.m5.xlarge", + "vcpuNum": 4 + }, + { + "_defaultOrder": 6, + "_isFastLaunch": false, + "category": "General purpose", + "gpuNum": 0, + "hideHardwareSpecs": false, + "memoryGiB": 32, + "name": "ml.m5.2xlarge", + "vcpuNum": 8 + }, + { + "_defaultOrder": 7, + "_isFastLaunch": false, + "category": "General purpose", + "gpuNum": 0, + "hideHardwareSpecs": false, + "memoryGiB": 64, + "name": "ml.m5.4xlarge", + "vcpuNum": 16 + }, + { + "_defaultOrder": 8, + "_isFastLaunch": false, + "category": "General purpose", + "gpuNum": 0, + "hideHardwareSpecs": false, + "memoryGiB": 128, + "name": "ml.m5.8xlarge", + "vcpuNum": 32 + }, + { + "_defaultOrder": 9, + "_isFastLaunch": false, + "category": "General purpose", + "gpuNum": 0, + "hideHardwareSpecs": false, + "memoryGiB": 192, + "name": "ml.m5.12xlarge", + "vcpuNum": 48 + }, + { + "_defaultOrder": 10, + "_isFastLaunch": false, + "category": "General purpose", + "gpuNum": 0, + "hideHardwareSpecs": false, + "memoryGiB": 256, + "name": "ml.m5.16xlarge", + "vcpuNum": 64 + }, + { + "_defaultOrder": 11, + "_isFastLaunch": false, + "category": "General purpose", + "gpuNum": 0, + "hideHardwareSpecs": false, + "memoryGiB": 384, + "name": "ml.m5.24xlarge", + "vcpuNum": 96 + }, + { + "_defaultOrder": 12, + "_isFastLaunch": false, + "category": "General purpose", + "gpuNum": 0, + "hideHardwareSpecs": false, + "memoryGiB": 8, + "name": "ml.m5d.large", + "vcpuNum": 2 + }, + { + "_defaultOrder": 13, + "_isFastLaunch": false, + "category": "General purpose", + "gpuNum": 0, + "hideHardwareSpecs": false, + "memoryGiB": 16, + "name": "ml.m5d.xlarge", + "vcpuNum": 4 + }, + { + "_defaultOrder": 14, + "_isFastLaunch": false, + "category": "General purpose", + "gpuNum": 0, + "hideHardwareSpecs": false, + "memoryGiB": 32, + "name": "ml.m5d.2xlarge", + "vcpuNum": 8 + }, + { + "_defaultOrder": 15, + "_isFastLaunch": false, + "category": "General purpose", + "gpuNum": 0, + "hideHardwareSpecs": false, + "memoryGiB": 64, + "name": "ml.m5d.4xlarge", + "vcpuNum": 16 + }, + { + "_defaultOrder": 16, + "_isFastLaunch": false, + "category": "General purpose", + "gpuNum": 0, + "hideHardwareSpecs": false, + "memoryGiB": 128, + "name": "ml.m5d.8xlarge", + "vcpuNum": 32 + }, + { + "_defaultOrder": 17, + "_isFastLaunch": false, + "category": "General purpose", + "gpuNum": 0, + "hideHardwareSpecs": false, + "memoryGiB": 192, + "name": "ml.m5d.12xlarge", + "vcpuNum": 48 + }, + { + "_defaultOrder": 18, + "_isFastLaunch": false, + "category": "General purpose", + "gpuNum": 0, + "hideHardwareSpecs": false, + "memoryGiB": 256, + "name": "ml.m5d.16xlarge", + "vcpuNum": 64 + }, + { + "_defaultOrder": 19, + "_isFastLaunch": false, + "category": "General purpose", + "gpuNum": 0, + "hideHardwareSpecs": false, + "memoryGiB": 384, + "name": "ml.m5d.24xlarge", + "vcpuNum": 96 + }, + { + "_defaultOrder": 20, + "_isFastLaunch": false, + "category": "General purpose", + "gpuNum": 0, + "hideHardwareSpecs": true, + "memoryGiB": 0, + "name": "ml.geospatial.interactive", + "supportedImageNames": [ + "sagemaker-geospatial-v1-0" + ], + "vcpuNum": 0 + }, + { + "_defaultOrder": 21, + "_isFastLaunch": true, + "category": "Compute optimized", + "gpuNum": 0, + "hideHardwareSpecs": false, + "memoryGiB": 4, + "name": "ml.c5.large", + "vcpuNum": 2 + }, + { + "_defaultOrder": 22, + "_isFastLaunch": false, + "category": "Compute optimized", + "gpuNum": 0, + "hideHardwareSpecs": false, + "memoryGiB": 8, + "name": "ml.c5.xlarge", + "vcpuNum": 4 + }, + { + "_defaultOrder": 23, + "_isFastLaunch": false, + "category": "Compute optimized", + "gpuNum": 0, + "hideHardwareSpecs": false, + "memoryGiB": 16, + "name": "ml.c5.2xlarge", + "vcpuNum": 8 + }, + { + "_defaultOrder": 24, + "_isFastLaunch": false, + "category": "Compute optimized", + "gpuNum": 0, + "hideHardwareSpecs": false, + "memoryGiB": 32, + "name": "ml.c5.4xlarge", + "vcpuNum": 16 + }, + { + "_defaultOrder": 25, + "_isFastLaunch": false, + "category": "Compute optimized", + "gpuNum": 0, + "hideHardwareSpecs": false, + "memoryGiB": 72, + "name": "ml.c5.9xlarge", + "vcpuNum": 36 + }, + { + "_defaultOrder": 26, + "_isFastLaunch": false, + "category": "Compute optimized", + "gpuNum": 0, + "hideHardwareSpecs": false, + "memoryGiB": 96, + "name": "ml.c5.12xlarge", + "vcpuNum": 48 + }, + { + "_defaultOrder": 27, + "_isFastLaunch": false, + "category": "Compute optimized", + "gpuNum": 0, + "hideHardwareSpecs": false, + "memoryGiB": 144, + "name": "ml.c5.18xlarge", + "vcpuNum": 72 + }, + { + "_defaultOrder": 28, + "_isFastLaunch": false, + "category": "Compute optimized", + "gpuNum": 0, + "hideHardwareSpecs": false, + "memoryGiB": 192, + "name": "ml.c5.24xlarge", + "vcpuNum": 96 + }, + { + "_defaultOrder": 29, + "_isFastLaunch": true, + "category": "Accelerated computing", + "gpuNum": 1, + "hideHardwareSpecs": false, + "memoryGiB": 16, + "name": "ml.g4dn.xlarge", + "vcpuNum": 4 + }, + { + "_defaultOrder": 30, + "_isFastLaunch": false, + "category": "Accelerated computing", + "gpuNum": 1, + "hideHardwareSpecs": false, + "memoryGiB": 32, + "name": "ml.g4dn.2xlarge", + "vcpuNum": 8 + }, + { + "_defaultOrder": 31, + "_isFastLaunch": false, + "category": "Accelerated computing", + "gpuNum": 1, + "hideHardwareSpecs": false, + "memoryGiB": 64, + "name": "ml.g4dn.4xlarge", + "vcpuNum": 16 + }, + { + "_defaultOrder": 32, + "_isFastLaunch": false, + "category": "Accelerated computing", + "gpuNum": 1, + "hideHardwareSpecs": false, + "memoryGiB": 128, + "name": "ml.g4dn.8xlarge", + "vcpuNum": 32 + }, + { + "_defaultOrder": 33, + "_isFastLaunch": false, + "category": "Accelerated computing", + "gpuNum": 4, + "hideHardwareSpecs": false, + "memoryGiB": 192, + "name": "ml.g4dn.12xlarge", + "vcpuNum": 48 + }, + { + "_defaultOrder": 34, + "_isFastLaunch": false, + "category": "Accelerated computing", + "gpuNum": 1, + "hideHardwareSpecs": false, + "memoryGiB": 256, + "name": "ml.g4dn.16xlarge", + "vcpuNum": 64 + }, + { + "_defaultOrder": 35, + "_isFastLaunch": false, + "category": "Accelerated computing", + "gpuNum": 1, + "hideHardwareSpecs": false, + "memoryGiB": 61, + "name": "ml.p3.2xlarge", + "vcpuNum": 8 + }, + { + "_defaultOrder": 36, + "_isFastLaunch": false, + "category": "Accelerated computing", + "gpuNum": 4, + "hideHardwareSpecs": false, + "memoryGiB": 244, + "name": "ml.p3.8xlarge", + "vcpuNum": 32 + }, + { + "_defaultOrder": 37, + "_isFastLaunch": false, + "category": "Accelerated computing", + "gpuNum": 8, + "hideHardwareSpecs": false, + "memoryGiB": 488, + "name": "ml.p3.16xlarge", + "vcpuNum": 64 + }, + { + "_defaultOrder": 38, + "_isFastLaunch": false, + "category": "Accelerated computing", + "gpuNum": 8, + "hideHardwareSpecs": false, + "memoryGiB": 768, + "name": "ml.p3dn.24xlarge", + "vcpuNum": 96 + }, + { + "_defaultOrder": 39, + "_isFastLaunch": false, + "category": "Memory Optimized", + "gpuNum": 0, + "hideHardwareSpecs": false, + "memoryGiB": 16, + "name": "ml.r5.large", + "vcpuNum": 2 + }, + { + "_defaultOrder": 40, + "_isFastLaunch": false, + "category": "Memory Optimized", + "gpuNum": 0, + "hideHardwareSpecs": false, + "memoryGiB": 32, + "name": "ml.r5.xlarge", + "vcpuNum": 4 + }, + { + "_defaultOrder": 41, + "_isFastLaunch": false, + "category": "Memory Optimized", + "gpuNum": 0, + "hideHardwareSpecs": false, + "memoryGiB": 64, + "name": "ml.r5.2xlarge", + "vcpuNum": 8 + }, + { + "_defaultOrder": 42, + "_isFastLaunch": false, + "category": "Memory Optimized", + "gpuNum": 0, + "hideHardwareSpecs": false, + "memoryGiB": 128, + "name": "ml.r5.4xlarge", + "vcpuNum": 16 + }, + { + "_defaultOrder": 43, + "_isFastLaunch": false, + "category": "Memory Optimized", + "gpuNum": 0, + "hideHardwareSpecs": false, + "memoryGiB": 256, + "name": "ml.r5.8xlarge", + "vcpuNum": 32 + }, + { + "_defaultOrder": 44, + "_isFastLaunch": false, + "category": "Memory Optimized", + "gpuNum": 0, + "hideHardwareSpecs": false, + "memoryGiB": 384, + "name": "ml.r5.12xlarge", + "vcpuNum": 48 + }, + { + "_defaultOrder": 45, + "_isFastLaunch": false, + "category": "Memory Optimized", + "gpuNum": 0, + "hideHardwareSpecs": false, + "memoryGiB": 512, + "name": "ml.r5.16xlarge", + "vcpuNum": 64 + }, + { + "_defaultOrder": 46, + "_isFastLaunch": false, + "category": "Memory Optimized", + "gpuNum": 0, + "hideHardwareSpecs": false, + "memoryGiB": 768, + "name": "ml.r5.24xlarge", + "vcpuNum": 96 + }, + { + "_defaultOrder": 47, + "_isFastLaunch": false, + "category": "Accelerated computing", + "gpuNum": 1, + "hideHardwareSpecs": false, + "memoryGiB": 16, + "name": "ml.g5.xlarge", + "vcpuNum": 4 + }, + { + "_defaultOrder": 48, + "_isFastLaunch": false, + "category": "Accelerated computing", + "gpuNum": 1, + "hideHardwareSpecs": false, + "memoryGiB": 32, + "name": "ml.g5.2xlarge", + "vcpuNum": 8 + }, + { + "_defaultOrder": 49, + "_isFastLaunch": false, + "category": "Accelerated computing", + "gpuNum": 1, + "hideHardwareSpecs": false, + "memoryGiB": 64, + "name": "ml.g5.4xlarge", + "vcpuNum": 16 + }, + { + "_defaultOrder": 50, + "_isFastLaunch": false, + "category": "Accelerated computing", + "gpuNum": 1, + "hideHardwareSpecs": false, + "memoryGiB": 128, + "name": "ml.g5.8xlarge", + "vcpuNum": 32 + }, + { + "_defaultOrder": 51, + "_isFastLaunch": false, + "category": "Accelerated computing", + "gpuNum": 1, + "hideHardwareSpecs": false, + "memoryGiB": 256, + "name": "ml.g5.16xlarge", + "vcpuNum": 64 + }, + { + "_defaultOrder": 52, + "_isFastLaunch": false, + "category": "Accelerated computing", + "gpuNum": 4, + "hideHardwareSpecs": false, + "memoryGiB": 192, + "name": "ml.g5.12xlarge", + "vcpuNum": 48 + }, + { + "_defaultOrder": 53, + "_isFastLaunch": false, + "category": "Accelerated computing", + "gpuNum": 4, + "hideHardwareSpecs": false, + "memoryGiB": 384, + "name": "ml.g5.24xlarge", + "vcpuNum": 96 + }, + { + "_defaultOrder": 54, + "_isFastLaunch": false, + "category": "Accelerated computing", + "gpuNum": 8, + "hideHardwareSpecs": false, + "memoryGiB": 768, + "name": "ml.g5.48xlarge", + "vcpuNum": 192 + }, + { + "_defaultOrder": 55, + "_isFastLaunch": false, + "category": "Accelerated computing", + "gpuNum": 8, + "hideHardwareSpecs": false, + "memoryGiB": 1152, + "name": "ml.p4d.24xlarge", + "vcpuNum": 96 + }, + { + "_defaultOrder": 56, + "_isFastLaunch": false, + "category": "Accelerated computing", + "gpuNum": 8, + "hideHardwareSpecs": false, + "memoryGiB": 1152, + "name": "ml.p4de.24xlarge", + "vcpuNum": 96 + }, + { + "_defaultOrder": 57, + "_isFastLaunch": false, + "category": "Accelerated computing", + "gpuNum": 0, + "hideHardwareSpecs": false, + "memoryGiB": 32, + "name": "ml.trn1.2xlarge", + "vcpuNum": 8 + }, + { + "_defaultOrder": 58, + "_isFastLaunch": false, + "category": "Accelerated computing", + "gpuNum": 0, + "hideHardwareSpecs": false, + "memoryGiB": 512, + "name": "ml.trn1.32xlarge", + "vcpuNum": 128 + }, + { + "_defaultOrder": 59, + "_isFastLaunch": false, + "category": "Accelerated computing", + "gpuNum": 0, + "hideHardwareSpecs": false, + "memoryGiB": 512, + "name": "ml.trn1n.32xlarge", + "vcpuNum": 128 + } + ], + "instance_type": "ml.t3.medium", + "kernelspec": { + "display_name": "Python 3 (ipykernel)", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.10.13" + } + }, + "nbformat": 4, + "nbformat_minor": 5 +} diff --git a/05-structured-rag/structured-rag-using-kb.ipynb b/05-structured-rag/structured-rag-using-kb.ipynb new file mode 100644 index 0000000..cc6fa57 --- /dev/null +++ b/05-structured-rag/structured-rag-using-kb.ipynb @@ -0,0 +1,711 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Structured RAG using Amazon Bedrock Knowledge Bases : end-to-end example using Amazon Redshift DB\n", + "\n", + "Structure RAG allows Amazon Bedrock Knowledge Bases customers to query structured data in Redshift using natural language, and receive natural language responses summarizing the data thereby providing an answer to the user question.\n", + "\n", + "Using advanced natural language processing, Amazon Bedrock Knowledge Bases can transform natural language queries into SQL queries, allowing users to retrieve data directly from the source without the need to move or preprocess the data. To generate accurate SQL queries, Bedrock Knowledge Base leverages database schema, previous query history, and other contextual information that are provided about the data sources. For more details. please see the [documentation](https://docs.aws.amazon.com/bedrock/latest/userguide/knowledge-base-build-structured.html).\n", + "\n", + "\n", + "This notebook provides sample code for building a Structured RAG using Amazon Bedrock Knowledgebases using Redshift.\n", + "\n", + "\n", + "#### Steps: \n", + "- Create Knowledge Base execution role with necessary policies for accessing data from Amazon Redshift.\n", + "- Create a knowledge base with Structured database (Redshift database)\n", + "- Create data source(s) within knowledge base\n", + "- Start ingestion jobs using KB APIs which will read metadata about structred database.\n", + "\n", + "Once the metadata is extracted and ingested, then user can interact with Structured databases via Amazon Bedrock Knowledge Base APIs using Natural language query." + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "#### Pre-requisites\n", + "This notebook requires :\n", + "- A Redshift serverless cluster with a workgroup [OR] Redshift provisioned cluster \n", + "- Your workgroup or cluster is already setup with your structured data ingested\n", + "- You've set-up the IAM Role [OR] Secrets manager with User Credentials [OR] the DB User \n", + "\n", + "To read more details about pre-requisites, see the [documentation](https://docs.aws.amazon.com/bedrock/latest/userguide/knowledge-base-prereq-structured.html)\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### 0 - Setup\n", + "Before running the rest of this notebook, you'll need to run the cells below to ensure necessary libraries are installed and connect to Bedrock.\n", + "\n", + "Please ignore any pip dependency error (if you see any while installing libraries)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "%pip install --force-reinstall -q -r ../../requirements.txt --quiet" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# %pip install --upgrade boto3\n", + "import boto3\n", + "print(boto3.__version__)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# restart kernel\n", + "from IPython.core.display import HTML\n", + "HTML(\"\")" + ] + }, + { + "cell_type": "code", + "execution_count": 4, + "metadata": {}, + "outputs": [], + "source": [ + "%load_ext autoreload\n", + "%autoreload 2" + ] + }, + { + "cell_type": "code", + "execution_count": 5, + "metadata": {}, + "outputs": [], + "source": [ + "import warnings\n", + "warnings.filterwarnings('ignore')" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "This code is part of the setup and used to :\n", + "- Add the parent directory to the python system path\n", + "- Imports a custom module (BedrockStructuredKnowledgeBase) from `utils` necessary for later executions" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "import sys\n", + "import logging\n", + "from pathlib import Path\n", + "\n", + "current_path = Path().resolve()\n", + "current_path = current_path.parent\n", + "\n", + "if str(current_path) not in sys.path:\n", + " sys.path.append(str(current_path))\n", + "\n", + "# Print sys.path to verify\n", + "print(sys.path)\n", + "\n", + "from utils.structured_knowledge_base import BedrockStructuredKnowledgeBase" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Setup and initialize boto3 clients " + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "s3_client = boto3.client('s3')\n", + "sts_client = boto3.client('sts')\n", + "session = boto3.session.Session(region_name='us-east-1')\n", + "region = session.region_name\n", + "account_id = sts_client.get_caller_identity()[\"Account\"]\n", + "bedrock_agent_client = boto3.client('bedrock-agent')\n", + "bedrock_agent_runtime_client = boto3.client('bedrock-agent-runtime') \n", + "logging.basicConfig(format='[%(asctime)s] p%(process)s {%(filename)s:%(lineno)d} %(levelname)s - %(message)s', level=logging.INFO)\n", + "logger = logging.getLogger(__name__)\n", + "region, account_id" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Initialize and configure the knowledge base name and the foundational model. This foundational model will be used to generate the natural language response based on the records received from the structured data store." + ] + }, + { + "cell_type": "code", + "execution_count": 29, + "metadata": {}, + "outputs": [], + "source": [ + "import time\n", + "\n", + "# Get the current timestamp\n", + "current_time = time.time()\n", + "\n", + "# Format the timestamp as a string\n", + "timestamp_str = time.strftime(\"%Y%m%d%H%M%S\", time.localtime(current_time))[-7:]\n", + "# Create the suffix using the timestamp\n", + "suffix = f\"{timestamp_str}\"\n", + "\n", + "knowledge_base_name = f\"bedrock-sample-structured-kb-{suffix}\"\n", + "knowledge_base_description = \"Sample Structured KB\"\n", + "\n", + "\n", + "foundation_model = \"anthropic.claude-3-sonnet-20240229-v1:0\"" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Amazon Bedrock Knowledge Bases uses a service role to connect knowledge bases to structured data stores, retrieve data from these data stores, and generate SQL queries based on user queries and the structure of the data stores. There are several access patterns based on if you're using Redshift Serverless vs Redshift Provisioned Cluster." + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "
\n", + "NOTE: Below are several access patterns based on if you're using Redshift Serverless vs Redshift Provisioned Cluster.\n", + "

\n", + "1. Secrets Manager + Redshift Serverless WorkGroup\n", + "
\n", + "2. IAM Role + Redshift Serverless WorkGroup \n", + "
\n", + "3. IAM Role + Redshift Cluster\n", + "
\n", + "4. Secrets Manager + Redshift Cluster \n", + "
\n", + "5. DB user + Redshift Cluster\n", + "
\n", + "\n", + "In this notebook, we'll look at all these access pattern.\n", + "
" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Please note that, you will have to initialize only the variables that are necessary based on following access patterns:\n", + "\n", + "1. Secrets Manager + Redshift Serverless WorkGroup \n", + "`workgroup_id` \n", + "`secretArn`\n", + "\n", + "2. IAM Role + Redshift Serverless WorkGroup \n", + "`workgroup_id` \n", + "`redshiftDBName`\n", + "\n", + "3. IAM Role + Redshift Provisioned Cluster \n", + "`provisioned_cluster_identifier` \n", + "`provisioned_cluster_dbname`\n", + "\n", + "4. Secrets Manager + Redshift Provisioned Cluster \n", + "`provisioned_cluster_identifier` \n", + "`provisioned_cluster_dbname` \n", + "`provisionedSecretArn`\n", + "\n", + "5. DB user + Redshift Provisioned Cluster \n", + "`provisioned_cluster_identifier` \n", + "`provisioned_cluster_dbname` \n", + "`databaseUser`\n", + "\n", + "Knowledge base configuration and the roles created will use these parameters to perform necessary configuration. Any additional steps required as part of execution will be covered as part of execution steps" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "#### Redshift acces pattern choice\n", + "Select the choice that aligns with your setup. " + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "import ipywidgets as widgets\n", + "from IPython.display import display\n", + "\n", + "# Display the choices to the user\n", + "print(\"Choose your Redshift access pattern:\")\n", + "print(\"1. Secrets Manager + Redshift Serverless WorkGroup\")\n", + "print(\"2. IAM Role + Redshift Serverless WorkGroup\")\n", + "print(\"3. IAM Role + Redshift Provisioned Cluster\")\n", + "print(\"4. Secrets Manager + Redshift Provisioned Cluster\")\n", + "print(\"5. DB User + Redshift Provisioned Cluster\")\n", + "\n", + "# Create a text input widget\n", + "choice_widget = widgets.Text(placeholder=\"Enter your choice (1 Only)\")\n", + "\n", + "# Display the widget\n", + "display(choice_widget)\n" + ] + }, + { + "cell_type": "code", + "execution_count": 31, + "metadata": {}, + "outputs": [], + "source": [ + "# Change below variables as needed\n", + "\n", + "#Redshift Serverless Cluster configuration details\n", + "workgroup_id = ''\n", + "redshiftDBName = \"\"\n", + "\n", + "#Redshift Provisioned Cluster configuration details\n", + "provisioned_cluster_identifier = \"\"\n", + "provisioned_cluster_dbname = \"\"\n", + "#Secrets manager ARN , this value is required to use \"Secrets Manager + Redshift Provisioned Cluster\" access pattern \n", + "provisionedSecretArn = \"\"\n", + "#Redshift Database UserName, this value is required to use \"DB User + Redshift Provisioned Cluster\" access pattern\n", + "databaseUser = \"\"\n", + "\n", + "# kb Configuration\n", + "kbConfigParam = {\n", + " \"type\": \"SQL\",\n", + " \"sqlKnowledgeBaseConfiguration\": {\n", + " \"type\": \"REDSHIFT\",\n", + " \"redshiftConfiguration\": {\n", + " \"storageConfigurations\": [{\n", + " \"type\": \"REDSHIFT\",\n", + " \"redshiftConfiguration\": {\n", + " \"databaseName\": redshiftDBName\n", + " }\n", + " }],\n", + " \"queryEngineConfiguration\": {\n", + " \"type\": \"SERVERLESS\",\n", + " \"serverlessConfiguration\": {\n", + " \"workgroupArn\": workgroupArn,\n", + " \"authConfiguration\": {}\n", + " }\n", + " }\n", + " }\n", + " }\n", + " }\n", + "\n", + "kbProvisionedConfigParam = {\n", + " \"type\": \"SQL\",\n", + " \"sqlKnowledgeBaseConfiguration\": {\n", + " \"type\": \"REDSHIFT\",\n", + " \"redshiftConfiguration\": {\n", + " \"queryEngineConfiguration\": {\n", + " \"type\": \"PROVISIONED\",\n", + " \"provisionedConfiguration\": {\n", + " \"authConfiguration\": {},\n", + " \"clusterIdentifier\": provisioned_cluster_identifier\n", + " }\n", + " },\n", + " \"storageConfigurations\": [{\n", + " \"redshiftConfiguration\": {\n", + " \"databaseName\": provisioned_cluster_dbname\n", + " },\n", + " \"type\": \"REDSHIFT\"\n", + " }]\n", + " } \n", + " } \n", + "}" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### 1 - Create Knowledge Base\n", + "\n", + "Based on the selected access pattern, \n", + "1. This code updates the knowledge base configuration with additional parameters. For example, if the access pattern is slected as `IAM Role + Redshift Serverless ` , the `[authCofiguration][type]` parameter willbe updated as \"IAM\"\n", + "2. Then it creates the knowledge base " + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# Access the entered value\n", + "access_pattern_choice = int(choice_widget.value)\n", + "try:\n", + " access_pattern_choice = int(choice_widget.value)\n", + " if access_pattern_choice ==1:\n", + " print(f\"Access pattern:{choice_widget.value}. Secrets Manager + Redshift Serverless WorkGroup\")\n", + "\n", + " kbConfigParam['sqlKnowledgeBaseConfiguration']['redshiftConfiguration']['queryEngineConfiguration']['serverlessConfiguration']['authConfiguration']['type'] = \"USERNAME_PASSWORD\"\n", + " kbConfigParam['sqlKnowledgeBaseConfiguration']['redshiftConfiguration']['queryEngineConfiguration']['serverlessConfiguration']['authConfiguration']['usernamePasswordSecretArn'] = secretArn\n", + "\n", + " knowledge_base = BedrockStructuredKnowledgeBase(\n", + " kb_name=f'{knowledge_base_name}',\n", + " kb_description=knowledge_base_description,\n", + " workgroup_arn=workgroupArn,\n", + " secrets_arn = secretArn,\n", + " kbConfigParam = kbConfigParam,\n", + " suffix = f'{suffix}-f'\n", + " )\n", + " \n", + " elif access_pattern_choice ==2:\n", + " print(f\"Access pattern:{choice_widget.value} IAM Role + Redshift Serverless WorkGroup\")\n", + "\n", + " kbConfigParam['sqlKnowledgeBaseConfiguration']['redshiftConfiguration']['queryEngineConfiguration']['serverlessConfiguration']['authConfiguration']['type'] = \"IAM\"\n", + " \n", + " knowledge_base = BedrockStructuredKnowledgeBase(\n", + " kb_name=f'{knowledge_base_name}',\n", + " kb_description=knowledge_base_description,\n", + " workgroup_arn=workgroupArn,\n", + " kbConfigParam = kbConfigParam,\n", + " suffix = f'{suffix}-f'\n", + " )\n", + " \n", + " elif access_pattern_choice == 3:\n", + " print(f\"Access pattern:{choice_widget.value} IAM Role + Redshift Provisioned Cluster\")\n", + "\n", + " kbProvisionedConfigParam['sqlKnowledgeBaseConfiguration']['redshiftConfiguration']['queryEngineConfiguration']['provisionedConfiguration']['authConfiguration']['type'] = \"IAM\"\n", + " \n", + " knowledge_base = BedrockStructuredKnowledgeBase(\n", + " kb_name=f'{knowledge_base_name}',\n", + " kb_description=knowledge_base_description,\n", + " cluster_identifier=provisioned_cluster_identifier,\n", + " db_name=provisioned_cluster_dbname,\n", + " kbConfigParam = kbProvisionedConfigParam,\n", + " suffix = f'{suffix}-f'\n", + " )\n", + " \n", + " elif access_pattern_choice == 4:\n", + " print(f\"Access pattern:{choice_widget.value} Secrets Manager + Redshift Provisioned Cluster\")\n", + "\n", + " kbProvisionedConfigParam['sqlKnowledgeBaseConfiguration']['redshiftConfiguration']['queryEngineConfiguration']['provisionedConfiguration']['authConfiguration']['type'] = \"USERNAME_PASSWORD\"\n", + " kbProvisionedConfigParam['sqlKnowledgeBaseConfiguration']['redshiftConfiguration']['queryEngineConfiguration']['provisionedConfiguration']['authConfiguration']['usernamePasswordSecretArn'] = provisionedSecretArn\n", + " \n", + " knowledge_base = BedrockStructuredKnowledgeBase(\n", + " kb_name=f'{knowledge_base_name}',\n", + " kb_description=knowledge_base_description,\n", + " cluster_identifier=provisioned_cluster_identifier,\n", + " db_name=provisioned_cluster_dbname,\n", + " secrets_arn = provisionedSecretArn,\n", + " kbConfigParam = kbProvisionedConfigParam,\n", + " suffix = f'{suffix}-f'\n", + " ) \n", + " elif access_pattern_choice == 5:\n", + " print(f\"Access pattern:{choice_widget.value} DB User + Redshift Provisioned Cluster\")\n", + "\n", + " kbProvisionedConfigParam['sqlKnowledgeBaseConfiguration']['redshiftConfiguration']['queryEngineConfiguration']['provisionedConfiguration']['authConfiguration']['type'] = \"USERNAME\"\n", + " kbProvisionedConfigParam['sqlKnowledgeBaseConfiguration']['redshiftConfiguration']['queryEngineConfiguration']['provisionedConfiguration']['authConfiguration']['databaseUser'] = databaseUser\n", + "\n", + " knowledge_base = BedrockStructuredKnowledgeBase(\n", + " kb_name=f'{knowledge_base_name}',\n", + " kb_description=knowledge_base_description,\n", + " cluster_identifier=provisioned_cluster_identifier,\n", + " db_name=provisioned_cluster_dbname,\n", + " db_user=databaseUser,\n", + " kbConfigParam = kbProvisionedConfigParam,\n", + " suffix = f'{suffix}-f'\n", + " ) \n", + " else:\n", + " print(\"Invalid choice. Please enter a number between 1 and 2.\")\n", + "except ValueError:\n", + " print(\"Invalid input. Please enter a number.\")" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### For IAM access pattern, Grant database access to the role you use for authentication\n", + "\n", + "You can use below sample SQL Statement to create user and provide access. Please update the GRANT statement based on the level of access that needs to be provided for your dataset. \n", + "\n", + "For more detailed steps, please see the [documentation](https://docs.aws.amazon.com/bedrock/latest/userguide/knowledge-base-prereq-structured.html#knowledge-base-prereq-structured-db-access)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "#Following SQL commands should be executed in Redshift Query Editor\n", + "print(f'CREATE USER \"IAMR:{knowledge_base.bedrock_kb_execution_role_name}\" WITH PASSWORD DISABLE;')\n", + "print(f'GRANT SELECT ON ALL tables IN SCHEMA public TO \"IAMR:{knowledge_base.bedrock_kb_execution_role_name}\";')" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### 2 - Start the ingestion job\n", + "\n", + "This step is to start the ingestion job to sync the datasources. " + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# ensure that the kb is available\n", + "time.sleep(60)\n", + "# sync knowledge base\n", + "knowledge_base.start_ingestion_job()" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# keep the kb_id for invocation later in the invoke request\n", + "kb_id = knowledge_base.get_knowledge_base_id()\n", + "%store kb_id" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### 3 - Test the Structured Knowledge Base\n", + "Now the Knowlegde Base is available we can test it out using the [**retrieve**](https://boto3.amazonaws.com/v1/documentation/api/latest/reference/services/bedrock-agent-runtime/client/retrieve.html), [**retrieve_and_generate**](https://boto3.amazonaws.com/v1/documentation/api/latest/reference/services/bedrock-agent-runtime/client/retrieve_and_generate.html), and [**generate_query**](https://docs.aws.amazon.com/bedrock/latest/APIReference/API_agent-runtime_GenerateQuery.html) functions. \n", + "\n", + "When you use [**retrieve**](https://boto3.amazonaws.com/v1/documentation/api/latest/reference/services/bedrock-agent-runtime/client/retrieve.html), the response returns the result of the SQL query execution. \n", + "\n", + "When you use [**retrieve_and_generate**](https://boto3.amazonaws.com/v1/documentation/api/latest/reference/services/bedrock-agent-runtime/client/retrieve_and_generate.html), the generated response is based on the result of the SQL query execution\n", + "\n", + "When using the [**generate_query**](https://docs.aws.amazon.com/bedrock/latest/APIReference/API_agent-runtime_GenerateQuery.html) API, it transforms a natural language query into SQL.\n", + "\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "query = \"\"" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "#### 3.1 - Using RetrieveAndGenerate API" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "foundation_model = \"anthropic.claude-3-sonnet-20240229-v1:0\"\n", + "\n", + "response = bedrock_agent_runtime_client.retrieve_and_generate(\n", + " input={\n", + " \"text\": query\n", + " },\n", + " retrieveAndGenerateConfiguration={\n", + " \"type\": \"KNOWLEDGE_BASE\",\n", + " \"knowledgeBaseConfiguration\": {\n", + " 'knowledgeBaseId': kb_id,\n", + " \"modelArn\": \"arn:aws:bedrock:{}::foundation-model/{}\".format(region, foundation_model),\n", + " \"retrievalConfiguration\": {\n", + " \"vectorSearchConfiguration\": {\n", + " \"numberOfResults\":5\n", + " } \n", + " }\n", + " }\n", + " }\n", + ")\n", + "\n", + "print(response['output']['text'],end='\\n'*2)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "#### 3.2 - Using Retrieve API" + ] + }, + { + "cell_type": "code", + "execution_count": 40, + "metadata": {}, + "outputs": [], + "source": [ + "response_ret = bedrock_agent_runtime_client.retrieve(\n", + " knowledgeBaseId=kb_id, \n", + " nextToken='string',\n", + " retrievalConfiguration={\n", + " \"vectorSearchConfiguration\": {\n", + " \"numberOfResults\":5,\n", + " } \n", + " },\n", + " retrievalQuery={\n", + " \"text\": query\n", + " }\n", + ")\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "import json\n", + "import pandas as pd\n", + "\n", + "# Function to extract retrieved results from Retrieve API response into a pandas dataframe.\n", + "\n", + "def response_print(retrieve_resp):\n", + "\n", + " # Extract the retrievalResults list\n", + " retrieval_results = retrieve_resp['retrievalResults']\n", + "\n", + " # Dictionary to store the extracted data\n", + " extracted_data = {}\n", + "\n", + " # Iterate through each item in retrievalResults\n", + " for item in retrieval_results:\n", + " row = item['content']['row']\n", + " for col in row:\n", + " column_name = col['columnName']\n", + " column_value = col['columnValue']\n", + " \n", + " # If this column hasn't been seen before, create a new list for it\n", + " if column_name not in extracted_data:\n", + " extracted_data[column_name] = []\n", + " \n", + " # Append the value to the appropriate list\n", + " extracted_data[column_name].append(column_value)\n", + "\n", + " # Create a DataFrame from the extracted data\n", + " df = pd.DataFrame(extracted_data)\n", + "\n", + " return df\n", + " " + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# Display the Retrieved results records\n", + "df = response_print(response_ret)\n", + "print(df.head())" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "#### 3.3 - Using Generate Query" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "query_response = bedrock_agent_runtime_client.generate_query(\n", + " queryGenerationInput={\n", + " \"text\": query,\n", + " \"type\": \"TEXT\"\n", + " },\n", + " transformationConfiguration={\n", + " \"mode\" : \"TEXT_TO_SQL\",\n", + " \"textToSqlConfiguration\": {\n", + " \"type\": \"KNOWLEDGE_BASE\",\n", + " \"knowledgeBaseConfiguration\": {\n", + " \"knowledgeBaseArn\": knowledge_base.knowledge_base['knowledgeBaseArn']\n", + " }\n", + " }\n", + " }\n", + ")\n", + "\n", + "generated_sql = query_response['queries'][0]['sql']\n", + "generated_sql" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Clean Up\n", + "Please make sure to uncomment and run the below section to delete all the resources" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# # Delete resources\n", + "# print(\"===============================Deleteing resources ==============================\\n\")\n", + "knowledge_base.delete_kb( delete_iam_roles_and_policies=True)" + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": "structured_rag", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.12.2" + } + }, + "nbformat": 4, + "nbformat_minor": 2 +} diff --git a/06-multi-modal-rag/text-images-rag-using-kb/text-images-rag-using-kb.ipynb b/06-multi-modal-rag/text-images-rag-using-kb/text-images-rag-using-kb.ipynb new file mode 100644 index 0000000..6365b1b --- /dev/null +++ b/06-multi-modal-rag/text-images-rag-using-kb/text-images-rag-using-kb.ipynb @@ -0,0 +1,1172 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Multi modal data processing - End to end example using Amazon Bedrock Knowledge Bases for text & images\n", + "\n", + "Multi-modal RAG can analyze and leverage insights from both textual and visual data, such as images, charts, diagrams, and tables.Bedrock Knowledge Bases offers end-to-end managed Retrieval-Augmented Generation (RAG) workflow that enables customers to create highly accurate, low-latency, secure, and custom generative AI applications by incorporating contextual information from their own data sources.\n", + "\n", + "Bedrock Knowledge Bases extracts content from both text and visual data, generates semantic embeddings using the selected embedding model, and stores them in the chosen vector store. This enables users to retrieve and generate answers to questions derived not only from text but also from visual data. Additionally, retrieved results now include source attribution for visual data, enhancing transparency and building trust in the generated outputs.\n", + "\n", + "You can choose between: Amazon Bedrock Data Automation, a managed service that automatically extracts content from multimodal data (currently in Preview), or FMs such as Claude 3.5 Sonnet or Claude 3 Haiku, with the flexibility to customize the default prompt.\n", + "\n", + "This notebook provides sample code for building a Multimodal RAG using Amazon Bedrock Knowledge Bases.\n", + "\n", + "#### Steps: \n", + "- Create Knowledge Base execution role with necessary policies for accessing/writing data from/to S3 and required Foundation models .\n", + "- Create a knowledge base with rich content documents\n", + "- Create data source(s) within knowledge base\n", + "- Start ingestion jobs using KB APIs which which will read data from the data source, parse the documents (images, charts, tables etc.)using Bedrock Data Automation or Foundation model, chunk it, convert chunks into embeddings using Amazon Titan Embeddings model and then store these embeddings in AOSS. All of this without having to build, deploy and manage the data pipeline.\n", + "\n", + "Once the data is available in the Bedrock Knowledge Base then a question answering application can be built using the Knowledge Base APIs provided by Amazon Bedrock.\n", + "\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "#### Pre-requisites:\n", + "\n", + "Please make sure to enable `Anthropic Claude 3 Sonnet` , `Amazon Nova Micro` and `Titan Text Embeddings V2` model access in Amazon Bedrock Console\n", + "\n", + "
\n", + "Note: Please run the notebook cell one at a time instead of using \"Run All Cells\" option.\n", + "
\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### 0 - Setup\n", + "Before running the rest of this notebook, you'll need to run the cells below to (ensure necessary libraries are installed and) connect to Bedrock.\n", + "\n", + "Please ignore any pip dependency error (if you see any while installing libraries)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "%pip install --force-reinstall -q -r ../../requirements.txt " + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "tags": [] + }, + "outputs": [], + "source": [ + "# %pip install --upgrade boto3\n", + "import boto3\n", + "print(boto3.__version__)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false, + "jupyter": { + "outputs_hidden": false + }, + "tags": [] + }, + "outputs": [], + "source": [ + "# restart kernel\n", + "from IPython.core.display import HTML\n", + "HTML(\"\")" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "%load_ext autoreload\n", + "%autoreload 2" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "tags": [] + }, + "outputs": [], + "source": [ + "import warnings\n", + "warnings.filterwarnings('ignore')" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "import os\n", + "import sys\n", + "import time\n", + "import boto3\n", + "import logging\n", + "import pprint\n", + "import json\n", + "\n", + "# Set the path to import module\n", + "from pathlib import Path\n", + "current_path = Path().resolve()\n", + "current_path = current_path.parent.parent\n", + "if str(current_path) not in sys.path:\n", + " sys.path.append(str(current_path))\n", + "# Print sys.path to verify\n", + "# print(sys.path)\n", + "\n", + "from utils.knowledge_base import BedrockKnowledgeBase" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "#Clients\n", + "s3_client = boto3.client('s3')\n", + "sts_client = boto3.client('sts')\n", + "session = boto3.session.Session()\n", + "region = session.region_name\n", + "account_id = sts_client.get_caller_identity()[\"Account\"]\n", + "bedrock_agent_client = boto3.client('bedrock-agent')\n", + "bedrock_agent_runtime_client = boto3.client('bedrock-agent-runtime') \n", + "logging.basicConfig(format='[%(asctime)s] p%(process)s {%(filename)s:%(lineno)d} %(levelname)s - %(message)s', level=logging.INFO)\n", + "logger = logging.getLogger(__name__)\n", + "region, account_id" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "import time\n", + "\n", + "# Get the current timestamp\n", + "current_time = time.time()\n", + "\n", + "# Format the timestamp as a string\n", + "timestamp_str = time.strftime(\"%Y%m%d%H%M%S\", time.localtime(current_time))[-7:]\n", + "# Create the suffix using the timestamp\n", + "suffix = f\"{timestamp_str}\"\n", + "\n", + "knowledge_base_name = f\"bedrock-multi-modal-kb-{suffix}\"\n", + "knowledge_base_description = \"Multi-modal RAG knowledge base.\"\n", + "\n", + "bucket_name = f'{knowledge_base_name}-{account_id}'\n", + "# intermediate_bucket_name = f'{knowledge_base_name}-mm-storage-{account_id}'\n", + "foundation_model = \"anthropic.claude-3-sonnet-20240229-v1:0\"" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "#### You can add multiple data sources (S3, Sharepoint) to a multimodal Knowledge Base. For this notebook, we'll test Knowledge Base creation with S3 Bucket." + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "\n", + "Each data source may have different pre-requisites, please refer to the AWS documetation for more information." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "tags": [] + }, + "outputs": [], + "source": [ + "## Please uncomment the data sources that you want to add and update the placeholder values accordingly.\n", + "\n", + "data_sources=[\n", + " {\"type\": \"S3\", \"bucket_name\": bucket_name}, \n", + "\n", + " # {\"type\": \"SHAREPOINT\", \"tenantId\": \"888d0b57-69f1-4fb8-957f-e1f0bedf64de\", \"domain\": \"yourdomain\",\n", + " # \"authType\": \"OAUTH2_CLIENT_CREDENTIALS\",\n", + " # \"credentialsSecretArn\": f\"arn:aws::secretsmanager:{region_name}:secret:<>\",\n", + " # \"siteUrls\": [\"https://yourdomain.sharepoint.com/sites/mysite\"]\n", + " # },\n", + " ]\n", + " \n", + "pp = pprint.PrettyPrinter(indent=2)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### 1 - Create Knowledge Base with Multi modality" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# For multi-modal RAG While instantiating BedrockKnowledgeBase, pass multi_modal= True and choose the parser you want to use\n", + "\n", + "knowledge_base = BedrockKnowledgeBase(\n", + " kb_name=f'{knowledge_base_name}',\n", + " kb_description=knowledge_base_description,\n", + " data_sources=data_sources,\n", + " multi_modal= True,\n", + " parser='BEDROCK_FOUNDATION_MODEL', # BEDROCK_DATA_AUTOMATION\n", + " chunking_strategy = \"FIXED_SIZE\", \n", + " suffix = f'{suffix}-f'\n", + ")" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### 2 - Data Ingestion\n", + "We'll download publically available rich content PDF and upload it to an S3 bucket" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "import os\n", + "\n", + "def create_directory(directory_name): \n", + " if not os.path.exists(directory_name):\n", + " os.makedirs(directory_name)\n", + " print(f\"Directory '{directory_name}' created successfully.\")\n", + " else:\n", + " print(f\"Directory '{directory_name}' already exists.\")\n", + "\n", + "# Call the function to create the directory\n", + "create_directory(\"mm-data\")" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "import requests\n", + "\n", + "def download_file(url, filename):\n", + " # Send a GET request to the URL\n", + " response = requests.get(url)\n", + " \n", + " # Check if the request was successful\n", + " if response.status_code == 200:\n", + " # Open the file in write-binary mode\n", + " with open(filename, 'wb') as file:\n", + " # Write the content of the response to the file\n", + " file.write(response.content)\n", + " print(f\"File downloaded successfully: {filename}\")\n", + " else:\n", + " print(f\"Failed to download file. Status code: {response.status_code}\")\n", + "\n", + "# URL of the file to download\n", + "url = \"https://sgp.fas.org/crs/misc/IF12695.pdf\"\n", + "\n", + "# Name for the downloaded file\n", + "filename = \"./mm-data/tornadoes_report.pdf\"\n", + "\n", + "# Call the function to download the file\n", + "download_file(url, filename)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "##### Upload data to S3 Bucket data source" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "tags": [] + }, + "outputs": [], + "source": [ + "def upload_directory(path, bucket_name):\n", + " for root,dirs,files in os.walk(path):\n", + " for file in files:\n", + " file_to_upload = os.path.join(root,file)\n", + " print(f\"uploading file {file_to_upload} to {bucket_name}\")\n", + " s3_client.upload_file(file_to_upload,bucket_name,file)\n", + "\n", + "upload_directory(\"./mm-data\", bucket_name)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Start ingestion job\n", + "Once the KB and data source(s) created, we can start the ingestion job for each data source.\n", + "During the ingestion job, KB will fetch the documents from the data source, Parse the document to extract text, chunk it based on the chunking size provided, create embeddings of each chunk and then write it to the vector database, in this case OSS.\n", + "\n", + "NOTE: Currently, you can only kick-off one ingestion job at one time." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# ensure that the kb is available\n", + "time.sleep(30)\n", + "# sync knowledge base\n", + "knowledge_base.start_ingestion_job()" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# keep the kb_id for invocation later in the invoke request\n", + "kb_id = knowledge_base.get_knowledge_base_id()\n", + "%store kb_id" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### 4 - Test the Knowledge Base\n", + "Now the Knowlegde Base is available we can test it out using the [**retrieve**](https://boto3.amazonaws.com/v1/documentation/api/latest/reference/services/bedrock-agent-runtime/client/retrieve.html) and [**retrieve_and_generate**](https://boto3.amazonaws.com/v1/documentation/api/latest/reference/services/bedrock-agent-runtime/client/retrieve_and_generate.html) functions. \n", + "\n", + "#### Testing Knowledge Base with Retrieve and Generate API\n", + "\n", + "Let's first test the knowledge base using the retrieve and generate API. With this API, Bedrock takes care of retrieving the necessary references from the knowledge base and generating the final answer using a foundation model from Bedrock.\n", + "\n", + "query = `Summarize annual trends of tornado reports and how it varies year over year.`\n", + "\n", + "The right response for this query is expected to fetch from a chart/graph from the PDF document." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "query = \"Summarize annual trends of tornado reports and how it varies year over year.\"" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "foundation_model = \"anthropic.claude-3-sonnet-20240229-v1:0\"\n", + "# foundation_model = \"amazon.nova-micro-v1:0\"\n", + "\n", + "response = bedrock_agent_runtime_client.retrieve_and_generate(\n", + " input={\n", + " \"text\": query\n", + " },\n", + " retrieveAndGenerateConfiguration={\n", + " \"type\": \"KNOWLEDGE_BASE\",\n", + " \"knowledgeBaseConfiguration\": {\n", + " 'knowledgeBaseId': kb_id,\n", + " \"modelArn\": \"arn:aws:bedrock:{}::foundation-model/{}\".format(region, foundation_model),\n", + " \"retrievalConfiguration\": {\n", + " \"vectorSearchConfiguration\": {\n", + " \"numberOfResults\":5\n", + " } \n", + " }\n", + " }\n", + " }\n", + ")\n", + "\n", + "print(response['output']['text'],end='\\n'*2)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "from PIL import Image\n", + "import s3fs\n", + "\n", + "fs = s3fs.S3FileSystem()\n", + "\n", + "## Function to print retrieved response\n", + "\n", + "def print_response(response):\n", + "#structure 'retrievalResults': list of contents. Each list has ['ResponseMetadata', 'citations', 'output', 'sessionId']\n", + " print( f'OUTPUT: {response[\"output\"][\"text\"]} \\n')\n", + " \n", + " print(f'CITATION DETAILS: \\n')\n", + " \n", + " for num, chunk in enumerate(response['citations']):\n", + " print(f'CHUNK {num}',end='\\n'*1)\n", + " print(\"========\")\n", + " print(f'\\t Generated Response Text: ')\n", + " print(f'\\t ------------------------- ')\n", + " print(f'\\t Generated Response Text: ',chunk['generatedResponsePart']['textResponsePart']['text'],end='\\n'*2)\n", + " for i, ref in enumerate (chunk['retrievedReferences']):\n", + " print(f'\\t Retrieved References: ')\n", + " print(f'\\t ---------------------', )\n", + " print(f'\\n\\t\\t --> Location:', ref['location'])\n", + " print(f'\\t\\n\\t\\t --> Metadata: \\n\\t\\t\\t ---> Source', ref['metadata']['x-amz-bedrock-kb-source-uri'])\n", + " # print(f'\\t\\n\\t\\t\\n\\t\\t\\t ---> x-amz-bedrock-kb-description', ref['metadata']['x-amz-bedrock-kb-description'])\n", + " print(f'\\t\\n\\t\\t\\n\\t\\t\\t ---> x-amz-bedrock-kb-byte-content-source', ref['metadata']['x-amz-bedrock-kb-byte-content-source'])\n", + " print(\"\")\n", + " with fs.open(ref['metadata']['x-amz-bedrock-kb-byte-content-source']) as f:\n", + " display(Image.open(f).resize((400, 400)))" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "print_response(response)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "#### Testing Knowledge Base with Retrieve API\n", + "If you need an extra layer of control, you can retrieve the chuncks that best match your query using the retrieve API. In this setup, we can configure the desired number of results and control the final answer with your own application logic. The API then provides you with the matching content, its S3 location, the similarity score and the chunk metadata." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "response_ret = bedrock_agent_runtime_client.retrieve(\n", + " knowledgeBaseId=kb_id, \n", + " nextToken='string',\n", + " retrievalConfiguration={\n", + " \"vectorSearchConfiguration\": {\n", + " \"numberOfResults\":5,\n", + " } \n", + " },\n", + " retrievalQuery={\n", + " \"text\": \"How many new positions were opened across Amazon's fulfillment and delivery network?\"\n", + " }\n", + ")\n", + "\n", + "def response_print(retrieve_resp):\n", + "#structure 'retrievalResults': list of contents. Each list has content, location, score, metadata\n", + " for num,chunk in enumerate(response_ret['retrievalResults'],1):\n", + " if 'text' in chunk['content']:\n", + " print(f'Chunk {num}: ',chunk['content']['text'],end='\\n'*2)\n", + " if 'byteContent' in chunk['content']:\n", + " print(f'Chunk {num}: ',chunk['content']['byteContent'],end='\\n'*2)\n", + " print(f'Chunk {num} Location: ',chunk['location'],end='\\n'*2)\n", + " print(f'Chunk {num} Score: ',chunk['score'],end='\\n'*2)\n", + " print(f'Chunk {num} Metadata: ',chunk['metadata'],end='\\n'*2)\n", + " print(\"--------------------------------\")\n", + "\n", + "response_print(response_ret)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Clean up\n", + "Please make sure to uncomment and run the below section to delete all the resources." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# delete local directory\n", + "import shutil\n", + "\n", + "dir_path = \"mm-data\" # Replace with the actual path\n", + "\n", + "try:\n", + " shutil.rmtree(dir_path)\n", + " print(f\"Directory '{dir_path}' and its contents have been deleted successfully.\")\n", + "except FileNotFoundError:\n", + " print(f\"Directory '{dir_path}' not found.\")\n", + "except Exception as e:\n", + " print(f\"An error occurred: {e}\")" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# # Delete resources\n", + "# print(\"===============================Deleteing resources ==============================\\n\")\n", + "knowledge_base.delete_kb(delete_s3_bucket=True, delete_iam_roles_and_policies=True)\n" + ] + } + ], + "metadata": { + "availableInstances": [ + { + "_defaultOrder": 0, + "_isFastLaunch": true, + "category": "General purpose", + "gpuNum": 0, + "hideHardwareSpecs": false, + "memoryGiB": 4, + "name": "ml.t3.medium", + "vcpuNum": 2 + }, + { + "_defaultOrder": 1, + "_isFastLaunch": false, + "category": "General purpose", + "gpuNum": 0, + "hideHardwareSpecs": false, + "memoryGiB": 8, + "name": "ml.t3.large", + "vcpuNum": 2 + }, + { + "_defaultOrder": 2, + "_isFastLaunch": false, + "category": "General purpose", + "gpuNum": 0, + "hideHardwareSpecs": false, + "memoryGiB": 16, + "name": "ml.t3.xlarge", + "vcpuNum": 4 + }, + { + "_defaultOrder": 3, + "_isFastLaunch": false, + "category": "General purpose", + "gpuNum": 0, + "hideHardwareSpecs": false, + "memoryGiB": 32, + "name": "ml.t3.2xlarge", + "vcpuNum": 8 + }, + { + "_defaultOrder": 4, + "_isFastLaunch": true, + "category": "General purpose", + "gpuNum": 0, + "hideHardwareSpecs": false, + "memoryGiB": 8, + "name": "ml.m5.large", + "vcpuNum": 2 + }, + { + "_defaultOrder": 5, + "_isFastLaunch": false, + "category": "General purpose", + "gpuNum": 0, + "hideHardwareSpecs": false, + "memoryGiB": 16, + "name": "ml.m5.xlarge", + "vcpuNum": 4 + }, + { + "_defaultOrder": 6, + "_isFastLaunch": false, + "category": "General purpose", + "gpuNum": 0, + "hideHardwareSpecs": false, + "memoryGiB": 32, + "name": "ml.m5.2xlarge", + "vcpuNum": 8 + }, + { + "_defaultOrder": 7, + "_isFastLaunch": false, + "category": "General purpose", + "gpuNum": 0, + "hideHardwareSpecs": false, + "memoryGiB": 64, + "name": "ml.m5.4xlarge", + "vcpuNum": 16 + }, + { + "_defaultOrder": 8, + "_isFastLaunch": false, + "category": "General purpose", + "gpuNum": 0, + "hideHardwareSpecs": false, + "memoryGiB": 128, + "name": "ml.m5.8xlarge", + "vcpuNum": 32 + }, + { + "_defaultOrder": 9, + "_isFastLaunch": false, + "category": "General purpose", + "gpuNum": 0, + "hideHardwareSpecs": false, + "memoryGiB": 192, + "name": "ml.m5.12xlarge", + "vcpuNum": 48 + }, + { + "_defaultOrder": 10, + "_isFastLaunch": false, + "category": "General purpose", + "gpuNum": 0, + "hideHardwareSpecs": false, + "memoryGiB": 256, + "name": "ml.m5.16xlarge", + "vcpuNum": 64 + }, + { + "_defaultOrder": 11, + "_isFastLaunch": false, + "category": "General purpose", + "gpuNum": 0, + "hideHardwareSpecs": false, + "memoryGiB": 384, + "name": "ml.m5.24xlarge", + "vcpuNum": 96 + }, + { + "_defaultOrder": 12, + "_isFastLaunch": false, + "category": "General purpose", + "gpuNum": 0, + "hideHardwareSpecs": false, + "memoryGiB": 8, + "name": "ml.m5d.large", + "vcpuNum": 2 + }, + { + "_defaultOrder": 13, + "_isFastLaunch": false, + "category": "General purpose", + "gpuNum": 0, + "hideHardwareSpecs": false, + "memoryGiB": 16, + "name": "ml.m5d.xlarge", + "vcpuNum": 4 + }, + { + "_defaultOrder": 14, + "_isFastLaunch": false, + "category": "General purpose", + "gpuNum": 0, + "hideHardwareSpecs": false, + "memoryGiB": 32, + "name": "ml.m5d.2xlarge", + "vcpuNum": 8 + }, + { + "_defaultOrder": 15, + "_isFastLaunch": false, + "category": "General purpose", + "gpuNum": 0, + "hideHardwareSpecs": false, + "memoryGiB": 64, + "name": "ml.m5d.4xlarge", + "vcpuNum": 16 + }, + { + "_defaultOrder": 16, + "_isFastLaunch": false, + "category": "General purpose", + "gpuNum": 0, + "hideHardwareSpecs": false, + "memoryGiB": 128, + "name": "ml.m5d.8xlarge", + "vcpuNum": 32 + }, + { + "_defaultOrder": 17, + "_isFastLaunch": false, + "category": "General purpose", + "gpuNum": 0, + "hideHardwareSpecs": false, + "memoryGiB": 192, + "name": "ml.m5d.12xlarge", + "vcpuNum": 48 + }, + { + "_defaultOrder": 18, + "_isFastLaunch": false, + "category": "General purpose", + "gpuNum": 0, + "hideHardwareSpecs": false, + "memoryGiB": 256, + "name": "ml.m5d.16xlarge", + "vcpuNum": 64 + }, + { + "_defaultOrder": 19, + "_isFastLaunch": false, + "category": "General purpose", + "gpuNum": 0, + "hideHardwareSpecs": false, + "memoryGiB": 384, + "name": "ml.m5d.24xlarge", + "vcpuNum": 96 + }, + { + "_defaultOrder": 20, + "_isFastLaunch": false, + "category": "General purpose", + "gpuNum": 0, + "hideHardwareSpecs": true, + "memoryGiB": 0, + "name": "ml.geospatial.interactive", + "supportedImageNames": [ + "sagemaker-geospatial-v1-0" + ], + "vcpuNum": 0 + }, + { + "_defaultOrder": 21, + "_isFastLaunch": true, + "category": "Compute optimized", + "gpuNum": 0, + "hideHardwareSpecs": false, + "memoryGiB": 4, + "name": "ml.c5.large", + "vcpuNum": 2 + }, + { + "_defaultOrder": 22, + "_isFastLaunch": false, + "category": "Compute optimized", + "gpuNum": 0, + "hideHardwareSpecs": false, + "memoryGiB": 8, + "name": "ml.c5.xlarge", + "vcpuNum": 4 + }, + { + "_defaultOrder": 23, + "_isFastLaunch": false, + "category": "Compute optimized", + "gpuNum": 0, + "hideHardwareSpecs": false, + "memoryGiB": 16, + "name": "ml.c5.2xlarge", + "vcpuNum": 8 + }, + { + "_defaultOrder": 24, + "_isFastLaunch": false, + "category": "Compute optimized", + "gpuNum": 0, + "hideHardwareSpecs": false, + "memoryGiB": 32, + "name": "ml.c5.4xlarge", + "vcpuNum": 16 + }, + { + "_defaultOrder": 25, + "_isFastLaunch": false, + "category": "Compute optimized", + "gpuNum": 0, + "hideHardwareSpecs": false, + "memoryGiB": 72, + "name": "ml.c5.9xlarge", + "vcpuNum": 36 + }, + { + "_defaultOrder": 26, + "_isFastLaunch": false, + "category": "Compute optimized", + "gpuNum": 0, + "hideHardwareSpecs": false, + "memoryGiB": 96, + "name": "ml.c5.12xlarge", + "vcpuNum": 48 + }, + { + "_defaultOrder": 27, + "_isFastLaunch": false, + "category": "Compute optimized", + "gpuNum": 0, + "hideHardwareSpecs": false, + "memoryGiB": 144, + "name": "ml.c5.18xlarge", + "vcpuNum": 72 + }, + { + "_defaultOrder": 28, + "_isFastLaunch": false, + "category": "Compute optimized", + "gpuNum": 0, + "hideHardwareSpecs": false, + "memoryGiB": 192, + "name": "ml.c5.24xlarge", + "vcpuNum": 96 + }, + { + "_defaultOrder": 29, + "_isFastLaunch": true, + "category": "Accelerated computing", + "gpuNum": 1, + "hideHardwareSpecs": false, + "memoryGiB": 16, + "name": "ml.g4dn.xlarge", + "vcpuNum": 4 + }, + { + "_defaultOrder": 30, + "_isFastLaunch": false, + "category": "Accelerated computing", + "gpuNum": 1, + "hideHardwareSpecs": false, + "memoryGiB": 32, + "name": "ml.g4dn.2xlarge", + "vcpuNum": 8 + }, + { + "_defaultOrder": 31, + "_isFastLaunch": false, + "category": "Accelerated computing", + "gpuNum": 1, + "hideHardwareSpecs": false, + "memoryGiB": 64, + "name": "ml.g4dn.4xlarge", + "vcpuNum": 16 + }, + { + "_defaultOrder": 32, + "_isFastLaunch": false, + "category": "Accelerated computing", + "gpuNum": 1, + "hideHardwareSpecs": false, + "memoryGiB": 128, + "name": "ml.g4dn.8xlarge", + "vcpuNum": 32 + }, + { + "_defaultOrder": 33, + "_isFastLaunch": false, + "category": "Accelerated computing", + "gpuNum": 4, + "hideHardwareSpecs": false, + "memoryGiB": 192, + "name": "ml.g4dn.12xlarge", + "vcpuNum": 48 + }, + { + "_defaultOrder": 34, + "_isFastLaunch": false, + "category": "Accelerated computing", + "gpuNum": 1, + "hideHardwareSpecs": false, + "memoryGiB": 256, + "name": "ml.g4dn.16xlarge", + "vcpuNum": 64 + }, + { + "_defaultOrder": 35, + "_isFastLaunch": false, + "category": "Accelerated computing", + "gpuNum": 1, + "hideHardwareSpecs": false, + "memoryGiB": 61, + "name": "ml.p3.2xlarge", + "vcpuNum": 8 + }, + { + "_defaultOrder": 36, + "_isFastLaunch": false, + "category": "Accelerated computing", + "gpuNum": 4, + "hideHardwareSpecs": false, + "memoryGiB": 244, + "name": "ml.p3.8xlarge", + "vcpuNum": 32 + }, + { + "_defaultOrder": 37, + "_isFastLaunch": false, + "category": "Accelerated computing", + "gpuNum": 8, + "hideHardwareSpecs": false, + "memoryGiB": 488, + "name": "ml.p3.16xlarge", + "vcpuNum": 64 + }, + { + "_defaultOrder": 38, + "_isFastLaunch": false, + "category": "Accelerated computing", + "gpuNum": 8, + "hideHardwareSpecs": false, + "memoryGiB": 768, + "name": "ml.p3dn.24xlarge", + "vcpuNum": 96 + }, + { + "_defaultOrder": 39, + "_isFastLaunch": false, + "category": "Memory Optimized", + "gpuNum": 0, + "hideHardwareSpecs": false, + "memoryGiB": 16, + "name": "ml.r5.large", + "vcpuNum": 2 + }, + { + "_defaultOrder": 40, + "_isFastLaunch": false, + "category": "Memory Optimized", + "gpuNum": 0, + "hideHardwareSpecs": false, + "memoryGiB": 32, + "name": "ml.r5.xlarge", + "vcpuNum": 4 + }, + { + "_defaultOrder": 41, + "_isFastLaunch": false, + "category": "Memory Optimized", + "gpuNum": 0, + "hideHardwareSpecs": false, + "memoryGiB": 64, + "name": "ml.r5.2xlarge", + "vcpuNum": 8 + }, + { + "_defaultOrder": 42, + "_isFastLaunch": false, + "category": "Memory Optimized", + "gpuNum": 0, + "hideHardwareSpecs": false, + "memoryGiB": 128, + "name": "ml.r5.4xlarge", + "vcpuNum": 16 + }, + { + "_defaultOrder": 43, + "_isFastLaunch": false, + "category": "Memory Optimized", + "gpuNum": 0, + "hideHardwareSpecs": false, + "memoryGiB": 256, + "name": "ml.r5.8xlarge", + "vcpuNum": 32 + }, + { + "_defaultOrder": 44, + "_isFastLaunch": false, + "category": "Memory Optimized", + "gpuNum": 0, + "hideHardwareSpecs": false, + "memoryGiB": 384, + "name": "ml.r5.12xlarge", + "vcpuNum": 48 + }, + { + "_defaultOrder": 45, + "_isFastLaunch": false, + "category": "Memory Optimized", + "gpuNum": 0, + "hideHardwareSpecs": false, + "memoryGiB": 512, + "name": "ml.r5.16xlarge", + "vcpuNum": 64 + }, + { + "_defaultOrder": 46, + "_isFastLaunch": false, + "category": "Memory Optimized", + "gpuNum": 0, + "hideHardwareSpecs": false, + "memoryGiB": 768, + "name": "ml.r5.24xlarge", + "vcpuNum": 96 + }, + { + "_defaultOrder": 47, + "_isFastLaunch": false, + "category": "Accelerated computing", + "gpuNum": 1, + "hideHardwareSpecs": false, + "memoryGiB": 16, + "name": "ml.g5.xlarge", + "vcpuNum": 4 + }, + { + "_defaultOrder": 48, + "_isFastLaunch": false, + "category": "Accelerated computing", + "gpuNum": 1, + "hideHardwareSpecs": false, + "memoryGiB": 32, + "name": "ml.g5.2xlarge", + "vcpuNum": 8 + }, + { + "_defaultOrder": 49, + "_isFastLaunch": false, + "category": "Accelerated computing", + "gpuNum": 1, + "hideHardwareSpecs": false, + "memoryGiB": 64, + "name": "ml.g5.4xlarge", + "vcpuNum": 16 + }, + { + "_defaultOrder": 50, + "_isFastLaunch": false, + "category": "Accelerated computing", + "gpuNum": 1, + "hideHardwareSpecs": false, + "memoryGiB": 128, + "name": "ml.g5.8xlarge", + "vcpuNum": 32 + }, + { + "_defaultOrder": 51, + "_isFastLaunch": false, + "category": "Accelerated computing", + "gpuNum": 1, + "hideHardwareSpecs": false, + "memoryGiB": 256, + "name": "ml.g5.16xlarge", + "vcpuNum": 64 + }, + { + "_defaultOrder": 52, + "_isFastLaunch": false, + "category": "Accelerated computing", + "gpuNum": 4, + "hideHardwareSpecs": false, + "memoryGiB": 192, + "name": "ml.g5.12xlarge", + "vcpuNum": 48 + }, + { + "_defaultOrder": 53, + "_isFastLaunch": false, + "category": "Accelerated computing", + "gpuNum": 4, + "hideHardwareSpecs": false, + "memoryGiB": 384, + "name": "ml.g5.24xlarge", + "vcpuNum": 96 + }, + { + "_defaultOrder": 54, + "_isFastLaunch": false, + "category": "Accelerated computing", + "gpuNum": 8, + "hideHardwareSpecs": false, + "memoryGiB": 768, + "name": "ml.g5.48xlarge", + "vcpuNum": 192 + }, + { + "_defaultOrder": 55, + "_isFastLaunch": false, + "category": "Accelerated computing", + "gpuNum": 8, + "hideHardwareSpecs": false, + "memoryGiB": 1152, + "name": "ml.p4d.24xlarge", + "vcpuNum": 96 + }, + { + "_defaultOrder": 56, + "_isFastLaunch": false, + "category": "Accelerated computing", + "gpuNum": 8, + "hideHardwareSpecs": false, + "memoryGiB": 1152, + "name": "ml.p4de.24xlarge", + "vcpuNum": 96 + }, + { + "_defaultOrder": 57, + "_isFastLaunch": false, + "category": "Accelerated computing", + "gpuNum": 0, + "hideHardwareSpecs": false, + "memoryGiB": 32, + "name": "ml.trn1.2xlarge", + "vcpuNum": 8 + }, + { + "_defaultOrder": 58, + "_isFastLaunch": false, + "category": "Accelerated computing", + "gpuNum": 0, + "hideHardwareSpecs": false, + "memoryGiB": 512, + "name": "ml.trn1.32xlarge", + "vcpuNum": 128 + }, + { + "_defaultOrder": 59, + "_isFastLaunch": false, + "category": "Accelerated computing", + "gpuNum": 0, + "hideHardwareSpecs": false, + "memoryGiB": 512, + "name": "ml.trn1n.32xlarge", + "vcpuNum": 128 + } + ], + "instance_type": "ml.t3.medium", + "kernelspec": { + "display_name": "Python 3", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.10.13" + } + }, + "nbformat": 4, + "nbformat_minor": 4 +} From 29f0d6e2d6361f1da91b350db1a59acfd5ed012b Mon Sep 17 00:00:00 2001 From: Rubab Khan Date: Wed, 19 Feb 2025 10:56:19 -0800 Subject: [PATCH 2/2] Kept module-1 NBs only, removed the rest --- .../autogenerated-metadata-filters.ipynb | 1591 ----------------- .../re-ranking_using_kb.ipynb | 1574 ---------------- .../structured-rag-using-kb.ipynb | 711 -------- .../text-images-rag-using-kb.ipynb | 1172 ------------ 4 files changed, 5048 deletions(-) delete mode 100644 02-optimizing-accuracy-retrieved-results/autogenerated-metadata-filters.ipynb delete mode 100644 02-optimizing-accuracy-retrieved-results/re-ranking_using_kb.ipynb delete mode 100644 05-structured-rag/structured-rag-using-kb.ipynb delete mode 100644 06-multi-modal-rag/text-images-rag-using-kb/text-images-rag-using-kb.ipynb diff --git a/02-optimizing-accuracy-retrieved-results/autogenerated-metadata-filters.ipynb b/02-optimizing-accuracy-retrieved-results/autogenerated-metadata-filters.ipynb deleted file mode 100644 index 4c9d823..0000000 --- a/02-optimizing-accuracy-retrieved-results/autogenerated-metadata-filters.ipynb +++ /dev/null @@ -1,1591 +0,0 @@ -{ - "cells": [ - { - "cell_type": "markdown", - "id": "15c08f81", - "metadata": {}, - "source": [ - "# Autogenerated filters\n", - "\n", - "## Overview\n", - "\n", - "This notebook demonstrates the **Autogenerated Filters** feature of Amazon Bedrock Knowledge Bases, which enhances search capabilities through automatic metadata filtering. By leveraging Amazon Bedrock's foundation models, the Autogenerated Filters feature dynamically interprets user queries and generates appropriate metadata filters based on the defined metadata schema for the Knowledge Base. This improves the quality and relevance of search results without requiring explicit filter specifications.\n", - "\n", - "The Autogenerated Filters feature is enabled through the `implicitFilterConfiguration` parameter within the `vectorSearchConfiguration` of the `retrievalConfiguration` in the `Retrieve` and `RetrieveAndGenerate` API calls. These APIs analyze the user's query, identify relevant metadata attributes based on the specified `implicitFilterConfiguration`, and apply these filters to narrow down the search results.\n", - "\n", - "For example, if a user searches for \"marketing reports from last year,\" the Autogenerated Filters feature can automatically recognize that \"last year\" refers to a specific time period and apply a filter based on the date metadata field. Similarly, if the query mentions a specific product or department, the system can apply filters based on the corresponding metadata fields.\n", - "\n", - "Let's explore how to implement and utilize Autogenerated Filters with Amazon Bedrock Knowledge Bases for an example use case." - ] - }, - { - "cell_type": "markdown", - "id": "ece99ba7", - "metadata": {}, - "source": [ - "## 1. Setup\n", - "Before running the rest of this notebook, you'll need to run the cells below to (ensure necessary libraries are installed and) connect to Bedrock.\n", - "\n", - "Please ignore any pip dependency error (if you see any while installing libraries)" - ] - }, - { - "cell_type": "code", - "execution_count": 1, - "id": "dc89fe3a", - "metadata": {}, - "outputs": [], - "source": [ - "%pip install --force-reinstall -q -r utils/requirements.txt --quiet" - ] - }, - { - "cell_type": "code", - "execution_count": 2, - "id": "57056c5d", - "metadata": {}, - "outputs": [], - "source": [ - "%pip install --upgrade boto3" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "165e5495", - "metadata": {}, - "outputs": [], - "source": [ - "# restart kernel\n", - "from IPython.core.display import HTML\n", - "HTML(\"\")" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "7c1c0eb1", - "metadata": {}, - "outputs": [], - "source": [ - "import boto3\n", - "print(boto3.__version__)" - ] - }, - { - "cell_type": "code", - "execution_count": 5, - "id": "7173b4bf", - "metadata": {}, - "outputs": [], - "source": [ - "import warnings\n", - "warnings.filterwarnings('ignore')" - ] - }, - { - "cell_type": "code", - "execution_count": 6, - "id": "84241929", - "metadata": {}, - "outputs": [], - "source": [ - "import os\n", - "import sys\n", - "import time\n", - "import boto3\n", - "import logging\n", - "import pprint\n", - "import json\n", - "\n", - "# Set the path to import module\n", - "from pathlib import Path\n", - "current_path = Path().resolve()\n", - "current_path = current_path.parent\n", - "if str(current_path) not in sys.path:\n", - " sys.path.append(str(current_path))\n", - "# Print sys.path to verify\n", - "# print(sys.path)\n", - "\n", - "from utils.knowledge_base import BedrockKnowledgeBase" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "cda1c18f", - "metadata": {}, - "outputs": [], - "source": [ - "#Clients\n", - "s3_client = boto3.client('s3')\n", - "sts_client = boto3.client('sts')\n", - "session = boto3.session.Session()\n", - "region = session.region_name\n", - "account_id = sts_client.get_caller_identity()[\"Account\"]\n", - "bedrock_agent_client = boto3.client('bedrock-agent')\n", - "bedrock_agent_runtime_client = boto3.client('bedrock-agent-runtime') \n", - "logging.basicConfig(format='[%(asctime)s] p%(process)s {%(filename)s:%(lineno)d} %(levelname)s - %(message)s', level=logging.INFO)\n", - "logger = logging.getLogger(__name__)\n", - "region, account_id" - ] - }, - { - "cell_type": "code", - "execution_count": 8, - "id": "5d74b5be", - "metadata": {}, - "outputs": [], - "source": [ - "import time\n", - "\n", - "# Get the current timestamp\n", - "current_time = time.time()\n", - "\n", - "# Format the timestamp as a string\n", - "timestamp_str = time.strftime(\"%Y%m%d%H%M%S\", time.localtime(current_time))[-7:]\n", - "# Create the suffix using the timestamp\n", - "suffix = f\"{timestamp_str}\"\n", - "knowledge_base_name = 'autogenerated-filters-kb'\n", - "knowledge_base_description = \"Knowledge Base autogenerated metadata filtering.\"\n", - "bucket_name = f'{knowledge_base_name}-{suffix}'\n", - "foundation_model = \"anthropic.claude-3-sonnet-20240229-v1:0\"" - ] - }, - { - "cell_type": "markdown", - "id": "e5142d7f", - "metadata": {}, - "source": [ - "## 2 - Create knowledge bases with fixed chunking strategy\n", - "Let's start by creating a [Knowledge Base for Amazon Bedrock](https://aws.amazon.com/bedrock/knowledge-bases/) to store video games data in csv format. Knowledge Bases allow you to integrate with different vector databases including [Amazon OpenSearch Serverless](https://aws.amazon.com/opensearch-service/features/serverless/), [Amazon Aurora](https://aws.amazon.com/rds/aurora/), [Pinecone](http://app.pinecone.io/bedrock-integration), [Redis Enterprise]() and [MongoDB Atlas](). For this example, we will integrate the knowledge base with Amazon OpenSearch Serverless. To do so, we will use the helper class `BedrockKnowledgeBase` which will create the knowledge base and all of its pre-requisites:\n", - "1. IAM roles and policies\n", - "2. S3 bucket\n", - "3. Amazon OpenSearch Serverless encryption, network and data access policies\n", - "4. Amazon OpenSearch Serverless collection\n", - "5. Amazon OpenSearch Serverless vector index\n", - "6. Knowledge base\n", - "7. Knowledge base data source" - ] - }, - { - "cell_type": "markdown", - "id": "8283567d", - "metadata": {}, - "source": [ - "We will create a knowledge base using fixed chunking strategy. \n", - "\n", - "You can chhose different chunking strategies by changing the below parameter values: \n", - "```\n", - "\"chunkingStrategy\": \"FIXED_SIZE | NONE | HIERARCHICAL | SEMANTIC\"\n", - "```" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "258fbb58", - "metadata": {}, - "outputs": [], - "source": [ - "knowledge_base_metadata = BedrockKnowledgeBase(\n", - " kb_name=f'{knowledge_base_name}-{suffix}',\n", - " kb_description=knowledge_base_description,\n", - " data_bucket_name=bucket_name, \n", - " chunking_strategy = \"FIXED_SIZE\", \n", - " suffix = suffix\n", - ")" - ] - }, - { - "cell_type": "markdown", - "id": "c79183c7", - "metadata": {}, - "source": [ - "### 2.1 Download Amazon 2019, 2020, 2021, 2022, & 2023 annual reports and upload it to Amazon S3\n", - "\n", - "Now that we have created the knowledge base, let's populate it with the `sec-10-k reports` dataset to KB. This data is being downloaded from [here](https://ir.aboutamazon.com/annual-reports-proxies-and-shareholder-letters/default.aspx). This data is about Amazon's annual reports, proxies and shareholder letters." - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "c758da68", - "metadata": {}, - "outputs": [], - "source": [ - "import os\n", - "\n", - "def create_directory(directory_name): \n", - " if not os.path.exists(directory_name):\n", - " os.makedirs(directory_name)\n", - " print(f\"Directory '{directory_name}' created successfully.\")\n", - " else:\n", - " print(f\"Directory '{directory_name}' already exists.\")\n", - "\n", - "# Call the function to create the directory\n", - "create_directory(\"sec-10-k\")" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "a2bf67c7", - "metadata": {}, - "outputs": [], - "source": [ - "import requests\n", - "\n", - "def download_file(url, filename):\n", - " # Send a GET request to the URL\n", - " response = requests.get(url)\n", - " \n", - " # Check if the request was successful\n", - " if response.status_code == 200:\n", - " # Open the file in write-binary mode\n", - " with open(filename, 'wb') as file:\n", - " # Write the content of the response to the file\n", - " file.write(response.content)\n", - " print(f\"File downloaded successfully: {filename}\")\n", - " else:\n", - " print(f\"Failed to download file. Status code: {response.status_code}\")\n", - "\n", - "# URL of the files to download\n", - "urls = [\"https://s2.q4cdn.com/299287126/files/doc_financials/2024/ar/Amazon-com-Inc-2023-Annual-Report.pdf\",\n", - " \"https://s2.q4cdn.com/299287126/files/doc_financials/2023/ar/Amazon-2022-Annual-Report.pdf\",\n", - " \"https://s2.q4cdn.com/299287126/files/doc_financials/2022/ar/Amazon-2021-Annual-Report.pdf\",\n", - " \"https://s2.q4cdn.com/299287126/files/doc_financials/2021/ar/Amazon-2020-Annual-Report.pdf\",\n", - " \"https://s2.q4cdn.com/299287126/files/doc_financials/2020/ar/2019-Annual-Report.pdf\"]\n", - "\n", - "\n", - "for url in urls:\n", - " # Name for the downloaded file\n", - " filename = url.split('/')[-1]\n", - "\n", - " # Path to save the downloaded file\n", - " filepath = f\"./sec-10-k/{filename}\"\n", - "\n", - " # Call the function to download the file\n", - " download_file(url, filepath)" - ] - }, - { - "cell_type": "markdown", - "id": "70b83f68", - "metadata": {}, - "source": [ - "Let's upload the annual reports data available in the `sec-10-k` folder to s3." - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "40e12fc8", - "metadata": {}, - "outputs": [], - "source": [ - "def upload_directory(path, bucket_name):\n", - " for root,dirs,files in os.walk(path):\n", - " for file in files:\n", - " if not file.startswith('.DS_Store'):\n", - " file_to_upload = os.path.join(root,file)\n", - " print(f\"uploading file {file_to_upload} to {bucket_name}\")\n", - " s3_client.upload_file(file_to_upload,bucket_name,file)\n", - "\n", - "upload_directory(\"sec-10-k\", bucket_name)" - ] - }, - { - "cell_type": "markdown", - "id": "71fc40a4", - "metadata": {}, - "source": [ - "#### 2.3 Prepare metadata for ingestion\n" - ] - }, - { - "cell_type": "code", - "execution_count": 13, - "id": "65939633", - "metadata": {}, - "outputs": [], - "source": [ - "import json\n", - "import re\n", - "\n", - "def generate_matadata(data_dir):\n", - " \n", - " # Loop through all PDF files in the directory\n", - " for filename in os.listdir(data_dir):\n", - " if not filename.startswith('.DS_Store'):\n", - " # Define the metadata dictionary\n", - " metadata ={}\n", - " \n", - " filename= f'{data_dir}/{filename}'\n", - " print(filename)\n", - " \n", - " # Create metadata\n", - " metadata[\"company\"] = \"Amazon\"\n", - " metadata[\"ticker\"] = \"AMZN\"\n", - " metadata[\"year\"] = re.search(r'\\d+', filename.split('/')[-1]).group(0)\n", - "\n", - " # Create a JSON object\n", - " json_data = {\"metadataAttributes\": metadata}\n", - "\n", - " # print(json_data)\n", - "\n", - " # Write the JSON object to a file\n", - " with open(f\"{filename.replace('.pdf', '.pdf.metadata.json')}\", \"w\") as f:\n", - " json.dump(json_data, f)\n" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "a41bbeb3", - "metadata": {}, - "outputs": [], - "source": [ - "data_dir = './sec-10-k'\n", - "generate_matadata(data_dir)" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "2c913820", - "metadata": {}, - "outputs": [], - "source": [ - "# upload metadata file to S3\n", - "upload_directory(\"sec-10-k\", bucket_name)" - ] - }, - { - "cell_type": "markdown", - "id": "c524cd79", - "metadata": {}, - "source": [ - "Now start the ingestion job. Since, we are using the same documents as used for fixed chunking, we are skipping the step to upload documents to s3 bucket. " - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "6c35f597", - "metadata": {}, - "outputs": [], - "source": [ - "# ensure that the kb is available\n", - "time.sleep(30)\n", - "# sync knowledge base\n", - "knowledge_base_metadata.start_ingestion_job()" - ] - }, - { - "cell_type": "markdown", - "id": "3cf820bc", - "metadata": {}, - "source": [ - "Finally we save the Knowledge Base Id to test the solution at a later stage. " - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "f3c28c47", - "metadata": {}, - "outputs": [], - "source": [ - "kb_id_metadata = knowledge_base_metadata.get_knowledge_base_id()" - ] - }, - { - "cell_type": "markdown", - "id": "73deb547", - "metadata": {}, - "source": [ - "### 2.4 Enable Cloudwatch logs for Debugging our Autogenerated filters\n", - "\n", - "Below we're creating some helper functions to enable the cloudwatch logs for debugging." - ] - }, - { - "cell_type": "markdown", - "id": "702425bd", - "metadata": {}, - "source": [ - "#### Helper functions for CloudWatch Logs\n", - "\n", - "The helper functions facilitate the analysis of autogenerated filter generation by querying and processing CloudWatch logs. They provide insights into how user queries are leveraged to generate metadata filters. \n", - "\n", - "These functions allow you to examine the actual filters being generated, verify their consistency across different user query variations, and ensure they align with your expectations and query logic. If any filters are inconsistent or generated unexpectedly, you can use these functions to troubleshoot and understand the reasons behind it." - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "7063db1b", - "metadata": {}, - "outputs": [], - "source": [ - "import boto3\n", - "from botocore.exceptions import ClientError\n", - "\n", - "def create_cloudwatch_log_group_for_bedrock(log_group_name):\n", - " logs_client = boto3.client('logs')\n", - " try:\n", - " logs_client.create_log_group(logGroupName=log_group_name)\n", - " print(f\"Successfully created CloudWatch log group: {log_group_name}\")\n", - " return True\n", - " except ClientError as e:\n", - " if e.response['Error']['Code'] == 'ResourceAlreadyExistsException':\n", - " print(f\"Log group {log_group_name} already exists.\")\n", - " return True\n", - " else:\n", - " print(f\"Error creating log group: {e}\")\n", - " return False\n", - "\n", - "def enable_bedrock_invokemodel_logs(cw_log_group_name):\n", - " bedrock_client = boto3.client('bedrock')\n", - " log_group_name = cw_log_group_name\n", - " \n", - " if not create_cloudwatch_log_group_for_bedrock(log_group_name):\n", - " print(\"Failed to create or confirm log group. Aborting log enablement.\")\n", - " return False\n", - "\n", - " try:\n", - " get_kb_response = bedrock_agent_client.get_knowledge_base(knowledgeBaseId = kb_id_metadata)\n", - " role_arn = get_kb_response['knowledgeBase']['roleArn']\n", - " kb_role_name = role_arn.split('/')[-1]\n", - "\n", - " sts_client = boto3.client('sts')\n", - " account_id = sts_client.get_caller_identity()[\"Account\"]\n", - " role_name = kb_role_name \n", - " role_arn = f\"arn:aws:iam::{account_id}:role/{role_name}\"\n", - "\n", - " # Get all available model types\n", - " response = bedrock_client.list_foundation_models()\n", - " all_model_types = list(set([model['modelName'] for model in response['modelSummaries']]))\n", - "\n", - " response = bedrock_client.put_model_invocation_logging_configuration(\n", - " loggingConfig={\n", - " 'cloudWatchConfig': {\n", - " 'logGroupName': log_group_name,\n", - " 'roleArn': role_arn\n", - " },\n", - " 'textDataDeliveryEnabled': True,\n", - " 'imageDataDeliveryEnabled': True,\n", - " 'embeddingDataDeliveryEnabled': True,\n", - " 'videoDataDeliveryEnabled': True\n", - " }\n", - " )\n", - " \n", - " print(f\"Successfully enabled InvokeModel logging for Bedrock with log group: {log_group_name}\")\n", - " return True\n", - " except ClientError as e:\n", - " print(f\"Error enabling InvokeModel logging: {e}\")\n", - " return False\n", - "\n", - "def delete_bedrock_invokemodel_log_group(log_group_name):\n", - " log_group_name = \"/aws/bedrock/invokemodel\"\n", - " logs_client = boto3.client('logs')\n", - " try:\n", - " # First, disable the logging configuration in Bedrock\n", - " bedrock_client = boto3.client('bedrock')\n", - " bedrock_client.delete_model_invocation_logging_configuration()\n", - " print(\"Successfully disabled InvokeModel logging for Bedrock\")\n", - "\n", - " # Then, delete the log group\n", - " logs_client.delete_log_group(logGroupName=log_group_name)\n", - " print(f\"Successfully deleted CloudWatch log group: {log_group_name}\")\n", - " return True\n", - " except ClientError as e:\n", - " if e.response['Error']['Code'] == 'ResourceNotFoundException':\n", - " print(f\"Log group {log_group_name} does not exist.\")\n", - " return True\n", - " else:\n", - " print(f\"Error deleting log group or disabling logging: {e}\")\n", - " return False\n", - "\n", - "\n", - "# Call the function\n", - "cw_log_group_name = \"/aws/bedrock/invokemodel\"\n", - "\n", - "if enable_bedrock_invokemodel_logs(cw_log_group_name):\n", - " print(\"Bedrock InvokeModel logging has been set up successfully.\")\n", - " log_group_name = cw_log_group_name\n", - "else:\n", - " print(\"Failed to set up Bedrock InvokeModel logging.\")\n", - "\n", - "\n", - "print(\"Logroup name: \", log_group_name)" - ] - }, - { - "cell_type": "code", - "execution_count": 19, - "id": "ef626f37", - "metadata": {}, - "outputs": [], - "source": [ - "import time\n", - "from datetime import datetime, timezone\n", - "from datetime import timedelta\n", - "import boto3\n", - "import json\n", - "\n", - "cw_client = boto3.client('logs', region_name=region)\n", - "\n", - "def query_model_invocation_log(query_string):\n", - " # Start query\n", - " startTime=int((datetime.now(timezone.utc) - timedelta(minutes=60)).timestamp())\n", - " start_query_response = cw_client.start_query(\n", - " logGroupName=log_group_name,\n", - " startTime=int((datetime.now(timezone.utc) - timedelta(minutes=60)).timestamp()),\n", - " endTime=int(datetime.now(timezone.utc).timestamp()),\n", - " queryString=query_string,\n", - " )\n", - " query_id = start_query_response['queryId']\n", - " # Wait for the query to complete\n", - " response = None\n", - " while response == None or response['status'] == 'Running':\n", - " print('Waiting for query to complete ...')\n", - " time.sleep(1)\n", - " response = cw_client.get_query_results(\n", - " queryId=query_id\n", - " )\n", - "\n", - " # Print the results\n", - " print(f\"Query status: {response['status']}\")\n", - " return response\n", - "\n", - "def print_filter_generation_output(user_query):\n", - " print(user_query)\n", - " # Construct CloudWatch Logs Insights query\n", - " # This query:\n", - " # 1. Selects timestamp and message fields\n", - " # 2. Filters for filter generation task messages\n", - " # 3. Matches the user's query\n", - " # 4. Orders results by most recent first\n", - " response = query_model_invocation_log(\n", - " f\"\"\"\n", - " fields @timestamp, @message\n", - " | filter @message like /Your task is to structure the user's query to match the request schema provided below./\n", - " | filter input.inputBodyJson.messages.0.content.0.text like /{user_query}/\n", - " | sort @timestamp desc\n", - " \"\"\")\n", - " print(response)\n", - " results = response['results']\n", - " if (len(results) == 0):\n", - " print(\"No results found\")\n", - " return\n", - " \n", - " result= results[0][1]['value']\n", - " result_dict = json.loads(result)\n", - " print(f\"Generated filter:\")\n", - " filter_gen_output = result_dict['output']['outputBodyJson']['output']['message']['content'][0]['text']\n", - " print(filter_gen_output)" - ] - }, - { - "cell_type": "markdown", - "id": "f9e2880b", - "metadata": {}, - "source": [ - "### 2.5 Update Knowledge Bases execution role" - ] - }, - { - "cell_type": "code", - "execution_count": 20, - "id": "54d82518", - "metadata": {}, - "outputs": [], - "source": [ - "# Before using autogenerated filters - update the knowledge base execution IAM role with right permissions\n", - "\n", - "iam = boto3.resource('iam')\n", - "client = boto3.client('iam')\n", - "\n", - "def get_attached_policies(role_name):\n", - " response = client.list_attached_role_policies(RoleName=role_name)\n", - " attached_policies = response['AttachedPolicies']\n", - " return attached_policies\n", - "\n", - "# get the knowledge base IAM role name\n", - "get_kb_response = bedrock_agent_client.get_knowledge_base(knowledgeBaseId = kb_id_metadata)\n", - "role_arn = get_kb_response['knowledgeBase']['roleArn']\n", - "role_name = role_arn.split('/')[-1]\n", - "\n", - "# get attached policies\n", - "attached_policies = get_attached_policies(role_name)\n", - "attached_policies\n", - "\n", - "def update_kb_execution_role(attached_policies, region_name):\n", - " \n", - " for policy in attached_policies:\n", - "\n", - " print(policy['PolicyArn'])\n", - " policy_name = policy['PolicyName']\n", - " policy_arn = policy['PolicyArn']\n", - "\n", - " if 'FoundationModel' in policy_arn:\n", - " print('Updating FoundationModel policy: ',policy_arn)\n", - " policy = iam.Policy(policy_arn)\n", - " version = policy.default_version\n", - " policyJson = version.document\n", - " policyJson['Statement'][0]['Resource'].append('arn:aws:bedrock:{}::foundation-model/anthropic.claude-3-sonnet-20240229-v1:0'.format(region)) \n", - " policyJson['Statement'][0]['Resource'].append('arn:aws:bedrock:{}::foundation-model/anthropic.claude-3-5-sonnet-20240620-v1:0'.format(region)) \n", - " \n", - " client.detach_role_policy(RoleName=role_name,\n", - " PolicyArn=policy_arn)\n", - " \n", - " response = client.delete_policy(\n", - " PolicyArn=policy_arn\n", - " )\n", - " print(response)\n", - " \n", - " response = client.create_policy(\n", - " PolicyName= policy_name,\n", - " PolicyDocument=json.dumps(policyJson)\n", - " )\n", - " print(response)\n", - " \n", - " client.attach_role_policy(\n", - " RoleName=role_name,\n", - " PolicyArn=policy_arn\n", - " )" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "540f149e", - "metadata": {}, - "outputs": [], - "source": [ - "update_kb_execution_role(attached_policies, region)\n", - "time.sleep(30)" - ] - }, - { - "cell_type": "markdown", - "id": "4890486e", - "metadata": {}, - "source": [ - "### 2.6 Query the Knowledge Base with Retrieve and Generate API - with metadata (using Autogenerated filters)\n", - "\n", - "Rather creating filters manually, We'll use auto generated filters by Amazon Bedrock Knowledge Bases." - ] - }, - { - "cell_type": "code", - "execution_count": 29, - "id": "b0f62917", - "metadata": {}, - "outputs": [], - "source": [ - "query = \"How many prime members does Amazon have after 2021?\"" - ] - }, - { - "cell_type": "markdown", - "id": "ffc3f298", - "metadata": {}, - "source": [ - "#### 2.6.1 Test - RetreiveAndGenerate API with Autogenerated filters\n", - "\n", - "Let's first test how the `RetrieveAndGenerate` API processes autogenerated filters with a sample user query. As a refresher, the `RetrieveAndGenerate` API is one of the APIs provided by Amazon Bedrock Knowledge Bases. This API queries the knowledge base to retrieve the desired number of document chunks based on a similarity search. It then integrates these retrieved chunks with a LLM to generate an answer to the user's question.\n", - "\n" - ] - }, - { - "cell_type": "markdown", - "id": "0bd75983", - "metadata": {}, - "source": [ - "In the code below, we are configuring the `RetrieveAndGenerate` API to use autogenerated filters based on specific metadata attributes. \n", - "\n", - "The `implicitFilterConfiguration` is a configuration object that defines the metadata attributes that can be used as filters for the similarity search during the retrieval process of the `RetrieveAndGenerate` API. \n", - "\n", - "This configuration specifies which metadata fields can potentially be used for filtering the retrieved document chunks. In this case, we included three fields:\n", - "\n", - "1. `year`: A number representing the year the document is about.\n", - "2. `company`: A string representing the company name the document describes.\n", - "3. `ticker`: A string representing the stock ticker symbol of the company.\n", - "\n", - "Each metadata attribute is defined as an object with the following properties:\n", - "\n", - "- `key`: The name of the metadata attribute.\n", - "- `type`: The data type of the metadata attribute (e.g., NUMBER, STRING).\n", - "- `description`: A human-readable description of the metadata attribute, including any potential values it may take.\n", - "\n", - "The `implicitFilterConfiguration` also specifies the model ARN for the foundation model used to generate filter expressions relevant to the user's query. In this case, it's set to `anthropic.claude-3-5-sonnet-20240620-v1:0`." - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "b87ae715", - "metadata": {}, - "outputs": [], - "source": [ - "foundation_model = \"anthropic.claude-3-sonnet-20240229-v1:0\"\n", - "\n", - "response = bedrock_agent_runtime_client.retrieve_and_generate(\n", - " input={\n", - " \"text\": query\n", - " },\n", - " retrieveAndGenerateConfiguration={\n", - " \"type\": \"KNOWLEDGE_BASE\",\n", - " \"knowledgeBaseConfiguration\": {\n", - " 'knowledgeBaseId': kb_id_metadata,\n", - " \"modelArn\": \"arn:aws:bedrock:{}::foundation-model/{}\".format(region, foundation_model),\n", - " \"retrievalConfiguration\": {\n", - " \"vectorSearchConfiguration\": {\n", - " \"numberOfResults\":10,\n", - " # \"filter\": { \"equals\": { \"key\": \"x-amz-bedrock-kb-data-source-id\", \"value\": ds_id }},\n", - " \"implicitFilterConfiguration\": {\n", - " \"metadataAttributes\":[\n", - " {\n", - " \"key\": \"year\",\n", - " \"type\": \"NUMBER\",\n", - " \"description\": \"The year in which the document is about.\"\n", - " },\n", - " {\n", - " \"key\": \"company\",\n", - " \"type\": \"STRING\",\n", - " \"description\": \"The company name the document is describing. Possible values include ['Amazon']\"\n", - " },\n", - " {\n", - " \"key\": \"ticker\",\n", - " \"type\": \"STRING\",\n", - " \"description\": \"The ticker name of the company. Possible values include ['AMZN']\"\n", - " }\n", - " ],\n", - " \"modelArn\": \"arn:aws:bedrock:{}::foundation-model/anthropic.claude-3-5-sonnet-20240620-v1:0\".format(region)\n", - " },\n", - " } \n", - " }\n", - " }\n", - " }\n", - ")\n", - "\n", - "print(response['output']['text'],end='\\n'*2)" - ] - }, - { - "cell_type": "markdown", - "id": "15aa23eb", - "metadata": {}, - "source": [ - "Now, let's check the CloudWatch logs for the autogenerated filter generated for the given user query.\n", - "\n", - "The `RetrieveAndGenerate` API, with the autogenerated filter configuration, processes the user query and generates a structured filter expression based on the metadata attributes. This filter expression is represented as a JSON object containing logical operations (`and`, `or`) and comparison statements (`eq`, `gt`, `lt`, etc.). The comparison statements specify the metadata attributes and their corresponding values to filter the documents.\n", - "\n", - "Behind the scenes, the model determines the logical operations and values that constitute the filter expressions. It does this by analyzing the user query and the configured metadata attributes. The model identifies the relevant metadata attributes and their values mentioned in the query, and then constructs the filter expression accordingly, using appropriate logical operations and comparison statements." - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "69ee8a26", - "metadata": {}, - "outputs": [], - "source": [ - "# check cloudwatch logs for the implict filter generated\n", - "time.sleep(60)\n", - "print_filter_generation_output(query)" - ] - }, - { - "cell_type": "markdown", - "id": "392a53df", - "metadata": {}, - "source": [ - "#### 2.6.2 Test - Retrieve API with autogenerated filters" - ] - }, - { - "cell_type": "markdown", - "id": "b1041117", - "metadata": {}, - "source": [ - "Next, we will test the autogenerated filter configuration with the `Retreive` API, another API provided by Knowledge bases for Amazon Bedrock which converts user queries into embeddings, searches the knowledge base, and returns the relevant results, giving you more control to build custom workflows on top of the semantic search results. The output of the Retrieve API includes the the retrieved text chunks, the location type and URI of the source data, as well as the scores of the retrievals.\n", - "\n", - "As we can see, some of the chunks returned by the `Retrieve` API includes associated metadata that has been filtered based on our autogenerated filters. \n", - "\n", - "1. Relevant Year: Notice that the chunks have a `year` metadata field set to greater than 2021, matching our query about \"Amazon's prime members after 2021\".\n", - "\n", - "2. Company Information: The `company` field in the metadata consistently shows \"Amazon\", which aligns with our query about a specific company .\n", - "\n", - "3. Stock Ticker Information: The `ticker` field consistently shows \"AMZN\", which aligns with our query about a specific stock.\n", - "\n", - "This demonstrates how the autogenerated filters are effectively narrowing down the search results based on the query's implied criteria, even without explicit filter specifications. The system has interpreted the user query about revenue in 2023 and automatically applied filters to return the most relevant information from the knowledge base." - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "03479cfd", - "metadata": {}, - "outputs": [], - "source": [ - "response_ret_with_implicit_fiters = bedrock_agent_runtime_client.retrieve(\n", - " knowledgeBaseId=kb_id_metadata, \n", - " nextToken='string',\n", - " retrievalConfiguration={\n", - " \"vectorSearchConfiguration\": {\n", - " \"numberOfResults\":10,\n", - " \"implicitFilterConfiguration\": {\n", - " \"metadataAttributes\":[\n", - " {\n", - " \"key\": \"year\",\n", - " \"type\": \"NUMBER\",\n", - " \"description\": \"The year in which the document is about.\"\n", - " },\n", - " {\n", - " \"key\": \"company\",\n", - " \"type\": \"STRING\",\n", - " \"description\": \"The company name the document is describing. Possible values include ['Amazon']\"\n", - " },\n", - " {\n", - " \"key\": \"ticker\",\n", - " \"type\": \"STRING\",\n", - " \"description\": \"The ticker name of the company. Possible values include ['AMZN']\"\n", - " }\n", - " ],\n", - " \"modelArn\": \"arn:aws:bedrock:{}::foundation-model/anthropic.claude-3-5-sonnet-20240620-v1:0\".format(region)\n", - " },\n", - " } \n", - " },\n", - " retrievalQuery={\n", - " \"text\": query\n", - " }\n", - ")\n", - "\n", - "def response_print(retrieve_resp):\n", - "#structure 'retrievalResults': list of contents. Each list has content, location, score, metadata\n", - " for num,chunk in enumerate(retrieve_resp['retrievalResults'],1):\n", - " print(f'Chunk {num}: ',chunk['content']['text'],end='\\n'*2)\n", - " print(f'Chunk {num} Location: ',chunk['location'],end='\\n'*2)\n", - " print(f'Chunk {num} Score: ',chunk['score'],end='\\n'*2)\n", - " print(f'Chunk {num} Metadata: ',chunk['metadata'],end='\\n'*2)\n", - "\n", - "response_print(response_ret_with_implicit_fiters)" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "7d4a64e1", - "metadata": {}, - "outputs": [], - "source": [ - "# check cloudwatch logs for the implict filter generated\n", - "time.sleep(20)\n", - "print_filter_generation_output(query)" - ] - }, - { - "cell_type": "markdown", - "id": "5577ab01-5239-4a19-9042-a263e8a3de6b", - "metadata": {}, - "source": [ - "### 2.7 Clean up\n", - "Please make sure to uncomment and run below cells to delete the resources created in this notebook." - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "33f8a07a", - "metadata": {}, - "outputs": [], - "source": [ - "# delete local directory\n", - "import shutil\n", - "\n", - "dir_path = \"sec-10-k\" # Replace with the actual path\n", - "\n", - "try:\n", - " shutil.rmtree(dir_path)\n", - " print(f\"Directory '{dir_path}' and its contents have been deleted successfully.\")\n", - "except FileNotFoundError:\n", - " print(f\"Directory '{dir_path}' not found.\")\n", - "except Exception as e:\n", - " print(f\"An error occurred: {e}\")" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "e761a7d9", - "metadata": {}, - "outputs": [], - "source": [ - "# Delete log group name\n", - "delete_bedrock_invokemodel_log_group(log_group_name)" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "9ab05eb1-76c9-47b7-8d28-16ee720966d9", - "metadata": { - "tags": [] - }, - "outputs": [], - "source": [ - "## Empty and delete S3 Bucket\n", - "\n", - "objects = s3_client.list_objects(Bucket=bucket_name) \n", - "if 'Contents' in objects:\n", - " for obj in objects['Contents']:\n", - " s3_client.delete_object(Bucket=bucket_name, Key=obj['Key']) \n", - "s3_client.delete_bucket(Bucket=bucket_name)" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "a0cab3a2-e121-4d65-9254-4d318cf428f1", - "metadata": { - "tags": [] - }, - "outputs": [], - "source": [ - "print(\"===============================Knowledge base==============================\")\n", - "knowledge_base_metadata.delete_kb(delete_s3_bucket=True, delete_iam_roles_and_policies=True)" - ] - } - ], - "metadata": { - "availableInstances": [ - { - "_defaultOrder": 0, - "_isFastLaunch": true, - "category": "General purpose", - "gpuNum": 0, - "hideHardwareSpecs": false, - "memoryGiB": 4, - "name": "ml.t3.medium", - "vcpuNum": 2 - }, - { - "_defaultOrder": 1, - "_isFastLaunch": false, - "category": "General purpose", - "gpuNum": 0, - "hideHardwareSpecs": false, - "memoryGiB": 8, - "name": "ml.t3.large", - "vcpuNum": 2 - }, - { - "_defaultOrder": 2, - "_isFastLaunch": false, - "category": "General purpose", - "gpuNum": 0, - "hideHardwareSpecs": false, - "memoryGiB": 16, - "name": "ml.t3.xlarge", - "vcpuNum": 4 - }, - { - "_defaultOrder": 3, - "_isFastLaunch": false, - "category": "General purpose", - "gpuNum": 0, - "hideHardwareSpecs": false, - "memoryGiB": 32, - "name": "ml.t3.2xlarge", - "vcpuNum": 8 - }, - { - "_defaultOrder": 4, - "_isFastLaunch": true, - "category": "General purpose", - "gpuNum": 0, - "hideHardwareSpecs": false, - "memoryGiB": 8, - "name": "ml.m5.large", - "vcpuNum": 2 - }, - { - "_defaultOrder": 5, - "_isFastLaunch": false, - "category": "General purpose", - "gpuNum": 0, - "hideHardwareSpecs": false, - "memoryGiB": 16, - "name": "ml.m5.xlarge", - "vcpuNum": 4 - }, - { - "_defaultOrder": 6, - "_isFastLaunch": false, - "category": "General purpose", - "gpuNum": 0, - "hideHardwareSpecs": false, - "memoryGiB": 32, - "name": "ml.m5.2xlarge", - "vcpuNum": 8 - }, - { - "_defaultOrder": 7, - "_isFastLaunch": false, - "category": "General purpose", - "gpuNum": 0, - "hideHardwareSpecs": false, - "memoryGiB": 64, - "name": "ml.m5.4xlarge", - "vcpuNum": 16 - }, - { - "_defaultOrder": 8, - "_isFastLaunch": false, - "category": "General purpose", - "gpuNum": 0, - "hideHardwareSpecs": false, - "memoryGiB": 128, - "name": "ml.m5.8xlarge", - "vcpuNum": 32 - }, - { - "_defaultOrder": 9, - "_isFastLaunch": false, - "category": "General purpose", - "gpuNum": 0, - "hideHardwareSpecs": false, - "memoryGiB": 192, - "name": "ml.m5.12xlarge", - "vcpuNum": 48 - }, - { - "_defaultOrder": 10, - "_isFastLaunch": false, - "category": "General purpose", - "gpuNum": 0, - "hideHardwareSpecs": false, - "memoryGiB": 256, - "name": "ml.m5.16xlarge", - "vcpuNum": 64 - }, - { - "_defaultOrder": 11, - "_isFastLaunch": false, - "category": "General purpose", - "gpuNum": 0, - "hideHardwareSpecs": false, - "memoryGiB": 384, - "name": "ml.m5.24xlarge", - "vcpuNum": 96 - }, - { - "_defaultOrder": 12, - "_isFastLaunch": false, - "category": "General purpose", - "gpuNum": 0, - "hideHardwareSpecs": false, - "memoryGiB": 8, - "name": "ml.m5d.large", - "vcpuNum": 2 - }, - { - "_defaultOrder": 13, - "_isFastLaunch": false, - "category": "General purpose", - "gpuNum": 0, - "hideHardwareSpecs": false, - "memoryGiB": 16, - "name": "ml.m5d.xlarge", - "vcpuNum": 4 - }, - { - "_defaultOrder": 14, - "_isFastLaunch": false, - "category": "General purpose", - "gpuNum": 0, - "hideHardwareSpecs": false, - "memoryGiB": 32, - "name": "ml.m5d.2xlarge", - "vcpuNum": 8 - }, - { - "_defaultOrder": 15, - "_isFastLaunch": false, - "category": "General purpose", - "gpuNum": 0, - "hideHardwareSpecs": false, - "memoryGiB": 64, - "name": "ml.m5d.4xlarge", - "vcpuNum": 16 - }, - { - "_defaultOrder": 16, - "_isFastLaunch": false, - "category": "General purpose", - "gpuNum": 0, - "hideHardwareSpecs": false, - "memoryGiB": 128, - "name": "ml.m5d.8xlarge", - "vcpuNum": 32 - }, - { - "_defaultOrder": 17, - "_isFastLaunch": false, - "category": "General purpose", - "gpuNum": 0, - "hideHardwareSpecs": false, - "memoryGiB": 192, - "name": "ml.m5d.12xlarge", - "vcpuNum": 48 - }, - { - "_defaultOrder": 18, - "_isFastLaunch": false, - "category": "General purpose", - "gpuNum": 0, - "hideHardwareSpecs": false, - "memoryGiB": 256, - "name": "ml.m5d.16xlarge", - "vcpuNum": 64 - }, - { - "_defaultOrder": 19, - "_isFastLaunch": false, - "category": "General purpose", - "gpuNum": 0, - "hideHardwareSpecs": false, - "memoryGiB": 384, - "name": "ml.m5d.24xlarge", - "vcpuNum": 96 - }, - { - "_defaultOrder": 20, - "_isFastLaunch": false, - "category": "General purpose", - "gpuNum": 0, - "hideHardwareSpecs": true, - "memoryGiB": 0, - "name": "ml.geospatial.interactive", - "supportedImageNames": [ - "sagemaker-geospatial-v1-0" - ], - "vcpuNum": 0 - }, - { - "_defaultOrder": 21, - "_isFastLaunch": true, - "category": "Compute optimized", - "gpuNum": 0, - "hideHardwareSpecs": false, - "memoryGiB": 4, - "name": "ml.c5.large", - "vcpuNum": 2 - }, - { - "_defaultOrder": 22, - "_isFastLaunch": false, - "category": "Compute optimized", - "gpuNum": 0, - "hideHardwareSpecs": false, - "memoryGiB": 8, - "name": "ml.c5.xlarge", - "vcpuNum": 4 - }, - { - "_defaultOrder": 23, - "_isFastLaunch": false, - "category": "Compute optimized", - "gpuNum": 0, - "hideHardwareSpecs": false, - "memoryGiB": 16, - "name": "ml.c5.2xlarge", - "vcpuNum": 8 - }, - { - "_defaultOrder": 24, - "_isFastLaunch": false, - "category": "Compute optimized", - "gpuNum": 0, - "hideHardwareSpecs": false, - "memoryGiB": 32, - "name": "ml.c5.4xlarge", - "vcpuNum": 16 - }, - { - "_defaultOrder": 25, - "_isFastLaunch": false, - "category": "Compute optimized", - "gpuNum": 0, - "hideHardwareSpecs": false, - "memoryGiB": 72, - "name": "ml.c5.9xlarge", - "vcpuNum": 36 - }, - { - "_defaultOrder": 26, - "_isFastLaunch": false, - "category": "Compute optimized", - "gpuNum": 0, - "hideHardwareSpecs": false, - "memoryGiB": 96, - "name": "ml.c5.12xlarge", - "vcpuNum": 48 - }, - { - "_defaultOrder": 27, - "_isFastLaunch": false, - "category": "Compute optimized", - "gpuNum": 0, - "hideHardwareSpecs": false, - "memoryGiB": 144, - "name": "ml.c5.18xlarge", - "vcpuNum": 72 - }, - { - "_defaultOrder": 28, - "_isFastLaunch": false, - "category": "Compute optimized", - "gpuNum": 0, - "hideHardwareSpecs": false, - "memoryGiB": 192, - "name": "ml.c5.24xlarge", - "vcpuNum": 96 - }, - { - "_defaultOrder": 29, - "_isFastLaunch": true, - "category": "Accelerated computing", - "gpuNum": 1, - "hideHardwareSpecs": false, - "memoryGiB": 16, - "name": "ml.g4dn.xlarge", - "vcpuNum": 4 - }, - { - "_defaultOrder": 30, - "_isFastLaunch": false, - "category": "Accelerated computing", - "gpuNum": 1, - "hideHardwareSpecs": false, - "memoryGiB": 32, - "name": "ml.g4dn.2xlarge", - "vcpuNum": 8 - }, - { - "_defaultOrder": 31, - "_isFastLaunch": false, - "category": "Accelerated computing", - "gpuNum": 1, - "hideHardwareSpecs": false, - "memoryGiB": 64, - "name": "ml.g4dn.4xlarge", - "vcpuNum": 16 - }, - { - "_defaultOrder": 32, - "_isFastLaunch": false, - "category": "Accelerated computing", - "gpuNum": 1, - "hideHardwareSpecs": false, - "memoryGiB": 128, - "name": "ml.g4dn.8xlarge", - "vcpuNum": 32 - }, - { - "_defaultOrder": 33, - "_isFastLaunch": false, - "category": "Accelerated computing", - "gpuNum": 4, - "hideHardwareSpecs": false, - "memoryGiB": 192, - "name": "ml.g4dn.12xlarge", - "vcpuNum": 48 - }, - { - "_defaultOrder": 34, - "_isFastLaunch": false, - "category": "Accelerated computing", - "gpuNum": 1, - "hideHardwareSpecs": false, - "memoryGiB": 256, - "name": "ml.g4dn.16xlarge", - "vcpuNum": 64 - }, - { - "_defaultOrder": 35, - "_isFastLaunch": false, - "category": "Accelerated computing", - "gpuNum": 1, - "hideHardwareSpecs": false, - "memoryGiB": 61, - "name": "ml.p3.2xlarge", - "vcpuNum": 8 - }, - { - "_defaultOrder": 36, - "_isFastLaunch": false, - "category": "Accelerated computing", - "gpuNum": 4, - "hideHardwareSpecs": false, - "memoryGiB": 244, - "name": "ml.p3.8xlarge", - "vcpuNum": 32 - }, - { - "_defaultOrder": 37, - "_isFastLaunch": false, - "category": "Accelerated computing", - "gpuNum": 8, - "hideHardwareSpecs": false, - "memoryGiB": 488, - "name": "ml.p3.16xlarge", - "vcpuNum": 64 - }, - { - "_defaultOrder": 38, - "_isFastLaunch": false, - "category": "Accelerated computing", - "gpuNum": 8, - "hideHardwareSpecs": false, - "memoryGiB": 768, - "name": "ml.p3dn.24xlarge", - "vcpuNum": 96 - }, - { - "_defaultOrder": 39, - "_isFastLaunch": false, - "category": "Memory Optimized", - "gpuNum": 0, - "hideHardwareSpecs": false, - "memoryGiB": 16, - "name": "ml.r5.large", - "vcpuNum": 2 - }, - { - "_defaultOrder": 40, - "_isFastLaunch": false, - "category": "Memory Optimized", - "gpuNum": 0, - "hideHardwareSpecs": false, - "memoryGiB": 32, - "name": "ml.r5.xlarge", - "vcpuNum": 4 - }, - { - "_defaultOrder": 41, - "_isFastLaunch": false, - "category": "Memory Optimized", - "gpuNum": 0, - "hideHardwareSpecs": false, - "memoryGiB": 64, - "name": "ml.r5.2xlarge", - "vcpuNum": 8 - }, - { - "_defaultOrder": 42, - "_isFastLaunch": false, - "category": "Memory Optimized", - "gpuNum": 0, - "hideHardwareSpecs": false, - "memoryGiB": 128, - "name": "ml.r5.4xlarge", - "vcpuNum": 16 - }, - { - "_defaultOrder": 43, - "_isFastLaunch": false, - "category": "Memory Optimized", - "gpuNum": 0, - "hideHardwareSpecs": false, - "memoryGiB": 256, - "name": "ml.r5.8xlarge", - "vcpuNum": 32 - }, - { - "_defaultOrder": 44, - "_isFastLaunch": false, - "category": "Memory Optimized", - "gpuNum": 0, - "hideHardwareSpecs": false, - "memoryGiB": 384, - "name": "ml.r5.12xlarge", - "vcpuNum": 48 - }, - { - "_defaultOrder": 45, - "_isFastLaunch": false, - "category": "Memory Optimized", - "gpuNum": 0, - "hideHardwareSpecs": false, - "memoryGiB": 512, - "name": "ml.r5.16xlarge", - "vcpuNum": 64 - }, - { - "_defaultOrder": 46, - "_isFastLaunch": false, - "category": "Memory Optimized", - "gpuNum": 0, - "hideHardwareSpecs": false, - "memoryGiB": 768, - "name": "ml.r5.24xlarge", - "vcpuNum": 96 - }, - { - "_defaultOrder": 47, - "_isFastLaunch": false, - "category": "Accelerated computing", - "gpuNum": 1, - "hideHardwareSpecs": false, - "memoryGiB": 16, - "name": "ml.g5.xlarge", - "vcpuNum": 4 - }, - { - "_defaultOrder": 48, - "_isFastLaunch": false, - "category": "Accelerated computing", - "gpuNum": 1, - "hideHardwareSpecs": false, - "memoryGiB": 32, - "name": "ml.g5.2xlarge", - "vcpuNum": 8 - }, - { - "_defaultOrder": 49, - "_isFastLaunch": false, - "category": "Accelerated computing", - "gpuNum": 1, - "hideHardwareSpecs": false, - "memoryGiB": 64, - "name": "ml.g5.4xlarge", - "vcpuNum": 16 - }, - { - "_defaultOrder": 50, - "_isFastLaunch": false, - "category": "Accelerated computing", - "gpuNum": 1, - "hideHardwareSpecs": false, - "memoryGiB": 128, - "name": "ml.g5.8xlarge", - "vcpuNum": 32 - }, - { - "_defaultOrder": 51, - "_isFastLaunch": false, - "category": "Accelerated computing", - "gpuNum": 1, - "hideHardwareSpecs": false, - "memoryGiB": 256, - "name": "ml.g5.16xlarge", - "vcpuNum": 64 - }, - { - "_defaultOrder": 52, - "_isFastLaunch": false, - "category": "Accelerated computing", - "gpuNum": 4, - "hideHardwareSpecs": false, - "memoryGiB": 192, - "name": "ml.g5.12xlarge", - "vcpuNum": 48 - }, - { - "_defaultOrder": 53, - "_isFastLaunch": false, - "category": "Accelerated computing", - "gpuNum": 4, - "hideHardwareSpecs": false, - "memoryGiB": 384, - "name": "ml.g5.24xlarge", - "vcpuNum": 96 - }, - { - "_defaultOrder": 54, - "_isFastLaunch": false, - "category": "Accelerated computing", - "gpuNum": 8, - "hideHardwareSpecs": false, - "memoryGiB": 768, - "name": "ml.g5.48xlarge", - "vcpuNum": 192 - }, - { - "_defaultOrder": 55, - "_isFastLaunch": false, - "category": "Accelerated computing", - "gpuNum": 8, - "hideHardwareSpecs": false, - "memoryGiB": 1152, - "name": "ml.p4d.24xlarge", - "vcpuNum": 96 - }, - { - "_defaultOrder": 56, - "_isFastLaunch": false, - "category": "Accelerated computing", - "gpuNum": 8, - "hideHardwareSpecs": false, - "memoryGiB": 1152, - "name": "ml.p4de.24xlarge", - "vcpuNum": 96 - }, - { - "_defaultOrder": 57, - "_isFastLaunch": false, - "category": "Accelerated computing", - "gpuNum": 0, - "hideHardwareSpecs": false, - "memoryGiB": 32, - "name": "ml.trn1.2xlarge", - "vcpuNum": 8 - }, - { - "_defaultOrder": 58, - "_isFastLaunch": false, - "category": "Accelerated computing", - "gpuNum": 0, - "hideHardwareSpecs": false, - "memoryGiB": 512, - "name": "ml.trn1.32xlarge", - "vcpuNum": 128 - }, - { - "_defaultOrder": 59, - "_isFastLaunch": false, - "category": "Accelerated computing", - "gpuNum": 0, - "hideHardwareSpecs": false, - "memoryGiB": 512, - "name": "ml.trn1n.32xlarge", - "vcpuNum": 128 - } - ], - "instance_type": "ml.t3.medium", - "kernelspec": { - "display_name": "Python 3 (ipykernel)", - "language": "python", - "name": "python3" - }, - "language_info": { - "codemirror_mode": { - "name": "ipython", - "version": 3 - }, - "file_extension": ".py", - "mimetype": "text/x-python", - "name": "python", - "nbconvert_exporter": "python", - "pygments_lexer": "ipython3", - "version": "3.10.13" - } - }, - "nbformat": 4, - "nbformat_minor": 5 -} diff --git a/02-optimizing-accuracy-retrieved-results/re-ranking_using_kb.ipynb b/02-optimizing-accuracy-retrieved-results/re-ranking_using_kb.ipynb deleted file mode 100644 index 32c1ba7..0000000 --- a/02-optimizing-accuracy-retrieved-results/re-ranking_using_kb.ipynb +++ /dev/null @@ -1,1574 +0,0 @@ -{ - "cells": [ - { - "cell_type": "markdown", - "id": "15c08f81", - "metadata": {}, - "source": [ - "# Re-ranking\n", - "\n", - "Amazon Bedrock provides access to reranker models that you can use when querying to improve the relevance of the retrieved results. reranker model calculates the relevance of chunks to a query and reorders the results based on the scores that it calculates. By using a reranker model, you can return responses that are better suited to answering the query. \n", - "\n", - "Reranker models are trained to identify relevance signals based on a query and then use those signals to rank documents. Because of this, the models can provide more relevant, more accurate results.\n", - "\n", - "If you're using `Amazon Bedrock Knowledge Bases` for building your Retrieval Augmented Generation (RAG) application, use a reranker model while calling the `Retrieve` or `RetrieveAndGenerate operation`. The results from reranking override the default ranking that Amazon Bedrock Knowledge Bases determines.\n", - "\n", - "This notebook demonstrates the use of **reranking model** with Amazon Bedrock Knowledge Bases, through the Rerank API which will help to further improve the accuracy and relevance of RAG applications. With a reranker model, you can retrieve fewer, but more relevant, results. By feeding these results to the foundation model that you use to generate a response, you can also decrease cost and latency.\n", - "\n", - "Let's explore how to implement and utilize reranking models with Amazon Bedrock Knowledge Bases for an example use case." - ] - }, - { - "cell_type": "markdown", - "id": "ece99ba7", - "metadata": {}, - "source": [ - "## 1. Setup\n", - "Before running the rest of this notebook, you'll need to run the cells below to (ensure necessary libraries are installed and) connect to Bedrock.\n", - "\n", - "Please ignore any pip dependency error (if you see any while installing libraries)" - ] - }, - { - "cell_type": "code", - "execution_count": 1, - "id": "dc89fe3a", - "metadata": {}, - "outputs": [], - "source": [ - "%pip install --force-reinstall -q -r utils/requirements.txt --quiet" - ] - }, - { - "cell_type": "code", - "execution_count": 2, - "id": "57056c5d", - "metadata": {}, - "outputs": [], - "source": [ - "%pip install --upgrade boto3" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "165e5495", - "metadata": {}, - "outputs": [], - "source": [ - "# restart kernel\n", - "from IPython.core.display import HTML\n", - "HTML(\"\")" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "7c1c0eb1", - "metadata": {}, - "outputs": [], - "source": [ - "import boto3\n", - "print(boto3.__version__)" - ] - }, - { - "cell_type": "code", - "execution_count": 3, - "id": "7173b4bf", - "metadata": {}, - "outputs": [], - "source": [ - "import warnings\n", - "warnings.filterwarnings('ignore')" - ] - }, - { - "cell_type": "code", - "execution_count": 4, - "id": "84241929", - "metadata": {}, - "outputs": [], - "source": [ - "import os\n", - "import sys\n", - "import time\n", - "import boto3\n", - "import logging\n", - "import pprint\n", - "import json\n", - "\n", - "# Set the path to import module\n", - "from pathlib import Path\n", - "current_path = Path().resolve()\n", - "current_path = current_path.parent\n", - "if str(current_path) not in sys.path:\n", - " sys.path.append(str(current_path))\n", - "# Print sys.path to verify\n", - "# print(sys.path)\n", - "\n", - "from utils.knowledge_base import BedrockKnowledgeBase" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "cda1c18f", - "metadata": {}, - "outputs": [], - "source": [ - "#Clients\n", - "s3_client = boto3.client('s3')\n", - "sts_client = boto3.client('sts')\n", - "session = boto3.session.Session(region_name = 'us-west-2')\n", - "region = session.region_name\n", - "account_id = sts_client.get_caller_identity()[\"Account\"]\n", - "bedrock_agent_client = boto3.client('bedrock-agent')\n", - "bedrock_agent_runtime_client = boto3.client('bedrock-agent-runtime') \n", - "logging.basicConfig(format='[%(asctime)s] p%(process)s {%(filename)s:%(lineno)d} %(levelname)s - %(message)s', level=logging.INFO)\n", - "logger = logging.getLogger(__name__)\n", - "region, account_id" - ] - }, - { - "cell_type": "code", - "execution_count": 8, - "id": "5d74b5be", - "metadata": {}, - "outputs": [], - "source": [ - "import time\n", - "\n", - "# Get the current timestamp\n", - "current_time = time.time()\n", - "\n", - "# Format the timestamp as a string\n", - "timestamp_str = time.strftime(\"%Y%m%d%H%M%S\", time.localtime(current_time))[-7:]\n", - "# Create the suffix using the timestamp\n", - "suffix = f\"{timestamp_str}\"\n", - "knowledge_base_name = 'reranking-kb'\n", - "knowledge_base_description = \"Knowledge Base for re-ranking.\"\n", - "bucket_name = f'{knowledge_base_name}-{suffix}'\n", - "foundation_model = \"anthropic.claude-3-sonnet-20240229-v1:0\"" - ] - }, - { - "cell_type": "markdown", - "id": "e5142d7f", - "metadata": {}, - "source": [ - "## 2 - Create knowledge bases with fixed chunking strategy\n", - "Let's start by creating a [Knowledge Base for Amazon Bedrock](https://aws.amazon.com/bedrock/knowledge-bases/) to store video games data in csv format. Knowledge Bases allow you to integrate with different vector databases including [Amazon OpenSearch Serverless](https://aws.amazon.com/opensearch-service/features/serverless/), [Amazon Aurora](https://aws.amazon.com/rds/aurora/), [Pinecone](http://app.pinecone.io/bedrock-integration), [Redis Enterprise]() and [MongoDB Atlas](). For this example, we will integrate the knowledge base with Amazon OpenSearch Serverless. To do so, we will use the helper class `BedrockKnowledgeBase` which will create the knowledge base and all of its pre-requisites:\n", - "1. IAM roles and policies\n", - "2. S3 bucket\n", - "3. Amazon OpenSearch Serverless encryption, network and data access policies\n", - "4. Amazon OpenSearch Serverless collection\n", - "5. Amazon OpenSearch Serverless vector index\n", - "6. Knowledge base\n", - "7. Knowledge base data source" - ] - }, - { - "cell_type": "markdown", - "id": "8283567d", - "metadata": {}, - "source": [ - "We will create a knowledge base using fixed chunking strategy. \n", - "\n", - "You can chhose different chunking strategies by changing the below parameter values: \n", - "```\n", - "\"chunkingStrategy\": \"FIXED_SIZE | NONE | HIERARCHICAL | SEMANTIC\"\n", - "```" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "258fbb58", - "metadata": {}, - "outputs": [], - "source": [ - "knowledge_base_metadata = BedrockKnowledgeBase(\n", - " kb_name=f'{knowledge_base_name}-{suffix}',\n", - " kb_description=knowledge_base_description,\n", - " data_bucket_name=bucket_name, \n", - " chunking_strategy = \"FIXED_SIZE\", \n", - " suffix = suffix\n", - ")" - ] - }, - { - "cell_type": "markdown", - "id": "c79183c7", - "metadata": {}, - "source": [ - "### 2.1 Download Amazon 2019, 2020, 2021, 2022, & 2023 annual reports and upload it to Amazon S3\n", - "\n", - "Now that we have created the knowledge base, let's populate it with the `sec-10-k reports` dataset to KB. This data is being downloaded from [here](https://ir.aboutamazon.com/annual-reports-proxies-and-shareholder-letters/default.aspx). This data is about Amazon's annual reports, proxies and shareholder letters." - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "c758da68", - "metadata": {}, - "outputs": [], - "source": [ - "import os\n", - "\n", - "def create_directory(directory_name): \n", - " if not os.path.exists(directory_name):\n", - " os.makedirs(directory_name)\n", - " print(f\"Directory '{directory_name}' created successfully.\")\n", - " else:\n", - " print(f\"Directory '{directory_name}' already exists.\")\n", - "\n", - "# Call the function to create the directory\n", - "create_directory(\"sec-10-k\")" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "a2bf67c7", - "metadata": {}, - "outputs": [], - "source": [ - "import requests\n", - "\n", - "def download_file(url, filename):\n", - " # Send a GET request to the URL\n", - " response = requests.get(url)\n", - " \n", - " # Check if the request was successful\n", - " if response.status_code == 200:\n", - " # Open the file in write-binary mode\n", - " with open(filename, 'wb') as file:\n", - " # Write the content of the response to the file\n", - " file.write(response.content)\n", - " print(f\"File downloaded successfully: {filename}\")\n", - " else:\n", - " print(f\"Failed to download file. Status code: {response.status_code}\")\n", - "\n", - "# URL of the files to download\n", - "urls = [\"https://s2.q4cdn.com/299287126/files/doc_financials/2024/ar/Amazon-com-Inc-2023-Annual-Report.pdf\",\n", - " \"https://s2.q4cdn.com/299287126/files/doc_financials/2023/ar/Amazon-2022-Annual-Report.pdf\",\n", - " \"https://s2.q4cdn.com/299287126/files/doc_financials/2022/ar/Amazon-2021-Annual-Report.pdf\",\n", - " \"https://s2.q4cdn.com/299287126/files/doc_financials/2021/ar/Amazon-2020-Annual-Report.pdf\",\n", - " \"https://s2.q4cdn.com/299287126/files/doc_financials/2020/ar/2019-Annual-Report.pdf\"]\n", - "\n", - "\n", - "for url in urls:\n", - " # Name for the downloaded file\n", - " filename = url.split('/')[-1]\n", - "\n", - " # Path to save the downloaded file\n", - " filepath = f\"./sec-10-k/{filename}\"\n", - "\n", - " # Call the function to download the file\n", - " download_file(url, filepath)" - ] - }, - { - "cell_type": "markdown", - "id": "70b83f68", - "metadata": {}, - "source": [ - "Let's upload the annual reports data available in the `sec-10-k` folder to s3." - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "40e12fc8", - "metadata": {}, - "outputs": [], - "source": [ - "def upload_directory(path, bucket_name):\n", - " for root,dirs,files in os.walk(path):\n", - " for file in files:\n", - " if not file.startswith('.DS_Store'):\n", - " file_to_upload = os.path.join(root,file)\n", - " print(f\"uploading file {file_to_upload} to {bucket_name}\")\n", - " s3_client.upload_file(file_to_upload,bucket_name,file)\n", - "\n", - "# upload metadata file to S3\n", - "upload_directory(\"sec-10-k\", bucket_name)" - ] - }, - { - "cell_type": "markdown", - "id": "b70a4b4b", - "metadata": {}, - "source": [ - "Now start the ingestion job. Since, we are using the same documents as used for fixed chunking, we are skipping the step to upload documents to s3 bucket. " - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "241a6ab9", - "metadata": {}, - "outputs": [], - "source": [ - "# ensure that the kb is available\n", - "time.sleep(30)\n", - "# sync knowledge base\n", - "knowledge_base_metadata.start_ingestion_job()" - ] - }, - { - "cell_type": "markdown", - "id": "bad55ab6", - "metadata": {}, - "source": [ - "Finally we save the Knowledge Base Id to test the solution at a later stage. " - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "677c97ce", - "metadata": {}, - "outputs": [], - "source": [ - "kb_id = knowledge_base_metadata.get_knowledge_base_id()" - ] - }, - { - "cell_type": "markdown", - "id": "fcc80032", - "metadata": {}, - "source": [ - "## 3. Evaluate the relevance of query responses with and without Re-ranking (using Ragas)" - ] - }, - { - "cell_type": "markdown", - "id": "1cea8edf", - "metadata": {}, - "source": [ - "Define models for generation, evaluation and re-ranking" - ] - }, - { - "cell_type": "code", - "execution_count": 14, - "id": "bfa5a6bb", - "metadata": {}, - "outputs": [], - "source": [ - "from langchain.llms.bedrock import Bedrock\n", - "from langchain_aws import ChatBedrock\n", - "from langchain_aws import BedrockEmbeddings\n", - "\n", - "bedrock_client = boto3.client('bedrock-runtime')\n", - "\n", - "TEXT_GENERATION_MODEL_ID = \"anthropic.claude-3-haiku-20240307-v1:0\"\n", - "EVALUATION_MODEL_ID = \"anthropic.claude-3-sonnet-20240229-v1:0\"\n", - "EMBEDDING_MODEL_ID = \"amazon.titan-embed-text-v2:0\"\n", - "\n", - "# Reranker model: there are two reranker models available at launch\n", - "AMAZON_RERANKER_MODEL_ID = \"amazon.rerank-v1:0\"\n", - "COHERE_RERANKER_MODEL_ID = \"cohere.rerank-v3-5:0\"\n", - "\n", - "\n", - "llm_for_evaluation = ChatBedrock(model_id=\"anthropic.claude-3-sonnet-20240229-v1:0\", client=bedrock_client)\n", - "bedrock_embeddings = BedrockEmbeddings(model_id=\"amazon.titan-embed-text-v2:0\", client=bedrock_client)\n" - ] - }, - { - "cell_type": "markdown", - "id": "1c336de9", - "metadata": {}, - "source": [ - "#### 3.1 Update Knowledge Bases execution role" - ] - }, - { - "cell_type": "code", - "execution_count": 17, - "id": "aeac148b", - "metadata": {}, - "outputs": [], - "source": [ - "# Before using autogenerated filters - update the knowledge base execution IAM role with right permissions\n", - "\n", - "iam = boto3.resource('iam')\n", - "client = boto3.client('iam')\n", - "\n", - "def get_attached_policies(role_name):\n", - " response = client.list_attached_role_policies(RoleName=role_name)\n", - " attached_policies = response['AttachedPolicies']\n", - " return attached_policies\n", - "\n", - "# get the knowledge base IAM role name\n", - "get_kb_response = bedrock_agent_client.get_knowledge_base(knowledgeBaseId = kb_id)\n", - "role_arn = get_kb_response['knowledgeBase']['roleArn']\n", - "role_name = role_arn.split('/')[-1]\n", - "\n", - "# get attached policies\n", - "attached_policies = get_attached_policies(role_name)\n", - "attached_policies\n", - "\n", - "def update_kb_execution_role(attached_policies, region_name):\n", - " \n", - " for policy in attached_policies:\n", - "\n", - " print(policy['PolicyArn'])\n", - " policy_name = policy['PolicyName']\n", - " policy_arn = policy['PolicyArn']\n", - "\n", - " if 'FoundationModel' in policy_arn:\n", - " print('Updating FoundationModel policy: ',policy_arn)\n", - " policy = iam.Policy(policy_arn)\n", - " version = policy.default_version\n", - " policyJson = version.document\n", - " policyJson['Statement'][0]['Resource'].append(f'arn:aws:bedrock:{region}::foundation-model/{TEXT_GENERATION_MODEL_ID}')\n", - " policyJson['Statement'][0]['Resource'].append(f'arn:aws:bedrock:{region}::foundation-model/{EVALUATION_MODEL_ID}') \n", - " policyJson['Statement'][0]['Resource'].append(f'arn:aws:bedrock:{region}::foundation-model/{AMAZON_RERANKER_MODEL_ID}') \n", - " policyJson['Statement'][0]['Resource'].append(f'arn:aws:bedrock:{region}::foundation-model/{COHERE_RERANKER_MODEL_ID}') \n", - " \n", - " client.detach_role_policy(RoleName=role_name,\n", - " PolicyArn=policy_arn)\n", - " \n", - " response = client.delete_policy(\n", - " PolicyArn=policy_arn\n", - " )\n", - " print(response)\n", - " \n", - " response = client.create_policy(\n", - " PolicyName= policy_name,\n", - " PolicyDocument=json.dumps(policyJson)\n", - " )\n", - " print(response)\n", - " \n", - " client.attach_role_policy(\n", - " RoleName=role_name,\n", - " PolicyArn=policy_arn\n", - " )" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "b3521cb4", - "metadata": {}, - "outputs": [], - "source": [ - "update_kb_execution_role(attached_policies, region)\n", - "# time.sleep(30)" - ] - }, - { - "cell_type": "markdown", - "id": "529118c5", - "metadata": {}, - "source": [ - "#### 3.2 Customize retrieve and generate configuraion" - ] - }, - { - "cell_type": "code", - "execution_count": 19, - "id": "df68891d", - "metadata": {}, - "outputs": [], - "source": [ - "def retrieve_and_generate(query, reranker_model=None, kb_id=None, TEXT_GENERATION_MODEL_ID=None, metadata_filters=None):\n", - " \n", - " # Prepare retrieval configuration\n", - " retrieval_config = {\n", - " \"vectorSearchConfiguration\": {\n", - " \"numberOfResults\": 30 if reranker_model else 3\n", - " }\n", - " }\n", - "\n", - " if reranker_model:\n", - " retrieval_config[\"vectorSearchConfiguration\"][\"rerankingConfiguration\"] = {\n", - " \"type\": \"BEDROCK_RERANKING_MODEL\",\n", - " \"bedrockRerankingConfiguration\": {\n", - " \"modelConfiguration\": {\n", - " \"modelArn\": f'arn:aws:bedrock:{region}::foundation-model/{reranker_model}',\n", - " },\n", - " \"numberOfRerankedResults\": 3\n", - " }\n", - " }\n", - "\n", - " if metadata_filters:\n", - " retrieval_config[\"vectorSearchConfiguration\"][\"rerankingConfiguration\"][\"bedrockRerankingConfiguration\"][\"metadataConfiguration\"] = {\n", - " \"selectionMode\" : \"SELECTIVE\",\n", - " \"selectiveModeConfiguration\" : {\n", - " \"fieldsToInclude\": [{\n", - " \"fieldName\": \"year\",\n", - " }]\n", - " }\n", - " }\n", - " \n", - "\n", - " # Call the retrieve and generate API\n", - " start = time.time()\n", - " response = bedrock_agent_runtime_client.retrieve_and_generate(\n", - " input={'text': query},\n", - " retrieveAndGenerateConfiguration={\n", - " 'type': 'KNOWLEDGE_BASE',\n", - " 'knowledgeBaseConfiguration': {\n", - " 'knowledgeBaseId': kb_id,\n", - " 'modelArn': f'arn:aws:bedrock:{region}::foundation-model/{TEXT_GENERATION_MODEL_ID}',\n", - " 'retrievalConfiguration': retrieval_config,\n", - " },\n", - " }\n", - " )\n", - " time_spent = time.time() - start\n", - "\n", - " print(f\"[Response] : {response['output']['text']}\\n\")\n", - " print(f\"[Invocation time] : {time_spent}\\n\")\n", - "\n", - " return response\n" - ] - }, - { - "cell_type": "markdown", - "id": "fdc724b4", - "metadata": {}, - "source": [ - "#### 3.3 Prepare dataset for evaluation" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "b086554a", - "metadata": {}, - "outputs": [], - "source": [ - "from datasets import Dataset\n", - "from ragas import evaluate\n", - "from ragas.metrics import (\n", - " context_relevancy,\n", - " context_recall,\n", - " context_precision,\n", - " context_entity_recall,\n", - " answer_correctness,\n", - ")\n", - "\n", - "#specify the metrics here\n", - "metrics = [\n", - " context_relevancy,\n", - " context_recall,\n", - " context_precision,\n", - " context_entity_recall,\n", - " answer_correctness,\n", - "]\n", - "\n", - "questions = [\n", - " \"How many jobs did Amazon create in 2020, and what was its total global workforce after this expansion?\",\n", - " \"How does the 2023 net sales mix reflect Amazon's global priorities and strategic investments across segments?\",\n", - " \"How did foreign exchange rate fluctuations impact Amazon's net sales and the corresponding segment's performance in 2023?\",\n", - " \"What is the cumulative growth contribution of AWS and Advertising segments to Amazon's 2022 consolidated revenue?\",\n", - " \"How did Amazon's investments in technology infrastructure and fulfillment operations affect its cash flows and operating expenses in 2022?\",\n", - " \"What types of securities does Amazon invest its excess cash in 2019 and how are these investments classified in the balance sheet?\"\n", - "]\n", - "ground_truths = [\n", - " \"Amazon added 500,000 jobs in 2020, bringing its total workforce to approximately 1.3 million employees worldwide.\",\n", - " \"Amazon's 2023 net sales mix highlights its global priorities, with North America contributing 61%, International 23%, and AWS 16% of total sales. Year-over-year growth in each segment—12% for North America, 11% for International, and 13% for AWS—was driven by increased unit sales, advertising services, and subscription offerings. These trends reflect Amazon's balanced approach to expanding its core markets, strengthening its international presence, and investing in AWS's innovative cloud services to sustain long-term growth.\",\n", - " \"In 2023, foreign exchange rate fluctuations had a mixed impact on Amazon's financial performance. While these changes reduced consolidated net sales by $71 million, they positively influenced the International segment, increasing its net sales by $88 million. This highlights the nuanced effects of currency fluctuations, where gains in specific regions, such as the International segment, helped offset broader challenges at the consolidated level.\",\n", - " \"In 2022, AWS achieved a 29% year-over-year revenue growth, increasing from $62.2 billion in 2021 to $80.1 billion. Similarly, the Advertising segment experienced a 25% year-over-year growth, reaching $31 billion in revenue for the year. Together, these segments contributed significantly to Amazon's total consolidated revenue of $434 billion. AWS accounted for 19.59%, while Advertising contributed 7.14%, resulting in a cumulative contribution of approximately 26.73%.\",\n", - " \"In 2022, Amazon's substantial investments in technology infrastructure and fulfillment operations significantly impacted its cash flows and operating expenses. The company allocated $58.3 billion in cash capital expenditures to support AWS growth and expand its fulfillment network, resulting in a 31% increase in technology and content expenses due to higher payroll costs for technical teams and infrastructure spending on servers, networking equipment, and data centers. Fulfillment costs rose by 12%, driven by increased product sales volume, inventory levels, and wage rate incentives. These investments led to a decline in free cash flow to $(11,569) million, compared to $(9,069) million in 2021. Despite the higher costs, these expenditures were crucial for scaling operations, enhancing the customer experience, and sustaining long-term growth, particularly in AWS and global fulfillment capacity, highlighting Amazon's commitment to maintaining its competitive edge in a rapidly evolving market.\",\n", - " \"Amazon typically invests its excess cash in AAA-rated money market funds and investment-grade short- to intermediate-term fixed income securities, which are classified as either Cash and cash equivalents or Marketable securities on its consolidated balance sheets. In 2019, Amazon's marketable securities portfolio included a variety of assets such as money market funds, equity securities, foreign government and agency securities, U.S. government and agency securities, corporate debt securities, asset-backed securities, and other fixed income securities. These marketable securities were categorized as either Level 1 or Level 2 securities on the balance sheet.\"\n", - "]" - ] - }, - { - "cell_type": "code", - "execution_count": 21, - "id": "4ff26dda", - "metadata": {}, - "outputs": [], - "source": [ - "def prepare_eval_dataset(questions, ground_truths, kb_id=None, TEXT_GENERATION_MODEL_ID=None, reranker_model=None, metadata_filters = None):\n", - " answers = []\n", - " contexts = []\n", - " \n", - " for query in questions:\n", - " response = retrieve_and_generate(\n", - " query,\n", - " reranker_model=reranker_model,\n", - " kb_id=kb_id,\n", - " TEXT_GENERATION_MODEL_ID=TEXT_GENERATION_MODEL_ID,\n", - " metadata_filters=metadata_filters\n", - " )\n", - " \n", - " answers.append(response[\"output\"][\"text\"])\n", - " \n", - " context_group = []\n", - " for citation in response[\"citations\"]:\n", - " context_group.extend([\n", - " ref[\"content\"][\"text\"]\n", - " for ref in citation[\"retrievedReferences\"]\n", - " if \"content\" in ref and \"text\" in ref[\"content\"]\n", - " ])\n", - " contexts.append(context_group)\n", - " time.sleep(15)\n", - "\n", - " # Create dictionary\n", - " data = {\n", - " \"question\": questions,\n", - " \"answer\": answers,\n", - " \"contexts\": contexts,\n", - " \"ground_truth\": ground_truths\n", - " }\n", - "\n", - " # Convert dict to dataset\n", - " dataset = Dataset.from_dict(data)\n", - " return dataset\n" - ] - }, - { - "cell_type": "markdown", - "id": "9c51b09a", - "metadata": {}, - "source": [ - "#### 3.4 Evaluate dataset - without re-ranker" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "84dc3d78", - "metadata": {}, - "outputs": [], - "source": [ - "without_reranker_dataset = prepare_eval_dataset(questions, ground_truths, kb_id, TEXT_GENERATION_MODEL_ID, reranker_model=None)" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "f9250cce", - "metadata": {}, - "outputs": [], - "source": [ - "without_reranker_result = evaluate(\n", - " dataset=without_reranker_dataset,\n", - " metrics=metrics,\n", - " llm=llm_for_evaluation,\n", - " embeddings=bedrock_embeddings,\n", - ")\n", - "\n", - "without_reranker_result_df = without_reranker_result.to_pandas()" - ] - }, - { - "cell_type": "markdown", - "id": "61243e2d", - "metadata": {}, - "source": [ - "#### 3.5 Evaluate dataset - with re-ranker" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "92591600", - "metadata": {}, - "outputs": [], - "source": [ - "with_reranker_dataset = prepare_eval_dataset(questions, ground_truths, kb_id, TEXT_GENERATION_MODEL_ID, reranker_model=AMAZON_RERANKER_MODEL_ID)" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "d9e78450", - "metadata": {}, - "outputs": [], - "source": [ - "with_reranker_result = evaluate(\n", - "dataset=with_reranker_dataset,\n", - "metrics=metrics,\n", - "llm=llm_for_evaluation,\n", - "embeddings=bedrock_embeddings,\n", - ")\n", - "\n", - "with_reranker_result_df = with_reranker_result.to_pandas()" - ] - }, - { - "cell_type": "markdown", - "id": "a2f2f965", - "metadata": {}, - "source": [ - "#### 3.4 Evaluate dataset - with re-ranker + metadata configuration" - ] - }, - { - "cell_type": "markdown", - "id": "29c85464", - "metadata": {}, - "source": [ - "##### 3.4.1 Prepare metadata for ingestion\n" - ] - }, - { - "cell_type": "code", - "execution_count": 25, - "id": "17fe7e6c", - "metadata": {}, - "outputs": [], - "source": [ - "import json\n", - "import re\n", - "\n", - "def generate_matadata(data_dir):\n", - " \n", - " # Loop through all PDF files in the directory\n", - " for filename in os.listdir(data_dir):\n", - " if not filename.startswith('.DS_Store'):\n", - " # Define the metadata dictionary\n", - " metadata ={}\n", - " \n", - " filename= f'{data_dir}/{filename}'\n", - " print(filename)\n", - " \n", - " # Create metadata\n", - " metadata[\"company\"] = \"Amazon\"\n", - " metadata[\"ticker\"] = \"AMZN\"\n", - " metadata[\"year\"] = re.search(r'\\d+', filename.split('/')[-1]).group(0)\n", - "\n", - " # Create a JSON object\n", - " json_data = {\"metadataAttributes\": metadata}\n", - "\n", - " # print(json_data)\n", - "\n", - " # Write the JSON object to a file\n", - " with open(f\"{filename.replace('.pdf', '.pdf.metadata.json')}\", \"w\") as f:\n", - " json.dump(json_data, f)\n" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "69a16a17", - "metadata": {}, - "outputs": [], - "source": [ - "data_dir = './sec-10-k'\n", - "generate_matadata(data_dir)" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "4ca6d8c0", - "metadata": {}, - "outputs": [], - "source": [ - "# upload metadata file to S3\n", - "upload_directory(\"sec-10-k\", bucket_name)" - ] - }, - { - "cell_type": "markdown", - "id": "c503656e", - "metadata": {}, - "source": [ - "##### 3.4.2 Ingest metadata into Knowledge Bases\n" - ] - }, - { - "cell_type": "markdown", - "id": "576f6fe6", - "metadata": {}, - "source": [ - "Now start the ingestion job. Since, we are using the same documents as used for fixed chunking, we are skipping the step to upload documents to s3 bucket. " - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "bdfb5938", - "metadata": {}, - "outputs": [], - "source": [ - "# ensure that the kb is available\n", - "time.sleep(30)\n", - "# sync knowledge base\n", - "knowledge_base_metadata.start_ingestion_job()" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "12589fe6", - "metadata": {}, - "outputs": [], - "source": [ - "with_reranker_metadata_filters_dataset = prepare_eval_dataset(questions, ground_truths, kb_id, TEXT_GENERATION_MODEL_ID, reranker_model=AMAZON_RERANKER_MODEL_ID, metadata_filters=True)" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "21463f6f", - "metadata": {}, - "outputs": [], - "source": [ - "with_reranker_metadata_filters_result = evaluate(\n", - "dataset=with_reranker_metadata_filters_dataset,\n", - "metrics=metrics,\n", - "llm=llm_for_evaluation,\n", - "embeddings=bedrock_embeddings,\n", - ")\n", - "\n", - "with_reranker_metadata_filters_result_df = with_reranker_result.to_pandas()" - ] - }, - { - "cell_type": "markdown", - "id": "c44ec665", - "metadata": {}, - "source": [ - "#### 3.5 Prepare Comparison data frame" - ] - }, - { - "cell_type": "code", - "execution_count": 31, - "id": "f5ca9fc4", - "metadata": {}, - "outputs": [], - "source": [ - "import pandas as pd\n", - "\n", - "# Create the side-by-side DataFrame\n", - "comparison_df = pd.DataFrame({\n", - " 'question': without_reranker_result_df['question'],\n", - " 'without_reranker_answer': without_reranker_result_df['answer'],\n", - " 'with_reranker_answer': with_reranker_result_df['answer'],\n", - " 'with_reranker_metadata_answer': with_reranker_metadata_filters_result_df['answer'],\n", - " \n", - " 'without_reranker_answer_correctness': without_reranker_result_df['answer_correctness'],\n", - " 'with_reranker_answer_correctness': with_reranker_result_df['answer_correctness'],\n", - " 'with_reranker_metadata_correctness': with_reranker_metadata_filters_result_df['answer_correctness'],\n", - " })" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "30363097", - "metadata": {}, - "outputs": [], - "source": [ - "pd.options.display.max_colwidth = 1000\n", - "comparison_df" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "a3e83ab3", - "metadata": {}, - "outputs": [], - "source": [ - "# Calculate average correctness\n", - "without_reranker_avg_correctness = without_reranker_result_df['answer_correctness'].mean()\n", - "with_reranker_avg_correctness = with_reranker_result_df['answer_correctness'].mean()\n", - "with_reranker_metadata_avg_correctness = with_reranker_metadata_filters_result_df['answer_correctness'].mean()\n", - "\n", - "print(f\"\\nAverage Correctness without Reranker: {without_reranker_avg_correctness:.4f}\")\n", - "print(f\"Average Correctness with Reranker: {with_reranker_avg_correctness:.4f}\")\n", - "print(f\"Average Correctness with Reranker and metadata filter: {with_reranker_metadata_avg_correctness:.4f}\")" - ] - }, - { - "cell_type": "markdown", - "id": "5577ab01-5239-4a19-9042-a263e8a3de6b", - "metadata": {}, - "source": [ - "### 2.7 Clean up\n", - "Please make sure to uncomment and run below cells to delete the resources created in this notebook." - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "33f8a07a", - "metadata": {}, - "outputs": [], - "source": [ - "# delete local directory\n", - "import shutil\n", - "\n", - "dir_path = \"sec-10-k\" # Replace with the actual path\n", - "\n", - "try:\n", - " shutil.rmtree(dir_path)\n", - " print(f\"Directory '{dir_path}' and its contents have been deleted successfully.\")\n", - "except FileNotFoundError:\n", - " print(f\"Directory '{dir_path}' not found.\")\n", - "except Exception as e:\n", - " print(f\"An error occurred: {e}\")" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "9ab05eb1-76c9-47b7-8d28-16ee720966d9", - "metadata": { - "tags": [] - }, - "outputs": [], - "source": [ - "## Empty and delete S3 Bucket\n", - "\n", - "objects = s3_client.list_objects(Bucket=bucket_name) \n", - "if 'Contents' in objects:\n", - " for obj in objects['Contents']:\n", - " s3_client.delete_object(Bucket=bucket_name, Key=obj['Key']) \n", - "s3_client.delete_bucket(Bucket=bucket_name)" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "a0cab3a2-e121-4d65-9254-4d318cf428f1", - "metadata": { - "tags": [] - }, - "outputs": [], - "source": [ - "print(\"===============================Knowledge base==============================\")\n", - "knowledge_base_metadata.delete_kb(delete_s3_bucket=True, delete_iam_roles_and_policies=True)" - ] - } - ], - "metadata": { - "availableInstances": [ - { - "_defaultOrder": 0, - "_isFastLaunch": true, - "category": "General purpose", - "gpuNum": 0, - "hideHardwareSpecs": false, - "memoryGiB": 4, - "name": "ml.t3.medium", - "vcpuNum": 2 - }, - { - "_defaultOrder": 1, - "_isFastLaunch": false, - "category": "General purpose", - "gpuNum": 0, - "hideHardwareSpecs": false, - "memoryGiB": 8, - "name": "ml.t3.large", - "vcpuNum": 2 - }, - { - "_defaultOrder": 2, - "_isFastLaunch": false, - "category": "General purpose", - "gpuNum": 0, - "hideHardwareSpecs": false, - "memoryGiB": 16, - "name": "ml.t3.xlarge", - "vcpuNum": 4 - }, - { - "_defaultOrder": 3, - "_isFastLaunch": false, - "category": "General purpose", - "gpuNum": 0, - "hideHardwareSpecs": false, - "memoryGiB": 32, - "name": "ml.t3.2xlarge", - "vcpuNum": 8 - }, - { - "_defaultOrder": 4, - "_isFastLaunch": true, - "category": "General purpose", - "gpuNum": 0, - "hideHardwareSpecs": false, - "memoryGiB": 8, - "name": "ml.m5.large", - "vcpuNum": 2 - }, - { - "_defaultOrder": 5, - "_isFastLaunch": false, - "category": "General purpose", - "gpuNum": 0, - "hideHardwareSpecs": false, - "memoryGiB": 16, - "name": "ml.m5.xlarge", - "vcpuNum": 4 - }, - { - "_defaultOrder": 6, - "_isFastLaunch": false, - "category": "General purpose", - "gpuNum": 0, - "hideHardwareSpecs": false, - "memoryGiB": 32, - "name": "ml.m5.2xlarge", - "vcpuNum": 8 - }, - { - "_defaultOrder": 7, - "_isFastLaunch": false, - "category": "General purpose", - "gpuNum": 0, - "hideHardwareSpecs": false, - "memoryGiB": 64, - "name": "ml.m5.4xlarge", - "vcpuNum": 16 - }, - { - "_defaultOrder": 8, - "_isFastLaunch": false, - "category": "General purpose", - "gpuNum": 0, - "hideHardwareSpecs": false, - "memoryGiB": 128, - "name": "ml.m5.8xlarge", - "vcpuNum": 32 - }, - { - "_defaultOrder": 9, - "_isFastLaunch": false, - "category": "General purpose", - "gpuNum": 0, - "hideHardwareSpecs": false, - "memoryGiB": 192, - "name": "ml.m5.12xlarge", - "vcpuNum": 48 - }, - { - "_defaultOrder": 10, - "_isFastLaunch": false, - "category": "General purpose", - "gpuNum": 0, - "hideHardwareSpecs": false, - "memoryGiB": 256, - "name": "ml.m5.16xlarge", - "vcpuNum": 64 - }, - { - "_defaultOrder": 11, - "_isFastLaunch": false, - "category": "General purpose", - "gpuNum": 0, - "hideHardwareSpecs": false, - "memoryGiB": 384, - "name": "ml.m5.24xlarge", - "vcpuNum": 96 - }, - { - "_defaultOrder": 12, - "_isFastLaunch": false, - "category": "General purpose", - "gpuNum": 0, - "hideHardwareSpecs": false, - "memoryGiB": 8, - "name": "ml.m5d.large", - "vcpuNum": 2 - }, - { - "_defaultOrder": 13, - "_isFastLaunch": false, - "category": "General purpose", - "gpuNum": 0, - "hideHardwareSpecs": false, - "memoryGiB": 16, - "name": "ml.m5d.xlarge", - "vcpuNum": 4 - }, - { - "_defaultOrder": 14, - "_isFastLaunch": false, - "category": "General purpose", - "gpuNum": 0, - "hideHardwareSpecs": false, - "memoryGiB": 32, - "name": "ml.m5d.2xlarge", - "vcpuNum": 8 - }, - { - "_defaultOrder": 15, - "_isFastLaunch": false, - "category": "General purpose", - "gpuNum": 0, - "hideHardwareSpecs": false, - "memoryGiB": 64, - "name": "ml.m5d.4xlarge", - "vcpuNum": 16 - }, - { - "_defaultOrder": 16, - "_isFastLaunch": false, - "category": "General purpose", - "gpuNum": 0, - "hideHardwareSpecs": false, - "memoryGiB": 128, - "name": "ml.m5d.8xlarge", - "vcpuNum": 32 - }, - { - "_defaultOrder": 17, - "_isFastLaunch": false, - "category": "General purpose", - "gpuNum": 0, - "hideHardwareSpecs": false, - "memoryGiB": 192, - "name": "ml.m5d.12xlarge", - "vcpuNum": 48 - }, - { - "_defaultOrder": 18, - "_isFastLaunch": false, - "category": "General purpose", - "gpuNum": 0, - "hideHardwareSpecs": false, - "memoryGiB": 256, - "name": "ml.m5d.16xlarge", - "vcpuNum": 64 - }, - { - "_defaultOrder": 19, - "_isFastLaunch": false, - "category": "General purpose", - "gpuNum": 0, - "hideHardwareSpecs": false, - "memoryGiB": 384, - "name": "ml.m5d.24xlarge", - "vcpuNum": 96 - }, - { - "_defaultOrder": 20, - "_isFastLaunch": false, - "category": "General purpose", - "gpuNum": 0, - "hideHardwareSpecs": true, - "memoryGiB": 0, - "name": "ml.geospatial.interactive", - "supportedImageNames": [ - "sagemaker-geospatial-v1-0" - ], - "vcpuNum": 0 - }, - { - "_defaultOrder": 21, - "_isFastLaunch": true, - "category": "Compute optimized", - "gpuNum": 0, - "hideHardwareSpecs": false, - "memoryGiB": 4, - "name": "ml.c5.large", - "vcpuNum": 2 - }, - { - "_defaultOrder": 22, - "_isFastLaunch": false, - "category": "Compute optimized", - "gpuNum": 0, - "hideHardwareSpecs": false, - "memoryGiB": 8, - "name": "ml.c5.xlarge", - "vcpuNum": 4 - }, - { - "_defaultOrder": 23, - "_isFastLaunch": false, - "category": "Compute optimized", - "gpuNum": 0, - "hideHardwareSpecs": false, - "memoryGiB": 16, - "name": "ml.c5.2xlarge", - "vcpuNum": 8 - }, - { - "_defaultOrder": 24, - "_isFastLaunch": false, - "category": "Compute optimized", - "gpuNum": 0, - "hideHardwareSpecs": false, - "memoryGiB": 32, - "name": "ml.c5.4xlarge", - "vcpuNum": 16 - }, - { - "_defaultOrder": 25, - "_isFastLaunch": false, - "category": "Compute optimized", - "gpuNum": 0, - "hideHardwareSpecs": false, - "memoryGiB": 72, - "name": "ml.c5.9xlarge", - "vcpuNum": 36 - }, - { - "_defaultOrder": 26, - "_isFastLaunch": false, - "category": "Compute optimized", - "gpuNum": 0, - "hideHardwareSpecs": false, - "memoryGiB": 96, - "name": "ml.c5.12xlarge", - "vcpuNum": 48 - }, - { - "_defaultOrder": 27, - "_isFastLaunch": false, - "category": "Compute optimized", - "gpuNum": 0, - "hideHardwareSpecs": false, - "memoryGiB": 144, - "name": "ml.c5.18xlarge", - "vcpuNum": 72 - }, - { - "_defaultOrder": 28, - "_isFastLaunch": false, - "category": "Compute optimized", - "gpuNum": 0, - "hideHardwareSpecs": false, - "memoryGiB": 192, - "name": "ml.c5.24xlarge", - "vcpuNum": 96 - }, - { - "_defaultOrder": 29, - "_isFastLaunch": true, - "category": "Accelerated computing", - "gpuNum": 1, - "hideHardwareSpecs": false, - "memoryGiB": 16, - "name": "ml.g4dn.xlarge", - "vcpuNum": 4 - }, - { - "_defaultOrder": 30, - "_isFastLaunch": false, - "category": "Accelerated computing", - "gpuNum": 1, - "hideHardwareSpecs": false, - "memoryGiB": 32, - "name": "ml.g4dn.2xlarge", - "vcpuNum": 8 - }, - { - "_defaultOrder": 31, - "_isFastLaunch": false, - "category": "Accelerated computing", - "gpuNum": 1, - "hideHardwareSpecs": false, - "memoryGiB": 64, - "name": "ml.g4dn.4xlarge", - "vcpuNum": 16 - }, - { - "_defaultOrder": 32, - "_isFastLaunch": false, - "category": "Accelerated computing", - "gpuNum": 1, - "hideHardwareSpecs": false, - "memoryGiB": 128, - "name": "ml.g4dn.8xlarge", - "vcpuNum": 32 - }, - { - "_defaultOrder": 33, - "_isFastLaunch": false, - "category": "Accelerated computing", - "gpuNum": 4, - "hideHardwareSpecs": false, - "memoryGiB": 192, - "name": "ml.g4dn.12xlarge", - "vcpuNum": 48 - }, - { - "_defaultOrder": 34, - "_isFastLaunch": false, - "category": "Accelerated computing", - "gpuNum": 1, - "hideHardwareSpecs": false, - "memoryGiB": 256, - "name": "ml.g4dn.16xlarge", - "vcpuNum": 64 - }, - { - "_defaultOrder": 35, - "_isFastLaunch": false, - "category": "Accelerated computing", - "gpuNum": 1, - "hideHardwareSpecs": false, - "memoryGiB": 61, - "name": "ml.p3.2xlarge", - "vcpuNum": 8 - }, - { - "_defaultOrder": 36, - "_isFastLaunch": false, - "category": "Accelerated computing", - "gpuNum": 4, - "hideHardwareSpecs": false, - "memoryGiB": 244, - "name": "ml.p3.8xlarge", - "vcpuNum": 32 - }, - { - "_defaultOrder": 37, - "_isFastLaunch": false, - "category": "Accelerated computing", - "gpuNum": 8, - "hideHardwareSpecs": false, - "memoryGiB": 488, - "name": "ml.p3.16xlarge", - "vcpuNum": 64 - }, - { - "_defaultOrder": 38, - "_isFastLaunch": false, - "category": "Accelerated computing", - "gpuNum": 8, - "hideHardwareSpecs": false, - "memoryGiB": 768, - "name": "ml.p3dn.24xlarge", - "vcpuNum": 96 - }, - { - "_defaultOrder": 39, - "_isFastLaunch": false, - "category": "Memory Optimized", - "gpuNum": 0, - "hideHardwareSpecs": false, - "memoryGiB": 16, - "name": "ml.r5.large", - "vcpuNum": 2 - }, - { - "_defaultOrder": 40, - "_isFastLaunch": false, - "category": "Memory Optimized", - "gpuNum": 0, - "hideHardwareSpecs": false, - "memoryGiB": 32, - "name": "ml.r5.xlarge", - "vcpuNum": 4 - }, - { - "_defaultOrder": 41, - "_isFastLaunch": false, - "category": "Memory Optimized", - "gpuNum": 0, - "hideHardwareSpecs": false, - "memoryGiB": 64, - "name": "ml.r5.2xlarge", - "vcpuNum": 8 - }, - { - "_defaultOrder": 42, - "_isFastLaunch": false, - "category": "Memory Optimized", - "gpuNum": 0, - "hideHardwareSpecs": false, - "memoryGiB": 128, - "name": "ml.r5.4xlarge", - "vcpuNum": 16 - }, - { - "_defaultOrder": 43, - "_isFastLaunch": false, - "category": "Memory Optimized", - "gpuNum": 0, - "hideHardwareSpecs": false, - "memoryGiB": 256, - "name": "ml.r5.8xlarge", - "vcpuNum": 32 - }, - { - "_defaultOrder": 44, - "_isFastLaunch": false, - "category": "Memory Optimized", - "gpuNum": 0, - "hideHardwareSpecs": false, - "memoryGiB": 384, - "name": "ml.r5.12xlarge", - "vcpuNum": 48 - }, - { - "_defaultOrder": 45, - "_isFastLaunch": false, - "category": "Memory Optimized", - "gpuNum": 0, - "hideHardwareSpecs": false, - "memoryGiB": 512, - "name": "ml.r5.16xlarge", - "vcpuNum": 64 - }, - { - "_defaultOrder": 46, - "_isFastLaunch": false, - "category": "Memory Optimized", - "gpuNum": 0, - "hideHardwareSpecs": false, - "memoryGiB": 768, - "name": "ml.r5.24xlarge", - "vcpuNum": 96 - }, - { - "_defaultOrder": 47, - "_isFastLaunch": false, - "category": "Accelerated computing", - "gpuNum": 1, - "hideHardwareSpecs": false, - "memoryGiB": 16, - "name": "ml.g5.xlarge", - "vcpuNum": 4 - }, - { - "_defaultOrder": 48, - "_isFastLaunch": false, - "category": "Accelerated computing", - "gpuNum": 1, - "hideHardwareSpecs": false, - "memoryGiB": 32, - "name": "ml.g5.2xlarge", - "vcpuNum": 8 - }, - { - "_defaultOrder": 49, - "_isFastLaunch": false, - "category": "Accelerated computing", - "gpuNum": 1, - "hideHardwareSpecs": false, - "memoryGiB": 64, - "name": "ml.g5.4xlarge", - "vcpuNum": 16 - }, - { - "_defaultOrder": 50, - "_isFastLaunch": false, - "category": "Accelerated computing", - "gpuNum": 1, - "hideHardwareSpecs": false, - "memoryGiB": 128, - "name": "ml.g5.8xlarge", - "vcpuNum": 32 - }, - { - "_defaultOrder": 51, - "_isFastLaunch": false, - "category": "Accelerated computing", - "gpuNum": 1, - "hideHardwareSpecs": false, - "memoryGiB": 256, - "name": "ml.g5.16xlarge", - "vcpuNum": 64 - }, - { - "_defaultOrder": 52, - "_isFastLaunch": false, - "category": "Accelerated computing", - "gpuNum": 4, - "hideHardwareSpecs": false, - "memoryGiB": 192, - "name": "ml.g5.12xlarge", - "vcpuNum": 48 - }, - { - "_defaultOrder": 53, - "_isFastLaunch": false, - "category": "Accelerated computing", - "gpuNum": 4, - "hideHardwareSpecs": false, - "memoryGiB": 384, - "name": "ml.g5.24xlarge", - "vcpuNum": 96 - }, - { - "_defaultOrder": 54, - "_isFastLaunch": false, - "category": "Accelerated computing", - "gpuNum": 8, - "hideHardwareSpecs": false, - "memoryGiB": 768, - "name": "ml.g5.48xlarge", - "vcpuNum": 192 - }, - { - "_defaultOrder": 55, - "_isFastLaunch": false, - "category": "Accelerated computing", - "gpuNum": 8, - "hideHardwareSpecs": false, - "memoryGiB": 1152, - "name": "ml.p4d.24xlarge", - "vcpuNum": 96 - }, - { - "_defaultOrder": 56, - "_isFastLaunch": false, - "category": "Accelerated computing", - "gpuNum": 8, - "hideHardwareSpecs": false, - "memoryGiB": 1152, - "name": "ml.p4de.24xlarge", - "vcpuNum": 96 - }, - { - "_defaultOrder": 57, - "_isFastLaunch": false, - "category": "Accelerated computing", - "gpuNum": 0, - "hideHardwareSpecs": false, - "memoryGiB": 32, - "name": "ml.trn1.2xlarge", - "vcpuNum": 8 - }, - { - "_defaultOrder": 58, - "_isFastLaunch": false, - "category": "Accelerated computing", - "gpuNum": 0, - "hideHardwareSpecs": false, - "memoryGiB": 512, - "name": "ml.trn1.32xlarge", - "vcpuNum": 128 - }, - { - "_defaultOrder": 59, - "_isFastLaunch": false, - "category": "Accelerated computing", - "gpuNum": 0, - "hideHardwareSpecs": false, - "memoryGiB": 512, - "name": "ml.trn1n.32xlarge", - "vcpuNum": 128 - } - ], - "instance_type": "ml.t3.medium", - "kernelspec": { - "display_name": "Python 3 (ipykernel)", - "language": "python", - "name": "python3" - }, - "language_info": { - "codemirror_mode": { - "name": "ipython", - "version": 3 - }, - "file_extension": ".py", - "mimetype": "text/x-python", - "name": "python", - "nbconvert_exporter": "python", - "pygments_lexer": "ipython3", - "version": "3.10.13" - } - }, - "nbformat": 4, - "nbformat_minor": 5 -} diff --git a/05-structured-rag/structured-rag-using-kb.ipynb b/05-structured-rag/structured-rag-using-kb.ipynb deleted file mode 100644 index cc6fa57..0000000 --- a/05-structured-rag/structured-rag-using-kb.ipynb +++ /dev/null @@ -1,711 +0,0 @@ -{ - "cells": [ - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "# Structured RAG using Amazon Bedrock Knowledge Bases : end-to-end example using Amazon Redshift DB\n", - "\n", - "Structure RAG allows Amazon Bedrock Knowledge Bases customers to query structured data in Redshift using natural language, and receive natural language responses summarizing the data thereby providing an answer to the user question.\n", - "\n", - "Using advanced natural language processing, Amazon Bedrock Knowledge Bases can transform natural language queries into SQL queries, allowing users to retrieve data directly from the source without the need to move or preprocess the data. To generate accurate SQL queries, Bedrock Knowledge Base leverages database schema, previous query history, and other contextual information that are provided about the data sources. For more details. please see the [documentation](https://docs.aws.amazon.com/bedrock/latest/userguide/knowledge-base-build-structured.html).\n", - "\n", - "\n", - "This notebook provides sample code for building a Structured RAG using Amazon Bedrock Knowledgebases using Redshift.\n", - "\n", - "\n", - "#### Steps: \n", - "- Create Knowledge Base execution role with necessary policies for accessing data from Amazon Redshift.\n", - "- Create a knowledge base with Structured database (Redshift database)\n", - "- Create data source(s) within knowledge base\n", - "- Start ingestion jobs using KB APIs which will read metadata about structred database.\n", - "\n", - "Once the metadata is extracted and ingested, then user can interact with Structured databases via Amazon Bedrock Knowledge Base APIs using Natural language query." - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "#### Pre-requisites\n", - "This notebook requires :\n", - "- A Redshift serverless cluster with a workgroup [OR] Redshift provisioned cluster \n", - "- Your workgroup or cluster is already setup with your structured data ingested\n", - "- You've set-up the IAM Role [OR] Secrets manager with User Credentials [OR] the DB User \n", - "\n", - "To read more details about pre-requisites, see the [documentation](https://docs.aws.amazon.com/bedrock/latest/userguide/knowledge-base-prereq-structured.html)\n" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "### 0 - Setup\n", - "Before running the rest of this notebook, you'll need to run the cells below to ensure necessary libraries are installed and connect to Bedrock.\n", - "\n", - "Please ignore any pip dependency error (if you see any while installing libraries)" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "%pip install --force-reinstall -q -r ../../requirements.txt --quiet" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "# %pip install --upgrade boto3\n", - "import boto3\n", - "print(boto3.__version__)" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "# restart kernel\n", - "from IPython.core.display import HTML\n", - "HTML(\"\")" - ] - }, - { - "cell_type": "code", - "execution_count": 4, - "metadata": {}, - "outputs": [], - "source": [ - "%load_ext autoreload\n", - "%autoreload 2" - ] - }, - { - "cell_type": "code", - "execution_count": 5, - "metadata": {}, - "outputs": [], - "source": [ - "import warnings\n", - "warnings.filterwarnings('ignore')" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "This code is part of the setup and used to :\n", - "- Add the parent directory to the python system path\n", - "- Imports a custom module (BedrockStructuredKnowledgeBase) from `utils` necessary for later executions" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "import sys\n", - "import logging\n", - "from pathlib import Path\n", - "\n", - "current_path = Path().resolve()\n", - "current_path = current_path.parent\n", - "\n", - "if str(current_path) not in sys.path:\n", - " sys.path.append(str(current_path))\n", - "\n", - "# Print sys.path to verify\n", - "print(sys.path)\n", - "\n", - "from utils.structured_knowledge_base import BedrockStructuredKnowledgeBase" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Setup and initialize boto3 clients " - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "s3_client = boto3.client('s3')\n", - "sts_client = boto3.client('sts')\n", - "session = boto3.session.Session(region_name='us-east-1')\n", - "region = session.region_name\n", - "account_id = sts_client.get_caller_identity()[\"Account\"]\n", - "bedrock_agent_client = boto3.client('bedrock-agent')\n", - "bedrock_agent_runtime_client = boto3.client('bedrock-agent-runtime') \n", - "logging.basicConfig(format='[%(asctime)s] p%(process)s {%(filename)s:%(lineno)d} %(levelname)s - %(message)s', level=logging.INFO)\n", - "logger = logging.getLogger(__name__)\n", - "region, account_id" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Initialize and configure the knowledge base name and the foundational model. This foundational model will be used to generate the natural language response based on the records received from the structured data store." - ] - }, - { - "cell_type": "code", - "execution_count": 29, - "metadata": {}, - "outputs": [], - "source": [ - "import time\n", - "\n", - "# Get the current timestamp\n", - "current_time = time.time()\n", - "\n", - "# Format the timestamp as a string\n", - "timestamp_str = time.strftime(\"%Y%m%d%H%M%S\", time.localtime(current_time))[-7:]\n", - "# Create the suffix using the timestamp\n", - "suffix = f\"{timestamp_str}\"\n", - "\n", - "knowledge_base_name = f\"bedrock-sample-structured-kb-{suffix}\"\n", - "knowledge_base_description = \"Sample Structured KB\"\n", - "\n", - "\n", - "foundation_model = \"anthropic.claude-3-sonnet-20240229-v1:0\"" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Amazon Bedrock Knowledge Bases uses a service role to connect knowledge bases to structured data stores, retrieve data from these data stores, and generate SQL queries based on user queries and the structure of the data stores. There are several access patterns based on if you're using Redshift Serverless vs Redshift Provisioned Cluster." - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "
\n", - "NOTE: Below are several access patterns based on if you're using Redshift Serverless vs Redshift Provisioned Cluster.\n", - "

\n", - "1. Secrets Manager + Redshift Serverless WorkGroup\n", - "
\n", - "2. IAM Role + Redshift Serverless WorkGroup \n", - "
\n", - "3. IAM Role + Redshift Cluster\n", - "
\n", - "4. Secrets Manager + Redshift Cluster \n", - "
\n", - "5. DB user + Redshift Cluster\n", - "
\n", - "\n", - "In this notebook, we'll look at all these access pattern.\n", - "
" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Please note that, you will have to initialize only the variables that are necessary based on following access patterns:\n", - "\n", - "1. Secrets Manager + Redshift Serverless WorkGroup \n", - "`workgroup_id` \n", - "`secretArn`\n", - "\n", - "2. IAM Role + Redshift Serverless WorkGroup \n", - "`workgroup_id` \n", - "`redshiftDBName`\n", - "\n", - "3. IAM Role + Redshift Provisioned Cluster \n", - "`provisioned_cluster_identifier` \n", - "`provisioned_cluster_dbname`\n", - "\n", - "4. Secrets Manager + Redshift Provisioned Cluster \n", - "`provisioned_cluster_identifier` \n", - "`provisioned_cluster_dbname` \n", - "`provisionedSecretArn`\n", - "\n", - "5. DB user + Redshift Provisioned Cluster \n", - "`provisioned_cluster_identifier` \n", - "`provisioned_cluster_dbname` \n", - "`databaseUser`\n", - "\n", - "Knowledge base configuration and the roles created will use these parameters to perform necessary configuration. Any additional steps required as part of execution will be covered as part of execution steps" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "#### Redshift acces pattern choice\n", - "Select the choice that aligns with your setup. " - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "import ipywidgets as widgets\n", - "from IPython.display import display\n", - "\n", - "# Display the choices to the user\n", - "print(\"Choose your Redshift access pattern:\")\n", - "print(\"1. Secrets Manager + Redshift Serverless WorkGroup\")\n", - "print(\"2. IAM Role + Redshift Serverless WorkGroup\")\n", - "print(\"3. IAM Role + Redshift Provisioned Cluster\")\n", - "print(\"4. Secrets Manager + Redshift Provisioned Cluster\")\n", - "print(\"5. DB User + Redshift Provisioned Cluster\")\n", - "\n", - "# Create a text input widget\n", - "choice_widget = widgets.Text(placeholder=\"Enter your choice (1 Only)\")\n", - "\n", - "# Display the widget\n", - "display(choice_widget)\n" - ] - }, - { - "cell_type": "code", - "execution_count": 31, - "metadata": {}, - "outputs": [], - "source": [ - "# Change below variables as needed\n", - "\n", - "#Redshift Serverless Cluster configuration details\n", - "workgroup_id = ''\n", - "redshiftDBName = \"\"\n", - "\n", - "#Redshift Provisioned Cluster configuration details\n", - "provisioned_cluster_identifier = \"\"\n", - "provisioned_cluster_dbname = \"\"\n", - "#Secrets manager ARN , this value is required to use \"Secrets Manager + Redshift Provisioned Cluster\" access pattern \n", - "provisionedSecretArn = \"\"\n", - "#Redshift Database UserName, this value is required to use \"DB User + Redshift Provisioned Cluster\" access pattern\n", - "databaseUser = \"\"\n", - "\n", - "# kb Configuration\n", - "kbConfigParam = {\n", - " \"type\": \"SQL\",\n", - " \"sqlKnowledgeBaseConfiguration\": {\n", - " \"type\": \"REDSHIFT\",\n", - " \"redshiftConfiguration\": {\n", - " \"storageConfigurations\": [{\n", - " \"type\": \"REDSHIFT\",\n", - " \"redshiftConfiguration\": {\n", - " \"databaseName\": redshiftDBName\n", - " }\n", - " }],\n", - " \"queryEngineConfiguration\": {\n", - " \"type\": \"SERVERLESS\",\n", - " \"serverlessConfiguration\": {\n", - " \"workgroupArn\": workgroupArn,\n", - " \"authConfiguration\": {}\n", - " }\n", - " }\n", - " }\n", - " }\n", - " }\n", - "\n", - "kbProvisionedConfigParam = {\n", - " \"type\": \"SQL\",\n", - " \"sqlKnowledgeBaseConfiguration\": {\n", - " \"type\": \"REDSHIFT\",\n", - " \"redshiftConfiguration\": {\n", - " \"queryEngineConfiguration\": {\n", - " \"type\": \"PROVISIONED\",\n", - " \"provisionedConfiguration\": {\n", - " \"authConfiguration\": {},\n", - " \"clusterIdentifier\": provisioned_cluster_identifier\n", - " }\n", - " },\n", - " \"storageConfigurations\": [{\n", - " \"redshiftConfiguration\": {\n", - " \"databaseName\": provisioned_cluster_dbname\n", - " },\n", - " \"type\": \"REDSHIFT\"\n", - " }]\n", - " } \n", - " } \n", - "}" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "### 1 - Create Knowledge Base\n", - "\n", - "Based on the selected access pattern, \n", - "1. This code updates the knowledge base configuration with additional parameters. For example, if the access pattern is slected as `IAM Role + Redshift Serverless ` , the `[authCofiguration][type]` parameter willbe updated as \"IAM\"\n", - "2. Then it creates the knowledge base " - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "# Access the entered value\n", - "access_pattern_choice = int(choice_widget.value)\n", - "try:\n", - " access_pattern_choice = int(choice_widget.value)\n", - " if access_pattern_choice ==1:\n", - " print(f\"Access pattern:{choice_widget.value}. Secrets Manager + Redshift Serverless WorkGroup\")\n", - "\n", - " kbConfigParam['sqlKnowledgeBaseConfiguration']['redshiftConfiguration']['queryEngineConfiguration']['serverlessConfiguration']['authConfiguration']['type'] = \"USERNAME_PASSWORD\"\n", - " kbConfigParam['sqlKnowledgeBaseConfiguration']['redshiftConfiguration']['queryEngineConfiguration']['serverlessConfiguration']['authConfiguration']['usernamePasswordSecretArn'] = secretArn\n", - "\n", - " knowledge_base = BedrockStructuredKnowledgeBase(\n", - " kb_name=f'{knowledge_base_name}',\n", - " kb_description=knowledge_base_description,\n", - " workgroup_arn=workgroupArn,\n", - " secrets_arn = secretArn,\n", - " kbConfigParam = kbConfigParam,\n", - " suffix = f'{suffix}-f'\n", - " )\n", - " \n", - " elif access_pattern_choice ==2:\n", - " print(f\"Access pattern:{choice_widget.value} IAM Role + Redshift Serverless WorkGroup\")\n", - "\n", - " kbConfigParam['sqlKnowledgeBaseConfiguration']['redshiftConfiguration']['queryEngineConfiguration']['serverlessConfiguration']['authConfiguration']['type'] = \"IAM\"\n", - " \n", - " knowledge_base = BedrockStructuredKnowledgeBase(\n", - " kb_name=f'{knowledge_base_name}',\n", - " kb_description=knowledge_base_description,\n", - " workgroup_arn=workgroupArn,\n", - " kbConfigParam = kbConfigParam,\n", - " suffix = f'{suffix}-f'\n", - " )\n", - " \n", - " elif access_pattern_choice == 3:\n", - " print(f\"Access pattern:{choice_widget.value} IAM Role + Redshift Provisioned Cluster\")\n", - "\n", - " kbProvisionedConfigParam['sqlKnowledgeBaseConfiguration']['redshiftConfiguration']['queryEngineConfiguration']['provisionedConfiguration']['authConfiguration']['type'] = \"IAM\"\n", - " \n", - " knowledge_base = BedrockStructuredKnowledgeBase(\n", - " kb_name=f'{knowledge_base_name}',\n", - " kb_description=knowledge_base_description,\n", - " cluster_identifier=provisioned_cluster_identifier,\n", - " db_name=provisioned_cluster_dbname,\n", - " kbConfigParam = kbProvisionedConfigParam,\n", - " suffix = f'{suffix}-f'\n", - " )\n", - " \n", - " elif access_pattern_choice == 4:\n", - " print(f\"Access pattern:{choice_widget.value} Secrets Manager + Redshift Provisioned Cluster\")\n", - "\n", - " kbProvisionedConfigParam['sqlKnowledgeBaseConfiguration']['redshiftConfiguration']['queryEngineConfiguration']['provisionedConfiguration']['authConfiguration']['type'] = \"USERNAME_PASSWORD\"\n", - " kbProvisionedConfigParam['sqlKnowledgeBaseConfiguration']['redshiftConfiguration']['queryEngineConfiguration']['provisionedConfiguration']['authConfiguration']['usernamePasswordSecretArn'] = provisionedSecretArn\n", - " \n", - " knowledge_base = BedrockStructuredKnowledgeBase(\n", - " kb_name=f'{knowledge_base_name}',\n", - " kb_description=knowledge_base_description,\n", - " cluster_identifier=provisioned_cluster_identifier,\n", - " db_name=provisioned_cluster_dbname,\n", - " secrets_arn = provisionedSecretArn,\n", - " kbConfigParam = kbProvisionedConfigParam,\n", - " suffix = f'{suffix}-f'\n", - " ) \n", - " elif access_pattern_choice == 5:\n", - " print(f\"Access pattern:{choice_widget.value} DB User + Redshift Provisioned Cluster\")\n", - "\n", - " kbProvisionedConfigParam['sqlKnowledgeBaseConfiguration']['redshiftConfiguration']['queryEngineConfiguration']['provisionedConfiguration']['authConfiguration']['type'] = \"USERNAME\"\n", - " kbProvisionedConfigParam['sqlKnowledgeBaseConfiguration']['redshiftConfiguration']['queryEngineConfiguration']['provisionedConfiguration']['authConfiguration']['databaseUser'] = databaseUser\n", - "\n", - " knowledge_base = BedrockStructuredKnowledgeBase(\n", - " kb_name=f'{knowledge_base_name}',\n", - " kb_description=knowledge_base_description,\n", - " cluster_identifier=provisioned_cluster_identifier,\n", - " db_name=provisioned_cluster_dbname,\n", - " db_user=databaseUser,\n", - " kbConfigParam = kbProvisionedConfigParam,\n", - " suffix = f'{suffix}-f'\n", - " ) \n", - " else:\n", - " print(\"Invalid choice. Please enter a number between 1 and 2.\")\n", - "except ValueError:\n", - " print(\"Invalid input. Please enter a number.\")" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "### For IAM access pattern, Grant database access to the role you use for authentication\n", - "\n", - "You can use below sample SQL Statement to create user and provide access. Please update the GRANT statement based on the level of access that needs to be provided for your dataset. \n", - "\n", - "For more detailed steps, please see the [documentation](https://docs.aws.amazon.com/bedrock/latest/userguide/knowledge-base-prereq-structured.html#knowledge-base-prereq-structured-db-access)" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "#Following SQL commands should be executed in Redshift Query Editor\n", - "print(f'CREATE USER \"IAMR:{knowledge_base.bedrock_kb_execution_role_name}\" WITH PASSWORD DISABLE;')\n", - "print(f'GRANT SELECT ON ALL tables IN SCHEMA public TO \"IAMR:{knowledge_base.bedrock_kb_execution_role_name}\";')" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "### 2 - Start the ingestion job\n", - "\n", - "This step is to start the ingestion job to sync the datasources. " - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "# ensure that the kb is available\n", - "time.sleep(60)\n", - "# sync knowledge base\n", - "knowledge_base.start_ingestion_job()" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "# keep the kb_id for invocation later in the invoke request\n", - "kb_id = knowledge_base.get_knowledge_base_id()\n", - "%store kb_id" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "### 3 - Test the Structured Knowledge Base\n", - "Now the Knowlegde Base is available we can test it out using the [**retrieve**](https://boto3.amazonaws.com/v1/documentation/api/latest/reference/services/bedrock-agent-runtime/client/retrieve.html), [**retrieve_and_generate**](https://boto3.amazonaws.com/v1/documentation/api/latest/reference/services/bedrock-agent-runtime/client/retrieve_and_generate.html), and [**generate_query**](https://docs.aws.amazon.com/bedrock/latest/APIReference/API_agent-runtime_GenerateQuery.html) functions. \n", - "\n", - "When you use [**retrieve**](https://boto3.amazonaws.com/v1/documentation/api/latest/reference/services/bedrock-agent-runtime/client/retrieve.html), the response returns the result of the SQL query execution. \n", - "\n", - "When you use [**retrieve_and_generate**](https://boto3.amazonaws.com/v1/documentation/api/latest/reference/services/bedrock-agent-runtime/client/retrieve_and_generate.html), the generated response is based on the result of the SQL query execution\n", - "\n", - "When using the [**generate_query**](https://docs.aws.amazon.com/bedrock/latest/APIReference/API_agent-runtime_GenerateQuery.html) API, it transforms a natural language query into SQL.\n", - "\n" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "query = \"\"" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "#### 3.1 - Using RetrieveAndGenerate API" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "foundation_model = \"anthropic.claude-3-sonnet-20240229-v1:0\"\n", - "\n", - "response = bedrock_agent_runtime_client.retrieve_and_generate(\n", - " input={\n", - " \"text\": query\n", - " },\n", - " retrieveAndGenerateConfiguration={\n", - " \"type\": \"KNOWLEDGE_BASE\",\n", - " \"knowledgeBaseConfiguration\": {\n", - " 'knowledgeBaseId': kb_id,\n", - " \"modelArn\": \"arn:aws:bedrock:{}::foundation-model/{}\".format(region, foundation_model),\n", - " \"retrievalConfiguration\": {\n", - " \"vectorSearchConfiguration\": {\n", - " \"numberOfResults\":5\n", - " } \n", - " }\n", - " }\n", - " }\n", - ")\n", - "\n", - "print(response['output']['text'],end='\\n'*2)" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "#### 3.2 - Using Retrieve API" - ] - }, - { - "cell_type": "code", - "execution_count": 40, - "metadata": {}, - "outputs": [], - "source": [ - "response_ret = bedrock_agent_runtime_client.retrieve(\n", - " knowledgeBaseId=kb_id, \n", - " nextToken='string',\n", - " retrievalConfiguration={\n", - " \"vectorSearchConfiguration\": {\n", - " \"numberOfResults\":5,\n", - " } \n", - " },\n", - " retrievalQuery={\n", - " \"text\": query\n", - " }\n", - ")\n" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "import json\n", - "import pandas as pd\n", - "\n", - "# Function to extract retrieved results from Retrieve API response into a pandas dataframe.\n", - "\n", - "def response_print(retrieve_resp):\n", - "\n", - " # Extract the retrievalResults list\n", - " retrieval_results = retrieve_resp['retrievalResults']\n", - "\n", - " # Dictionary to store the extracted data\n", - " extracted_data = {}\n", - "\n", - " # Iterate through each item in retrievalResults\n", - " for item in retrieval_results:\n", - " row = item['content']['row']\n", - " for col in row:\n", - " column_name = col['columnName']\n", - " column_value = col['columnValue']\n", - " \n", - " # If this column hasn't been seen before, create a new list for it\n", - " if column_name not in extracted_data:\n", - " extracted_data[column_name] = []\n", - " \n", - " # Append the value to the appropriate list\n", - " extracted_data[column_name].append(column_value)\n", - "\n", - " # Create a DataFrame from the extracted data\n", - " df = pd.DataFrame(extracted_data)\n", - "\n", - " return df\n", - " " - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "# Display the Retrieved results records\n", - "df = response_print(response_ret)\n", - "print(df.head())" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "#### 3.3 - Using Generate Query" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "query_response = bedrock_agent_runtime_client.generate_query(\n", - " queryGenerationInput={\n", - " \"text\": query,\n", - " \"type\": \"TEXT\"\n", - " },\n", - " transformationConfiguration={\n", - " \"mode\" : \"TEXT_TO_SQL\",\n", - " \"textToSqlConfiguration\": {\n", - " \"type\": \"KNOWLEDGE_BASE\",\n", - " \"knowledgeBaseConfiguration\": {\n", - " \"knowledgeBaseArn\": knowledge_base.knowledge_base['knowledgeBaseArn']\n", - " }\n", - " }\n", - " }\n", - ")\n", - "\n", - "generated_sql = query_response['queries'][0]['sql']\n", - "generated_sql" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "### Clean Up\n", - "Please make sure to uncomment and run the below section to delete all the resources" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "# # Delete resources\n", - "# print(\"===============================Deleteing resources ==============================\\n\")\n", - "knowledge_base.delete_kb( delete_iam_roles_and_policies=True)" - ] - } - ], - "metadata": { - "kernelspec": { - "display_name": "structured_rag", - "language": "python", - "name": "python3" - }, - "language_info": { - "codemirror_mode": { - "name": "ipython", - "version": 3 - }, - "file_extension": ".py", - "mimetype": "text/x-python", - "name": "python", - "nbconvert_exporter": "python", - "pygments_lexer": "ipython3", - "version": "3.12.2" - } - }, - "nbformat": 4, - "nbformat_minor": 2 -} diff --git a/06-multi-modal-rag/text-images-rag-using-kb/text-images-rag-using-kb.ipynb b/06-multi-modal-rag/text-images-rag-using-kb/text-images-rag-using-kb.ipynb deleted file mode 100644 index 6365b1b..0000000 --- a/06-multi-modal-rag/text-images-rag-using-kb/text-images-rag-using-kb.ipynb +++ /dev/null @@ -1,1172 +0,0 @@ -{ - "cells": [ - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "# Multi modal data processing - End to end example using Amazon Bedrock Knowledge Bases for text & images\n", - "\n", - "Multi-modal RAG can analyze and leverage insights from both textual and visual data, such as images, charts, diagrams, and tables.Bedrock Knowledge Bases offers end-to-end managed Retrieval-Augmented Generation (RAG) workflow that enables customers to create highly accurate, low-latency, secure, and custom generative AI applications by incorporating contextual information from their own data sources.\n", - "\n", - "Bedrock Knowledge Bases extracts content from both text and visual data, generates semantic embeddings using the selected embedding model, and stores them in the chosen vector store. This enables users to retrieve and generate answers to questions derived not only from text but also from visual data. Additionally, retrieved results now include source attribution for visual data, enhancing transparency and building trust in the generated outputs.\n", - "\n", - "You can choose between: Amazon Bedrock Data Automation, a managed service that automatically extracts content from multimodal data (currently in Preview), or FMs such as Claude 3.5 Sonnet or Claude 3 Haiku, with the flexibility to customize the default prompt.\n", - "\n", - "This notebook provides sample code for building a Multimodal RAG using Amazon Bedrock Knowledge Bases.\n", - "\n", - "#### Steps: \n", - "- Create Knowledge Base execution role with necessary policies for accessing/writing data from/to S3 and required Foundation models .\n", - "- Create a knowledge base with rich content documents\n", - "- Create data source(s) within knowledge base\n", - "- Start ingestion jobs using KB APIs which which will read data from the data source, parse the documents (images, charts, tables etc.)using Bedrock Data Automation or Foundation model, chunk it, convert chunks into embeddings using Amazon Titan Embeddings model and then store these embeddings in AOSS. All of this without having to build, deploy and manage the data pipeline.\n", - "\n", - "Once the data is available in the Bedrock Knowledge Base then a question answering application can be built using the Knowledge Base APIs provided by Amazon Bedrock.\n", - "\n" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "#### Pre-requisites:\n", - "\n", - "Please make sure to enable `Anthropic Claude 3 Sonnet` , `Amazon Nova Micro` and `Titan Text Embeddings V2` model access in Amazon Bedrock Console\n", - "\n", - "
\n", - "Note: Please run the notebook cell one at a time instead of using \"Run All Cells\" option.\n", - "
\n" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "### 0 - Setup\n", - "Before running the rest of this notebook, you'll need to run the cells below to (ensure necessary libraries are installed and) connect to Bedrock.\n", - "\n", - "Please ignore any pip dependency error (if you see any while installing libraries)" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "%pip install --force-reinstall -q -r ../../requirements.txt " - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": { - "tags": [] - }, - "outputs": [], - "source": [ - "# %pip install --upgrade boto3\n", - "import boto3\n", - "print(boto3.__version__)" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": { - "collapsed": false, - "jupyter": { - "outputs_hidden": false - }, - "tags": [] - }, - "outputs": [], - "source": [ - "# restart kernel\n", - "from IPython.core.display import HTML\n", - "HTML(\"\")" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "%load_ext autoreload\n", - "%autoreload 2" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": { - "tags": [] - }, - "outputs": [], - "source": [ - "import warnings\n", - "warnings.filterwarnings('ignore')" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "import os\n", - "import sys\n", - "import time\n", - "import boto3\n", - "import logging\n", - "import pprint\n", - "import json\n", - "\n", - "# Set the path to import module\n", - "from pathlib import Path\n", - "current_path = Path().resolve()\n", - "current_path = current_path.parent.parent\n", - "if str(current_path) not in sys.path:\n", - " sys.path.append(str(current_path))\n", - "# Print sys.path to verify\n", - "# print(sys.path)\n", - "\n", - "from utils.knowledge_base import BedrockKnowledgeBase" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "#Clients\n", - "s3_client = boto3.client('s3')\n", - "sts_client = boto3.client('sts')\n", - "session = boto3.session.Session()\n", - "region = session.region_name\n", - "account_id = sts_client.get_caller_identity()[\"Account\"]\n", - "bedrock_agent_client = boto3.client('bedrock-agent')\n", - "bedrock_agent_runtime_client = boto3.client('bedrock-agent-runtime') \n", - "logging.basicConfig(format='[%(asctime)s] p%(process)s {%(filename)s:%(lineno)d} %(levelname)s - %(message)s', level=logging.INFO)\n", - "logger = logging.getLogger(__name__)\n", - "region, account_id" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "import time\n", - "\n", - "# Get the current timestamp\n", - "current_time = time.time()\n", - "\n", - "# Format the timestamp as a string\n", - "timestamp_str = time.strftime(\"%Y%m%d%H%M%S\", time.localtime(current_time))[-7:]\n", - "# Create the suffix using the timestamp\n", - "suffix = f\"{timestamp_str}\"\n", - "\n", - "knowledge_base_name = f\"bedrock-multi-modal-kb-{suffix}\"\n", - "knowledge_base_description = \"Multi-modal RAG knowledge base.\"\n", - "\n", - "bucket_name = f'{knowledge_base_name}-{account_id}'\n", - "# intermediate_bucket_name = f'{knowledge_base_name}-mm-storage-{account_id}'\n", - "foundation_model = \"anthropic.claude-3-sonnet-20240229-v1:0\"" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "#### You can add multiple data sources (S3, Sharepoint) to a multimodal Knowledge Base. For this notebook, we'll test Knowledge Base creation with S3 Bucket." - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "\n", - "Each data source may have different pre-requisites, please refer to the AWS documetation for more information." - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": { - "tags": [] - }, - "outputs": [], - "source": [ - "## Please uncomment the data sources that you want to add and update the placeholder values accordingly.\n", - "\n", - "data_sources=[\n", - " {\"type\": \"S3\", \"bucket_name\": bucket_name}, \n", - "\n", - " # {\"type\": \"SHAREPOINT\", \"tenantId\": \"888d0b57-69f1-4fb8-957f-e1f0bedf64de\", \"domain\": \"yourdomain\",\n", - " # \"authType\": \"OAUTH2_CLIENT_CREDENTIALS\",\n", - " # \"credentialsSecretArn\": f\"arn:aws::secretsmanager:{region_name}:secret:<>\",\n", - " # \"siteUrls\": [\"https://yourdomain.sharepoint.com/sites/mysite\"]\n", - " # },\n", - " ]\n", - " \n", - "pp = pprint.PrettyPrinter(indent=2)" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "### 1 - Create Knowledge Base with Multi modality" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "# For multi-modal RAG While instantiating BedrockKnowledgeBase, pass multi_modal= True and choose the parser you want to use\n", - "\n", - "knowledge_base = BedrockKnowledgeBase(\n", - " kb_name=f'{knowledge_base_name}',\n", - " kb_description=knowledge_base_description,\n", - " data_sources=data_sources,\n", - " multi_modal= True,\n", - " parser='BEDROCK_FOUNDATION_MODEL', # BEDROCK_DATA_AUTOMATION\n", - " chunking_strategy = \"FIXED_SIZE\", \n", - " suffix = f'{suffix}-f'\n", - ")" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "### 2 - Data Ingestion\n", - "We'll download publically available rich content PDF and upload it to an S3 bucket" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "import os\n", - "\n", - "def create_directory(directory_name): \n", - " if not os.path.exists(directory_name):\n", - " os.makedirs(directory_name)\n", - " print(f\"Directory '{directory_name}' created successfully.\")\n", - " else:\n", - " print(f\"Directory '{directory_name}' already exists.\")\n", - "\n", - "# Call the function to create the directory\n", - "create_directory(\"mm-data\")" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "import requests\n", - "\n", - "def download_file(url, filename):\n", - " # Send a GET request to the URL\n", - " response = requests.get(url)\n", - " \n", - " # Check if the request was successful\n", - " if response.status_code == 200:\n", - " # Open the file in write-binary mode\n", - " with open(filename, 'wb') as file:\n", - " # Write the content of the response to the file\n", - " file.write(response.content)\n", - " print(f\"File downloaded successfully: {filename}\")\n", - " else:\n", - " print(f\"Failed to download file. Status code: {response.status_code}\")\n", - "\n", - "# URL of the file to download\n", - "url = \"https://sgp.fas.org/crs/misc/IF12695.pdf\"\n", - "\n", - "# Name for the downloaded file\n", - "filename = \"./mm-data/tornadoes_report.pdf\"\n", - "\n", - "# Call the function to download the file\n", - "download_file(url, filename)" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "##### Upload data to S3 Bucket data source" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": { - "tags": [] - }, - "outputs": [], - "source": [ - "def upload_directory(path, bucket_name):\n", - " for root,dirs,files in os.walk(path):\n", - " for file in files:\n", - " file_to_upload = os.path.join(root,file)\n", - " print(f\"uploading file {file_to_upload} to {bucket_name}\")\n", - " s3_client.upload_file(file_to_upload,bucket_name,file)\n", - "\n", - "upload_directory(\"./mm-data\", bucket_name)" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "### Start ingestion job\n", - "Once the KB and data source(s) created, we can start the ingestion job for each data source.\n", - "During the ingestion job, KB will fetch the documents from the data source, Parse the document to extract text, chunk it based on the chunking size provided, create embeddings of each chunk and then write it to the vector database, in this case OSS.\n", - "\n", - "NOTE: Currently, you can only kick-off one ingestion job at one time." - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "# ensure that the kb is available\n", - "time.sleep(30)\n", - "# sync knowledge base\n", - "knowledge_base.start_ingestion_job()" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "# keep the kb_id for invocation later in the invoke request\n", - "kb_id = knowledge_base.get_knowledge_base_id()\n", - "%store kb_id" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "### 4 - Test the Knowledge Base\n", - "Now the Knowlegde Base is available we can test it out using the [**retrieve**](https://boto3.amazonaws.com/v1/documentation/api/latest/reference/services/bedrock-agent-runtime/client/retrieve.html) and [**retrieve_and_generate**](https://boto3.amazonaws.com/v1/documentation/api/latest/reference/services/bedrock-agent-runtime/client/retrieve_and_generate.html) functions. \n", - "\n", - "#### Testing Knowledge Base with Retrieve and Generate API\n", - "\n", - "Let's first test the knowledge base using the retrieve and generate API. With this API, Bedrock takes care of retrieving the necessary references from the knowledge base and generating the final answer using a foundation model from Bedrock.\n", - "\n", - "query = `Summarize annual trends of tornado reports and how it varies year over year.`\n", - "\n", - "The right response for this query is expected to fetch from a chart/graph from the PDF document." - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "query = \"Summarize annual trends of tornado reports and how it varies year over year.\"" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "foundation_model = \"anthropic.claude-3-sonnet-20240229-v1:0\"\n", - "# foundation_model = \"amazon.nova-micro-v1:0\"\n", - "\n", - "response = bedrock_agent_runtime_client.retrieve_and_generate(\n", - " input={\n", - " \"text\": query\n", - " },\n", - " retrieveAndGenerateConfiguration={\n", - " \"type\": \"KNOWLEDGE_BASE\",\n", - " \"knowledgeBaseConfiguration\": {\n", - " 'knowledgeBaseId': kb_id,\n", - " \"modelArn\": \"arn:aws:bedrock:{}::foundation-model/{}\".format(region, foundation_model),\n", - " \"retrievalConfiguration\": {\n", - " \"vectorSearchConfiguration\": {\n", - " \"numberOfResults\":5\n", - " } \n", - " }\n", - " }\n", - " }\n", - ")\n", - "\n", - "print(response['output']['text'],end='\\n'*2)" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "from PIL import Image\n", - "import s3fs\n", - "\n", - "fs = s3fs.S3FileSystem()\n", - "\n", - "## Function to print retrieved response\n", - "\n", - "def print_response(response):\n", - "#structure 'retrievalResults': list of contents. Each list has ['ResponseMetadata', 'citations', 'output', 'sessionId']\n", - " print( f'OUTPUT: {response[\"output\"][\"text\"]} \\n')\n", - " \n", - " print(f'CITATION DETAILS: \\n')\n", - " \n", - " for num, chunk in enumerate(response['citations']):\n", - " print(f'CHUNK {num}',end='\\n'*1)\n", - " print(\"========\")\n", - " print(f'\\t Generated Response Text: ')\n", - " print(f'\\t ------------------------- ')\n", - " print(f'\\t Generated Response Text: ',chunk['generatedResponsePart']['textResponsePart']['text'],end='\\n'*2)\n", - " for i, ref in enumerate (chunk['retrievedReferences']):\n", - " print(f'\\t Retrieved References: ')\n", - " print(f'\\t ---------------------', )\n", - " print(f'\\n\\t\\t --> Location:', ref['location'])\n", - " print(f'\\t\\n\\t\\t --> Metadata: \\n\\t\\t\\t ---> Source', ref['metadata']['x-amz-bedrock-kb-source-uri'])\n", - " # print(f'\\t\\n\\t\\t\\n\\t\\t\\t ---> x-amz-bedrock-kb-description', ref['metadata']['x-amz-bedrock-kb-description'])\n", - " print(f'\\t\\n\\t\\t\\n\\t\\t\\t ---> x-amz-bedrock-kb-byte-content-source', ref['metadata']['x-amz-bedrock-kb-byte-content-source'])\n", - " print(\"\")\n", - " with fs.open(ref['metadata']['x-amz-bedrock-kb-byte-content-source']) as f:\n", - " display(Image.open(f).resize((400, 400)))" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "print_response(response)" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "#### Testing Knowledge Base with Retrieve API\n", - "If you need an extra layer of control, you can retrieve the chuncks that best match your query using the retrieve API. In this setup, we can configure the desired number of results and control the final answer with your own application logic. The API then provides you with the matching content, its S3 location, the similarity score and the chunk metadata." - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "response_ret = bedrock_agent_runtime_client.retrieve(\n", - " knowledgeBaseId=kb_id, \n", - " nextToken='string',\n", - " retrievalConfiguration={\n", - " \"vectorSearchConfiguration\": {\n", - " \"numberOfResults\":5,\n", - " } \n", - " },\n", - " retrievalQuery={\n", - " \"text\": \"How many new positions were opened across Amazon's fulfillment and delivery network?\"\n", - " }\n", - ")\n", - "\n", - "def response_print(retrieve_resp):\n", - "#structure 'retrievalResults': list of contents. Each list has content, location, score, metadata\n", - " for num,chunk in enumerate(response_ret['retrievalResults'],1):\n", - " if 'text' in chunk['content']:\n", - " print(f'Chunk {num}: ',chunk['content']['text'],end='\\n'*2)\n", - " if 'byteContent' in chunk['content']:\n", - " print(f'Chunk {num}: ',chunk['content']['byteContent'],end='\\n'*2)\n", - " print(f'Chunk {num} Location: ',chunk['location'],end='\\n'*2)\n", - " print(f'Chunk {num} Score: ',chunk['score'],end='\\n'*2)\n", - " print(f'Chunk {num} Metadata: ',chunk['metadata'],end='\\n'*2)\n", - " print(\"--------------------------------\")\n", - "\n", - "response_print(response_ret)" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "### Clean up\n", - "Please make sure to uncomment and run the below section to delete all the resources." - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "# delete local directory\n", - "import shutil\n", - "\n", - "dir_path = \"mm-data\" # Replace with the actual path\n", - "\n", - "try:\n", - " shutil.rmtree(dir_path)\n", - " print(f\"Directory '{dir_path}' and its contents have been deleted successfully.\")\n", - "except FileNotFoundError:\n", - " print(f\"Directory '{dir_path}' not found.\")\n", - "except Exception as e:\n", - " print(f\"An error occurred: {e}\")" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "# # Delete resources\n", - "# print(\"===============================Deleteing resources ==============================\\n\")\n", - "knowledge_base.delete_kb(delete_s3_bucket=True, delete_iam_roles_and_policies=True)\n" - ] - } - ], - "metadata": { - "availableInstances": [ - { - "_defaultOrder": 0, - "_isFastLaunch": true, - "category": "General purpose", - "gpuNum": 0, - "hideHardwareSpecs": false, - "memoryGiB": 4, - "name": "ml.t3.medium", - "vcpuNum": 2 - }, - { - "_defaultOrder": 1, - "_isFastLaunch": false, - "category": "General purpose", - "gpuNum": 0, - "hideHardwareSpecs": false, - "memoryGiB": 8, - "name": "ml.t3.large", - "vcpuNum": 2 - }, - { - "_defaultOrder": 2, - "_isFastLaunch": false, - "category": "General purpose", - "gpuNum": 0, - "hideHardwareSpecs": false, - "memoryGiB": 16, - "name": "ml.t3.xlarge", - "vcpuNum": 4 - }, - { - "_defaultOrder": 3, - "_isFastLaunch": false, - "category": "General purpose", - "gpuNum": 0, - "hideHardwareSpecs": false, - "memoryGiB": 32, - "name": "ml.t3.2xlarge", - "vcpuNum": 8 - }, - { - "_defaultOrder": 4, - "_isFastLaunch": true, - "category": "General purpose", - "gpuNum": 0, - "hideHardwareSpecs": false, - "memoryGiB": 8, - "name": "ml.m5.large", - "vcpuNum": 2 - }, - { - "_defaultOrder": 5, - "_isFastLaunch": false, - "category": "General purpose", - "gpuNum": 0, - "hideHardwareSpecs": false, - "memoryGiB": 16, - "name": "ml.m5.xlarge", - "vcpuNum": 4 - }, - { - "_defaultOrder": 6, - "_isFastLaunch": false, - "category": "General purpose", - "gpuNum": 0, - "hideHardwareSpecs": false, - "memoryGiB": 32, - "name": "ml.m5.2xlarge", - "vcpuNum": 8 - }, - { - "_defaultOrder": 7, - "_isFastLaunch": false, - "category": "General purpose", - "gpuNum": 0, - "hideHardwareSpecs": false, - "memoryGiB": 64, - "name": "ml.m5.4xlarge", - "vcpuNum": 16 - }, - { - "_defaultOrder": 8, - "_isFastLaunch": false, - "category": "General purpose", - "gpuNum": 0, - "hideHardwareSpecs": false, - "memoryGiB": 128, - "name": "ml.m5.8xlarge", - "vcpuNum": 32 - }, - { - "_defaultOrder": 9, - "_isFastLaunch": false, - "category": "General purpose", - "gpuNum": 0, - "hideHardwareSpecs": false, - "memoryGiB": 192, - "name": "ml.m5.12xlarge", - "vcpuNum": 48 - }, - { - "_defaultOrder": 10, - "_isFastLaunch": false, - "category": "General purpose", - "gpuNum": 0, - "hideHardwareSpecs": false, - "memoryGiB": 256, - "name": "ml.m5.16xlarge", - "vcpuNum": 64 - }, - { - "_defaultOrder": 11, - "_isFastLaunch": false, - "category": "General purpose", - "gpuNum": 0, - "hideHardwareSpecs": false, - "memoryGiB": 384, - "name": "ml.m5.24xlarge", - "vcpuNum": 96 - }, - { - "_defaultOrder": 12, - "_isFastLaunch": false, - "category": "General purpose", - "gpuNum": 0, - "hideHardwareSpecs": false, - "memoryGiB": 8, - "name": "ml.m5d.large", - "vcpuNum": 2 - }, - { - "_defaultOrder": 13, - "_isFastLaunch": false, - "category": "General purpose", - "gpuNum": 0, - "hideHardwareSpecs": false, - "memoryGiB": 16, - "name": "ml.m5d.xlarge", - "vcpuNum": 4 - }, - { - "_defaultOrder": 14, - "_isFastLaunch": false, - "category": "General purpose", - "gpuNum": 0, - "hideHardwareSpecs": false, - "memoryGiB": 32, - "name": "ml.m5d.2xlarge", - "vcpuNum": 8 - }, - { - "_defaultOrder": 15, - "_isFastLaunch": false, - "category": "General purpose", - "gpuNum": 0, - "hideHardwareSpecs": false, - "memoryGiB": 64, - "name": "ml.m5d.4xlarge", - "vcpuNum": 16 - }, - { - "_defaultOrder": 16, - "_isFastLaunch": false, - "category": "General purpose", - "gpuNum": 0, - "hideHardwareSpecs": false, - "memoryGiB": 128, - "name": "ml.m5d.8xlarge", - "vcpuNum": 32 - }, - { - "_defaultOrder": 17, - "_isFastLaunch": false, - "category": "General purpose", - "gpuNum": 0, - "hideHardwareSpecs": false, - "memoryGiB": 192, - "name": "ml.m5d.12xlarge", - "vcpuNum": 48 - }, - { - "_defaultOrder": 18, - "_isFastLaunch": false, - "category": "General purpose", - "gpuNum": 0, - "hideHardwareSpecs": false, - "memoryGiB": 256, - "name": "ml.m5d.16xlarge", - "vcpuNum": 64 - }, - { - "_defaultOrder": 19, - "_isFastLaunch": false, - "category": "General purpose", - "gpuNum": 0, - "hideHardwareSpecs": false, - "memoryGiB": 384, - "name": "ml.m5d.24xlarge", - "vcpuNum": 96 - }, - { - "_defaultOrder": 20, - "_isFastLaunch": false, - "category": "General purpose", - "gpuNum": 0, - "hideHardwareSpecs": true, - "memoryGiB": 0, - "name": "ml.geospatial.interactive", - "supportedImageNames": [ - "sagemaker-geospatial-v1-0" - ], - "vcpuNum": 0 - }, - { - "_defaultOrder": 21, - "_isFastLaunch": true, - "category": "Compute optimized", - "gpuNum": 0, - "hideHardwareSpecs": false, - "memoryGiB": 4, - "name": "ml.c5.large", - "vcpuNum": 2 - }, - { - "_defaultOrder": 22, - "_isFastLaunch": false, - "category": "Compute optimized", - "gpuNum": 0, - "hideHardwareSpecs": false, - "memoryGiB": 8, - "name": "ml.c5.xlarge", - "vcpuNum": 4 - }, - { - "_defaultOrder": 23, - "_isFastLaunch": false, - "category": "Compute optimized", - "gpuNum": 0, - "hideHardwareSpecs": false, - "memoryGiB": 16, - "name": "ml.c5.2xlarge", - "vcpuNum": 8 - }, - { - "_defaultOrder": 24, - "_isFastLaunch": false, - "category": "Compute optimized", - "gpuNum": 0, - "hideHardwareSpecs": false, - "memoryGiB": 32, - "name": "ml.c5.4xlarge", - "vcpuNum": 16 - }, - { - "_defaultOrder": 25, - "_isFastLaunch": false, - "category": "Compute optimized", - "gpuNum": 0, - "hideHardwareSpecs": false, - "memoryGiB": 72, - "name": "ml.c5.9xlarge", - "vcpuNum": 36 - }, - { - "_defaultOrder": 26, - "_isFastLaunch": false, - "category": "Compute optimized", - "gpuNum": 0, - "hideHardwareSpecs": false, - "memoryGiB": 96, - "name": "ml.c5.12xlarge", - "vcpuNum": 48 - }, - { - "_defaultOrder": 27, - "_isFastLaunch": false, - "category": "Compute optimized", - "gpuNum": 0, - "hideHardwareSpecs": false, - "memoryGiB": 144, - "name": "ml.c5.18xlarge", - "vcpuNum": 72 - }, - { - "_defaultOrder": 28, - "_isFastLaunch": false, - "category": "Compute optimized", - "gpuNum": 0, - "hideHardwareSpecs": false, - "memoryGiB": 192, - "name": "ml.c5.24xlarge", - "vcpuNum": 96 - }, - { - "_defaultOrder": 29, - "_isFastLaunch": true, - "category": "Accelerated computing", - "gpuNum": 1, - "hideHardwareSpecs": false, - "memoryGiB": 16, - "name": "ml.g4dn.xlarge", - "vcpuNum": 4 - }, - { - "_defaultOrder": 30, - "_isFastLaunch": false, - "category": "Accelerated computing", - "gpuNum": 1, - "hideHardwareSpecs": false, - "memoryGiB": 32, - "name": "ml.g4dn.2xlarge", - "vcpuNum": 8 - }, - { - "_defaultOrder": 31, - "_isFastLaunch": false, - "category": "Accelerated computing", - "gpuNum": 1, - "hideHardwareSpecs": false, - "memoryGiB": 64, - "name": "ml.g4dn.4xlarge", - "vcpuNum": 16 - }, - { - "_defaultOrder": 32, - "_isFastLaunch": false, - "category": "Accelerated computing", - "gpuNum": 1, - "hideHardwareSpecs": false, - "memoryGiB": 128, - "name": "ml.g4dn.8xlarge", - "vcpuNum": 32 - }, - { - "_defaultOrder": 33, - "_isFastLaunch": false, - "category": "Accelerated computing", - "gpuNum": 4, - "hideHardwareSpecs": false, - "memoryGiB": 192, - "name": "ml.g4dn.12xlarge", - "vcpuNum": 48 - }, - { - "_defaultOrder": 34, - "_isFastLaunch": false, - "category": "Accelerated computing", - "gpuNum": 1, - "hideHardwareSpecs": false, - "memoryGiB": 256, - "name": "ml.g4dn.16xlarge", - "vcpuNum": 64 - }, - { - "_defaultOrder": 35, - "_isFastLaunch": false, - "category": "Accelerated computing", - "gpuNum": 1, - "hideHardwareSpecs": false, - "memoryGiB": 61, - "name": "ml.p3.2xlarge", - "vcpuNum": 8 - }, - { - "_defaultOrder": 36, - "_isFastLaunch": false, - "category": "Accelerated computing", - "gpuNum": 4, - "hideHardwareSpecs": false, - "memoryGiB": 244, - "name": "ml.p3.8xlarge", - "vcpuNum": 32 - }, - { - "_defaultOrder": 37, - "_isFastLaunch": false, - "category": "Accelerated computing", - "gpuNum": 8, - "hideHardwareSpecs": false, - "memoryGiB": 488, - "name": "ml.p3.16xlarge", - "vcpuNum": 64 - }, - { - "_defaultOrder": 38, - "_isFastLaunch": false, - "category": "Accelerated computing", - "gpuNum": 8, - "hideHardwareSpecs": false, - "memoryGiB": 768, - "name": "ml.p3dn.24xlarge", - "vcpuNum": 96 - }, - { - "_defaultOrder": 39, - "_isFastLaunch": false, - "category": "Memory Optimized", - "gpuNum": 0, - "hideHardwareSpecs": false, - "memoryGiB": 16, - "name": "ml.r5.large", - "vcpuNum": 2 - }, - { - "_defaultOrder": 40, - "_isFastLaunch": false, - "category": "Memory Optimized", - "gpuNum": 0, - "hideHardwareSpecs": false, - "memoryGiB": 32, - "name": "ml.r5.xlarge", - "vcpuNum": 4 - }, - { - "_defaultOrder": 41, - "_isFastLaunch": false, - "category": "Memory Optimized", - "gpuNum": 0, - "hideHardwareSpecs": false, - "memoryGiB": 64, - "name": "ml.r5.2xlarge", - "vcpuNum": 8 - }, - { - "_defaultOrder": 42, - "_isFastLaunch": false, - "category": "Memory Optimized", - "gpuNum": 0, - "hideHardwareSpecs": false, - "memoryGiB": 128, - "name": "ml.r5.4xlarge", - "vcpuNum": 16 - }, - { - "_defaultOrder": 43, - "_isFastLaunch": false, - "category": "Memory Optimized", - "gpuNum": 0, - "hideHardwareSpecs": false, - "memoryGiB": 256, - "name": "ml.r5.8xlarge", - "vcpuNum": 32 - }, - { - "_defaultOrder": 44, - "_isFastLaunch": false, - "category": "Memory Optimized", - "gpuNum": 0, - "hideHardwareSpecs": false, - "memoryGiB": 384, - "name": "ml.r5.12xlarge", - "vcpuNum": 48 - }, - { - "_defaultOrder": 45, - "_isFastLaunch": false, - "category": "Memory Optimized", - "gpuNum": 0, - "hideHardwareSpecs": false, - "memoryGiB": 512, - "name": "ml.r5.16xlarge", - "vcpuNum": 64 - }, - { - "_defaultOrder": 46, - "_isFastLaunch": false, - "category": "Memory Optimized", - "gpuNum": 0, - "hideHardwareSpecs": false, - "memoryGiB": 768, - "name": "ml.r5.24xlarge", - "vcpuNum": 96 - }, - { - "_defaultOrder": 47, - "_isFastLaunch": false, - "category": "Accelerated computing", - "gpuNum": 1, - "hideHardwareSpecs": false, - "memoryGiB": 16, - "name": "ml.g5.xlarge", - "vcpuNum": 4 - }, - { - "_defaultOrder": 48, - "_isFastLaunch": false, - "category": "Accelerated computing", - "gpuNum": 1, - "hideHardwareSpecs": false, - "memoryGiB": 32, - "name": "ml.g5.2xlarge", - "vcpuNum": 8 - }, - { - "_defaultOrder": 49, - "_isFastLaunch": false, - "category": "Accelerated computing", - "gpuNum": 1, - "hideHardwareSpecs": false, - "memoryGiB": 64, - "name": "ml.g5.4xlarge", - "vcpuNum": 16 - }, - { - "_defaultOrder": 50, - "_isFastLaunch": false, - "category": "Accelerated computing", - "gpuNum": 1, - "hideHardwareSpecs": false, - "memoryGiB": 128, - "name": "ml.g5.8xlarge", - "vcpuNum": 32 - }, - { - "_defaultOrder": 51, - "_isFastLaunch": false, - "category": "Accelerated computing", - "gpuNum": 1, - "hideHardwareSpecs": false, - "memoryGiB": 256, - "name": "ml.g5.16xlarge", - "vcpuNum": 64 - }, - { - "_defaultOrder": 52, - "_isFastLaunch": false, - "category": "Accelerated computing", - "gpuNum": 4, - "hideHardwareSpecs": false, - "memoryGiB": 192, - "name": "ml.g5.12xlarge", - "vcpuNum": 48 - }, - { - "_defaultOrder": 53, - "_isFastLaunch": false, - "category": "Accelerated computing", - "gpuNum": 4, - "hideHardwareSpecs": false, - "memoryGiB": 384, - "name": "ml.g5.24xlarge", - "vcpuNum": 96 - }, - { - "_defaultOrder": 54, - "_isFastLaunch": false, - "category": "Accelerated computing", - "gpuNum": 8, - "hideHardwareSpecs": false, - "memoryGiB": 768, - "name": "ml.g5.48xlarge", - "vcpuNum": 192 - }, - { - "_defaultOrder": 55, - "_isFastLaunch": false, - "category": "Accelerated computing", - "gpuNum": 8, - "hideHardwareSpecs": false, - "memoryGiB": 1152, - "name": "ml.p4d.24xlarge", - "vcpuNum": 96 - }, - { - "_defaultOrder": 56, - "_isFastLaunch": false, - "category": "Accelerated computing", - "gpuNum": 8, - "hideHardwareSpecs": false, - "memoryGiB": 1152, - "name": "ml.p4de.24xlarge", - "vcpuNum": 96 - }, - { - "_defaultOrder": 57, - "_isFastLaunch": false, - "category": "Accelerated computing", - "gpuNum": 0, - "hideHardwareSpecs": false, - "memoryGiB": 32, - "name": "ml.trn1.2xlarge", - "vcpuNum": 8 - }, - { - "_defaultOrder": 58, - "_isFastLaunch": false, - "category": "Accelerated computing", - "gpuNum": 0, - "hideHardwareSpecs": false, - "memoryGiB": 512, - "name": "ml.trn1.32xlarge", - "vcpuNum": 128 - }, - { - "_defaultOrder": 59, - "_isFastLaunch": false, - "category": "Accelerated computing", - "gpuNum": 0, - "hideHardwareSpecs": false, - "memoryGiB": 512, - "name": "ml.trn1n.32xlarge", - "vcpuNum": 128 - } - ], - "instance_type": "ml.t3.medium", - "kernelspec": { - "display_name": "Python 3", - "language": "python", - "name": "python3" - }, - "language_info": { - "codemirror_mode": { - "name": "ipython", - "version": 3 - }, - "file_extension": ".py", - "mimetype": "text/x-python", - "name": "python", - "nbconvert_exporter": "python", - "pygments_lexer": "ipython3", - "version": "3.10.13" - } - }, - "nbformat": 4, - "nbformat_minor": 4 -}