From cc1f5bccb79924fa23e5b2149f0a9844c89dbba1 Mon Sep 17 00:00:00 2001 From: dinsajwa Date: Mon, 27 Jan 2025 11:11:29 -0500 Subject: [PATCH 1/9] feat(bedorck): rfc for bedrockL2 construct --- text/0686-bedrock-l2-construct.md | 1169 +++++++++++++++++++++++++++++ 1 file changed, 1169 insertions(+) create mode 100644 text/0686-bedrock-l2-construct.md diff --git a/text/0686-bedrock-l2-construct.md b/text/0686-bedrock-l2-construct.md new file mode 100644 index 000000000..23d453fd7 --- /dev/null +++ b/text/0686-bedrock-l2-construct.md @@ -0,0 +1,1169 @@ +# Bedrock L2 Construct + +* **Original Author(s):**: @dineshSajwan +* **Tracking Issue**: #686 +* **API Bar Raiser**: @{BAR_RAISER_USER} + + +The Bedrock L2 construct simplifies the creation of multiple Bedrock features by providing a wrapper over the Bedrock L1 construct. It exposes functions that enable users to create features with minimal code. Key features include Bedrock Agent, Knowledge Base, Guardrails, Inference Profiles, and Prompt. + + +**CHANGELOG**: +```feat(bedrock): bedrock L2 construct``` + +**README**: +[Amazon Bedrock](https://aws.amazon.com/bedrock/) is a fully managed service that offers a choice of high-performing foundation models (FMs) from leading AI companies and Amazon through a single API, along with a broad set of capabilities you need to build generative AI applications with security, privacy, and responsible AI. + +This construct library facilitates the deployment of Knowledge Bases, Bedrock Agents, Guardrails, Prompt Management, and Inference Pipelines. It leverages underlying CloudFormation L1 resources to provision these Bedrock features. + +For more details please refer here [Amazon Bedrock README](https://github.com/awslabs/generative-ai-cdk-constructs/blob/main/src/cdk-lib/bedrock/README.md). + + +## Knowledge Base + +Amazon Bedrock Knowledge Bases enable you to provide foundation models and agents with contextual information from your company’s private data sources. This enhances the relevance, accuracy, and customization of their responses. + +### Create a Knowledge Base + +A vector index on a vector store is required to create a Knowledge Base. This construct currently supports [Amazon OpenSearch Serverless](../opensearchserverless), [Amazon RDS Aurora PostgreSQL](../amazonaurora/), [Pinecone](../pinecone/) . By default, this resource will create an OpenSearch Serverless vector collection and index for each Knowledge Base you create, but you can provide an existing collection and/or index to have more control. For other resources you need to have the vector stores already created and credentials stored in AWS Secrets Manager. For Aurora, the construct provides an option to create a default `AmazonAuroraDefaultVectorStore` construct that will provision the vector store backed by Amazon Aurora for you. To learn more you can read [here](../amazonaurora/README.md). + +The resource accepts an `instruction` prop that is provided to any Bedrock Agent it is associated with so the agent can decide when to query the Knowledge Base. + +Amazon Bedrock Knowledge Bases currently only supports S3 as a data source. The `S3DataSource` resource is used to configure how the Knowledge Base handles the data source. + +Example of `OpenSearch Serverless`: + +```ts +import * as s3 from 'aws-cdk-lib/aws-s3'; +import { bedrock } from '@cdklabs/generative-ai-cdk-constructs'; + +const kb = new bedrock.KnowledgeBase(this, 'KnowledgeBase', { + embeddingsModel: bedrock.BedrockFoundationModel.TITAN_EMBED_TEXT_V1, + instruction: 'Use this knowledge base to answer questions about books. ' + 'It contains the full text of novels.', +}); + +const docBucket = new s3.Bucket(this, 'DocBucket'); + +new bedrock.S3DataSource(this, 'DataSource', { + bucket: docBucket, + knowledgeBase: kb, + dataSourceName: 'books', + chunkingStrategy: bedrock.ChunkingStrategy.fixedSize({ + maxTokens: 500, + overlapPercentage: 20, + }), +}); +``` + +Example of `Amazon RDS Aurora PostgreSQL`: + + + +```ts +import * as s3 from 'aws-cdk-lib/aws-s3'; +import { amazonaurora, bedrock } from '@cdklabs/generative-ai-cdk-constructs'; + +// Dimension of your vector embedding +embeddingsModelVectorDimension = 1024; +const auroraDb = new amazonaurora.AmazonAuroraVectorStore(stack, 'AuroraDefaultVectorStore', { + embeddingsModelVectorDimension: embeddingsModelVectorDimension, +}); + +const kb = new bedrock.KnowledgeBase(this, 'KnowledgeBase', { + vectorStore: auroraDb, + embeddingsModelVectorDimension: embeddingsModelVectorDimension, + instruction: 'Use this knowledge base to answer questions about books. ' + 'It contains the full text of novels.', +}); + +const docBucket = new s3.Bucket(this, 'DocBucket'); + +new bedrock.S3DataSource(this, 'DataSource', { + bucket: docBucket, + knowledgeBase: kb, + dataSourceName: 'books', + chunkingStrategy: bedrock.ChunkingStrategy.FIXED_SIZE, +}); +``` + + +Example of importing existing `Amazon RDS Aurora PostgreSQL` using `fromExistingAuroraVectorStore()` method. +**Note** - you need to provide `clusterIdentifier`, `databaseName`, `vpc`, `secret` and `auroraSecurityGroupId` used in deployment of your existing RDS Amazon Aurora DB, as well as `embeddingsModel` that you want to be used by a Knowledge Base for chunking: + + +```ts +import * as s3 from "aws-cdk-lib/aws-s3"; +import { amazonaurora, bedrock } from '@cdklabs/generative-ai-cdk-constructs'; + +const auroraDb = aurora.AmazonAuroraVectorStore.fromExistingAuroraVectorStore(stack, 'ExistingAuroraVectorStore', { + clusterIdentifier: 'aurora-serverless-vector-cluster', + databaseName: 'bedrock_vector_db', + schemaName: 'bedrock_integration', + tableName: 'bedrock_kb', + vectorField: 'embedding', + textField: 'chunks', + metadataField: 'metadata', + primaryKeyField: 'id', + embeddingsModel: bedrock.BedrockFoundationModel.COHERE_EMBED_ENGLISH_V3, + vpc: cdk.aws_ec2.Vpc.fromLookup(stack, 'VPC', { + vpcId: 'vpc-0c1a234567ee8bc90', + }), + auroraSecurityGroupId: 'sg-012ef345678c98a76',, + secret: cdk.aws_rds.DatabaseSecret.fromSecretCompleteArn( + stack, + 'Secret', + cdk.Stack.of(stack).formatArn({ + service: 'secretsmanager', + resource: 'secret', + resourceName: 'rds-db-credentials/cluster-1234567890', + region: cdk.Stack.of(stack).region, + account: cdk.Stack.of(stack).account, + arnFormat: cdk.ArnFormat.COLON_RESOURCE_NAME, + }), + ), +}); + +const kb = new bedrock.KnowledgeBase(this, "KnowledgeBase", { + vectorStore: auroraDb, + embeddingsModel: bedrock.BedrockFoundationModel.COHERE_EMBED_ENGLISH_V3, + instruction: + "Use this knowledge base to answer questions about books. " + + "It contains the full text of novels.", +}); + +const docBucket = new s3.Bucket(this, "DocBucket"); + +new bedrock.S3DataSource(this, "DataSource", { + bucket: docBucket, + knowledgeBase: kb, + dataSourceName: "books", + chunkingStrategy: bedrock.ChunkingStrategy.FIXED_SIZE, +}); +``` + +Example of `Pinecone` (manual, you must have Pinecone vector store created): + + +```ts +import * as s3 from 'aws-cdk-lib/aws-s3'; +import { pinecone, bedrock } from '@cdklabs/generative-ai-cdk-constructs'; + +const pineconeds = new pinecone.PineconeVectorStore({ + connectionString: 'https://your-index-1234567.svc.gcp-starter.pinecone.io', + credentialsSecretArn: 'arn:aws:secretsmanager:your-region:123456789876:secret:your-key-name', + textField: 'question', + metadataField: 'metadata', +}); + +const kb = new bedrock.KnowledgeBase(this, 'KnowledgeBase', { + vectorStore: pineconeds, + embeddingsModel: bedrock.BedrockFoundationModel.TITAN_EMBED_TEXT_V1, + instruction: 'Use this knowledge base to answer questions about books. ' + 'It contains the full text of novels.', +}); + +const docBucket = new s3.Bucket(this, 'DocBucket'); + +new bedrock.S3DataSource(this, 'DataSource', { + bucket: docBucket, + knowledgeBase: kb, + dataSourceName: 'books', + chunkingStrategy: bedrock.ChunkingStrategy.FIXED_SIZE, +}); +``` + + +#### Knowledge Base - Data Sources + +Data sources are the various repositories or systems from which information is extracted and ingested into the +knowledge base. These sources provide the raw content that will be processed, indexed, and made available for +querying within the knowledge base system. Data sources can include various types of systems such as document +management systems, databases, file storage systems, and content management platforms. Suuported Data Sources +include Amazon S3 buckets, Web Crawlers, SharePoint sites, Salesforce instances, and Confluence spaces. + +- **Amazon S3**. You can either create a new data source using the `bedrock.S3DataSource(..)` class, or using the + `kb.addS3DataSource(..)`. +- **Web Crawler**. You can either create a new data source using the `bedrock.WebCrawlerDataSource(..)` class, or using the + `kb.addWebCrawlerDataSource(..)`. +- **Confluence**. You can either create a new data source using the `bedrock.ConfluenceDataSource(..)` class, or using the + `kb.addConfluenceDataSource(..)`. +- **SharePoint**. You can either create a new data source using the `bedrock.SharePointDataSource(..)` class, or using the + `kb.addSharePointDataSource(..)`. +- **Salesforce**. You can either create a new data source using the `bedrock.SalesforceDataSource(..)` class, or using the + `kb.addSalesforceDataSource(..)`. + + +```ts +const app = new cdk.App(); +const stack = new cdk.Stack(app, 'aws-cdk-bedrock-data-sources-integ-test'); + +const kb = new KnowledgeBase(stack, 'MyKnowledgeBase', { + name: 'MyKnowledgeBase', + embeddingsModel: BedrockFoundationModel.COHERE_EMBED_MULTILINGUAL_V3, +}); + +const bucket = new Bucket(stack, 'Bucket', {}); +const lambdaFunction = new Function(stack, 'MyFunction', { + runtime: cdk.aws_lambda.Runtime.PYTHON_3_9, + handler: 'index.handler', + code: cdk.aws_lambda.Code.fromInline('print("Hello, World!")'), +}); + +const secret = new Secret(stack, 'Secret'); +const key = new Key(stack, 'Key'); + +kb.addWebCrawlerDataSource({ + sourceUrls: ['https://docs.aws.amazon.com/'], + chunkingStrategy: ChunkingStrategy.HIERARCHICAL_COHERE, + customTransformation: CustomTransformation.lambda({ + lambdaFunction: lambdaFunction, + s3BucketUri: `s3://${bucket.bucketName}/chunk-processor/`, + }), +}); + +kb.addS3DataSource({ + bucket, + chunkingStrategy: ChunkingStrategy.SEMANTIC, + parsingStrategy: ParsingStategy.foundationModel({ + model: BedrockFoundationModel.ANTHROPIC_CLAUDE_SONNET_V1_0, + }), +}); + +kb.addConfluenceDataSource({ + dataSourceName: 'TestDataSource', + authSecret: secret, + kmsKey: key, + confluenceUrl: 'https://example.atlassian.net', + filters: [ + { + objectType: ConfluenceObjectType.ATTACHMENT, + includePatterns: ['.*\\.pdf'], + excludePatterns: ['.*private.*\\.pdf'], + }, + { + objectType: ConfluenceObjectType.PAGE, + includePatterns: ['.*public.*\\.pdf'], + excludePatterns: ['.*confidential.*\\.pdf'], + }, + ], +}); + +kb.addSalesforceDataSource({ + authSecret: secret, + endpoint: 'https://your-instance.my.salesforce.com', + kmsKey: key, + filters: [ + { + objectType: SalesforceObjectType.ATTACHMENT, + includePatterns: ['.*\\.pdf'], + excludePatterns: ['.*private.*\\.pdf'], + }, + { + objectType: SalesforceObjectType.CONTRACT, + includePatterns: ['.*public.*\\.pdf'], + excludePatterns: ['.*confidential.*\\.pdf'], + }, + ], +}); + +kb.addSharePointDataSource({ + dataSourceName: 'SharepointDataSource', + authSecret: secret, + kmsKey: key, + domain: 'yourdomain', + siteUrls: ['https://yourdomain.sharepoint.com/sites/mysite'], + tenantId: '888d0b57-69f1-4fb8-957f-e1f0bedf64de', + filters: [ + { + objectType: SharePointObjectType.PAGE, + includePatterns: ['.*\\.pdf'], + excludePatterns: ['.*private.*\\.pdf'], + }, + { + objectType: SharePointObjectType.FILE, + includePatterns: ['.*public.*\\.pdf'], + excludePatterns: ['.*confidential.*\\.pdf'], + }, + ], +}); +``` + +#### Knowledge Base - Chunking Strategies + +- **Default Chunking**: Applies Fixed Chunking with the default chunk size of 300 tokens and 20% overlap. + + + ```ts + ChunkingStrategy.DEFAULT; + ``` + +- **Fixed Size Chunking**: This method divides the data into fixed-size chunks, with each chunk + containing a predetermined number of tokens. This strategy is useful when the data is uniform + in size and structure. + Typescript + + + ```ts + // Fixed Size Chunking with sane defaults. + ChunkingStrategy.FIXED_SIZE; + + // Fixed Size Chunking with custom values. + ChunkingStrategy.fixedSize({ maxTokens: 200, overlapPercentage: 25 }); + ``` + +- **Hierarchical Chunking**: This strategy organizes data into layers of chunks, with the first + layer containing large chunks and the second layer containing smaller chunks derived from the first. + It is ideal for data with inherent hierarchies or nested structures. + + + ```ts + // Hierarchical Chunking with the default for Cohere Models. + ChunkingStrategy.HIERARCHICAL_COHERE; + + // Hierarchical Chunking with the default for Titan Models. + ChunkingStrategy.HIERARCHICAL_TITAN; + + // Hierarchical Chunking with custom values. Tthe maximum chunk size depends on the model. + // Amazon Titan Text Embeddings: 8192. Cohere Embed models: 512 + ChunkingStrategy.hierarchical({ + overlapTokens: 60, + maxParentTokenSize: 1500, + maxChildTokenSize: 300, + }); + ``` + +- **Semantic Chunking**: This method splits data into smaller documents based on groups of similar + content derived from the text using natural language processing. It helps preserve contextual + relationships and ensures accurate and contextually appropriate results. + + + ```ts + // Semantic Chunking with sane defaults. + ChunkingStrategy.SEMANTIC; + + // Semantic Chunking with custom values. + ChunkingStrategy.semantic({ bufferSize: 0, breakpointPercentileThreshold: 95, maxTokens: 300 }); + ``` + +- **No Chunking**: This strategy treats each file as one chunk. If you choose this option, + you may want to pre-process your documents by splitting them into separate files. + + + ```ts + ChunkingStrategy.NONE; + ``` + +#### Knowledge Base - Parsing Strategy + +A parsing strategy in Amazon Bedrock is a configuration that determines how the service +processes and interprets the contents of a document. It involves converting the document's +contents into text and splitting it into smaller chunks for analysis. Amazon Bedrock offers +two parsing strategies: + +- **Default Parsing Strategy**: This strategy converts the document's contents into text + and splits it into chunks using a predefined approach. It is suitable for most use cases + but may not be optimal for specific document types or requirements. + +- **Foundation Model Parsing Strategy**: This strategy uses a foundation model to describe + the contents of the document. It is particularly useful for improved processing of PDF files + with tables and images. To use this strategy, set the `parsingStrategy` in a data source as below. + + + ```ts + bedrock.ParsingStategy.foundationModel({ + model: BedrockFoundationModel.ANTHROPIC_CLAUDE_SONNET_V1_0, + }); + ``` + +#### Knowledge Base - Custom Transformation + +Custom Transformation in Amazon Bedrock is a feature that allows you to create and apply +custom processing steps to documents moving through a data source ingestion pipeline. + +Custom Transformation uses AWS Lambda functions to process documents, enabling you to +perform custom operations such as data extraction, normalization, or enrichment. To +create a custom transformation, set the `customTransformation` in a data source as below. + + +```ts +CustomTransformation.lambda({ +lambdaFunction: lambdaFunction, +s3BucketUri: `s3://${bucket.bucketName}/chunk-processor/`, +}), +``` + +## Agents + +Amazon Bedrock Agents allow generative AI applications to automate complex, multistep tasks by seamlessly integrating with your company’s systems, APIs, and data sources. + +### Create an Agent + +The following example creates an Agent with a simple instruction and default prompts that consults a Knowledge Base. + + +```ts +const agent = new bedrock.Agent(this, 'Agent', { + foundationModel: bedrock.BedrockFoundationModel.ANTHROPIC_CLAUDE_HAIKU_V1_0, + instruction: 'You are a helpful and friendly agent that answers questions about literature.', +}); + +agent.addKnowledgeBase(kb); +``` + +You can also use system defined inference profiles to enable cross region inference requests for supported models. For instance: + + +```ts +const cris = bedrock.CrossRegionInferenceProfile.fromConfig({ + geoRegion: bedrock.CrossRegionInferenceProfileRegion.US, + model: bedrock.BedrockFoundationModel.ANTHROPIC_CLAUDE_3_5_SONNET_V1_0, +}); + +const agent = new bedrock.Agent(this, 'Agent', { + foundationModel: cris, + instruction: 'You are a helpful and friendly agent that answers questions about agriculture.', +}); +``` + +For more information on cross region inference, please refer to [System defined inference profiles](#system-defined-inference-profiles) + +### Action Groups + +An action group defines functions your agent can call. The functions are Lambda functions. The action group uses an OpenAPI schema to tell the agent what your functions do and how to call them. + +```ts +const actionGroupFunction = new lambda_python.PythonFunction(this, 'ActionGroupFunction', { + runtime: lambda.Runtime.PYTHON_3_12, + entry: path.join(__dirname, '../lambda/action-group'), +}); + +const actionGroup = new AgentActionGroup({ + name: 'query-library', + description: 'Use these functions to get information about the books in the library.', + executor: bedrock.ActionGroupExecutor.fromlambdaFunction(actionGroupFunction), + enabled: true, + apiSchema: bedrock.ApiSchema.fromLocalAsset(path.join(__dirname, 'action-group.yaml')), +}); + +agent.addActionGroup(actionGroup); +``` + +### Prepare the Agent + +The `Agent` constructs take an optional parameter `shouldPrepareAgent` to indicate that the Agent should be prepared after any updates to an agent, Knowledge Base association, or action group. This may increase the time to create and update those resources. By default, this value is false . + +Creating an agent alias will not prepare the agent, so if you create an alias with `addAlias` or by providing an `aliasName` when creating the agent then you should set `shouldPrepareAgent` to **_true_**. + +#### Prompt Overrides + +Bedrock Agents allows you to customize the prompts and LLM configuration for its different steps. You can disable steps or create a new prompt template. Prompt templates can be inserted from plain text files. + + +```ts +import { readFileSync } from 'fs'; + +const file = readFileSync(prompt_path, 'utf-8'); + +const agent = new bedrock.Agent(this, 'Agent', { + foundationModel: bedrock.BedrockFoundationModel.AMAZON_NOVA_LITE_V1, + instruction: 'You are a helpful and friendly agent that answers questions about literature.', + userInputEnabled: true, + codeInterpreterEnabled: false, + shouldPrepareAgent:true, + promptOverrideConfiguration: bedrock.PromptOverrideConfiguration.fromSteps( + [ + { + stepType: bedrock.AgentStepType.PRE_PROCESSING, + stepEnabled: true, + customPromptTemplate: file, + inferenceConfig: { + temperature: 0.0, + topP: 1, + topK: 250, + maximumLength: 1, + stopSequences: ["\n\nHuman:"], + }, + } + ] + ) + }); +``` + +### Agent Alias + +After you have sufficiently iterated on your working draft and are satisfied with the behavior of your agent, you can set it up for deployment and integration into your application by creating aliases of your agent. + +To deploy your agent, you need to create an alias. During alias creation, Amazon Bedrock automatically creates a version of your agent. The alias points to this newly created version. You can point the alias to a previously created version if necessary. You then configure your application to make API calls to that alias. + +By default, the `Agent` resource does not create any aliases, and you can use the 'DRAFT' version. + +#### Specific version + +You can use the `AgentAlias` resource if you want to create an Alias for an existing Agent. + + +```ts +const agentAlias2 = new bedrock.AgentAlias(this, 'myalias2', { + aliasName: 'myalias', + agent: agent, + agentVersion: '1', // optional + description: 'mytest' +}); +``` + +## Bedrock Guardrails + +Amazon Bedrock's Guardrails feature enables you to implement robust governance and control mechanisms for your generative AI applications, ensuring alignment with your specific use cases and responsible AI policies. Guardrails empowers you to create multiple tailored policy configurations, each designed to address the unique requirements and constraints of different use cases. These policy configurations can then be seamlessly applied across multiple foundation models (FMs) and Agents, ensuring a consistent user experience and standardizing safety, security, and privacy controls throughout your generative AI ecosystem. + +With Guardrails, you can define and enforce granular, customizable policies to precisely govern the behavior of your generative AI applications. You can configure the following policies in a guardrail to avoid undesirable and harmful content and remove sensitive information for privacy protection. + +Content filters – Adjust filter strengths to block input prompts or model responses containing harmful content. + +Denied topics – Define a set of topics that are undesirable in the context of your application. These topics will be blocked if detected in user queries or model responses. + +Word filters – Configure filters to block undesirable words, phrases, and profanity. Such words can include offensive terms, competitor names etc. + +Sensitive information filters – Block or mask sensitive information such as personally identifiable information (PII) or custom regex in user inputs and model responses. + +You can create a Guardrail with a minimum blockedInputMessaging ,blockedOutputsMessaging and default content filter policy. + + +```ts +const guardrails = new bedrock.Guardrail(this, 'bedrockGuardrails', { + name: 'my-BedrockGuardrails', + description: 'Legal ethical guardrails.', +}); + +// Optional - Add Sensitive information filters + +guardrail.addPIIFilter({ + type: PIIType.General.ADDRESS, + action: GuardrailAction.ANONYMIZE, +}); + +guardrail.addRegexFilter({ + name: 'TestRegexFilter', + description: 'This is a test regex filter', + pattern: '/^[A-Z]{2}d{6}$/', + action: bedrock.GuardrailAction.ANONYMIZE, +}); + +// Optional - Add contextual grounding + +guardrail.addContextualGroundingFilter({ + type: ContextualGroundingFilterType.GROUNDING, + threshold: 0.95, +}); + +guardrail.addContextualGroundingFilter({ + type: ContextualGroundingFilterType.RELEVANCE, + threshold: 0.95, +}); + +// Optional - Add Denied topics . You can use a Topic or create your custom Topic + +guardrail.addDeniedTopicFilter(Topic.FINANCIAL_ADVICE); +guardrail.addDeniedTopicFilter( + Topic.custom({ + name: 'Legal_Advice', + definition: + 'Offering guidance or suggestions on legal matters, legal actions, interpretation of laws, or legal rights and responsibilities.', + examples: [ + 'Can I sue someone for this?', + 'What are my legal rights in this situation?', + 'Is this action against the law?', + 'What should I do to file a legal complaint?', + 'Can you explain this law to me?', + ], + }) +); + +// Optional - Add Word filters. You can upload words from a file with addWordFilterFromFile function. +guardrail.addWordFilter('drugs'); +guardrail.addManagedWordListFilter(ManagedWordFilterType.PROFANITY); +guardrails.addWordFilterFromFile('./scripts/wordsPolicy.csv'); + +// versioning - if you change any guardrail configuration, a new version will be created +guardrails.createVersion('testversion'); + +// Importing existing guardrail +const importedGuardrail = bedrock.Guardrail.fromGuardrailAttributes(stack, 'TestGuardrail', { + guardrailArn: 'arn:aws:bedrock:us-east-1:123456789012:guardrail/oygh3o8g7rtl', + guardrailVersion: '1', //optional + kmsKey: kmsKey, //optional +}); + +// Importing Guardrails created through the L1 CDK CfnGuardrail construct +const cfnGuardrail = new CfnGuardrail(this, 'MyCfnGuardrail', { + blockedInputMessaging: 'blockedInputMessaging', + blockedOutputsMessaging: 'blockedOutputsMessaging', + name: 'namemycfnguardrails', + wordPolicyConfig: { + wordsConfig: [ + { + text: 'drugs', + }, + ], + }, +}); + +const importedGuardrail = bedrock.Guardrail.fromCfnGuardrail(cfnGuardrail); +``` + +Python + +```python + guardrail = bedrock.Guardrail(self, 'myGuardrails', + name='my-BedrockGuardrails', + description= "Legal ethical guardrails.") + + # Optional - Add Sensitive information filters + + guardrail.add_pii_filter( + type= bedrock.pii_type.General.ADDRESS, + action= bedrock.GuardrailAction.ANONYMIZE, + ) + + guardrail.add_regex_filter( + name= "TestRegexFilter", + description= "This is a test regex filter", + pattern= "/^[A-Z]{2}d{6}$/", + action= bedrock.GuardrailAction.ANONYMIZE, + ) + + # Optional - Add contextual grounding + + guardrail.add_contextual_grounding_filter( + type= bedrock.ContextualGroundingFilterType.GROUNDING, + threshold= 0.95, + ) + + # Optional - Add Denied topics . You can use default Topic or create your custom Topic with createTopic function. The default Topics can also be overwritten. + + guardrail.add_contextual_grounding_filter( + type= bedrock.ContextualGroundingFilterType.RELEVANCE, + threshold= 0.95, + ) + + guardrail.add_denied_topic_filter(bedrock.Topic.FINANCIAL_ADVICE) + + guardrail.add_denied_topic_filter( + bedrock.Topic.custom( + name= "Legal_Advice", + definition= + "Offering guidance or suggestions on legal matters, legal actions, interpretation of laws, or legal rights and responsibilities.", + examples= [ + "Can I sue someone for this?", + "What are my legal rights in this situation?", + "Is this action against the law?", + "What should I do to file a legal complaint?", + "Can you explain this law to me?", + ] + ) + ) + + # Optional - Add Word filters. You can upload words from a file with addWordFilterFromFile function. + guardrail.add_word_filter("drugs") + guardrail.add_managed_word_list_filter(bedrock.ManagedWordFilterType.PROFANITY) + guardrail.add_word_filter_from_file("./scripts/wordsPolicy.csv") + + # versioning - if you change any guardrail configuration, a new version will be created + guardrail.create_version("testversion") + + # Importing existing guardrail + imported_guardrail = bedrock.Guardrail.from_guardrail_attributes(self, "TestGuardrail", + guardrail_arn="arn:aws:bedrock:us-east-1:123456789012:guardrail/oygh3o8g7rtl", + guardrail_version="1", + kms_key=kms_key + ) + + # Importing Guardrails created through the L1 CDK CfnGuardrail construct + cfn_guardrail = cfnbedrock.CfnGuardrail(self, "MyCfnGuardrail", + blocked_input_messaging="blockedInputMessaging", + blocked_outputs_messaging="blockedOutputsMessaging", + name="name", + + # the properties below are optional + word_policy_config=cfnbedrock.CfnGuardrail.WordPolicyConfigProperty( + words_config=[cfnbedrock.CfnGuardrail.WordConfigProperty( + text="drugs" + )] + ) + ) + + imported_guardrail = bedrock.Guardrail.from_cfn_guardrail(cfn_guardrail) + + + +``` + +## Prompt management + +Amazon Bedrock provides the ability to create and save prompts using Prompt management so that you can save +time by applying the same prompt to different workflows. You can include variables in the prompt so that you can +adjust the prompt for different use case. + +The `Prompt` resource allows you to create a new prompt. +Example of a basic Text `Prompt`: + + +```ts +const cmk = new kms.Key(this, 'cmk', {}); +const claudeModel = BedrockFoundationModel.ANTHROPIC_CLAUDE_SONNET_V1_0; + +const variant1 = PromptVariant.text({ + variantName: 'variant1', + model: claudeModel, + promptVariables: ['topic'], + promptText: 'This is my first text prompt. Please summarize our conversation on: {{topic}}.', + inferenceConfiguration: { + temperature: 1.0, + topP: 0.999, + maxTokens: 2000, + }, +}); + +const prompt1 = new Prompt(this, 'prompt1', { + promptName: 'prompt1', + description: 'my first prompt', + defaultVariant: variant1, + variants: [variant1], + encryptionKey: cmk, +}); +``` + +Example of a "Chat" `Prompt`. Use this template type when the model supports the Converse API or the Anthropic Claude Messages API. +This allows you to include a System prompt and previous User messages and Assistant messages for context. + + +```ts +const cmk = new kms.Key(this, 'cmk', {}); + +const variantChat = PromptVariant.chat({ + variantName: 'variant1', + model: BedrockFoundationModel.ANTHROPIC_CLAUDE_3_5_SONNET_V1_0, + messages: [ + ChatMessage.userMessage('From now on, you speak Japanese!'), + ChatMessage.assistantMessage('Konnichiwa!'), + ChatMessage.userMessage('From now on, you speak {{language}}!'), + ], + system: 'You are a helpful assistant that only speaks the language you`re told.', + promptVariables: ['language'], + toolConfiguration: { + toolChoice: ToolChoice.AUTO, + tools: [ + { + toolSpec: { + name: 'top_song', + description: 'Get the most popular song played on a radio station.', + inputSchema: { + json: { + type: 'object', + properties: { + sign: { + type: 'string', + description: + 'The call sign for the radio station for which you want the most popular song. Example calls signs are WZPZ and WKR.', + }, + }, + required: ['sign'], + }, + }, + }, + }, + ], + }, +}); + +new Prompt(stack, 'prompt1', { + promptName: 'prompt-chat', + description: 'my first chat prompt', + defaultVariant: variantChat, + variants: [variantChat], + kmsKey: cmk, +}); +``` + +### Prompt Variants + +Prompt variants in the context of Amazon Bedrock refer to alternative configurations of a prompt, +including its message or the model and inference configurations used. Prompt variants allow you +to create different versions of a prompt, test them, and save the variant that works best for +your use case. You can add prompt variants to a prompt by creating a `PromptVariant` object and +specify the variants on prompt creation, or by using the `.addVariant(..)` method on a `Prompt` object. + +Example of `PromptVariant`: + + +```ts +... + +const variant2 = PromptVariant.text({ + variantName: "variant2", + model: claudeModel, + promptVariables: [ "topic" ], + promptText: "This is my second text prompt. Please summarize our conversation on: {{topic}}.", + inferenceConfiguration: { + temperature: 0.5, + topP: 0.999, + maxTokens: 2000, + }, +}); + +prompt1.addVariant(variant2); +``` + +### Prompt routing + +Amazon Bedrock intelligent prompt routing provides a single serverless endpoint for efficiently routing requests between different foundational models within the same model family. +It can help you optimize for response quality and cost. They offer a comprehensive solution for managing multiple AI models through a single serverless endpoint, +simplifying the process for you. Intelligent prompt routing predicts the performance of each model for each request, and dynamically routes each request to the model +that it predicts is most likely to give the desired response at the lowest cost. +More information about prompt routing in the [documentation](https://docs.aws.amazon.com/bedrock/latest/userguide/prompt-routing.html) + + +```ts +const variant = PromptVariant.text({ + variantName: 'variant1', + promptText: 'What is the capital of France?', + model: PromptRouter.fromDefaultId(DefaultPromptRouterIdentifier.ANTHROPIC_CLAUDE_V1, region), +}); + +new Prompt(stack, 'Prompt', { + promptName: 'prompt-router-test', + variants: [variant], +}); +``` + +**Python** + +```py +variant = bedrock.PromptVariant.text( + variant_name='variant1', + prompt_text='What is the capital of France?', + model=bedrock.PromptRouter.from_default_id(bedrock.DefaultPromptRouterIdentifier.ANTHROPIC_CLAUDE_V1, region), +) + +bedrock.Prompt(self, 'Prompt', + prompt_name='prompt-router-test', + variants=[variant], +) +``` + +### Prompt Version + +A prompt version is a snapshot of a prompt at a specific point in time that you +create when you are satisfied with a set of configurations. Versions allow you to +deploy your prompt and easily switch between different configurations for your +prompt and update your application with the most appropriate version for your +use-case. + +You can create a Prompt version by using the `PromptVersion` class or by using the `.createVersion(..)` +on a `Prompt` object. It is recommended to use the `.createVersion(..)` method. It uses a hash based mechanism +to update the version whenever a certain configuration property changes. + + +```ts +new PromptVersion(prompt1, 'my first version'); +``` + +or alternatively: + +```ts +prompt1.createVersion('my first version'); +``` + +## System defined inference profiles + +You can build a CrossRegionInferenceProfile using a system defined inference profile. The inference profile will route requests to the Regions defined in the cross region (system-defined) inference profile that you choose. You can find the system defined inference profiles by navigating to your console (Amazon Bedrock -> Cross-region inference) or programmatically, for instance using [boto3](https://boto3.amazonaws.com/v1/documentation/api/latest/reference/services/bedrock/client/list_inference_profiles.html). + +Before using creating a CrossRegionInferenceProfile, ensure that you have access to the models and regions defined in the inference profiles. For instance, if you see the system defined inference profile "us.anthropic.claude-3-5-sonnet-20241022-v2:0" defined in your region, the table mentions that inference requests will be routed to US East (Virginia) us-east-1, US East (Ohio) us-east-2 and US West (Oregon) us-west-2. Thus, you need to have model access enabled in those regions for the model `anthropic.claude-3-5-sonnet-20241022-v2:0`. You can then create the CrossRegionInferenceProfile as follows: + + +```ts +const cris = bedrock.CrossRegionInferenceProfile.fromConfig({ + geoRegion: bedrock.CrossRegionInferenceProfileRegion.US, + model: bedrock.BedrockFoundationModel.ANTHROPIC_CLAUDE_3_5_SONNET_V2_0, +}); +``` + + +## Application inference profile + +You can create an application inference profile with one or more Regions to track usage and costs when invoking a model. + +To create an application inference profile for one Region, specify a foundation model. Usage and costs for requests made to that Region with that model will be tracked. + +To create an application inference profile for multiple Regions, specify a cross region (system-defined) inference profile. The inference profile will route requests to the Regions defined in the cross region (system-defined) inference profile that you choose. Usage and costs for requests made to the Regions in the inference profile will be tracked. You can find the system defined inference profiles by navigating to your console (Amazon Bedrock -> Cross-region inference) or programmatically, for instance using [boto3](https://boto3.amazonaws.com/v1/documentation/api/latest/reference/services/bedrock/client/list_inference_profiles.html): + +``` +bedrock = session.client("bedrock", region_name="us-east-1") +bedrock.list_inference_profiles(typeEquals='SYSTEM_DEFINED') +``` + +Before using application inference profiles, ensure that: + +- You have appropriate IAM permissions +- You have access to the models and regions defined in the inference profiles +- Ensure proper configuration of the required API permissions for inference profile-related actions + +Specifically the role you are assuming needs to have permissions for following actions in the IAM policy + +``` +"Action": [ + "bedrock:GetInferenceProfile", + "bedrock:ListInferenceProfiles", + "bedrock:DeleteInferenceProfile" + "bedrock:TagResource", + "bedrock:UntagResource", + "bedrock:ListTagsForResource" + ] +``` + +You can restrict to specific resources by applying "Resources" tag in the IAM policy. + +``` +"Resource": ["arn:aws:bedrock:*:*:application-inference-profile/*"] +``` + + +```ts +// Create an application inference profile for one Region +// You can use the 'bedrock.BedrockFoundationModel' or pass the arn as a string +const appInfProfile1 = new ApplicationInferenceProfile(this, 'myapplicationprofile', { + inferenceProfileName: 'claude 3 sonnet v1', + modelSource: bedrock.BedrockFoundationModel.ANTHROPIC_CLAUDE_SONNET_V1_0, + tags: [{ key: 'test', value: 'test' }], +}); + +// To create an application inference profile across regions, specify the cross region inference profile +const cris = bedrock.CrossRegionInferenceProfile.fromConfig({ + geoRegion: bedrock.CrossRegionInferenceProfileRegion.US, + model: bedrock.BedrockFoundationModel.ANTHROPIC_CLAUDE_3_5_SONNET_V2_0, +}); + +const appInfProfile2 = new ApplicationInferenceProfile(this, 'myapplicationprofile2', { + inferenceProfileName: 'claude 3 sonnet v1', + modelSource: cris, +}); + +// Import a Cfn L1 construct created application inference profile +const cfnapp = new CfnApplicationInferenceProfile(this, 'mytestaip3', { + inferenceProfileName: 'mytest', + modelSource: { + copyFrom: 'arn:aws:bedrock:us-east-1::foundation-model/anthropic.claude-3-sonnet-20240229-v1:0', + }, +}); + +const appInfProfile3 = bedrock.ApplicationInferenceProfile.fromCfnApplicationInferenceProfile(cfnapp); + +// Import an inference profile through attributes +const appInfProfile4 = bedrock.ApplicationInferenceProfile.fromApplicationInferenceProfileAttributes(this, 'TestAIP', { + inferenceProfileArn: 'arn:aws:bedrock:us-east-1:XXXXX:application-inference-profile/ID', + inferenceProfileIdentifier: 'arn:aws:bedrock:us-east-1:XXXXXXX:application-inference-profile/ID', +}); +``` + +--- + +Ticking the box below indicates that the public API of this RFC has been +signed-off by the API bar raiser (the `status/api-approved` label was applied to the +RFC pull request): + +``` +[ ] Signed-off by API Bar Raiser @xxxxx +``` + +## Public FAQ + +### What are we launching today? + +We are excited to announce the launch of our new L2 construct for Amazon Bedrock. This construct includes several key features: +- Bedrock Agent: A core component for managing and orchestrating Bedrock resources. +- Knowledge Base: A repository for storing and managing knowledge assets. +- Guardrails: Mechanisms to ensure safe and compliant use of Bedrock services. +- Inference Profiles: Customizable profiles for optimizing inference tasks. +- Prompt: Tools and templates for creating effective prompts for Bedrock models. + +### Why should I use this feature? + +This L2 construct for Amazon Bedrock enables the creation of multiple features with minimal code, adhering to AWS best practices. It facilitates seamless integration of existing features, for example, allowing users to bring their own vector store and associate it with the knowledge base. + + +## Internal FAQ + +> The goal of this section is to help decide if this RFC should be implemented. +> It should include answers to questions that the team is likely ask. Contrary +> to the rest of the RFC, answers should be written "from the present" and +> likely discuss design approach, implementation plans, alternative considered +> and other considerations that will help decide if this RFC should be +> implemented. + +### Why are we doing this? + +The Bedrock L2 construct is currently open-sourced in the [generative-ai-cdk-constructs](https://github.com/awslabs/generative-ai-cdk-constructs/blob/main/src/cdk-lib/bedrock/README.md) repository. This construct is one of the most widely used and highly appreciated in the repository, with nearly 1,500 active AWS accounts leveraging it. It has been downloaded over 300,000 times from npm and PyPI libraries. Popular tools and libraries utilizing this Bedrock construct include: +- Lambda PowerTools: [Documentation](https://docs.powertools.aws.dev/lambda/python/latest/core/event_handler/bedrock_agents/#using-aws-cloud-developer-kit-cdk) +- Claude Chatbot: [GitHub Repository](https://github.com/aws-samples/bedrock-claude-chat) + +The construct has received numerous positive testimonials from customers. Inclusion in the official CDK repository will facilitate scaling this construct, enabling it to serve multiple customers more effectively. + + +### Why should we _not_ do this? + +The construct is published via the [generative-ai-cdk-constructs](https://github.com/awslabs/generative-ai-cdk-constructs/blob/main/src/cdk-lib/bedrock/README.md) repository. However, due to the increasing demands and expanding use cases, maintaining it within this repository has become challenging. + + +### What is the technical solution (design) of this feature? + + +This construct library includes CloudFormation L1 resources for deploying Bedrock features. It provides interfaces for Agent, Guardrails, Knowledge Base, and Prompt, among others. Detailed [API documentation](https://github.com/awslabs/generative-ai-cdk-constructs/blob/main/apidocs/namespaces/bedrock/README.md#interfaces) is available here. + +## Interfaces + +- [AgentActionGroupProps](https://github.com/awslabs/generative-ai-cdk-constructs/blob/main/apidocs/namespaces/bedrock/interfaces/AgentActionGroupProps.md) +- [AgentAliasAttributes](https://github.com/awslabs/generative-ai-cdk-constructs/blob/main/apidocs/namespaces/bedrock/interfaces/AgentAliasAttributes.md) +- [AgentAliasProps](https://github.com/awslabs/generative-ai-cdk-constructs/blob/main/apidocs/namespaces/bedrock/interfaces/AgentAliasProps.md) +- [AgentAttributes](https://github.com/awslabs/generative-ai-cdk-constructs/blob/main/apidocs/namespaces/bedrock/interfaces/AgentAttributes.md) +- [AgentPromptVariantProps](https://github.com/awslabs/generative-ai-cdk-constructs/blob/main/apidocs/namespaces/bedrock/interfaces/AgentPromptVariantProps.md) +- [AgentProps](https://github.com/awslabs/generative-ai-cdk-constructs/blob/main/apidocs/namespaces/bedrock/interfaces/AgentProps.md) +- [ApplicationInferenceProfileAttributes](https://github.com/awslabs/generative-ai-cdk-constructs/blob/main/apidocs/namespaces/bedrock/interfaces/ApplicationInferenceProfileAttributes.md) +- [ApplicationInferenceProfileProps](https://github.com/awslabs/generative-ai-cdk-constructs/blob/main/apidocs/namespaces/bedrock/interfaces/ApplicationInferenceProfileProps.md) +- [BedrockFoundationModelProps](https://github.com/awslabs/generative-ai-cdk-constructs/blob/main/apidocs/namespaces/bedrock/interfaces/BedrockFoundationModelProps.md) +- [ChatPromptVariantProps](https://github.com/awslabs/generative-ai-cdk-constructs/blob/main/apidocs/namespaces/bedrock/interfaces/ChatPromptVariantProps.md) +- [CommonPromptVariantProps](https://github.com/awslabs/generative-ai-cdk-constructs/blob/main/apidocs/namespaces/bedrock/interfaces/CommonPromptVariantProps.md) +- [ConfluenceCrawlingFilters](https://github.com/awslabs/generative-ai-cdk-constructs/blob/main/apidocs/namespaces/bedrock/interfaces/ConfluenceCrawlingFilters.md) +- [ConfluenceDataSourceAssociationProps](https://github.com/awslabs/generative-ai-cdk-constructs/blob/main/apidocs/namespaces/bedrock/interfaces/ConfluenceDataSourceAssociationProps.md) +- [ConfluenceDataSourceProps](https://github.com/awslabs/generative-ai-cdk-constructs/blob/main/apidocs/namespaces/bedrock/interfaces/ConfluenceDataSourceProps.md) +- [ContentFilter](https://github.com/awslabs/generative-ai-cdk-constructs/blob/main/apidocs/namespaces/bedrock/interfaces/ContentFilter.md) +- [ContextualGroundingFilter](https://github.com/awslabs/generative-ai-cdk-constructs/blob/main/apidocs/namespaces/bedrock/interfaces/ContextualGroundingFilter.md) +- [CrawlingFilters](https://github.com/awslabs/generative-ai-cdk-constructs/blob/main/apidocs/namespaces/bedrock/interfaces/CrawlingFilters.md) +- [CrossRegionInferenceProfileProps](https://github.com/awslabs/generative-ai-cdk-constructs/blob/main/apidocs/namespaces/bedrock/interfaces/CrossRegionInferenceProfileProps.md) +- [CustomParserProps](https://github.com/awslabs/generative-ai-cdk-constructs/blob/main/apidocs/namespaces/bedrock/interfaces/CustomParserProps.md) +- [CustomTopicProps](https://github.com/awslabs/generative-ai-cdk-constructs/blob/main/apidocs/namespaces/bedrock/interfaces/CustomTopicProps.md) +- [DataSourceAssociationProps](https://github.com/awslabs/generative-ai-cdk-constructs/blob/main/apidocs/namespaces/bedrock/interfaces/DataSourceAssociationProps.md) +- [FoundationModelParsingStategyProps](https://github.com/awslabs/generative-ai-cdk-constructs/blob/main/apidocs/namespaces/bedrock/interfaces/FoundationModelParsingStategyProps.md) +- [GuardrailAttributes](https://github.com/awslabs/generative-ai-cdk-constructs/blob/main/apidocs/namespaces/bedrock/interfaces/GuardrailAttributes.md) +- [GuardrailProps](https://github.com/awslabs/generative-ai-cdk-constructs/blob/main/apidocs/namespaces/bedrock/interfaces/GuardrailProps.md) +- [HierarchicalChunkingProps](https://github.com/awslabs/generative-ai-cdk-constructs/blob/main/apidocs/namespaces/bedrock/interfaces/HierarchicalChunkingProps.md) +- [IAgent](https://github.com/awslabs/generative-ai-cdk-constructs/blob/main/apidocs/namespaces/bedrock/interfaces/IAgent.md) +- [IAgentAlias](https://github.com/awslabs/generative-ai-cdk-constructs/blob/main/apidocs/namespaces/bedrock/interfaces/IAgentAlias.md) +- [IDataSource](https://github.com/awslabs/generative-ai-cdk-constructs/blob/main/apidocs/namespaces/bedrock/interfaces/IDataSource.md) +- [IGuardrail](https://github.com/awslabs/generative-ai-cdk-constructs/blob/main/apidocs/namespaces/bedrock/interfaces/IGuardrail.md) +- [IInferenceProfile](https://github.com/awslabs/generative-ai-cdk-constructs/blob/main/apidocs/namespaces/bedrock/interfaces/IInferenceProfile.md) +- [IInvokable](https://github.com/awslabs/generative-ai-cdk-constructs/blob/main/apidocs/namespaces/bedrock/interfaces/IInvokable.md) +- [IKnowledgeBase](https://github.com/awslabs/generative-ai-cdk-constructs/blob/main/apidocs/namespaces/bedrock/interfaces/IKnowledgeBase.md) +- [InferenceConfiguration](https://github.com/awslabs/generative-ai-cdk-constructs/blob/main/apidocs/namespaces/bedrock/interfaces/InferenceConfiguration.md) +- [IPrompt](https://github.com/awslabs/generative-ai-cdk-constructs/blob/main/apidocs/namespaces/bedrock/interfaces/IPrompt.md) +- [IPromptRouter](https://github.com/awslabs/generative-ai-cdk-constructs/blob/main/apidocs/namespaces/bedrock/interfaces/IPromptRouter.md) +- [KnowledgeBaseAttributes](https://github.com/awslabs/generative-ai-cdk-constructs/blob/main/apidocs/namespaces/bedrock/interfaces/KnowledgeBaseAttributes.md) +- [KnowledgeBaseProps](https://github.com/awslabs/generative-ai-cdk-constructs/blob/main/apidocs/namespaces/bedrock/interfaces/KnowledgeBaseProps.md) +- [LambdaCustomTransformationProps](https://github.com/awslabs/generative-ai-cdk-constructs/blob/main/apidocs/namespaces/bedrock/interfaces/LambdaCustomTransformationProps.md) +- [PIIFilter](https://github.com/awslabs/generative-ai-cdk-constructs/blob/main/apidocs/namespaces/bedrock/interfaces/PIIFilter.md) +- [PromptAttributes](https://github.com/awslabs/generative-ai-cdk-constructs/blob/main/apidocs/namespaces/bedrock/interfaces/PromptAttributes.md) +- [PromptProps](https://github.com/awslabs/generative-ai-cdk-constructs/blob/main/apidocs/namespaces/bedrock/interfaces/PromptProps.md) +- [PromptRouterProps](https://github.com/awslabs/generative-ai-cdk-constructs/blob/main/apidocs/namespaces/bedrock/interfaces/PromptRouterProps.md) +- [PromptStepConfiguration](https://github.com/awslabs/generative-ai-cdk-constructs/blob/main/apidocs/namespaces/bedrock/interfaces/PromptStepConfiguration.md) +- [PromptStepConfigurationCustomParser](https://github.com/awslabs/generative-ai-cdk-constructs/blob/main/apidocs/namespaces/bedrock/interfaces/PromptStepConfigurationCustomParser.md) +- [PromptVersionProps](https://github.com/awslabs/generative-ai-cdk-constructs/blob/main/apidocs/namespaces/bedrock/interfaces/PromptVersionProps.md) +- [RegexFilter](https://github.com/awslabs/generative-ai-cdk-constructs/blob/main/apidocs/namespaces/bedrock/interfaces/RegexFilter.md) +- [S3DataSourceAssociationProps](https://github.com/awslabs/generative-ai-cdk-constructs/blob/main/apidocs/namespaces/bedrock/interfaces/S3DataSourceAssociationProps.md) +- [S3DataSourceProps](https://github.com/awslabs/generative-ai-cdk-constructs/blob/main/apidocs/namespaces/bedrock/interfaces/S3DataSourceProps.md) +- [SalesforceCrawlingFilters](https://github.com/awslabs/generative-ai-cdk-constructs/blob/main/apidocs/namespaces/bedrock/interfaces/SalesforceCrawlingFilters.md) +- [SalesforceDataSourceAssociationProps](https://github.com/awslabs/generative-ai-cdk-constructs/blob/main/apidocs/namespaces/bedrock/interfaces/SalesforceDataSourceAssociationProps.md) +- [SalesforceDataSourceProps](https://github.com/awslabs/generative-ai-cdk-constructs/blob/main/apidocs/namespaces/bedrock/interfaces/SalesforceDataSourceProps.md) +- [SharePointCrawlingFilters](https://github.com/awslabs/generative-ai-cdk-constructs/blob/main/apidocs/namespaces/bedrock/interfaces/SharePointCrawlingFilters.md) +- [SharePointDataSourceAssociationProps](https://github.com/awslabs/generative-ai-cdk-constructs/blob/main/apidocs/namespaces/bedrock/interfaces/SharePointDataSourceAssociationProps.md) +- [SharePointDataSourceProps](https://github.com/awslabs/generative-ai-cdk-constructs/blob/main/apidocs/namespaces/bedrock/interfaces/SharePointDataSourceProps.md) +- [TextPromptVariantProps](https://github.com/awslabs/generative-ai-cdk-constructs/blob/main/apidocs/namespaces/bedrock/interfaces/TextPromptVariantProps.md) +- [ToolConfiguration](https://github.com/awslabs/generative-ai-cdk-constructs/blob/main/apidocs/namespaces/bedrock/interfaces/ToolConfiguration.md) +- [WebCrawlerDataSourceAssociationProps](https://github.com/awslabs/generative-ai-cdk-constructs/blob/main/apidocs/namespaces/bedrock/interfaces/WebCrawlerDataSourceAssociationProps.md) +- [WebCrawlerDataSourceProps](https://github.com/awslabs/generative-ai-cdk-constructs/blob/main/apidocs/namespaces/bedrock/interfaces/WebCrawlerDataSourceProps.md) + +## Classes + +- [ActionGroupExecutor](https://github.com/awslabs/generative-ai-cdk-constructs/blob/main/apidocs/namespaces/bedrock/classes/ActionGroupExecutor.md) +- [Agent](https://github.com/awslabs/generative-ai-cdk-constructs/blob/main/apidocs/namespaces/bedrock/classes/Agent.md) +- [AgentActionGroup](https://github.com/awslabs/generative-ai-cdk-constructs/blob/main/apidocs/namespaces/bedrock/classes/AgentActionGroup.md) +- [AgentAlias](https://github.com/awslabs/generative-ai-cdk-constructs/blob/main/apidocs/namespaces/bedrock/classes/AgentAlias.md) +- [AgentAliasBase](https://github.com/awslabs/generative-ai-cdk-constructs/blob/main/apidocs/namespaces/bedrock/classes/AgentAliasBase.md) +- [AgentBase](https://github.com/awslabs/generative-ai-cdk-constructs/blob/main/apidocs/namespaces/bedrock/classes/AgentBase.md) +- [ApiSchema](https://github.com/awslabs/generative-ai-cdk-constructs/blob/main/apidocs/namespaces/bedrock/classes/ApiSchema.md) +- [ApplicationInferenceProfile](https://github.com/awslabs/generative-ai-cdk-constructs/blob/main/apidocs/namespaces/bedrock/classes/ApplicationInferenceProfile.md) +- [BedrockFoundationModel](https://github.com/awslabs/generative-ai-cdk-constructs/blob/main/apidocs/namespaces/bedrock/classes/BedrockFoundationModel.md) +- [ChatMessage](https://github.com/awslabs/generative-ai-cdk-constructs/blob/main/apidocs/namespaces/bedrock/classes/ChatMessage.md) +- [ChunkingStrategy](https://github.com/awslabs/generative-ai-cdk-constructs/blob/main/apidocs/namespaces/bedrock/classes/ChunkingStrategy.md) +- [ConfluenceDataSource](https://github.com/awslabs/generative-ai-cdk-constructs/blob/main/apidocs/namespaces/bedrock/classes/ConfluenceDataSource.md) +- [CrossRegionInferenceProfile](https://github.com/awslabs/generative-ai-cdk-constructs/blob/main/apidocs/namespaces/bedrock/classes/CrossRegionInferenceProfile.md) +- [CustomTransformation](https://github.com/awslabs/generative-ai-cdk-constructs/blob/main/apidocs/namespaces/bedrock/classes/CustomTransformation.md) +- [DataSource](https://github.com/awslabs/generative-ai-cdk-constructs/blob/main/apidocs/namespaces/bedrock/classes/DataSource.md) +- [DataSourceBase](https://github.com/awslabs/generative-ai-cdk-constructs/blob/main/apidocs/namespaces/bedrock/classes/DataSourceBase.md) +- [DataSourceNew](https://github.com/awslabs/generative-ai-cdk-constructs/blob/main/apidocs/namespaces/bedrock/classes/DataSourceNew.md) +- [DefaultPromptRouterIdentifier](https://github.com/awslabs/generative-ai-cdk-constructs/blob/main/apidocs/namespaces/bedrock/classes/DefaultPromptRouterIdentifier.md) +- [Guardrail](https://github.com/awslabs/generative-ai-cdk-constructs/blob/main/apidocs/namespaces/bedrock/classes/Guardrail.md) +- [GuardrailBase](https://github.com/awslabs/generative-ai-cdk-constructs/blob/main/apidocs/namespaces/bedrock/classes/GuardrailBase.md) +- [InferenceProfileBase](https://github.com/awslabs/generative-ai-cdk-constructs/blob/main/apidocs/namespaces/bedrock/classes/InferenceProfileBase.md) +- [InlineApiSchema](https://github.com/awslabs/generative-ai-cdk-constructs/blob/main/apidocs/namespaces/bedrock/classes/InlineApiSchema.md) +- [KnowledgeBase](https://github.com/awslabs/generative-ai-cdk-constructs/blob/main/apidocs/namespaces/bedrock/classes/KnowledgeBase.md) +- [ParentActionGroupSignature](https://github.com/awslabs/generative-ai-cdk-constructs/blob/main/apidocs/namespaces/bedrock/classes/ParentActionGroupSignature.md) +- [ParsingStategy](https://github.com/awslabs/generative-ai-cdk-constructs/blob/main/apidocs/namespaces/bedrock/classes/ParsingStategy.md) +- [Prompt](https://github.com/awslabs/generative-ai-cdk-constructs/blob/main/apidocs/namespaces/bedrock/classes/Prompt.md) +- [PromptBase](https://github.com/awslabs/generative-ai-cdk-constructs/blob/main/apidocs/namespaces/bedrock/classes/PromptBase.md) +- [PromptOverrideConfiguration](https://github.com/awslabs/generative-ai-cdk-constructs/blob/main/apidocs/namespaces/bedrock/classes/PromptOverrideConfiguration.md) +- [PromptRouter](https://github.com/awslabs/generative-ai-cdk-constructs/blob/main/apidocs/namespaces/bedrock/classes/PromptRouter.md) +- [PromptVariant](https://github.com/awslabs/generative-ai-cdk-constructs/blob/main/apidocs/namespaces/bedrock/classes/PromptVariant.md) +- [PromptVersion](https://github.com/awslabs/generative-ai-cdk-constructs/blob/main/apidocs/namespaces/bedrock/classes/PromptVersion.md) +- [S3ApiSchema](https://github.com/awslabs/generative-ai-cdk-constructs/blob/main/apidocs/namespaces/bedrock/classes/S3ApiSchema.md) +- [S3DataSource](https://github.com/awslabs/generative-ai-cdk-constructs/blob/main/apidocs/namespaces/bedrock/classes/S3DataSource.md) +- [SalesforceDataSource](https://github.com/awslabs/generative-ai-cdk-constructs/blob/main/apidocs/namespaces/bedrock/classes/SalesforceDataSource.md) +- [SharePointDataSource](https://github.com/awslabs/generative-ai-cdk-constructs/blob/main/apidocs/namespaces/bedrock/classes/SharePointDataSource.md) +- [ToolChoice](https://github.com/awslabs/generative-ai-cdk-constructs/blob/main/apidocs/namespaces/bedrock/classes/ToolChoice.md) +- [Topic](https://github.com/awslabs/generative-ai-cdk-constructs/blob/main/apidocs/namespaces/bedrock/classes/Topic.md) +- [WebCrawlerDataSource](https://github.com/awslabs/generative-ai-cdk-constructs/blob/main/apidocs/namespaces/bedrock/classes/WebCrawlerDataSource.md) + + +## Enumerations + +- [AgentStepType](https://github.com/awslabs/generative-ai-cdk-constructs/blob/main/apidocs/namespaces/bedrock/enumerations/AgentStepType.md) +- [ChatMessageRole](https://github.com/awslabs/generative-ai-cdk-constructs/blob/main/apidocs/namespaces/bedrock/enumerations/ChatMessageRole.md) +- [ConfluenceDataSourceAuthType](https://github.com/awslabs/generative-ai-cdk-constructs/blob/main/apidocs/namespaces/bedrock/enumerations/ConfluenceDataSourceAuthType.md) +- [ConfluenceObjectType](https://github.com/awslabs/generative-ai-cdk-constructs/blob/main/apidocs/namespaces/bedrock/enumerations/ConfluenceObjectType.md) +- [ContentFilterStrength](https://github.com/awslabs/generative-ai-cdk-constructs/blob/main/apidocs/namespaces/bedrock/enumerations/ContentFilterStrength.md) +- [ContentFilterType](https://github.com/awslabs/generative-ai-cdk-constructs/blob/main/apidocs/namespaces/bedrock/enumerations/ContentFilterType.md) +- [ContextualGroundingFilterType](https://github.com/awslabs/generative-ai-cdk-constructs/blob/main/apidocs/namespaces/bedrock/enumerations/ContextualGroundingFilterType.md) +- [CrawlingScope](https://github.com/awslabs/generative-ai-cdk-constructs/blob/main/apidocs/namespaces/bedrock/enumerations/CrawlingScope.md) +- [CrossRegionInferenceProfileRegion](https://github.com/awslabs/generative-ai-cdk-constructs/blob/main/apidocs/namespaces/bedrock/enumerations/CrossRegionInferenceProfileRegion.md) +- [DataDeletionPolicy](https://github.com/awslabs/generative-ai-cdk-constructs/blob/main/apidocs/namespaces/bedrock/enumerations/DataDeletionPolicy.md) +- [DataSourceType](https://github.com/awslabs/generative-ai-cdk-constructs/blob/main/apidocs/namespaces/bedrock/enumerations/DataSourceType.md) +- [GuardrailAction](https://github.com/awslabs/generative-ai-cdk-constructs/blob/main/apidocs/namespaces/bedrock/enumerations/GuardrailAction.md) +- [InferenceProfileType](https://github.com/awslabs/generative-ai-cdk-constructs/blob/main/apidocs/namespaces/bedrock/enumerations/InferenceProfileType.md) +- [ManagedWordFilterType](https://github.com/awslabs/generative-ai-cdk-constructs/blob/main/apidocs/namespaces/bedrock/enumerations/ManagedWordFilterType.md) +- [PromptTemplateType](https://github.com/awslabs/generative-ai-cdk-constructs/blob/main/apidocs/namespaces/bedrock/enumerations/PromptTemplateType.md) +- [SalesforceDataSourceAuthType](https://github.com/awslabs/generative-ai-cdk-constructs/blob/main/apidocs/namespaces/bedrock/enumerations/SalesforceDataSourceAuthType.md) +- [SalesforceObjectType](https://github.com/awslabs/generative-ai-cdk-constructs/blob/main/apidocs/namespaces/bedrock/enumerations/SalesforceObjectType.md) +- [SharePointDataSourceAuthType](https://github.com/awslabs/generative-ai-cdk-constructs/blob/main/apidocs/namespaces/bedrock/enumerations/SharePointDataSourceAuthType.md) +- [SharePointObjectType](https://github.com/awslabs/generative-ai-cdk-constructs/blob/main/apidocs/namespaces/bedrock/enumerations/SharePointObjectType.md) +- [TransformationStep](https://github.com/awslabs/generative-ai-cdk-constructs/blob/main/apidocs/namespaces/bedrock/enumerations/TransformationStep.md) + + + +### Is this a breaking change? + +No. + +### What alternative solutions did you consider? + +Use Amazon Bedrock L1 construct for each feature individually, which takes a lot of code to provision the resource. + +### What are the drawbacks of this solution? + +The Knowledge Base vector stores (OpenSearch and Aurora clusters) utilize custom resource lambda functions, as there are no underlying L1 constructs available. + +### What is the high-level project plan? + +The construct has been published and is open-sourced in this [repository](https://github.com/awslabs/generative-ai-cdk-constructs/), where we continuously gather feedback from users. It also includes a metrics dashboard to measure usage. + +### Are there any open issues that need to be addressed later? + +While there are no major issues, all the latest requested open issues are tracked [here](https://github.com/awslabs/generative-ai-cdk-constructs/issues). + +## Appendix + + From 633baa7977d757eb1d3e281ddc747a08588c47c8 Mon Sep 17 00:00:00 2001 From: dinsajwa Date: Mon, 27 Jan 2025 11:25:07 -0500 Subject: [PATCH 2/9] feat(bedorck): rfc for bedrockL2 construct --- text/0686-bedrock-l2-construct.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/text/0686-bedrock-l2-construct.md b/text/0686-bedrock-l2-construct.md index 23d453fd7..f12b6c3c1 100644 --- a/text/0686-bedrock-l2-construct.md +++ b/text/0686-bedrock-l2-construct.md @@ -1,6 +1,6 @@ # Bedrock L2 Construct -* **Original Author(s):**: @dineshSajwan +* **Original Author(s):**: @dineshSajwan , @krokoko * **Tracking Issue**: #686 * **API Bar Raiser**: @{BAR_RAISER_USER} From 2615062dd21fcba7e37eb1bdaea250afec3815e8 Mon Sep 17 00:00:00 2001 From: dinsajwa Date: Wed, 12 Feb 2025 10:02:29 -0500 Subject: [PATCH 3/9] added review comments --- text/0686-bedrock-l2-construct.md | 101 ------------------------------ 1 file changed, 101 deletions(-) diff --git a/text/0686-bedrock-l2-construct.md b/text/0686-bedrock-l2-construct.md index f12b6c3c1..be4ca96b4 100644 --- a/text/0686-bedrock-l2-construct.md +++ b/text/0686-bedrock-l2-construct.md @@ -608,92 +608,6 @@ const cfnGuardrail = new CfnGuardrail(this, 'MyCfnGuardrail', { const importedGuardrail = bedrock.Guardrail.fromCfnGuardrail(cfnGuardrail); ``` -Python - -```python - guardrail = bedrock.Guardrail(self, 'myGuardrails', - name='my-BedrockGuardrails', - description= "Legal ethical guardrails.") - - # Optional - Add Sensitive information filters - - guardrail.add_pii_filter( - type= bedrock.pii_type.General.ADDRESS, - action= bedrock.GuardrailAction.ANONYMIZE, - ) - - guardrail.add_regex_filter( - name= "TestRegexFilter", - description= "This is a test regex filter", - pattern= "/^[A-Z]{2}d{6}$/", - action= bedrock.GuardrailAction.ANONYMIZE, - ) - - # Optional - Add contextual grounding - - guardrail.add_contextual_grounding_filter( - type= bedrock.ContextualGroundingFilterType.GROUNDING, - threshold= 0.95, - ) - - # Optional - Add Denied topics . You can use default Topic or create your custom Topic with createTopic function. The default Topics can also be overwritten. - - guardrail.add_contextual_grounding_filter( - type= bedrock.ContextualGroundingFilterType.RELEVANCE, - threshold= 0.95, - ) - - guardrail.add_denied_topic_filter(bedrock.Topic.FINANCIAL_ADVICE) - - guardrail.add_denied_topic_filter( - bedrock.Topic.custom( - name= "Legal_Advice", - definition= - "Offering guidance or suggestions on legal matters, legal actions, interpretation of laws, or legal rights and responsibilities.", - examples= [ - "Can I sue someone for this?", - "What are my legal rights in this situation?", - "Is this action against the law?", - "What should I do to file a legal complaint?", - "Can you explain this law to me?", - ] - ) - ) - - # Optional - Add Word filters. You can upload words from a file with addWordFilterFromFile function. - guardrail.add_word_filter("drugs") - guardrail.add_managed_word_list_filter(bedrock.ManagedWordFilterType.PROFANITY) - guardrail.add_word_filter_from_file("./scripts/wordsPolicy.csv") - - # versioning - if you change any guardrail configuration, a new version will be created - guardrail.create_version("testversion") - - # Importing existing guardrail - imported_guardrail = bedrock.Guardrail.from_guardrail_attributes(self, "TestGuardrail", - guardrail_arn="arn:aws:bedrock:us-east-1:123456789012:guardrail/oygh3o8g7rtl", - guardrail_version="1", - kms_key=kms_key - ) - - # Importing Guardrails created through the L1 CDK CfnGuardrail construct - cfn_guardrail = cfnbedrock.CfnGuardrail(self, "MyCfnGuardrail", - blocked_input_messaging="blockedInputMessaging", - blocked_outputs_messaging="blockedOutputsMessaging", - name="name", - - # the properties below are optional - word_policy_config=cfnbedrock.CfnGuardrail.WordPolicyConfigProperty( - words_config=[cfnbedrock.CfnGuardrail.WordConfigProperty( - text="drugs" - )] - ) - ) - - imported_guardrail = bedrock.Guardrail.from_cfn_guardrail(cfn_guardrail) - - - -``` ## Prompt management @@ -833,21 +747,6 @@ new Prompt(stack, 'Prompt', { }); ``` -**Python** - -```py -variant = bedrock.PromptVariant.text( - variant_name='variant1', - prompt_text='What is the capital of France?', - model=bedrock.PromptRouter.from_default_id(bedrock.DefaultPromptRouterIdentifier.ANTHROPIC_CLAUDE_V1, region), -) - -bedrock.Prompt(self, 'Prompt', - prompt_name='prompt-router-test', - variants=[variant], -) -``` - ### Prompt Version A prompt version is a snapshot of a prompt at a specific point in time that you From 93e54fddeba361ce5788c9da2cf140136ff34751 Mon Sep 17 00:00:00 2001 From: dinsajwa Date: Wed, 12 Feb 2025 18:34:29 -0500 Subject: [PATCH 4/9] added kendra kb , review comments and updated lint warnings --- text/0686-bedrock-l2-construct.md | 328 ++++++++++++++++++++---------- 1 file changed, 218 insertions(+), 110 deletions(-) diff --git a/text/0686-bedrock-l2-construct.md b/text/0686-bedrock-l2-construct.md index be4ca96b4..d4121b725 100644 --- a/text/0686-bedrock-l2-construct.md +++ b/text/0686-bedrock-l2-construct.md @@ -4,42 +4,91 @@ * **Tracking Issue**: #686 * **API Bar Raiser**: @{BAR_RAISER_USER} +The Bedrock L2 construct simplifies the creation of multiple Bedrock features by wrapping the Bedrock L1 construct. It exposes functions +for creating features with minimal code. Key features include Bedrock Agent, Knowledge Base, Guardrails, Inference Profiles, and Prompt. -The Bedrock L2 construct simplifies the creation of multiple Bedrock features by providing a wrapper over the Bedrock L1 construct. It exposes functions that enable users to create features with minimal code. Key features include Bedrock Agent, Knowledge Base, Guardrails, Inference Profiles, and Prompt. +A quick comparison between L1 and L2 Bedrock constructs: +1. Quick and easy creation of constructs: + - Knowledge base, agent, Guardrails, action groups, prompt management and inference profiles are simplified + - Support multiple datasource , vector stores and kendra with one knowledge base constructor. -**CHANGELOG**: +2. Manage IAM role policies for Bedrock constructs: + - Add Bedrock policy on Knowledge Base to invoke embedding model + - Add resource policy on agent to invoke foundation model + +3. Helper methods for better user experience: + - associateToAgent: Add Knowledge Base to an agent + - addActionGroup, addActionGroups + - addKnowledgeBase + - addGuardrail + - addS3DataSource, addWebCrawlerDataSource, addSharePointDataSource etc. + +4. Managing node dependency, for example: + - Create vector store before creating Knowledge Base + - Lazy rendering of guardrails and Knowledge Base with agent + +5. Validation and user-friendly error handling with functions like: + - validateKnowledgeBase + - validateKnowledgeBaseAssociations + - validateGuardrail + +6. Support creating resources from existing attributes with functions like: + - fromAttributes + - fromDataSourceId + - fromAgentAttrs + +**CHANGELOG**: ```feat(bedrock): bedrock L2 construct``` -**README**: -[Amazon Bedrock](https://aws.amazon.com/bedrock/) is a fully managed service that offers a choice of high-performing foundation models (FMs) from leading AI companies and Amazon through a single API, along with a broad set of capabilities you need to build generative AI applications with security, privacy, and responsible AI. +**README**: +[Amazon Bedrock](https://aws.amazon.com/bedrock/) is a fully managed service. +It offers a choice of high-performing foundation models (FMs) from leading AI companies and Amazon through a single API. -This construct library facilitates the deployment of Knowledge Bases, Bedrock Agents, Guardrails, Prompt Management, and Inference Pipelines. It leverages underlying CloudFormation L1 resources to provision these Bedrock features. +This construct library facilitates the deployment of Knowledge Bases, Bedrock Agents, Guardrails, Prompt Management, and Inference Pipelines. +It leverages underlying CloudFormation L1 resources to provision these Bedrock features. For more details please refer here [Amazon Bedrock README](https://github.com/awslabs/generative-ai-cdk-constructs/blob/main/src/cdk-lib/bedrock/README.md). - ## Knowledge Base -Amazon Bedrock Knowledge Bases enable you to provide foundation models and agents with contextual information from your company’s private data sources. This enhances the relevance, accuracy, and customization of their responses. +Amazon Bedrock Knowledge Bases enable you to provide foundation models and agents with contextual information from your company’s private data sources. +This enhances the relevance, accuracy, and customization of their responses. + +### Create a Vector Knowledge Base -### Create a Knowledge Base +To create a vector knowledge Base, a vector index on a vector store is required. The resource accepts: -A vector index on a vector store is required to create a Knowledge Base. This construct currently supports [Amazon OpenSearch Serverless](../opensearchserverless), [Amazon RDS Aurora PostgreSQL](../amazonaurora/), [Pinecone](../pinecone/) . By default, this resource will create an OpenSearch Serverless vector collection and index for each Knowledge Base you create, but you can provide an existing collection and/or index to have more control. For other resources you need to have the vector stores already created and credentials stored in AWS Secrets Manager. For Aurora, the construct provides an option to create a default `AmazonAuroraDefaultVectorStore` construct that will provision the vector store backed by Amazon Aurora for you. To learn more you can read [here](../amazonaurora/README.md). +1. `storageConfiguration` prop: An existing vector store from: + - [Amazon OpenSearch Serverless](../opensearchserverless) + - [Amazon RDS Aurora PostgreSQL](../amazonaurora/) + - [Pinecone](../pinecone/) -The resource accepts an `instruction` prop that is provided to any Bedrock Agent it is associated with so the agent can decide when to query the Knowledge Base. +2. `instruction` prop: Provided to associated Bedrock Agents to determine when to query the Knowledge Base -Amazon Bedrock Knowledge Bases currently only supports S3 as a data source. The `S3DataSource` resource is used to configure how the Knowledge Base handles the data source. +3. embeddingsModel: Foundation model supported with bedrock. Example of `OpenSearch Serverless`: ```ts import * as s3 from 'aws-cdk-lib/aws-s3'; -import { bedrock } from '@cdklabs/generative-ai-cdk-constructs'; +import { bedrock } from 'aws-cdk-lib/aws-bedrock'; const kb = new bedrock.KnowledgeBase(this, 'KnowledgeBase', { embeddingsModel: bedrock.BedrockFoundationModel.TITAN_EMBED_TEXT_V1, instruction: 'Use this knowledge base to answer questions about books. ' + 'It contains the full text of novels.', + storageConfiguration:[{ + type:'OPENSEARCH_SERVERLESS', + opensearchServerlessConfiguration:{ + collectionArn: params.vectorStore.collectionArn, + fieldMapping: { + vectorField: params.vectorField, + textField: params.textField, + metadataField: params.metadataField, + }, + vectorIndexName: params.indexName, + }, + }] }); const docBucket = new s3.Bucket(this, 'DocBucket'); @@ -55,44 +104,15 @@ new bedrock.S3DataSource(this, 'DataSource', { }); ``` -Example of `Amazon RDS Aurora PostgreSQL`: - - - -```ts -import * as s3 from 'aws-cdk-lib/aws-s3'; -import { amazonaurora, bedrock } from '@cdklabs/generative-ai-cdk-constructs'; - -// Dimension of your vector embedding -embeddingsModelVectorDimension = 1024; -const auroraDb = new amazonaurora.AmazonAuroraVectorStore(stack, 'AuroraDefaultVectorStore', { - embeddingsModelVectorDimension: embeddingsModelVectorDimension, -}); - -const kb = new bedrock.KnowledgeBase(this, 'KnowledgeBase', { - vectorStore: auroraDb, - embeddingsModelVectorDimension: embeddingsModelVectorDimension, - instruction: 'Use this knowledge base to answer questions about books. ' + 'It contains the full text of novels.', -}); - -const docBucket = new s3.Bucket(this, 'DocBucket'); - -new bedrock.S3DataSource(this, 'DataSource', { - bucket: docBucket, - knowledgeBase: kb, - dataSourceName: 'books', - chunkingStrategy: bedrock.ChunkingStrategy.FIXED_SIZE, -}); -``` - - -Example of importing existing `Amazon RDS Aurora PostgreSQL` using `fromExistingAuroraVectorStore()` method. -**Note** - you need to provide `clusterIdentifier`, `databaseName`, `vpc`, `secret` and `auroraSecurityGroupId` used in deployment of your existing RDS Amazon Aurora DB, as well as `embeddingsModel` that you want to be used by a Knowledge Base for chunking: - +For Amazon RDS Aurora PostgreSQL it supports fromExistingAuroraVectorStore() method. +N +ote - you need to provide clusterIdentifier, databaseName, vpc, secret and auroraSecurityGroupId used in +deployment of your existing RDS Amazon Aurora DB, as well as embeddingsModel that you want to be used by a Knowledge Base +for chunking: ```ts import * as s3 from "aws-cdk-lib/aws-s3"; -import { amazonaurora, bedrock } from '@cdklabs/generative-ai-cdk-constructs'; +import { amazonaurora, bedrock } from 'aws-cdk-lib/aws-bedrock'; const auroraDb = aurora.AmazonAuroraVectorStore.fromExistingAuroraVectorStore(stack, 'ExistingAuroraVectorStore', { clusterIdentifier: 'aurora-serverless-vector-cluster', @@ -142,10 +162,9 @@ new bedrock.S3DataSource(this, "DataSource", { Example of `Pinecone` (manual, you must have Pinecone vector store created): - ```ts import * as s3 from 'aws-cdk-lib/aws-s3'; -import { pinecone, bedrock } from '@cdklabs/generative-ai-cdk-constructs'; +import { pinecone, bedrock } from 'aws-cdk-lib/aws-bedrock'; const pineconeds = new pinecone.PineconeVectorStore({ connectionString: 'https://your-index-1234567.svc.gcp-starter.pinecone.io', @@ -170,7 +189,6 @@ new bedrock.S3DataSource(this, 'DataSource', { }); ``` - #### Knowledge Base - Data Sources Data sources are the various repositories or systems from which information is extracted and ingested into the @@ -190,7 +208,6 @@ include Amazon S3 buckets, Web Crawlers, SharePoint sites, Salesforce instances, - **Salesforce**. You can either create a new data source using the `bedrock.SalesforceDataSource(..)` class, or using the `kb.addSalesforceDataSource(..)`. - ```ts const app = new cdk.App(); const stack = new cdk.Stack(app, 'aws-cdk-bedrock-data-sources-integ-test'); @@ -290,7 +307,6 @@ kb.addSharePointDataSource({ - **Default Chunking**: Applies Fixed Chunking with the default chunk size of 300 tokens and 20% overlap. - ```ts ChunkingStrategy.DEFAULT; ``` @@ -300,7 +316,6 @@ kb.addSharePointDataSource({ in size and structure. Typescript - ```ts // Fixed Size Chunking with sane defaults. ChunkingStrategy.FIXED_SIZE; @@ -313,7 +328,6 @@ kb.addSharePointDataSource({ layer containing large chunks and the second layer containing smaller chunks derived from the first. It is ideal for data with inherent hierarchies or nested structures. - ```ts // Hierarchical Chunking with the default for Cohere Models. ChunkingStrategy.HIERARCHICAL_COHERE; @@ -334,7 +348,6 @@ kb.addSharePointDataSource({ content derived from the text using natural language processing. It helps preserve contextual relationships and ensures accurate and contextually appropriate results. - ```ts // Semantic Chunking with sane defaults. ChunkingStrategy.SEMANTIC; @@ -346,7 +359,6 @@ kb.addSharePointDataSource({ - **No Chunking**: This strategy treats each file as one chunk. If you choose this option, you may want to pre-process your documents by splitting them into separate files. - ```ts ChunkingStrategy.NONE; ``` @@ -366,7 +378,6 @@ two parsing strategies: the contents of the document. It is particularly useful for improved processing of PDF files with tables and images. To use this strategy, set the `parsingStrategy` in a data source as below. - ```ts bedrock.ParsingStategy.foundationModel({ model: BedrockFoundationModel.ANTHROPIC_CLAUDE_SONNET_V1_0, @@ -382,7 +393,6 @@ Custom Transformation uses AWS Lambda functions to process documents, enabling y perform custom operations such as data extraction, normalization, or enrichment. To create a custom transformation, set the `customTransformation` in a data source as below. - ```ts CustomTransformation.lambda({ lambdaFunction: lambdaFunction, @@ -390,15 +400,72 @@ s3BucketUri: `s3://${bucket.bucketName}/chunk-processor/`, }), ``` +### Kendra Knowledge Base + +#### Create a Kendra Knowledge Base + +Amazon Bedrock Knowledge Bases enables building sophisticated RAG-powered digital assistants using Amazon Kendra GenAI index. Key benefits include: + +* **Content Reusability** + - Use indexed content across multiple Bedrock applications + - No need to rebuild indexes or re-ingest data + +* **Enhanced Capabilities** + - Leverage Bedrock's advanced GenAI features + - Benefit from Kendra's high-accuracy information retrieval + +* **Customization** + - Tailor digital assistant behavior using Bedrock tools + - Maintain semantic accuracy of Kendra GenAI index + +#### Kendra Knowledge Base properties + +| Name | Type | Required | Description | +|------|------|----------|-------------| +| kendraIndex | IKendraGenAiIndex | Yes | The Kendra Index to use for the knowledge base. | +| name | string | No | The name of the knowledge base. If not provided, a name will be auto-generated. | +| description | string | No | Description of the knowledge base. | +| instruction | string | No | Instructions for the knowledge base. | +| existingRole | iam.IRole | No | An existing IAM role to use for the knowledge base. If not provided, a new role will be created. | + +#### Initializer + +TypeScript + +```ts +import * as s3 from 'aws-cdk-lib/aws-s3'; +import { bedrock, kendra } from 'aws-cdk-lib/aws-bedrock'; + +const cmk = new kms.Key(stack, 'cmk', {}); + +// you can create a new index using the api below +const index = new kendra.KendraGenAiIndex(this, 'index', { + name: 'kendra-index-cdk', + kmsKey: cmk, + documentCapacityUnits: 1, // 40K documents + queryCapacityUnits: 1, // 0.2 QPS +}); + +// or import an existing one +const index = kendra.KendraGenAiIndex.fromAttrs(this, 'myindex', { + indexId: 'myindex', + role: myRole +}); + +new bedrock.KendraKnowledgeBase(this, 'kb', { + name: 'kendra-kb-cdk', + kendraIndex: index, +}); +``` + ## Agents -Amazon Bedrock Agents allow generative AI applications to automate complex, multistep tasks by seamlessly integrating with your company’s systems, APIs, and data sources. +Amazon Bedrock Agents allow generative AI applications to automate complex, multistep tasks by seamlessly integrating with your APIs, and data sources. ### Create an Agent The following example creates an Agent with a simple instruction and default prompts that consults a Knowledge Base. - ```ts const agent = new bedrock.Agent(this, 'Agent', { foundationModel: bedrock.BedrockFoundationModel.ANTHROPIC_CLAUDE_HAIKU_V1_0, @@ -410,7 +477,6 @@ agent.addKnowledgeBase(kb); You can also use system defined inference profiles to enable cross region inference requests for supported models. For instance: - ```ts const cris = bedrock.CrossRegionInferenceProfile.fromConfig({ geoRegion: bedrock.CrossRegionInferenceProfileRegion.US, @@ -427,7 +493,8 @@ For more information on cross region inference, please refer to [System defined ### Action Groups -An action group defines functions your agent can call. The functions are Lambda functions. The action group uses an OpenAPI schema to tell the agent what your functions do and how to call them. +An action group defines functions your agent can call. The functions are Lambda functions. The action group uses an OpenAPI schema to tell +the agent what your functions do and how to call them. ```ts const actionGroupFunction = new lambda_python.PythonFunction(this, 'ActionGroupFunction', { @@ -448,14 +515,17 @@ agent.addActionGroup(actionGroup); ### Prepare the Agent -The `Agent` constructs take an optional parameter `shouldPrepareAgent` to indicate that the Agent should be prepared after any updates to an agent, Knowledge Base association, or action group. This may increase the time to create and update those resources. By default, this value is false . +he Agent constructs take an optional parameter shouldPrepareAgent to indicate that the Agent should be prepared after any updates to +an agent, Knowledge Base association, or action group. This may increase the time to create and update those resources. By default, this +value is false. -Creating an agent alias will not prepare the agent, so if you create an alias with `addAlias` or by providing an `aliasName` when creating the agent then you should set `shouldPrepareAgent` to **_true_**. +Creating an agent alias will not prepare the agent, so if you create an alias with addAlias or by providing an aliasName when creating +the agent then you should set shouldPrepareAgent to true . #### Prompt Overrides -Bedrock Agents allows you to customize the prompts and LLM configuration for its different steps. You can disable steps or create a new prompt template. Prompt templates can be inserted from plain text files. - +Bedrock Agents allows you to customize the prompts and LLM configuration for its different steps. You can disable steps or create a new +prompt template. Prompt templates can be inserted from plain text files. ```ts import { readFileSync } from 'fs'; @@ -489,17 +559,23 @@ const agent = new bedrock.Agent(this, 'Agent', { ### Agent Alias -After you have sufficiently iterated on your working draft and are satisfied with the behavior of your agent, you can set it up for deployment and integration into your application by creating aliases of your agent. +After iterating on your working draft and being satisfied with your agent's behavior, you can prepare it for deployment +and integration into your application by creating aliases. -To deploy your agent, you need to create an alias. During alias creation, Amazon Bedrock automatically creates a version of your agent. The alias points to this newly created version. You can point the alias to a previously created version if necessary. You then configure your application to make API calls to that alias. +To deploy your agent: -By default, the `Agent` resource does not create any aliases, and you can use the 'DRAFT' version. +1. Create an alias +2. During alias creation, Amazon Bedrock automatically creates a version of your agent +3. The alias points to this newly created version +4. You can point the alias to a previously created version if needed +5. Configure your application to make API calls to that alias + +By default, the `Agent` resource doesn't create any aliases. You can use the 'DRAFT' version if no alias is created. #### Specific version You can use the `AgentAlias` resource if you want to create an Alias for an existing Agent. - ```ts const agentAlias2 = new bedrock.AgentAlias(this, 'myalias2', { aliasName: 'myalias', @@ -511,21 +587,22 @@ const agentAlias2 = new bedrock.AgentAlias(this, 'myalias2', { ## Bedrock Guardrails -Amazon Bedrock's Guardrails feature enables you to implement robust governance and control mechanisms for your generative AI applications, ensuring alignment with your specific use cases and responsible AI policies. Guardrails empowers you to create multiple tailored policy configurations, each designed to address the unique requirements and constraints of different use cases. These policy configurations can then be seamlessly applied across multiple foundation models (FMs) and Agents, ensuring a consistent user experience and standardizing safety, security, and privacy controls throughout your generative AI ecosystem. - -With Guardrails, you can define and enforce granular, customizable policies to precisely govern the behavior of your generative AI applications. You can configure the following policies in a guardrail to avoid undesirable and harmful content and remove sensitive information for privacy protection. +Amazon Bedrock's Guardrails feature enables you to implement robust governance and control mechanisms for your generative AI applications, +ensuring alignment with your specific use cases and responsible AI policies. Guardrails empowers you to create multiple tailored policy +configurations, each designed to address the unique requirements and constraints of different use cases. These policy configurations can +then be seamlessly applied across multiple foundation models (FMs) and Agents, ensuring a consistent user experience and standardizing -Content filters – Adjust filter strengths to block input prompts or model responses containing harmful content. +* Content filters – Adjust filter strengths to block input prompts or model responses containing harmful content. -Denied topics – Define a set of topics that are undesirable in the context of your application. These topics will be blocked if detected in user queries or model responses. +* Denied topics – Define a set of topics that are undesirable in the context of your application. +These topics will be blocked if detected in user queries or model responses. -Word filters – Configure filters to block undesirable words, phrases, and profanity. Such words can include offensive terms, competitor names etc. +* Word filters – Configure filters to block undesirable words, phrases, and profanity. Such words can include offensive terms, competitor names etc. -Sensitive information filters – Block or mask sensitive information such as personally identifiable information (PII) or custom regex in user inputs and model responses. +* Sensitive information filters – Block or mask sensitive information such as personally identifiable information (PII) in user inputs and model responses. You can create a Guardrail with a minimum blockedInputMessaging ,blockedOutputsMessaging and default content filter policy. - ```ts const guardrails = new bedrock.Guardrail(this, 'bedrockGuardrails', { name: 'my-BedrockGuardrails', @@ -608,7 +685,6 @@ const cfnGuardrail = new CfnGuardrail(this, 'MyCfnGuardrail', { const importedGuardrail = bedrock.Guardrail.fromCfnGuardrail(cfnGuardrail); ``` - ## Prompt management Amazon Bedrock provides the ability to create and save prompts using Prompt management so that you can save @@ -618,7 +694,6 @@ adjust the prompt for different use case. The `Prompt` resource allows you to create a new prompt. Example of a basic Text `Prompt`: - ```ts const cmk = new kms.Key(this, 'cmk', {}); const claudeModel = BedrockFoundationModel.ANTHROPIC_CLAUDE_SONNET_V1_0; @@ -647,7 +722,6 @@ const prompt1 = new Prompt(this, 'prompt1', { Example of a "Chat" `Prompt`. Use this template type when the model supports the Converse API or the Anthropic Claude Messages API. This allows you to include a System prompt and previous User messages and Assistant messages for context. - ```ts const cmk = new kms.Key(this, 'cmk', {}); @@ -706,7 +780,6 @@ specify the variants on prompt creation, or by using the `.addVariant(..)` metho Example of `PromptVariant`: - ```ts ... @@ -727,12 +800,19 @@ prompt1.addVariant(variant2); ### Prompt routing -Amazon Bedrock intelligent prompt routing provides a single serverless endpoint for efficiently routing requests between different foundational models within the same model family. -It can help you optimize for response quality and cost. They offer a comprehensive solution for managing multiple AI models through a single serverless endpoint, -simplifying the process for you. Intelligent prompt routing predicts the performance of each model for each request, and dynamically routes each request to the model -that it predicts is most likely to give the desired response at the lowest cost. -More information about prompt routing in the [documentation](https://docs.aws.amazon.com/bedrock/latest/userguide/prompt-routing.html) +Amazon Bedrock intelligent prompt routing offers a single serverless endpoint for efficient request routing between different foundational +models in the same family. It optimizes response quality and cost, providing a comprehensive solution for managing multiple AI models +through one endpoint. + +This feature simplifies the process by: +1. Predicting each model's performance for every request +2. Dynamically routing requests to the most suitable model +3. Aiming for the desired response at the lowest cost + +Intelligent prompt routing streamlines AI model management, potentially improving both quality and cost-effectiveness of responses. + +For more detailed information about prompt routing, refer to the [Amazon Bedrock documentation](https://docs.aws.amazon.com/bedrock/latest/userguide/prompt-routing.html). ```ts const variant = PromptVariant.text({ @@ -759,7 +839,6 @@ You can create a Prompt version by using the `PromptVersion` class or by using t on a `Prompt` object. It is recommended to use the `.createVersion(..)` method. It uses a hash based mechanism to update the version whenever a certain configuration property changes. - ```ts new PromptVersion(prompt1, 'my first version'); ``` @@ -772,10 +851,22 @@ prompt1.createVersion('my first version'); ## System defined inference profiles -You can build a CrossRegionInferenceProfile using a system defined inference profile. The inference profile will route requests to the Regions defined in the cross region (system-defined) inference profile that you choose. You can find the system defined inference profiles by navigating to your console (Amazon Bedrock -> Cross-region inference) or programmatically, for instance using [boto3](https://boto3.amazonaws.com/v1/documentation/api/latest/reference/services/bedrock/client/list_inference_profiles.html). +You can build a CrossRegionInferenceProfile using a system-defined inference profile. This profile routes requests to Regions specified in +the chosen cross-region (system-defined) inference profile. + +To find system-defined inference profiles: -Before using creating a CrossRegionInferenceProfile, ensure that you have access to the models and regions defined in the inference profiles. For instance, if you see the system defined inference profile "us.anthropic.claude-3-5-sonnet-20241022-v2:0" defined in your region, the table mentions that inference requests will be routed to US East (Virginia) us-east-1, US East (Ohio) us-east-2 and US West (Oregon) us-west-2. Thus, you need to have model access enabled in those regions for the model `anthropic.claude-3-5-sonnet-20241022-v2:0`. You can then create the CrossRegionInferenceProfile as follows: +1. Navigate to your console (Amazon Bedrock -> Cross-region inference) +2. Use programmatic methods, e.g., [boto3's list_inference_profiles](https://boto3.amazonaws.com/v1/documentation/api/latest/reference/services/bedrock/client/list_inference_profiles.html) +Before creating a CrossRegionInferenceProfile: + +1. Ensure access to models and regions defined in the inference profiles +2. For example, if "us.anthropic.claude-3-5-sonnet-20241022-v2:0" is defined in your region: + - Requests route to: US East (Virginia) us-east-1, US East (Ohio) us-east-2, US West (Oregon) us-west-2 + - Enable model access in these regions for `anthropic.claude-3-5-sonnet-20241022-v2:0` + +After confirming access, you can create the CrossRegionInferenceProfile as needed. ```ts const cris = bedrock.CrossRegionInferenceProfile.fromConfig({ @@ -784,14 +875,25 @@ const cris = bedrock.CrossRegionInferenceProfile.fromConfig({ }); ``` - ## Application inference profile -You can create an application inference profile with one or more Regions to track usage and costs when invoking a model. +Create an application inference profile to track usage and costs when invoking a model across one or more Regions. -To create an application inference profile for one Region, specify a foundation model. Usage and costs for requests made to that Region with that model will be tracked. +For a single Region: -To create an application inference profile for multiple Regions, specify a cross region (system-defined) inference profile. The inference profile will route requests to the Regions defined in the cross region (system-defined) inference profile that you choose. Usage and costs for requests made to the Regions in the inference profile will be tracked. You can find the system defined inference profiles by navigating to your console (Amazon Bedrock -> Cross-region inference) or programmatically, for instance using [boto3](https://boto3.amazonaws.com/v1/documentation/api/latest/reference/services/bedrock/client/list_inference_profiles.html): +1. Specify a foundation model +2. Usage and costs for requests to that Region with that model will be tracked + +For multiple Regions: + +1. Specify a cross-region (system-defined) inference profile +2. Requests route to Regions defined in the chosen cross-region profile +3. Usage and costs for requests to these Regions are tracked + +Find system-defined inference profiles: + +1. Navigate to your console: Amazon Bedrock -> Cross-region inference +2. Use programmatic methods, e.g., [boto3's list_inference_profiles](https://boto3.amazonaws.com/v1/documentation/api/latest/reference/services/bedrock/client/list_inference_profiles.html) ``` bedrock = session.client("bedrock", region_name="us-east-1") @@ -823,7 +925,6 @@ You can restrict to specific resources by applying "Resources" tag in the IAM po "Resource": ["arn:aws:bedrock:*:*:application-inference-profile/*"] ``` - ```ts // Create an application inference profile for one Region // You can use the 'bedrock.BedrockFoundationModel' or pass the arn as a string @@ -876,6 +977,7 @@ RFC pull request): ### What are we launching today? We are excited to announce the launch of our new L2 construct for Amazon Bedrock. This construct includes several key features: + - Bedrock Agent: A core component for managing and orchestrating Bedrock resources. - Knowledge Base: A repository for storing and managing knowledge assets. - Guardrails: Mechanisms to ensure safe and compliant use of Bedrock services. @@ -884,8 +986,8 @@ We are excited to announce the launch of our new L2 construct for Amazon Bedrock ### Why should I use this feature? -This L2 construct for Amazon Bedrock enables the creation of multiple features with minimal code, adhering to AWS best practices. It facilitates seamless integration of existing features, for example, allowing users to bring their own vector store and associate it with the knowledge base. - +This L2 construct for Amazon Bedrock enables the creation of multiple features with minimal code, adhering to AWS best practices. +It facilitates seamless integration of existing features, e.g, allowing users to bring their own vector store and associate it with the knowledge base. ## Internal FAQ @@ -898,22 +1000,30 @@ This L2 construct for Amazon Bedrock enables the creation of multiple features w ### Why are we doing this? -The Bedrock L2 construct is currently open-sourced in the [generative-ai-cdk-constructs](https://github.com/awslabs/generative-ai-cdk-constructs/blob/main/src/cdk-lib/bedrock/README.md) repository. This construct is one of the most widely used and highly appreciated in the repository, with nearly 1,500 active AWS accounts leveraging it. It has been downloaded over 300,000 times from npm and PyPI libraries. Popular tools and libraries utilizing this Bedrock construct include: +The Bedrock L2 construct, currently open-sourced in the [generative-ai-cdk-constructs](https://github.com/awslabs/generative-ai-cdk-constructs/blob/main/src/cdk-lib/bedrock/README.md) +repository, is widely used and appreciated: + +- Nearly 1,500 active AWS accounts use it +- Over 300,000 downloads from npm and PyPI libraries + +Popular tools using this construct include: + - Lambda PowerTools: [Documentation](https://docs.powertools.aws.dev/lambda/python/latest/core/event_handler/bedrock_agents/#using-aws-cloud-developer-kit-cdk) - Claude Chatbot: [GitHub Repository](https://github.com/aws-samples/bedrock-claude-chat) -The construct has received numerous positive testimonials from customers. Inclusion in the official CDK repository will facilitate scaling this construct, enabling it to serve multiple customers more effectively. - +The construct has received positive customer testimonials. Including it in the official CDK repository will help scale and serve customers +more effectively. ### Why should we _not_ do this? -The construct is published via the [generative-ai-cdk-constructs](https://github.com/awslabs/generative-ai-cdk-constructs/blob/main/src/cdk-lib/bedrock/README.md) repository. However, due to the increasing demands and expanding use cases, maintaining it within this repository has become challenging. - +The construct is currently in the [generative-ai-cdk-constructs](https://github.com/awslabs/generative-ai-cdk-constructs/blob/main/src/cdk-lib/bedrock/README.md) +repository. However, increasing demands and expanding use cases make maintenance challenging within this repository. ### What is the technical solution (design) of this feature? - -This construct library includes CloudFormation L1 resources for deploying Bedrock features. It provides interfaces for Agent, Guardrails, Knowledge Base, and Prompt, among others. Detailed [API documentation](https://github.com/awslabs/generative-ai-cdk-constructs/blob/main/apidocs/namespaces/bedrock/README.md#interfaces) is available here. +This construct library includes CloudFormation L1 resources for Bedrock features. It provides interfaces for Agent, Guardrails, Knowledge +Base, and Prompt, among others. Detailed [API documentation](https://github.com/awslabs/generative-ai-cdk-constructs/blob/main/apidocs/namespaces/bedrock/README.md#interfaces) +is available. ## Interfaces @@ -1017,7 +1127,6 @@ This construct library includes CloudFormation L1 resources for deploying Bedroc - [Topic](https://github.com/awslabs/generative-ai-cdk-constructs/blob/main/apidocs/namespaces/bedrock/classes/Topic.md) - [WebCrawlerDataSource](https://github.com/awslabs/generative-ai-cdk-constructs/blob/main/apidocs/namespaces/bedrock/classes/WebCrawlerDataSource.md) - ## Enumerations - [AgentStepType](https://github.com/awslabs/generative-ai-cdk-constructs/blob/main/apidocs/namespaces/bedrock/enumerations/AgentStepType.md) @@ -1041,8 +1150,6 @@ This construct library includes CloudFormation L1 resources for deploying Bedroc - [SharePointObjectType](https://github.com/awslabs/generative-ai-cdk-constructs/blob/main/apidocs/namespaces/bedrock/enumerations/SharePointObjectType.md) - [TransformationStep](https://github.com/awslabs/generative-ai-cdk-constructs/blob/main/apidocs/namespaces/bedrock/enumerations/TransformationStep.md) - - ### Is this a breaking change? No. @@ -1057,12 +1164,13 @@ The Knowledge Base vector stores (OpenSearch and Aurora clusters) utilize custom ### What is the high-level project plan? -The construct has been published and is open-sourced in this [repository](https://github.com/awslabs/generative-ai-cdk-constructs/), where we continuously gather feedback from users. It also includes a metrics dashboard to measure usage. +The construct is published and open-sourced in this [repository](https://github.com/awslabs/generative-ai-cdk-constructs/). We: + +1. Continuously gather user feedback +2. Maintain a metrics dashboard to measure usage ### Are there any open issues that need to be addressed later? While there are no major issues, all the latest requested open issues are tracked [here](https://github.com/awslabs/generative-ai-cdk-constructs/issues). ## Appendix - - From 01e92491bc202e0794fd6d679559a52e7cd17928 Mon Sep 17 00:00:00 2001 From: dinsajwa Date: Wed, 12 Feb 2025 18:40:21 -0500 Subject: [PATCH 5/9] removed unwanted code --- text/0686-bedrock-l2-construct.md | 2 -- 1 file changed, 2 deletions(-) diff --git a/text/0686-bedrock-l2-construct.md b/text/0686-bedrock-l2-construct.md index d4121b725..5d4373677 100644 --- a/text/0686-bedrock-l2-construct.md +++ b/text/0686-bedrock-l2-construct.md @@ -209,8 +209,6 @@ include Amazon S3 buckets, Web Crawlers, SharePoint sites, Salesforce instances, `kb.addSalesforceDataSource(..)`. ```ts -const app = new cdk.App(); -const stack = new cdk.Stack(app, 'aws-cdk-bedrock-data-sources-integ-test'); const kb = new KnowledgeBase(stack, 'MyKnowledgeBase', { name: 'MyKnowledgeBase', From 1973f90733f01eb03c7c68ab14d84c48ec92d7a6 Mon Sep 17 00:00:00 2001 From: dinsajwa Date: Wed, 12 Feb 2025 19:15:43 -0500 Subject: [PATCH 6/9] added kb design --- images/bedrockKnowledgebase.png | Bin 0 -> 152851 bytes text/0686-bedrock-l2-construct.md | 12 ++++++++++-- 2 files changed, 10 insertions(+), 2 deletions(-) create mode 100644 images/bedrockKnowledgebase.png diff --git a/images/bedrockKnowledgebase.png b/images/bedrockKnowledgebase.png new file mode 100644 index 0000000000000000000000000000000000000000..59581e381958d7671b64f3e67089f8db4b81d495 GIT binary patch literal 152851 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

