diff --git a/kendra-bedrock-cdk-python/README.md b/kendra-bedrock-cdk-python/README.md new file mode 100644 index 000000000..828e7d33f --- /dev/null +++ b/kendra-bedrock-cdk-python/README.md @@ -0,0 +1,76 @@ +# AWS Lambda to Amazon Kendra to Amazon Bedrock + +This pattern contains a sample stack that utilizes an AWS Lambda function to retrieve documents from an Amazon Kendra index and then pass it to Amazon Bedrock to generate a response. The pattern includes usage of the Amazon S3 data source connector. + +Important: this application uses various AWS services and there are costs associated with these services after the Free Tier usage - please see the AWS Pricing page for details. You are responsible for any AWS costs incurred. No warranty is implied in this example. + +## Requirements +* [Create an AWS account](https://portal.aws.amazon.com/gp/aws/developer/registration/index.html) if you do not already have one and log in. The IAM user that you use must have sufficient permissions to make necessary AWS service calls and manage AWS resources. +* [AWS CLI](https://docs.aws.amazon.com/cli/latest/userguide/install-cliv2.html) installed and configured +* [Git Installed](https://git-scm.com/book/en/v2/Getting-Started-Installing-Git) +* [AWS CDK CLI](https://docs.aws.amazon.com/cdk/v2/guide/getting_started.html) (AWS CDK) installed +* [Request Amazon Bedrock Model Access for Anthropic Claude models on Amazon Bedrock](https://docs.aws.amazon.com/bedrock/latest/userguide/model-access.html) +* [Create an S3 Bucket](https://docs.aws.amazon.com/AmazonS3/latest/userguide/creating-bucket.html) and [upload documents](https://docs.aws.amazon.com/AmazonS3/latest/userguide/upload-objects.html) that you want to be indexed. If you already have an S3 bucket with data that you want to crawl, you can skip this step. Note down the name of the S3 bucket for later use. + +## Deployment Instructions +1. Create a new directory, navigate to that directory in a terminal and clone the GitHub repository: + ``` + git clone https://github.com/aws-samples/serverless-patterns + ``` +1. Change directory to the pattern directory: + ``` + cd kendra-bedrock-cdk-python + ``` +1. From the command line, use AWS CDK to deploy the AWS resources for the pattern as specified in the app.py file: + ``` + cdk deploy --parameters S3DSBucketName=${YourS3BucketName} + ``` + +1. Note the outputs from the CDK deployment process. These contain the resource names and/or ARNs which are used for testing. + +# How it works +Please refer to the architecture diagram below: + +![End to End Architecture](images/architecture.png) + +Here's a breakdown of the steps: + +**AWS Lambda:** Two AWS Lambda functions are created. `DataSourceSync` crawls and indexes the content. `InvokeBedrockLambda` invokes the specified model by passing the retrieved content from Amazon Kendra as context to the generative AI model. + +**Amazon Kendra:** An Amazon Kendra index is created with a S3 data source connector. When a the `InvokeBedrockLambda` function is called, documents are retrieved from the Amazon Kendra index. + +**Amazon Bedrock:** Documents retrieved from the Amazon Kendra index are sent to Amazon Bedrock which responds with a generated response. + +## Testing + +CLI Lambda invoke with test event: + +```bash +payload_base64=$(echo -n '{"question": "Value"}' | base64) + +aws lambda invoke \ + --function-name INVOKE_LAMBDA_FUNCTION_ARN \ + --payload "$payload_base64" \ + output.txt +``` + +The output.txt will contain the response generated by Amazon Bedrock. + +Example JSON Lambda test event: + +``` +{ + "question": "Value" +} +``` + +## Cleanup + +1. Delete the stack + ```bash + cdk destroy + ``` +---- +Copyright 2024 Amazon.com, Inc. or its affiliates. All Rights Reserved. + +SPDX-License-Identifier: MIT-0 \ No newline at end of file diff --git a/kendra-bedrock-cdk-python/app.py b/kendra-bedrock-cdk-python/app.py new file mode 100644 index 000000000..627e97c43 --- /dev/null +++ b/kendra-bedrock-cdk-python/app.py @@ -0,0 +1,229 @@ +#!/usr/bin/env python3 +import os + +import aws_cdk as cdk + +from aws_cdk import ( + # Duration, + Stack, + aws_iam as iam, + aws_kendra as kendra, + aws_lambda as lambda_, + aws_s3 as s3, + RemovalPolicy, + Duration, + CfnParameter, + CfnOutput, + triggers + +) + +from constructs import Construct + +class BedrockKendraStack(Stack): + def __init__(self, scope: Construct, construct_id: str, **kwargs) -> None: + super().__init__(scope, construct_id, **kwargs) + + # Define parameters + model_id_param = CfnParameter( + self, "ModelId", + type="String", + default="anthropic.claude-instant-v1", + allowed_values=[ + "anthropic.claude-instant-v1", + "anthropic.claude-3-sonnet-20240229-v1:0", + "anthropic.claude-3-haiku-20240307-v1:0", + "anthropic.claude-v2" + ], + description="Enter the Model Id of the Anthropic LLM" + ) + + s3_bucket_name_param = CfnParameter( + self, "S3DSBucketName", + type="String", + description="Enter the S3 bucket name where the contents you want to be indexed are stored." + ) + + kendra_edition_param = CfnParameter( + self, "KendraEdition", + type="String", + default="DEVELOPER_EDITION", + allowed_values=[ + "DEVELOPER_EDITION", + "ENTERPRISE_EDITION" + ], + description="Kendra edition (DEVELOPER_EDITION, ENTERPRISE_EDITION)" + ) + + # Use the parameter values in your stack + model_id = model_id_param.value_as_string + s3_bucket_name = s3_bucket_name_param.value_as_string + kendra_edition = kendra_edition_param.value_as_string + + # Create Kendra index role + kendra_index_role = iam.Role( + self, "KendraIndexRole", + assumed_by=iam.ServicePrincipal("kendra.amazonaws.com"), + role_name=f"{construct_id}-KendraIndexRole", + managed_policies=[ + iam.ManagedPolicy.from_aws_managed_policy_name("CloudWatchLogsFullAccess") + ] + ) + + # Create Kendra index + kendra_index = kendra.CfnIndex( + self, "KendraIndex", + name=f"{construct_id}-KendraIndex", + role_arn=kendra_index_role.role_arn, + edition=kendra_edition + ) + + # Create Kendra data source role + kendra_ds_role = iam.Role( + self, "KendraDSRole", + assumed_by=iam.ServicePrincipal("kendra.amazonaws.com"), + role_name=f"{construct_id}-DocsDSRole", + managed_policies=[ + iam.ManagedPolicy.from_aws_managed_policy_name("CloudWatchLogsFullAccess")], + inline_policies={ + "KendraDataSourcePolicy": iam.PolicyDocument( + statements=[ + iam.PolicyStatement( + actions=["kendra:BatchPutDocument", "kendra:BatchDeleteDocument"], + resources=[kendra_index.attr_arn] + ) + ] + ), + "S3DataSourcePolicy": iam.PolicyDocument( + statements=[ + iam.PolicyStatement( + actions=["s3:GetObject"], + resources=[f"arn:aws:s3:::{s3_bucket_name}/*"] + ) + ] + ), + "ListBucketPolicy": iam.PolicyDocument( + statements=[ + iam.PolicyStatement( + actions=["s3:ListBucket"], + resources=[f"arn:aws:s3:::{s3_bucket_name}"] + ) + ] + ) + } + ) + + # Create Kendra S3 data source + kendra_ds = kendra.CfnDataSource( + self, "KendraDS", + index_id=kendra_index.attr_id, + name=f"{construct_id}-KendraS3DS", + type='S3', + data_source_configuration=kendra.CfnDataSource.DataSourceConfigurationProperty( + s3_configuration=kendra.CfnDataSource.S3DataSourceConfigurationProperty( + bucket_name=s3_bucket_name)), + role_arn=kendra_ds_role.role_arn + ) + + # Add dependency + kendra_ds.node.add_dependency(kendra_index) + + # Create a role for the DataSourceSyncLambda + data_source_sync_lambda_role = iam.Role( + self, "DataSourceSyncLambdaRole", + assumed_by=iam.ServicePrincipal("lambda.amazonaws.com"), + managed_policies=[ + iam.ManagedPolicy.from_aws_managed_policy_name("CloudWatchLogsFullAccess")], + inline_policies={ + "KendraDataSourceSyncPolicy": iam.PolicyDocument( + statements=[ + iam.PolicyStatement( + actions=[ + "kendra:StartDataSourceSyncJob", + "kendra:StopDataSourceSyncJob" + ], + resources=[ + kendra_index.attr_arn, + f"{kendra_index.attr_arn}/*"] + ) + ] + ) + } + ) + + # Lambda function for initiating data source sync + data_source_sync_lambda = lambda_.Function( + self, "DataSourceSyncLambda", + runtime=lambda_.Runtime.PYTHON_3_12, + code=lambda_.Code.from_asset("src/dataSourceSync"), + handler="dataSourceSyncLambda.lambda_handler", + timeout=Duration.minutes(15), + memory_size=1024, + role = data_source_sync_lambda_role, + environment={ + "INDEX_ID": kendra_index.attr_id, + "DS_ID": kendra_ds.attr_id + } + ) + + # Trigger data source sync lambda + triggers.Trigger(self, "data_source_sync_lambda_trigger", + handler=data_source_sync_lambda, + timeout=Duration.minutes(10), + invocation_type=triggers.InvocationType.EVENT + ) + + # Create the IAM role + invoke_bedrock_lambda_role = iam.Role( + self, "InvokeBedRockLambdaRole", + assumed_by=iam.ServicePrincipal("lambda.amazonaws.com"), + managed_policies=[ + iam.ManagedPolicy.from_aws_managed_policy_name("CloudWatchLogsFullAccess") + ], + inline_policies={ + "InvokeBedRockPolicy": iam.PolicyDocument( + statements=[ + iam.PolicyStatement( + actions=["bedrock:InvokeModel"], + resources=[f"arn:aws:bedrock:{self.region}::foundation-model/{model_id}"] + ) + ] + ), + "KendraRetrievalPolicy": iam.PolicyDocument( + statements=[ + iam.PolicyStatement( + actions=["kendra:Retrieve"], + resources=[kendra_index.attr_arn] + ) + ] + ) + } + ) + + # Lambda function for invoking Bedrock + invoke_bedrock_lambda = lambda_.Function( + self, "InvokeBedrockLambda", + runtime=lambda_.Runtime.PYTHON_3_12, + code=lambda_.Code.from_asset("src/invokeBedrockLambda"), + handler="invokeBedrockLambda.lambda_handler", + timeout=Duration.seconds(120), + memory_size=3008, + role = invoke_bedrock_lambda_role, + tracing=lambda_.Tracing.ACTIVE, + environment={ + "INDEX_ID": kendra_index.attr_id, + "MODEL_ID": model_id + } + ) + + # Output values + CfnOutput(self, "KendraIndexRoleArn", value=kendra_index_role.role_arn, description="Kendra index role ARN") + CfnOutput(self, "KendraIndexID", value=kendra_index.attr_id, description="Kendra index ID") + CfnOutput(self, "KendraS3DataSourceArn", value=kendra_ds.attr_arn, description="Kendra S3 data source ARN") + CfnOutput(self, "DataSourceSyncLambdaArn", value=data_source_sync_lambda.function_arn, description="Data source sync lambda function ARN") + CfnOutput(self, "InvokeBedrockLambdaArn", value=invoke_bedrock_lambda.function_arn, description="Invoke bedrock lambda function ARN") + +app = cdk.App() +BedrockKendraStack(app, "BedrockKendraStack") + +app.synth() diff --git a/kendra-bedrock-cdk-python/cdk.json b/kendra-bedrock-cdk-python/cdk.json new file mode 100644 index 000000000..eb79b783a --- /dev/null +++ b/kendra-bedrock-cdk-python/cdk.json @@ -0,0 +1,62 @@ +{ + "app": "python3 app.py", + "watch": { + "include": [ + "**" + ], + "exclude": [ + "README.md", + "cdk*.json", + "requirements*.txt", + "source.bat", + "**/__init__.py", + "**/__pycache__", + "tests" + ] + }, + "context": { + "@aws-cdk/aws-lambda:recognizeLayerVersion": true, + "@aws-cdk/core:checkSecretUsage": true, + "@aws-cdk/core:target-partitions": [ + "aws", + "aws-cn" + ], + "@aws-cdk-containers/ecs-service-extensions:enableDefaultLogDriver": true, + "@aws-cdk/aws-ec2:uniqueImdsv2TemplateName": true, + "@aws-cdk/aws-ecs:arnFormatIncludesClusterName": true, + "@aws-cdk/aws-iam:minimizePolicies": true, + "@aws-cdk/core:validateSnapshotRemovalPolicy": true, + "@aws-cdk/aws-codepipeline:crossAccountKeyAliasStackSafeResourceName": true, + "@aws-cdk/aws-s3:createDefaultLoggingPolicy": true, + "@aws-cdk/aws-sns-subscriptions:restrictSqsDescryption": true, + "@aws-cdk/aws-apigateway:disableCloudWatchRole": true, + "@aws-cdk/core:enablePartitionLiterals": true, + "@aws-cdk/aws-events:eventsTargetQueueSameAccount": true, + "@aws-cdk/aws-iam:standardizedServicePrincipals": true, + "@aws-cdk/aws-ecs:disableExplicitDeploymentControllerForCircuitBreaker": true, + "@aws-cdk/aws-iam:importedRoleStackSafeDefaultPolicyName": true, + "@aws-cdk/aws-s3:serverAccessLogsUseBucketPolicy": true, + "@aws-cdk/aws-route53-patters:useCertificate": true, + "@aws-cdk/customresources:installLatestAwsSdkDefault": false, + "@aws-cdk/aws-rds:databaseProxyUniqueResourceName": true, + "@aws-cdk/aws-codedeploy:removeAlarmsFromDeploymentGroup": true, + "@aws-cdk/aws-apigateway:authorizerChangeDeploymentLogicalId": true, + "@aws-cdk/aws-ec2:launchTemplateDefaultUserData": true, + "@aws-cdk/aws-secretsmanager:useAttachedSecretResourcePolicyForSecretTargetAttachments": true, + "@aws-cdk/aws-redshift:columnId": true, + "@aws-cdk/aws-stepfunctions-tasks:enableEmrServicePolicyV2": true, + "@aws-cdk/aws-ec2:restrictDefaultSecurityGroup": true, + "@aws-cdk/aws-apigateway:requestValidatorUniqueId": true, + "@aws-cdk/aws-kms:aliasNameRef": true, + "@aws-cdk/aws-autoscaling:generateLaunchTemplateInsteadOfLaunchConfig": true, + "@aws-cdk/core:includePrefixInUniqueNameGeneration": true, + "@aws-cdk/aws-efs:denyAnonymousAccess": true, + "@aws-cdk/aws-opensearchservice:enableOpensearchMultiAzWithStandby": true, + "@aws-cdk/aws-lambda-nodejs:useLatestRuntimeVersion": true, + "@aws-cdk/aws-efs:mountTargetOrderInsensitiveLogicalId": true, + "@aws-cdk/aws-rds:auroraClusterChangeScopeOfInstanceParameterGroupWithEachParameters": true, + "@aws-cdk/aws-appsync:useArnForSourceApiAssociationIdentifier": true, + "@aws-cdk/aws-rds:preventRenderingDeprecatedCredentials": true, + "@aws-cdk/aws-codepipeline-actions:useNewDefaultBranchForCodeCommitSource": true + } +} diff --git a/kendra-bedrock-cdk-python/example-pattern.json b/kendra-bedrock-cdk-python/example-pattern.json new file mode 100644 index 000000000..194875a84 --- /dev/null +++ b/kendra-bedrock-cdk-python/example-pattern.json @@ -0,0 +1,57 @@ +{ + "title": "Lambda to Kendra to Bedrock", + "description": "AWS Lambda function to retrieve documents from an Amazon Kendra index and pass it to Amazon Bedrock for a generated response.", + "language": "Python", + "level": "200", + "framework": "CDK", + "introBox": { + "headline": "How it works", + "text": [ + "AWS Lambda: Two AWS Lambda functions are created. DataSourceSync Lambda function crawls and indexes the content. InvokeBedrockLambda AWS Lambda function that invokes the specified model by passing the retrieved content from Amazon Kendra as context to the generative AI model.", + "Amazon Kendra: An Amazon Kendra index is created with a S3 data source. When a the InvokeBedrockLambda function is called, documents are retrieved from the Amazon Kendra index.", + "Amazon Bedrock: Documents retrieved from the Amazon Kendra index are sent to Amazon Bedrock which responds with a generated response." + ] + }, + "gitHub": { + "template": { + "repoURL": "https://github.com/aws-samples/serverless-patterns/tree/main/kendra-bedrock-cdk-python", + "templateURL": "serverless-patterns/kendra-bedrock-cdk-python", + "projectFolder": "kendra-bedrock-cdk-python", + "templateFile": "app.py" + } + }, + "resources": { + "bullets": [ + { + "text": "Amazon Kendra - Enterprise Search Engine", + "link": "https://aws.amazon.com/kendra/" + }, + { + "text": "Amazon Bedrock - Generative AI", + "link": "https://aws.amazon.com/bedrock/" + } + ] + }, + "deploy": { + "text": [ + "cdk deploy BedrockKendraStack --parameters S3DSBucketName=${YourS3BucketName}" + ] + }, + "testing": { + "text": [ + "See the GitHub repo for detailed testing instructions." + ] + }, + "cleanup": { + "text": [ + "Delete the stack: cdk destroy." + ] + }, + "authors": [ + { + "name": "Kruthi Jayasimha Rao", + "bio": "Kruthi is a Partner Solutions Architect specializing in AI and ML. She provides technical guidance to AWS Partners in following best practices to build secure, resilient, and highly available solutions in the AWS Cloud.", + "linkedin": "https://www.linkedin.com/in/kruthi-jayasimha-rao-132a78167" + } + ] +} \ No newline at end of file diff --git a/kendra-bedrock-cdk-python/images/architecture.png b/kendra-bedrock-cdk-python/images/architecture.png new file mode 100644 index 000000000..ca866a6a1 Binary files /dev/null and b/kendra-bedrock-cdk-python/images/architecture.png differ diff --git a/kendra-bedrock-cdk-python/kendra-bedrock-cdk-python.json b/kendra-bedrock-cdk-python/kendra-bedrock-cdk-python.json new file mode 100644 index 000000000..ed9a57e5b --- /dev/null +++ b/kendra-bedrock-cdk-python/kendra-bedrock-cdk-python.json @@ -0,0 +1,83 @@ +{ + "title": "Lambda to Kendra to Bedrock", + "description": "AWS Lambda function to retrieve documents from an Amazon Kendra index and pass it to Amazon Bedrock for a generated response.", + "language": "Python", + "level": "200", + "framework": "CDK", + "introBox": { + "headline": "How it works", + "text": [ + "AWS Lambda: Two AWS Lambda functions are created. DataSourceSync Lambda function crawls and indexes the content. InvokeBedrockLambda AWS Lambda function that invokes the specified model by passing the retrieved content from Amazon Kendra as context to the generative AI model.", + "Amazon Kendra: An Amazon Kendra index is created with a S3 data source. When a the InvokeBedrockLambda function is called, documents are retrieved from the Amazon Kendra index.", + "Amazon Bedrock: Documents retrieved from the Amazon Kendra index are sent to Amazon Bedrock which responds with a generated response." + ] + }, + "gitHub": { + "template": { + "repoURL": "https://github.com/aws-samples/serverless-patterns/tree/main/kendra-bedrock-cdk-python", + "templateURL": "serverless-patterns/kendra-bedrock-cdk-python", + "projectFolder": "kendra-bedrock-cdk-python", + "templateFile": "app.py" + } + }, + "resources": { + "bullets": [ + { + "text": "Amazon Kendra - Enterprise Search Engine", + "link": "https://aws.amazon.com/kendra/" + }, + { + "text": "Amazon Bedrock - Generative AI", + "link": "https://aws.amazon.com/bedrock/" + } + ] + }, + "deploy": { + "text": [ + "cdk deploy BedrockKendraStack --parameters S3DSBucketName=${YourS3BucketName}" + ] + }, + "testing": { + "text": ["See the GitHub repo for detailed testing instructions."] + }, + "cleanup": { + "text": ["Delete the stack: cdk destroy."] + }, + "authors": [ + { + "name": "Kruthi Jayasimha Rao", + "bio": "Kruthi is a Partner Solutions Architect specializing in AI and ML. She provides technical guidance to AWS Partners in following best practices to build secure, resilient, and highly available solutions in the AWS Cloud.", + "linkedin": "kruthi-jayasimha-rao-132a78167" + } + ], + "patternArch": { + "icon1": { + "x": 20, + "y": 50, + "service": "lambda", + "label": "AWS Lambda" + }, + "icon2": { + "x": 50, + "y": 50, + "service": "kendra", + "label": "Amazon Kendra" + }, + "icon3": { + "x": 80, + "y": 50, + "service": "bedrock", + "label": "Amazon Bedrock" + }, + "line1": { + "from": "icon1", + "to": "icon2", + "label": "" + }, + "line2": { + "from": "icon2", + "to": "icon3", + "label": "" + } + } +} diff --git a/kendra-bedrock-cdk-python/requirements.txt b/kendra-bedrock-cdk-python/requirements.txt new file mode 100644 index 000000000..0b75fe75d --- /dev/null +++ b/kendra-bedrock-cdk-python/requirements.txt @@ -0,0 +1,2 @@ +aws-cdk-lib==2.110.0 +constructs>=10.0.0,<11.0.0 diff --git a/kendra-bedrock-cdk-python/src/dataSourceSync/dataSourceSyncLambda.py b/kendra-bedrock-cdk-python/src/dataSourceSync/dataSourceSyncLambda.py new file mode 100644 index 000000000..cd7183f5d --- /dev/null +++ b/kendra-bedrock-cdk-python/src/dataSourceSync/dataSourceSyncLambda.py @@ -0,0 +1,26 @@ + +# Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. +# SPDX-License-Identifier: MIT-0 + +import json +import logging +import boto3 +import os + +logger = logging.getLogger() +logger.setLevel(logging.INFO) + +INDEX_ID = os.environ['INDEX_ID'] +DS_ID = os.environ['DS_ID'] +AWS_REGION = os.environ['AWS_REGION'] +KENDRA = boto3.client('kendra') + +def start_data_source_sync(dsId, indexId): + logger.info(f"start_data_source_sync(dsId={dsId}, indexId={indexId})") + resp = KENDRA.start_data_source_sync_job(Id=dsId, IndexId=indexId) + logger.info(f"response:" + json.dumps(resp)) + +def lambda_handler(event, context): + logger.info("Received event: %s" % json.dumps(event)) + start_data_source_sync(DS_ID, INDEX_ID) + return diff --git a/kendra-bedrock-cdk-python/src/invokeBedrockLambda/invokeBedrockLambda.py b/kendra-bedrock-cdk-python/src/invokeBedrockLambda/invokeBedrockLambda.py new file mode 100644 index 000000000..d06757360 --- /dev/null +++ b/kendra-bedrock-cdk-python/src/invokeBedrockLambda/invokeBedrockLambda.py @@ -0,0 +1,56 @@ +import os +import boto3 +import json +# retrieves kendra index id +kendra_index_id = os.environ['INDEX_ID'] +region = os.environ['AWS_REGION'] +model_id = os.environ['MODEL_ID'] +def kendra_retrieve_document(question): + """ + This function takes in the question from the user, and retrieves relevant passages based on default PageSize of 10. + :param question: The question the user is asking. + :return: Returns the context to be sent to the LLM and document URIs to be returned as relevant data sources. + """ + kendra_client = boto3.client('kendra') + documents = kendra_client.retrieve(IndexId=kendra_index_id, QueryText=question) + text = "" + uris = set() + if len(documents['ResultItems']) > 0: + for i in range(len(documents['ResultItems'])): + text += documents['ResultItems'][i]['Content'] + "\n" + uris.add(documents['ResultItems'][i]['DocumentURI']) + return (text, uris) +def invokeLLM(question, context): + """ + This function takes in the question from the user, along with the Kendra responses as context to generate an answer + for the user on the frontend. + :param question: The question the user is asking . + :param context: The context to be sent to the LLM to generate a better + answer. + :return: Returns the final answer that will be provided to the end-user of the application who asked the original + question. + """ + # Setup Bedrock client + bedrock = boto3.client('bedrock-runtime') + # body of data with parameters that is passed into the bedrock invoke model request + body = json.dumps({"max_tokens": 350, + "system": "You are a truthful AI assistant. Your goal is to provide informative and substantive responses to queries based on the documents provided. If you do not know the answer to a question, you truthfully say you do not know.", + "messages": [{"role": "user", "content": "Answer this user query:" + question + "with the following context:" + context}], + "anthropic_version": "bedrock-2023-05-31", + "temperature":0, + "top_k":250, + "top_p":0.999}) + # Invoking the bedrock model + response = bedrock.invoke_model(body=body, + modelId=model_id) + response_body = json.loads(response.get('body').read()) + answer = response_body.get('content') + # returning the answer as a final result, which ultimately gets returned to the end user + return answer + +def lambda_handler(event, context): + question = event['question'] + context = kendra_retrieve_document(question) + llm_response = invokeLLM(question, context[0]) + answer = llm_response[0]['text'] +"\n" + "*Relevant links:* " + "\n" + "\n".join(context[1]) + return answer \ No newline at end of file