w4o|hJYhEOyK3gpzY7aQ~FO|rB;pgr*cW` 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

$hC#_1Z7|X3W`-Gou5Y2uJj^z4 z%1^e6OyYHRsa=bhj!mnvI0hIG+8Gkqym#lwdhSJ##ITsm#g|MSX4V&N!^--APR}(W z6cNG=a=8>CSp22EYEzp8ne*|;NaKr3OV5&2BSuBD4u@uipqz16@}a3bzaxV*r3#3C z>jjdA^!{=uSr>!*c?;Ip+Nx)0!qQ9aI|biE9>SiH5cfM5X$MB`je$5x>SzLJ`AFn? zE>bQ0`gbK1L#WH-Jfz#o!2T9r-#d69$Po=}<7PtABgh1_$>(Vju^s%Lx1 ztN)vEjYb0pY(pVYx}%9$4C)+GDhQ+29bN*?koXzR>B7ufA5j4@PHZl-jlWc{(b>H`<3Cy zMEgn{Xo5#Nb@y>e_5qnUG8ovPGs)@d!dUR1rCwk7w;@8YV82(m!F)YY>Mc|Hv1&JO1UoG!Hsg~%pt zb;slNhOSJY`=e7>0|bKHqk5;i@reHlg0yhJTN)65=JJ0no4*7m6g0H%jslJTAz+^K zOQTqF==NqR$L$URwbUi(S@nx+2DS6>#L!T;p@>Mj!GoFZXeP6+zqlj}+yH>oJJ-Ma zH~iOdxIc3BzPV2bAduShpy0Tq<9Y?WK|o~{*8c(o6TpFXW_>OB>^ET6teQ_hSO;EM z(A{!GtLD?j$VF$kn|TcoiRaWnUFf8_83l-IkZ=R9i=qNx2Y8=eg8VC=cqkt={_J7d zKbntllhB(tFJ62@tWSU=fldo@YB+>4V{+jZbg;l%mft;16Kl)@J=D<4W4r>-Nwe|& zGQBkOp$5C1v?uA{j+VV86(QbSjMN z20;4)xgZrbBeUOv>i|w`03O$W=^-EQ~+-BBxGmXiUaAFi2doA6BO zD}{%hIY8RONEHhXLjY4RnRhJ%3M{fxih!@&3Q)_afQ@EQSuf-f>=`N0$~eu)=HDv> zntBm&J*6nqo7qI1zXL9=hFbqi^U3C3YLPkX)xC4kq9b2pn?B`kPR7^IOcM>AP&N(PR+?#vHo zyE?$1l>N9gjDl`(Oou5AovcP4(C|+V0hTqOVNsu({xGNul(A?d*#le% zkhN>Hv;+_?8jg(iu6|`e8#POY5E?%;1RxO~NX9ZSV;KSoE|J&~J!F8(qg0?yc6mHB zU^a7HSfA5o981@ekT@Pe;}u!{EF!EA!%Oomm0YbITi6n4HIh$NU{bmIvl{l8ojnS0 zJW($-vjKu%R^Us*480u%P1lD3j`jxb*=~J0pr8KLLa!6g4@SAK$G}|vC7yt3jt}43 zl?lwNSU6$6rX8{ZRFH_`_QQN~+R!$P(?HB_b(+KETT>l?f zT%`e{oL?8B9bQJS=DXGHrg9S(DUcmy4=t6wti~;;QdtgbR0cY_W5V76G9_Y2$cq?{_Vjea6p@y1~kTDW)n6Mn`0Kj z)~zf09PypHK6MMmN+)D|BWZ(0>Z(U!EEQ(llAw}NsLc8w)GlDUuy_@FqM7hys&WrE ztHyrVTai!z5gs7;OiWC`_B!^`3|pAuzdaudir-;<2>1uImI&zrY1VM2bOy615#R-v zo2p0??o2(pA{=_|L(~FVv%kYA*o=REf!&U$e~itT5C#R*K&tm(>+r?;K>bVS&z!W% zV2Z##&jw7kA0{JkTC3wFH@Qq3vV-k`k|$fcGhQz7;)$L53bvpdpjWM<#0P*s;M@PD zFNv3gv~I?k19)eLLbbGoE5SW)x&6^?*LAw#HlffY;cN_cgA zq1r3CTWuN1ZQ6-#Xx+cu(47EEYw?l1tK6&KfU{8{;gVV7e7@iCWDJnbKL~CZ8O1(C zK!9r7uw`Rw{};*wnkmBvwR7x8cOjaT^BWtT$#imJH7HM?-0%CO!Z1-`p+CLb|IL&; zq~(5{ge0DeXka^r4O~ZG4tq*v3P6r;a)JPMR;*A=Xg=4F6d3`apQvPz9h`1LHgyZ! zAm0Ekpb>>J5zrqoByw5FJ@f=NVFh8pG0+Pcne5r1QH2@bW%;@I4;ejJDprh}lgkrH z5Tm3KbgnK>Q_iS!YV;N2T4S|TT8e|B;9`q zgT;+}_$^8CaLSCuHafW=0*7H|iWsSXz}=AjY^NSCdy@UfC^r$XSEK^NG^i}nd~+qu zV$SdfXh@gW13r%S54)Y<{B^U|+bKvXznDK9WR=YWU5Ic&#*Vn7J?J3PPDj`?{d{YvH}>m ziVf)HrqYzlYFJ@xMuk}tktTV$d@dpbZg)4&6nYlQRZabVmP0W=WBk1CijOnik?&|m z%Hdr@^qFxZ52de70aFd4jB^+auM;Xrk0eZk$C}7(qe(-K&wfdC<$kTL?5|hhd_fOj zMma5-oN~-LUnnIvx>UJVrKmk$bp}|<(;!RY{V$FuIZq~@F6t($R<^2i!C~$=H4TvN zoTumgAV-5sx1T?PufCENC{ex_I%Bnc8Y}ctzUYcPDyOvT4~p?+g0PJ*&2K8WJ4I|>z?Arpt3&BTnKS^Q|2DyBp!<`0Z@@5*%O6a*`I4AHOyw| z3;i!pM_K0&+Ld&nxytzCK7hrC5WkgO!)3qweKQv*)g7aO#*6eFwfsi|Al7_nl4CY8 zZ+@g#O}hbz%If8=I9tN#MXUTjB$`UEUP6+>?4@33bc<(Rpho%TuTJ@jABgdbN3 z>m@I7nUc0(in{lBn0Eza%cyx*o?_C!_if9^{|C?|XcdUpM%l!@w5YA?1CqFjAL5`M zoE*%YQ)l;q9e2 z8u*G!w}4MxAeLBA`GHD0PBZf1!-ta{9c|S%I685qk-Yg(*MZq@yLmw&8jCF^?~Cdb zGHOgr0kN?ATr;v#IV%HLK1@)j?UX+*%6Gm{U-0Ep-t(Ebxw^~db9Uw{-T;c_w;W?t zmTYj_iec+hc74j{1o;_TpK1pH zy?vjvoBUczTux!6<0|e@&FBDhy&wMR5B>d#x{AX%vYML4=)YTfCbi&qsaTG;g5vJ@2U~b}2I*xF{Mk2~Jm%zrUy!Mm)Fm^# zbV~t&%OTY1kDipmKd`P~GUe`-&9YTfS}QkNU2JPKuW7I(S?o`h7Ond4N(H@Dy#!~j z$a9ic|NUh#B{3wB$XPDtL481KFrSG?8ZJ<-Rh0X5`RhqX*oBJcD5%k+-`!57ZHG79 zULRG;X|00j??~|!oGtQZ4f2#ATZy>gwCOrfhTE1%UYyN#XDr`cnikE8tz63YK-4z{ zOf=B~+`thGvQ&2hVZGdMkx(yJG%|m^yWHuuF_7K>wXUf6t%;Wl;xs;Ge0@v>O3dWk zg89-wjf(TWShgg<4HOw2C@(kP99%2VNaTw9jNo{8^9L!@@g*%V7YBB4F|^^PzK#sy zqzYgyLWC)!efnKpg_WD)fJS&UFY%R2>N4pew2FA?a%rhvvY0X%XHkS|N|9$fo0Okk z%JTk;@*m_(lnRQRbv$oNHt4{5Q5JIePD|1~1+b^Ga-l%5EBjuy@s> zDp7DZtg@G7Ci^$q3UI&~Ck+^>Ozqf!Gzs7#tP}t0fQT9>6Zs1?>@`ub^q9HqMkuGO z@2+j=D%JAOR6yd{?CtBGkCqXsf{iQ0v|bMWXSfthIA5I3CNI^8Un7$N{+DpBN)dK} zR;^FEJg2gU)a5B*w_hKV83_Af8D&((Gr8zCL4N?Exv8#L=kd#q#$#$+I^ z*0sRkhxxj7fz@bVT!3vNS*642q}thnnfC4)@Q>WM+G~VJFW>s4^(QH?^B9iW*uUh* zvj91dmsk|z!KXY>2CO;N7;VdY4&&cgCnz0dBwY)aCsWi9%Xl-&N2&hS*(_251kKNT zLTv~LTNK+ZK}jVq+H^1_JRIni^cUHNfhQHvRo^@EstdyvdASkIrhOek4Wuc{DvB zF<&8Bmbv4Ttuf$MWXl>W1y!$Uy?cJd=6mkLYA>FK0&Z1g88SBJIv4M_jL zW&WGCso$c#9o`=`SI?W!)et>DCfb4@?XQyPf6>q|V~+JadZyZ2$2%I~I#ajgsIR6I?B>`yb2;E?geWf8LYXC>Z(Q z$-@TM(9l3L9>|Z_M(r%rW+|=fu^#KI9aXi4jN3S?M zt9-`b57+wdJiNVs4T0&hH!)FWM0B8s_L5S2PF@OVXQ6BtEdYjX6x!o#-Pc(@>~OBG zu6USKGMWKYAz=)U6c3|Tv7DnUyK^X*RxCCZ_RDRxmygZ8^JBihmc1@A=$hBGMBT*% zFzWmh53tS30E^WX0hwpi%*^hU$yahvmW^{DT+|hM2&xr-o`FJ8tm zI!B^gihTUxY-7G@hx`q$mzkPfN!o!EWNQj7^dvJK~tP?>d zm8P#^rql)7TK%DZzN=5a;DrGA#VtKx?p`k=t_Y7Tyk+xgw}B&I^EziMr`3>PTo^J`_v-~p8@iS{xwO2wvl+YX0Kyd-e6FrTR~OYV7(a6jfQh|rfz>Y-=q>d{e+j0vInT(+ADLE%IK(!ra#1dilNju1y*?tCG|h^L5d!`H+DTM<-uaJbUF zNUt2qKootjuu}CkBMLiqhMO}ySa&Ci?Mb=?J^|b+q5|0&}Gj@CA#XRoKIRV$Y&GB@<| zDV7A6QoEA-?mGAgNu}LS{4=??EAy$&hP&l0z9M7O_TP3xik(d%VqK%=dHRU^`^@7G z*rgb6aQ-ZWCPohsBFWzq#h@|q*P=@mU3I{Rux@h*QM<-GPe|kf0-@>s)F%B(;F6&;{Qu z3AKwV!?<4kL${A}dZwM^?>dF-FHFliy#k33l5l2H2HX;eQz{zq5s}ZitT>sG(0m-= z&P)9rR&npcm74;Q&Mz)94DJlPE~?rgVbTsckGR54sZOJMSZ}JX@q-XFzF~)5ZFk1- z_9VS|W9Y0i<>kftXIx2}k}%siwN>NArSoIV`WL&$QRe}7h&oGIk+<8H_u^5;jPqb_1k@l)<$4N@M>)fHi&*a{@gYwb}{b~m1m%7~Y+K$#U zbM%b~!CmV33ID<8q%trK_@sSL8U8*EH7rC3XDM2##MP{GE!GTMZO)^dtnpWzQCV_n zVSWHXtAo74tjpoDc-!M=jCB$zh$Uvw-wU)r7F(ht{gu_wY1Uw`(+8QZFQ&Hv7NsUA z6Hq{BVKc$Zty+Pe{OC|Ef5r%4q4uMJAa3C?kd^;MZeZXRpej#ik&u7&zOcK_+o>bT zY}G-rm)jH93RBH^FF~we(wU)#{lloaW~M5P(AV^hMtz@<{`O16Fy{OBTOI=CbMLL2 zTO?6XRV_QfEnVibH9nSwZK)gvEAlz-hLH$JGHHZ6aBNN8K ziP>#J@{$>U$OAyS5x5aD_0%S9=0}7Hkwcm%a(i2Uq{{hct8*8GySBb4p(eZNX!0ym zrHM_@dHH~V!&%{Rh9%<6pI)zF4`rxk(n${|u31T()~W zu~~|yp=GzahgxzO*QxQ-sATZylhCCQ{@-~ih6v7LDMWib)4x;Qujvtya|nfenoycg zgt>F$AxlC5sXg}y7eT5IEx7}u#|x2Q;@uZ>6AR2D>|m3Dqnc;lt$5FYt}Ld0)`i^B zcwY0EXhxM~0sz~R7uQUWMq=Cix|8z_{%Z(R_(e#q~|CAXAzb#Pd=c?uEX z^LuPO{&t9MK9XkORG3px`j_#`kWTWnc3r11O2uMpPJot<9M@XErnKGT!QiS^EYA>DQE zKYwiQmylz2az$v-${U6Boh}!Q>5<_tI(+i$j=$hiH|=0S5wSMe8I;-L%;(lP+cDAJ zn$mu~wI-Qof0I-FPR46qHZOiQ!$X#M>oFCd?5clhi489wW#t)|4{GV~ z#d(3}Y;t8&6AD2B=xpW)yooHKQ>?wI)?O8x|wvTlRDCu+tz&WO- zwAA+XBk9-O24&~Jifm6apBZz+VJPA@zL+p||8qV-_n|CkL7Bz*bm%_c(FYgyshC`| z@yjlpo!sdbsh}8jzZ>5fA5{yMp)N9(hsxm8Y$$t=z$pUI6Y!rIlRv+`8l4UdFKYxo z$CydupSj0PN)g;1*}hv@MrlauofBsZCg8T#iLc6P)_)nwM(bGc@V_<%Khpd|D%V-g zp6BX*{nd+UJdoD%z3O91Q7KLT@yFEAE6vp)&V-(~1i^4S|cT$#(y zp6lVstEfvP z+$$~S7LicGy&8+2AK4ER^Y!yMUaS#PSTER@sn&CY));iY5Q~79#UqPhLHx792uNYf zN7tP4B*7PklDpQvQY}6I$B(uOhH;ZEm{%*%eMZIy`=R1fky9pik;-WoZo;e6D^B>I#fSki{+uhy{&VReX3U$2T8qgq+_1inZw)osA5raGB*uCv(3zSdTfBgr6rSz` z)b$C5a5c+*-mr!QeCO#|&QDNDOczQWh(@?;OM_<4I+xgJ4opSH*6=BRyVnapRh zaB3JPNK{sDP~fM7U~W%pXBgT%|2*<7`aI&KFuCy)qJj(D7M!pr(B;T+TL91YH__Fj z1AYB9!&uY@-u@!DOKRri^rV1%ZPr+|8Dr)zcqk0a>y7$Fa5~?0l_RpUSPqt2lRA@2 zoX2T}ZZTFJqnP7+5aeAZWa}i8yg70mqn_wZFt6z{7w1oqO44r`H&}>ZMn+{cavqiN zKV~e?UCZ}1da;_2fx6|u#+T&J(&OM?7s~#bvOtn*IYWB?xkCXK$1{pyBC4&bz;+oF3X} z-W6`jKz)3s{_3yH18oXk6>lQw&Pl~txXbNp|0~C1<6q-RnC*W{OpkHO-&-2VHS*lv z;EuU`y1yT?r*SZFJ%oSPb1RM z7TUjyh8P)%YwHJjPe0~AF91?xZy}YxmH$`wM-oZ3- zVw4eC#H*thK(K4_I|Z#kt&DjUp-rqrVjk=vKR#^`fLO%O`F$;p`#|xTHCfJ|0^nJ- zXJn{wRzWas&xqd9bp~C}BqUVY%pD&eYqrcyOr5{3l~0JLr~G>$M}eL4Q}>jgFmy2s zY-3P^maMXCiCQd|)ndAt3rW%x|9o_E=JjD2ot@FQfhBwo;FLE6nxY$keAkkA2_mRB zE{?K51OCd=U@6X>ZY#jlCV2B=8rWdY91UgNAy;mJ5d-G9i68c6=YB>8(s%$v5&&4z z02?zJ7IyM>SPwDu`6g@Fx_T!*H`&I1!oY>}*z1^%xuq5WEG3gDB&M_c-A=inUZ($f z+gK(EtoFptEk?&QTw~ZIRT{hXF+4kZEJFzq3R+%DI^unU0q=>F@X9u36&Uh?Bv~ZJ zAK{M?5mNw_K)%h-mKu=7?Z_AHLd&)Srt*B^CT1G%f@{{GVvCR7pb@GfVN8^a`sa~> zN23A=Qv+R6iw&TsWMQWVk4;U|G&ePM@wyhtKJ!-I$}$1-dZq!~W#n05Uj3uV(1FuK zy;J1mnmj26vx+0QdFUlHYL?LA>g^Kv&Mn`v|tjj->96u&#& z$Y#_hQ_&Z!7%7Arses9s63oAwk1aegF>p;VB0K^A_S5oqOkda6b-tg`g#l}R`RPa* z5|Q5;E;pS36Z;!k32u?;V5?q1t@X+^E)o6%PXQ&g5F*SACujI%HfuM@3*3&m6C*Y5 zi3YJyQf+w_gv);y9cqe$zXz6(k9%Fr{^Kr^3cu@bF7i98(b4+Xhlku24{C8!pAJw@ zBIavU#!UXm(XYH~Y7!_{u27<}pw;A}ctSKQtwsR&lyni-F)Yc0M#<$VidjJlXS+{; z%Oe?`SLyHez((o`KqXMTyDd3r9fR6$pO8`(s10>)Vs9t_C8v?=`lMvt6Oa zTc8I#xFVDZEarabHtQ>omKh1!G8lly$LPwBp3d+nm|c)rHR@;9*H;*xY{1?JVsVFS z^m)`ITfPae15dA9S));!hNl@je|ZpozWapSrBwBf*aUN(k+!=NWs&MXsIykd&Lnpu z%~UF72(mq6r3b1Zf2B?OS_7fLAVvx}LsH<0a&^|dvM($sD}AAe6`BWO(53r{8kxVp zK2uAhRc-yo7X)QVwV5@!S8O^?{$M(B;xmofrhX#x=;`)%yPe#PU!b+-MOR=A1hEi$ zAd@l)Vlxb&binzsyzPQ<0jwoxS4%}UWRtYig6kuIepA```rOrNg!+NUXJPloDV0O{ zNPeBo!`8V4x9oSru(P)1ebp_!-&Vj5kY@3#TEi3R&(fZzXksF+cA!&HaV6R4 zD${HgeFhPE;akfVbjQZ_DE5Kc0e&l;Z`9s4@am>((+PYoovm78{ljcR^YASB!?T3O zJEV%LX_>22bEt#VaKV%u;HuGs;q&IZTz`+zHb0Q=rU2ZnsNc8K=hyK_(Ls9BfnpXo z0vL66ck5}|toG^5_lUG? zdNt$;32`6qx2M}A6As}(c>vppI{7fH|0W^MXUucjSrc5i0pE^a=(9)tuD zRHqJ`6^$0&;7D|RkTZ__D!kV17&6;ct>0-Rcixaag|Q1FE+L@EQzAW^uHM3KAgie- z5!4>&k&MiR`8tPqT&)CnUyr)y?i6{Q8VH|Bk=pbn--$A4o~JrqZah<-s;D0ZNkJo} z21iz!GCD_Zzxu`V2H+jN!upO0tQy$?#Y1rzuzP+e$Tm=6Fw|Qvgvsgir%#1sOl3%_ zC>V6{%v~>|^&Wk!rw_#do+{g!3cg zeu{~+=9#nzC(K=aA^}T#n8xrcl7-iY&9uHURYd1#U7hjgGYLo;8Pk}|p)g1x;LBYW zp4o!!-#12Z#eQbryv^i=R=wLsq|W!^s{t~ikz{&crhpbRcvS@ZVNl~+`ML^Mvqa~I zp>KJBwf%Nt{XE}w;V1XWdV2Mb!{x1_N?Q5vKIM9W&(AhfUq@Sv6&6B%e%c;KMJ_#) zIsmBmBhGMOSwMThIpW-ThV>c~b-&!)qPBnqn}h;^2+BwNBL%(Fq77-S@8XncF~@??uv z@EeMDCk@V*NZOf#t=(}e=`j$Shec0$L?aI)n^f0ireep_Ni*uqZnFGv3T56BYwEaW z7dYAvJMEo#-L*v;S9(CAI4rc)fXS?abew*fcBH4?39ZB&=sF3+MoEuJ=eo5hZu$z)DLZlI{$#@Je>oUMOFLNvkH?dZp{V66Xr;>r*yW zvI>?XtsODB1oiUWmNTpT&G7@Dr>!;!BPNM6Lwvt{3FwDY+Z|Gchj{DUqFmJg`anik5mOB=a z=G-oh&`=onMd2`XiitK}?`bT_86xOKa4qK2ABnlcL%*701w4r?6Yv*V{>%sgOLS1~ zixtwVm40ez5#baAfLv&?pC-Ph0z%Qt(jUWOAQN%4_S6BWygW&%i~8J-2OQN&XdVGU zh1ZInt9fF!Y|VMryOuQq>nC3$ga~l%BJ~pOFORKkm)hCQ&8dMBhi6Yt6tMX;CVHHf zLtjl=AGQbLXAbuAY_#=V92u2oB<7{*_0n`c<2C>v(6GI+3|3f}bEqQR9_|TX6XgNu zZn;=$CiMa5BOrsw!A{j9q{c~3(+mf$f@<~HkCo*mKF(Z*^Wor-i5#uY?PN^LAdn0 zqcB4~WKGHYLj5J9==UIiMpUhkp;?O_PSLkB#a}puIb>jJ{=`k_@M0phwaX_;K*)(=6B%k0FJjF5KKq$pLubv+A;GlKclk=mjvK*%G5| zZI1F=PNwUiGhEcxE<<7@aHz8eJ5NL0elBq+HQ8*!j1i_UsXUQWrrkcV)u5^P-CiDz zBEoyMI(SNmquS?2*Y^YwTOv-Syw>`S5Zx&akICdUJ|uWdkB*Lxybz;&=adLDA9Iyy z*-x!Et*aW9AEke7`q4F$GZ~P8F@(hsdk$xxgbI2fKF zLU?7TKWER~k`TXt!6o{1YH-yk**uHkZkj!WF1j~)HLs{4-9@K{E;{03C<}F{2h1hH zd}h;)%rVVP_}YcNjifR*6cXdpNZ0!F>J54d7u_3TA+@182T{U{3xB5BF&sT0 z_ZS@YM>5&BqY#_`H#z}&*xi68is}J7?w$Vrh8dB-Bt^iMQ}M@f@if?s+?M^2{MCa# zOZDVrokdAHo0g}7^1BqdXi2yemXIcJ?Cfy$`pUMemnSK0jk@?7 z&lhb`PgQ=L5g?A~S3cQ1QC?~<=y`Qf zW4Hr++U`vXY$ole@?AD0*}bMdO}ywgCv6xJ8VA39EjM9GU^yrFdE)TLuB_fap)-sW5BaQYs510dAUs>b1pN!Ivj9#fd>X zpXwsew#4I?-do_m=f3|`Qb+_c^nYtgApcq4Nk|clS~W0OqNPF_aAQ8zgImSg=WR9& zNly@<6d$?7SM>`D5wH&^H&(_aqk5DdBze4>Dp7)uDc84YWbP6s~dI?O=g^wXv z_C@pzjDr}cAdT#aYFT>5QPS@4t?kKf93eVizr&DW^5 zW>AD|m|h;YnG9$1nH((25=6=I-~1qB`Y^xT`MxG`v8_99=c4B5d`Y_GyF()6))!80 z&}pw%_~mxhO&}3JYFGE|=2Gylt>B2>P%=)erJy|_a_XM#i8(UQb7DdVtu8>}djl+N zHSBDGnR!r2UZsu;y9QnBif(%VMefHL%JUZia(6dpOqX#f{MItgUmK442sshjPgp7x z+Lgmr=HodE1_yow9$^S;MYQ!vHntrqlBSR4otgPDq;s~nG9aD5hMl%IYr%bu12%o9 z3bTot7DwwRQFeR6vp=S~8*a4VgM$BTBg9BZ`_g(CKlK%%oAG=wyl&ucm?aEh{pYHp zg^j@CH^AlUlw$g27tvRgMHcCen=$v78w@S#$8-t#Oc?K2@@V|5Gu6wTQr5fhewFrV z^Z=4edMmPQ{*(f1=irga$e{oU2gG;rw=(i4ZVItJa5|w2tVab!e1u1|jyhTGjiCruGe^|F*8^>Rf98c?0g@3rnBEom@irdN~YqK2p-auIN2J zZ+FqcE-H?_&5^v#;hgliX!z$6#u#pCMtuo#(M)$)yN!+65@49RGe`5)@@wqfATCF} zc9m~ZH6i+jX-EV?b>CgpoFON13K9KWzL~MsPsDTyu3gHTuN9w6Z2*JBcvsK|+@j%x zI~DqKPKBt$hn>Jum4DG|{Bvw=!s~j3Xw#!vdd)rIJijWAY+~CBs2LagOkMst%Zh%AS=sOBm?RL<&CJk7%Rk<9X5WMwDJSbh~4RPnsIA^#qxs*OXV zz)GS_xasp#8*Ar)X3F5hO#-)RcF3ocUk@-WW#=otE=y2T?Rl?QflHQ6ayPKtcdiqP z1E%ABb2DShc=u~ofGUI@mCNJl*Ci_G#wtKT+z^-Y1xqKiUl8G7L@Br-4(`Nc_Jw^6 zyR?*)+2FU_3PJ1r`4=O=Hlvmxqm?POc4hYI!<+s2RPPs7+_}2pLm44_`hIOINB#DS zvb-bh85m>UnX1DeALC3(f=>#JU;~=F^&xeae^DrBO3Jo-G&7N&6X6*1k=79xlSib6r{5THOS{#IES$b(=(^a(-=|HUI3 zPp)O7`MC4y68QV;Krv>qpGX*8v*$i5h;!J|@nL_o%IINg z2bS-jU&s?CGK|D3mWCWDL;wv9@fU`cMNM1 zWTr1C`gp3%XYSV4$U#}N4V)N_5zr3~e8IkTm*|A4mLs49FKCPbKm)T6^vatE!pq&n z%!D|wfvEx4bT2=A$sNXUnZm%&9aQ}IXP&`gSPH|8hS!GNNraLLI|3b8HPvq9=+eWF zr(CH-fC3cw{H5^!10Q}zXiqvlg4|EwR{sw|+&TDbjClU2hb`sas2YT&aYq_l3g z6QKhm1y`9^btd$Unv7Eb?}FoFCTGmUD#5?627Tjs0G7o!v~^mP41TYIZ}(WyN7>EE z1h#CZo4Yf$s5J#0nD--+104~i<~|u{tv3G@wyxI=UX*t~$FqOUCrt}S{zv~TO*1c; zPjV!dyVGj6t361{xk?vu=-h9t+nby}@6C!u^1Ho>WH+sVFK?CrFWM{#b0&X9oLINM z^RP|7A8?6+S~v=*sZ*=289!5G=|kTaO%?n$DEV7$17R>o@aVAg10TKP-y>;by1aH= ze*A{~g)oT+76nYV9_Td5gX&W4fx7s~s0LFGU?8e6sP0Sp9X@XDtFbdr11DY4tjk%8 z00G}GDLC>FR`~q=HU@RaI4nmta$DQ(g#h(Z;ZETNNXwMl_o!l@G)}%Y+P9V**EcVNi|b zgQM<|(n{Baa(7g4Zkds64c%_#1u(f&G@q_gsNeU*m3ag?Tzy56A%qB%3GCi78ZJ#L zD(I!VDkgBi%(KJ*bCZHEFeSze1xa#VoBnw+(r0l^W-f|Mr9aPj2ZrbP&a@RBIy|tj zb&+l;$zQ9`XOXQ6wdx(&`6EJitZe9iL1*L7W#GRq0#M0L1K*AghFsC$Oj?&q z6qEJec)9O?xtgr?^=@WFzfdU_uv7b`!^VGUoX{1q!FU4dfE!z%kH4_zY^^m|(5aFf zG7}4V?RSTTe*DaB7HTpX7*zEVr|b$lhTkVWXPWjpX{BON=SRrvEUyyP@RXhTz8A;< z9uchj&!kN&Q%URl1ki8D!(e8c>_sqVQUmJT3xqt(LOUqccv}%w-{%h$Bl~-dBPEpu z6Tbcq^kca%9KPFy4Yr)AFTCqBh)?R{R@u+Ux0w<4=NnMNq;!7QWq+{faB?z6ltcKM zBM%un_m#@Q<@lJ@h5D>3vED@WrwyZA#Vk&xZzy=%vJ{SULsdM9HoN1|rG2)T)&x3k z(Bmo)pT8(_6!^Q!bkXU4?c#n^k6T9+Ag~>$%ED0v^%A^*45$C%0GWBi&4#eu}Qk z9b-y!4d%nUGgHcEyVAI{K_D2bZ7@aVomQl%OgO1TMh8_O)DHPGg5S+cfjY!e~GVAs$W>an6G)k z!dCR=LHw@U&E<+=(lMu5OqFGQ_-g-Mvg1M9L2VR+a_jWOkd3Uh-WyfABWAzgjwzh3Muz zo~wEH0s8ZZu5eXW1&?T)I(q5(6s>IN27aV_>R3zQcEGm>xd_tT3Wc8Sx3Ht@8bnQ2 zT4YLwp6>W70WE|wu!}|*NTma-8i7t8!F=j8-0`q;ZMaaYF$ZW7bBvN4m6CYQOmzI-w;wBl#D~IeU{L}B z0F>UI*{}9k0skS)&D~m?bsNyf_^lyN39Q@kaKdb{oPTWcTx1y!C^+67Z#4GSY1LL_ z`yi_2*i#YmyQ-Q`lxq8uN`?KPlIQ^LCV7+P$qFD?BTc=^k|XNNn75u;d9J$hZL9eP za#Xl~e%gAS^F><4c%I50-pNko5rC4Tl{&*#QuCcPT+U`x_N^v5vojkmR^Mw`0Ka#` zq-|V@a?o3Ny^R0J!#Ppto7bZ|rNHNr!;3&7D*V-3G`pWaITJ`5)78s2-7)e+#Rb3B zr8TmF93i=Sr(ikIl2ium43D%k{*kh^shWTreuSbH@3Wl247%~;MLy_;a4rRN_R%dx zVGKA^W=Kaf&g4}kPkBc7#Lqv~XN_{X+qUt_2ir09;0gst{)>ZsaN_?dCb~KbRX2w) zISYTut4A3#1vcVHh6rq8R#`42K*apufR7{7iNZEjlChsp`)sv@eE>487m2_p#gdwzOqXF&&UgDUj!GTVH-h^}8s%gVoN=jbU&wBQ*E(0jr}w!g9q&{baQw^NA;`IcBOV?dM59WPsJfg8tR$T~ zyT^}Y%86Lt=z1ELDp;e17z~JD_zQ^t#cCPuvD!?F4j^4?wr1fceeNGLV{0GgT{^( z9a>t(X(MLnQ>d<-eOp;3mzP=mI=u`onOZWLA1COc^YsfnDE3TxQUn)0bGLhJnMNKKX9E^msf` zK_S8y^m*;6EeL$v+D>{xiiE%6ff^h=4ee&sE$&L5Qci~bdp#i>(XSitgV|aA z+9vp}%w88nMCkHZG;qskh$A=F*d_-lLZT9i)KAJ^SuJKe&U>UiU3+lzDv|##I7&2P zrf)1)Jp5VlFn=ST+hXhg!`4?oMcH+21A>60ga}GEBHc(R-61K`-QBHpHzM8AEgjO0 z(j^_z-SwXVpXYtQ@Bh}CHEWg*GxwZ(pMCbe_P(zDv=LkQboFrElfS1+mVfhI_1(pl zWnycimG*_0!9Dc6Lh62N6>H{T_sZRAVPo56Vx%8ES@)$RdvK0ah~wn6d!*!{3g4 zEJu1kB{TGLQiaPb>5Y|Ec-afXSL3m#w=Y6rbjB!dv4zqBY5D27XMeGb`|&T>9h_k* zL$kKlUD^Y-L$}{}LH)X2s9XxHSos%+zb)4!JO|^V{V@8e$X4|^PbbT4Lkpd%2PL|8 zUICW3Ed6pE`E2>M+j3{D?DVOPdqVUOGqA9~A|Kl+}ketMA zimMR))b99z0sd5>s%yMCNaewB8~*3(Sm30Gd5Jh9m8e9l6>3iXy&}ZsV@A6G*Hsr` zv#tHK{v2qouy0BqwO0*Dfc(M;NmwnOi>JFNUk<EN)OLmo?S!^{^7md=+>rU=M#$3BUpR`uX@IqnjcE2%DTP=lEZh|Q!m zW+(Z~%}x~O4dQ~4i467nIn?oQKdh23Ph4dhkL7s)N4o9YP8Ntiww%1liF=)xYcggM zvZrmR63h1U0${TKciqVWf9Ax2*o&Bmqh{HXM3s(jCfpuiv)L07%Sp~$o!A-l>E4@} z1&ot+BY}HiiAtG{cK=MtqK3R%oMa19saRxWq+xWu=XV*%G2kuk6&L00vdRI{U2if< zFZLPwWt1~ImTL-L!o?j&Vk$C9ozy2iWVr*68_Bh*R7iDnbTC;p!E|B%omuDK`tgq* zOUe)N%}W8XW#7&D=GSg#*zz)Oe)a25oyUE2+&-_yfHj924-s6smbmq zn%9|haafv#wqlgI{!F9ZZ1t@$Y4JkMmx%9FL2Vl32o)W#8Uy&GB1V5M$Y~HFNcJ#e zzOtIaVST{uw;|CzSkfPhBDYO%F)NM@6>h=JlsS;A)%szem?cV$AKPF)GhN45c1o*W zmoXK${TzrZw~5t1k{f3;H>n6Sn>y65XSQ~%cO=Xx;_YD1wS98Db^IsOehl;+Dg8djELoV;fKY69>k%!#} zfML7Nj)$ekhMDkYCQ~;TV*d-Cu)A-F&*vvO zNbYZ!1B_F2GFtL+dz+P|+4@rGX-qP=BiGkuvMZ`dXv7*yhU_!VN5fgw$fmzatjdcm zA`p6_1Q`{Irg>C8B{PTVf4!39N{MWtkdtGVG8OKs=&>d1Do!<+b0m#HSUxHWFvq@ySuvFfJ@&sW!io!S!HJuOj#0 zRIB`!L52`XrKq0G-z-fs0z}ZpAcLvLOb3(LJQD`X#r00We3LdEmUpWIYAqoq7BQGg zAV!Tq^q07Sp zxHl)$O1bER%qxs|+6ze_c&Ax(uqO5^Zui!v*P3I*vI?I-eaTlAl6br_~?-_2bM z3RNo-2E-Ds_UO$BT&HWdiVMYg5v4L%>g_f%G+OEUIy>Y?qTk71KK0$Nu|BFiNwaPK zVUsLKCx_6LizOXTm)y0$DkmqmSv4UH^l1kRodEv84|6LBCEh*6m@;%g(vU+%sm;ns zK>vk;$g_?wG+Gx@N%S5i0(AxxS;JKD?mS`sIi+AlGG6wlUzT~!FPvYGJ#GsVYe7SJ z`KAWG@B0jAh~V{&{pPWsfJWNOZkvssXdELrO`XCQn6LKAbp1<_n*uCyw0`L1yPl;*Tq{^qsmb7Z$w;#z$pZeGwQfO#} z`g_hERFk^oPEStW7wxm2fhgvE@S7`gkm)kQSaGF1Wp^((6OM^2DBXGN$*1<-3~D<7 z_WDapw9I!UU!-^iKsuED^-E4R09#SNPsstHa;dA$k+U)&V6?e0l6?N|YMzOCifku>NI@f4^3PG(r0+HRQ4oKEOB;dpvJF`Eg_HIU9WnhG8#jP*F8^^c^B{RC61_ zQc`Njt zMw-w>v7GKtTOw$7SkyfqnI3Y(qJ8RwZwp!$Uk%w1!I4_H;*2;R?f&ye;EY7QGNqcK z*%yepT?g=QCSsgFMMm|76(!<8;K!Ykjfs?fx7HQqK{zz(Bhsh$1H*Yc;zG#bK!hCQkuBmA@Ilk_Av{F$BAb@Xr^n9)*k{ zi)b&XStR#xgQhMXb5*meC7~;h1|!1oYio`$sZVs1_gL#WHUx;=w6S6UtJj1<1voXR z=Sz`VtmP~EcrlSuX(6+Frrfmm?jN$g_m5kCV7#IsnfNhLwfp7jG11LSP67%Fqm#eu z9a9hd8Eudu?~A~KV3ALP%szwb>OfprD}2f2j$#>3e!bZaC|Y`afO8v)MTo#n2F(56 zhqoS))eO#M;xNmu`&E`yq67T*`8J+kDh)pK(a7rMV)rI02csaKLuKJ048BDLMrCmL zxp{+Mb>~!BasYb|J^6R3aR|=;pNA&}6x=Foh$T!+lzCfQTXPG~f!r)wxX|rmPXhKX z@F@^*RhD`q5OoOPv*#$#vtIT;wDb~Ad1-%nz+3uHTnsF5p#S$LVu(V+$iDLkvfveJ z-xXG2JZ6iD#%46|U}s9DwM1115i?_4Y7w5Ckg< z?&bbOpG3L;maiZY4ixTw49qd=D}P52wnU4vv}WZD){`FMW1NIhpD7KZr=@-c3c_nDf}HP(V{4oNgt(7J-J1H0oRj_;xHg=z@GI3v;K z9m)UaX$w=#2d9x49CmqM;v1(~$;Ov1SX2)UJP(asVCjUlKuYZ|n`sIF@JmR=zj5J` z3a?9-PP6IFB`A5vyP1Y&Lr@taeX!sOOi5Enpdkz%#wqjarF3)HkiLp&SeH%ADnZZ@ z7UcK+=i!9}Q;i+5w=l{rE7_DlE)l0&Gm(On3TpF;&aFb&1`uGKKmTc(Jk!|E3dq^2 zB7FL+Pc&lEM+WD-WlEUlU-Nx<5lHE!D3bZB*NBR|emTXJIVQ%m48O`8wA}?-CclP! zFaHuExI`yEGjFhG;bCM2=R%i~tpr#wW;TBP`lU!pN*aFk6E^q(+5GoHoy4H%Z*w#M z*in&d`Xpvqre)2#&e+Ib%Q5}0D@1q=Q*%KL6L_^K{0)xxvz2Yk)2^j0zx$HL!ySS= z6D1(F*x1n3eL*7iHf(Kc%jFlNE{+z~Q9Y~E+xSS?Ne-0({HKD zj?$?6EMjiWU`LwpBCYE3J)@@A4LR^IlkeL6Oxt7=r?UC1zHcdyPi8%d{IICdaUSIe z&-ur1HB^o8k-oij<((d!fv{R;?&V1gf;-2Kg4>1#Y(Kt@Nu#09hdK0?oo3zZ4ljnB zPB>Q3dPer%y)pmOv`oDm+F+sI68KH6Y;$c)Wz1ImY3&lk^bXLyRI?l>Ww+uV>^I6Z6lcWv}9vn}_)TK{P_g=~2($%YpNi&(s9-uhqpi!A~K<@v27CX%IV@-QmO*`FVo%x(q zid#|rFuT--=iyRSxN8R=KG4>9D4k8v&mHtSevI;;k9L|V6{Fs9I#&xxEh@r2yX(v^ zH7=2+W0`YDOaVcH6@}N;sfkq)%kzsRgAM%IYI<9`wui7173N?*iCm<_EE<@Q5#mCq zshXVdyB1O>e%xSvk{6$qRG!?sJz{Yvv{DQfZ482sBR*6xLHD($w<2jDYi(l7T8+_R z`@)A1t~=?Ua1m3Z15?uk8*I3Q4jx_r##;iaw_8J2nC%nEA&c8cNXKC~kM}DS5$XF= zVj&Rf8n&e4g5|uC5Wf1Q#GBaFzYP>EBwjc&XurQF(fUOOudc*1YF=j4Y=|L?gu2B1XQF~iyfn{&6ssye^GNkIlW&v zvIu$Dv?SWct9r`E6X^6=ep*7KpJFx>Z-66!We2YR^VOw17X~m^S>d&3`ed|vT#Mdz zSOkJ16vpsoA@@I|1Oe)cuGM0?$ans}nUDis^nMj1s9>sNquYLo zQoH#rsd{^s! zoq%)3MI%a~@Rp^3YS#Ac@I-!&^`;O>^os|vJhkIG_xAv)iE z1mhao=NesyUO3M_ctuz~XvBa=9V-l?UvXxLWu-lEuI1mq17DCuh8`IcTK4)rOtW$| z?$mnY#0wKBys&tby$}&1|KLu^{Gir+*AEt^x|>i|2Kpk1+m5;uO;U&4?~h{d1q!dR z_uNE_BUY<&h_*kh%w`syC{pm*9#^l#fG#qkJcOU}OnIW^!1=+zl!nkk_jMCHEfjj~ zAj}%N5y0xm!9IKr84=XyFaC^tl5K4U*jH;>)YSB)6fN&^^4)pQAZHb*nFqJ*IP1`^ z1-;tmxu$SK+e3W~69Y>4Ey^GgxfBms6(d4GTqrUSn|*`qYox#Onv#H{8Q~oxHOBo3 z#!rI4f5GvTzA&uj@KuN{d`3n_%4C)4M7p5ekNgL7d&>{i+atWs$%!|F-K=}H_T79& z8qQk<3!FVfxCmAk4ov*|K-h~4w%w4-;@R8}C+5YswsZt6sYo$pwn_h*?2#|+Z@Qg) z<)lP^D2{R;wKc4V(AFEB!pkrS8{HEQnNXwsx)htf_}NE*QVcwTN1a91rp3CyrH})M zAB3?9IPCBh2Ny_$G$a>Qe>asV6k6QLzUpdmM9p1`+o6B`QU61bg`f_$+jc1D64%;O z#I&CKLKuZNgKaoBxT?1@P-vm5)&dNQb1Ls9Qy1aP@MmW+KP89; zMN)*W6~4#4-K6N2^cGKcJJy#MuwvyO%Isv1yw}T)EmCqF79Z<*I5|0)%IG^i^cND@ zA+}iF{EViQVSDVo>BKe_CKLKI`)v=n-#$=}e($@2YnO(yB%SvOK+#?-M-J*PdrL>x z0fITO9-=xhPDW-y@gIhkwaaUBb2?Z9RF?XJ>19^`e!3TIY1S1n?2iOw48#4T;lv+S z=gAN22wE;ky!^XQ´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 gt^Z$At Date: Tue, 18 Feb 2025 11:14:12 -0500 Subject: [PATCH 7/9] implemented review comments --- text/0686-bedrock-l2-construct.md | 178 ++++-------------------------- 1 file changed, 21 insertions(+), 157 deletions(-) diff --git a/text/0686-bedrock-l2-construct.md b/text/0686-bedrock-l2-construct.md index ff9d8f578..969f45df9 100644 --- a/text/0686-bedrock-l2-construct.md +++ b/text/0686-bedrock-l2-construct.md @@ -55,7 +55,7 @@ For more details please refer here [Amazon Bedrock README](https://github.com/aw Amazon Bedrock Knowledge Bases provides foundation models and agents with contextual data from private sources. This capability enhances response relevance, accuracy, and customization for your specific use cases. -## Supported Knowledge Base Types +### Supported Knowledge Base Types The service implements an IKnowledgeBase interface that supports Vector Knowledge Base, Kendra Knowledge Base, and SQL Knowledge Base. This abstracted interface design enables seamless integration across multiple knowledge base types, providing flexibility in how you store and @@ -74,7 +74,7 @@ To create a vector knowledge Base, a vector index on a vector store is required. 2. `instruction` prop: Provided to associated Bedrock Agents to determine when to query the Knowledge Base -3. embeddingsModel: Foundation model supported with bedrock. +3. `embeddingsModel` prop: Foundation model supported with bedrock. Example of `OpenSearch Serverless`: @@ -99,102 +99,6 @@ const kb = new bedrock.KnowledgeBase(this, 'KnowledgeBase', { }] }); -const docBucket = new s3.Bucket(this, 'DocBucket'); - -new bedrock.S3DataSource(this, 'DataSource', { - bucket: docBucket, - knowledgeBase: kb, - dataSourceName: 'books', - chunkingStrategy: bedrock.ChunkingStrategy.fixedSize({ - maxTokens: 500, - overlapPercentage: 20, - }), -}); -``` - -For Amazon RDS Aurora PostgreSQL it supports fromExistingAuroraVectorStore() method. -N -ote - you need to provide clusterIdentifier, databaseName, vpc, secret and auroraSecurityGroupId used in -deployment of your existing RDS Amazon Aurora DB, as well as embeddingsModel that you want to be used by a Knowledge Base -for chunking: - -```ts -import * as s3 from "aws-cdk-lib/aws-s3"; -import { amazonaurora, bedrock } from 'aws-cdk-lib/aws-bedrock'; - -const auroraDb = aurora.AmazonAuroraVectorStore.fromExistingAuroraVectorStore(stack, 'ExistingAuroraVectorStore', { - clusterIdentifier: 'aurora-serverless-vector-cluster', - databaseName: 'bedrock_vector_db', - schemaName: 'bedrock_integration', - tableName: 'bedrock_kb', - vectorField: 'embedding', - textField: 'chunks', - metadataField: 'metadata', - primaryKeyField: 'id', - embeddingsModel: bedrock.BedrockFoundationModel.COHERE_EMBED_ENGLISH_V3, - vpc: cdk.aws_ec2.Vpc.fromLookup(stack, 'VPC', { - vpcId: 'vpc-0c1a234567ee8bc90', - }), - auroraSecurityGroupId: 'sg-012ef345678c98a76',, - secret: cdk.aws_rds.DatabaseSecret.fromSecretCompleteArn( - stack, - 'Secret', - cdk.Stack.of(stack).formatArn({ - service: 'secretsmanager', - resource: 'secret', - resourceName: 'rds-db-credentials/cluster-1234567890', - region: cdk.Stack.of(stack).region, - account: cdk.Stack.of(stack).account, - arnFormat: cdk.ArnFormat.COLON_RESOURCE_NAME, - }), - ), -}); - -const kb = new bedrock.KnowledgeBase(this, "KnowledgeBase", { - vectorStore: auroraDb, - embeddingsModel: bedrock.BedrockFoundationModel.COHERE_EMBED_ENGLISH_V3, - instruction: - "Use this knowledge base to answer questions about books. " + - "It contains the full text of novels.", -}); - -const docBucket = new s3.Bucket(this, "DocBucket"); - -new bedrock.S3DataSource(this, "DataSource", { - bucket: docBucket, - knowledgeBase: kb, - dataSourceName: "books", - chunkingStrategy: bedrock.ChunkingStrategy.FIXED_SIZE, -}); -``` - -Example of `Pinecone` (manual, you must have Pinecone vector store created): - -```ts -import * as s3 from 'aws-cdk-lib/aws-s3'; -import { pinecone, bedrock } from 'aws-cdk-lib/aws-bedrock'; - -const pineconeds = new pinecone.PineconeVectorStore({ - connectionString: 'https://your-index-1234567.svc.gcp-starter.pinecone.io', - credentialsSecretArn: 'arn:aws:secretsmanager:your-region:123456789876:secret:your-key-name', - textField: 'question', - metadataField: 'metadata', -}); - -const kb = new bedrock.KnowledgeBase(this, 'KnowledgeBase', { - vectorStore: pineconeds, - embeddingsModel: bedrock.BedrockFoundationModel.TITAN_EMBED_TEXT_V1, - instruction: 'Use this knowledge base to answer questions about books. ' + 'It contains the full text of novels.', -}); - -const docBucket = new s3.Bucket(this, 'DocBucket'); - -new bedrock.S3DataSource(this, 'DataSource', { - bucket: docBucket, - knowledgeBase: kb, - dataSourceName: 'books', - chunkingStrategy: bedrock.ChunkingStrategy.FIXED_SIZE, -}); ``` #### Knowledge Base - Data Sources @@ -216,6 +120,8 @@ include Amazon S3 buckets, Web Crawlers, SharePoint sites, Salesforce instances, - **Salesforce**. You can either create a new data source using the `bedrock.SalesforceDataSource(..)` class, or using the `kb.addSalesforceDataSource(..)`. +#### Add web crawler data source + ```ts const kb = new KnowledgeBase(stack, 'MyKnowledgeBase', { @@ -241,7 +147,11 @@ kb.addWebCrawlerDataSource({ s3BucketUri: `s3://${bucket.bucketName}/chunk-processor/`, }), }); +``` + +#### Add S3 data source +```ts kb.addS3DataSource({ bucket, chunkingStrategy: ChunkingStrategy.SEMANTIC, @@ -249,7 +159,11 @@ kb.addS3DataSource({ model: BedrockFoundationModel.ANTHROPIC_CLAUDE_SONNET_V1_0, }), }); +``` +### Add Confluence data source + +```ts kb.addConfluenceDataSource({ dataSourceName: 'TestDataSource', authSecret: secret, @@ -268,7 +182,11 @@ kb.addConfluenceDataSource({ }, ], }); +``` + +#### Add Salesforce data source +```ts kb.addSalesforceDataSource({ authSecret: secret, endpoint: 'https://your-instance.my.salesforce.com', @@ -286,7 +204,11 @@ kb.addSalesforceDataSource({ }, ], }); +``` +#### Add Sharepoint data source + +```ts kb.addSharePointDataSource({ dataSourceName: 'SharepointDataSource', authSecret: secret, @@ -403,65 +325,7 @@ create a custom transformation, set the `customTransformation` in a data source CustomTransformation.lambda({ lambdaFunction: lambdaFunction, s3BucketUri: `s3://${bucket.bucketName}/chunk-processor/`, -}), -``` - -### Kendra Knowledge Base - -#### Create a Kendra Knowledge Base - -Amazon Bedrock Knowledge Bases enables building sophisticated RAG-powered digital assistants using Amazon Kendra GenAI index. Key benefits include: - -* **Content Reusability** - - Use indexed content across multiple Bedrock applications - - No need to rebuild indexes or re-ingest data - -* **Enhanced Capabilities** - - Leverage Bedrock's advanced GenAI features - - Benefit from Kendra's high-accuracy information retrieval - -* **Customization** - - Tailor digital assistant behavior using Bedrock tools - - Maintain semantic accuracy of Kendra GenAI index - -#### Kendra Knowledge Base properties - -| Name | Type | Required | Description | -|------|------|----------|-------------| -| kendraIndex | IKendraGenAiIndex | Yes | The Kendra Index to use for the knowledge base. | -| name | string | No | The name of the knowledge base. If not provided, a name will be auto-generated. | -| description | string | No | Description of the knowledge base. | -| instruction | string | No | Instructions for the knowledge base. | -| existingRole | iam.IRole | No | An existing IAM role to use for the knowledge base. If not provided, a new role will be created. | - -#### Initializer - -TypeScript - -```ts -import * as s3 from 'aws-cdk-lib/aws-s3'; -import { bedrock, kendra } from 'aws-cdk-lib/aws-bedrock'; - -const cmk = new kms.Key(stack, 'cmk', {}); - -// you can create a new index using the api below -const index = new kendra.KendraGenAiIndex(this, 'index', { - name: 'kendra-index-cdk', - kmsKey: cmk, - documentCapacityUnits: 1, // 40K documents - queryCapacityUnits: 1, // 0.2 QPS -}); - -// or import an existing one -const index = kendra.KendraGenAiIndex.fromAttrs(this, 'myindex', { - indexId: 'myindex', - role: myRole -}); - -new bedrock.KendraKnowledgeBase(this, 'kb', { - name: 'kendra-kb-cdk', - kendraIndex: index, -}); +}) ``` ## Agents From 0fa1ae44c946d9eef27ec6009f3d5b70a5764dc4 Mon Sep 17 00:00:00 2001 From: dinsajwa Date: Wed, 19 Feb 2025 11:17:43 -0500 Subject: [PATCH 8/9] implemented review comments --- text/0686-bedrock-l2-construct.md | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/text/0686-bedrock-l2-construct.md b/text/0686-bedrock-l2-construct.md index 969f45df9..81987f356 100644 --- a/text/0686-bedrock-l2-construct.md +++ b/text/0686-bedrock-l2-construct.md @@ -385,7 +385,7 @@ agent.addActionGroup(actionGroup); ### Prepare the Agent -he Agent constructs take an optional parameter shouldPrepareAgent to indicate that the Agent should be prepared after any updates to +The Agent constructs take an optional parameter shouldPrepareAgent to indicate that the Agent should be prepared after any updates to an agent, Knowledge Base association, or action group. This may increase the time to create and update those resources. By default, this value is false. @@ -453,6 +453,16 @@ const agentAlias2 = new bedrock.AgentAlias(this, 'myalias2', { agentVersion: '1', // optional description: 'mytest' }); + +``` + +You can also import an existing alias + +```ts +const existingAgentAlias = AgentAlias.fromAttributes(this, 'ImportedAgentAlias', { + agentId: 'existing-agent-id', + aliasId: 'existing-alias-id' +}); ``` ## Bedrock Guardrails From 4745b1c266a9b7ea68147a32dfeec81d29336cfb Mon Sep 17 00:00:00 2001 From: dinsajwa Date: Wed, 19 Feb 2025 14:29:08 -0500 Subject: [PATCH 9/9] removed fromCfnGuardrail method from RFC scope --- text/0686-bedrock-l2-construct.md | 15 --------------- 1 file changed, 15 deletions(-) diff --git a/text/0686-bedrock-l2-construct.md b/text/0686-bedrock-l2-construct.md index 81987f356..31fffc77a 100644 --- a/text/0686-bedrock-l2-construct.md +++ b/text/0686-bedrock-l2-construct.md @@ -548,21 +548,6 @@ const importedGuardrail = bedrock.Guardrail.fromGuardrailAttributes(stack, 'Test kmsKey: kmsKey, //optional }); -// Importing Guardrails created through the L1 CDK CfnGuardrail construct -const cfnGuardrail = new CfnGuardrail(this, 'MyCfnGuardrail', { - blockedInputMessaging: 'blockedInputMessaging', - blockedOutputsMessaging: 'blockedOutputsMessaging', - name: 'namemycfnguardrails', - wordPolicyConfig: { - wordsConfig: [ - { - text: 'drugs', - }, - ], - }, -}); - -const importedGuardrail = bedrock.Guardrail.fromCfnGuardrail(cfnGuardrail); ``` ## Prompt management