Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions s3-vectors-lambda-bedrock-cdk/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
node_modules
cdk.out
*.js
!src/**/*.js
*.d.ts
package-lock.json
120 changes: 120 additions & 0 deletions s3-vectors-lambda-bedrock-cdk/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,120 @@
# S3 Vectors with Lambda and Amazon Bedrock RAG

This pattern deploys a serverless RAG (Retrieval-Augmented Generation) pipeline using Amazon S3 Vectors for vector storage, Lambda for orchestration, and Amazon Bedrock for embeddings and text generation.

Learn more about this pattern at Serverless Land Patterns: https://serverlessland.com/patterns/s3-vectors-lambda-bedrock-cdk

Important: this application uses various AWS services and there are costs associated with these services after the Free Tier usage - please see the [AWS Pricing page](https://aws.amazon.com/pricing/) for details. You are responsible for any AWS costs incurred. No warranty is implied in this example.

## Requirements

* [Create an AWS account](https://portal.aws.amazon.com/gp/aws/developer/registration/index.html) if you do not already have one and log in.
* [AWS CLI](https://docs.aws.amazon.com/cli/latest/userguide/install-cliv2.html) installed and configured
* [Git Installed](https://git-scm.com/book/en/v2/Getting-Started-Installing-Git)
* [Node.js 18+](https://nodejs.org/en/download/) installed
* [AWS CDK v2](https://docs.aws.amazon.com/cdk/v2/guide/getting-started.html) installed
* [Amazon Bedrock model access](https://docs.aws.amazon.com/bedrock/latest/userguide/model-access.html) enabled for Amazon Titan Text Embeddings V2 and Anthropic Claude Sonnet

## Architecture

```
┌──────────────────────────────────────────────────────┐
│ S3 Vector Bucket │
│ ┌──────────────────────────────────┐ │
│ │ Vector Index (1024-dim, cosine) │ │
│ └──────────────────────────────────┘ │
└──────────────┬───────────────┬───────────────────────┘
│ │
┌──────────────┴──┐ ┌───────┴──────────────┐
│ Ingest Lambda │ │ Query Lambda │
│ (embed + store) │ │ (search + generate) │
└────────┬─────────┘ └────────┬──────────────┘
│ │
┌────────┴──────────────────────┴──────────┐
│ Amazon Bedrock │
│ Titan Embeddings V2 │ Claude Sonnet │
└──────────────────────────────────────────┘
```

## How it works

**Ingest flow:**
1. Invoke the Ingest Lambda with an array of text documents.
2. Lambda calls Bedrock Titan Embeddings V2 to generate 1024-dimensional vectors.
3. Vectors are stored in an S3 vector index with metadata (source text, timestamp).

**Query flow:**
1. Invoke the Query Lambda with a natural language question.
2. Lambda embeds the question using the same Titan model.
3. Lambda queries S3 Vectors for the top-K most similar documents.
4. Retrieved context is sent to Bedrock Claude to generate a grounded answer.

## Deployment Instructions

1. Clone the repository:
```bash
git clone https://github.com/aws-samples/serverless-patterns
cd serverless-patterns/s3-vectors-lambda-bedrock-cdk
```

2. Install dependencies:
```bash
npm install
```

3. Deploy the stack:
```bash
cdk deploy
```

4. Note the function names from the stack outputs.

## Testing

1. Ingest sample documents:
```bash
aws lambda invoke \
--function-name <IngestFunctionName> \
--payload '{
"documents": [
{"key": "serverless", "text": "Serverless computing lets you run code without managing servers. AWS Lambda automatically scales your application."},
{"key": "containers", "text": "Containers package applications with their dependencies. Amazon ECS and EKS manage container orchestration."},
{"key": "s3-vectors", "text": "Amazon S3 Vectors provides purpose-built vector storage for AI applications with sub-second query latency."}
]
}' \
--cli-binary-format raw-in-base64-out \
ingest-output.json
```

2. Query with a question:
```bash
aws lambda invoke \
--function-name <QueryFunctionName> \
--payload '{"question": "How do I store vectors for AI applications?"}' \
--cli-binary-format raw-in-base64-out \
query-output.json

cat query-output.json | jq .
```

## Cleanup

1. Delete vectors and the vector index manually (S3 Vectors resources are not managed by CloudFormation):
```bash
aws s3vectors delete-vector-index \
--vector-bucket-name <VectorBucketName> \
--index-name knowledge-base

aws s3vectors delete-vector-bucket \
--vector-bucket-name <VectorBucketName>
```

2. Delete the CDK stack:
```bash
cdk destroy
```

----
Copyright 2026 Amazon.com, Inc. or its affiliates. All Rights Reserved.

SPDX-License-Identifier: MIT-0
7 changes: 7 additions & 0 deletions s3-vectors-lambda-bedrock-cdk/bin/app.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
#!/usr/bin/env node
import "source-map-support/register";
import * as cdk from "aws-cdk-lib";
import { S3VectorsLambdaBedrockStack } from "../lib/s3-vectors-lambda-bedrock-stack";

const app = new cdk.App();
new S3VectorsLambdaBedrockStack(app, "S3VectorsLambdaBedrockStack");
11 changes: 11 additions & 0 deletions s3-vectors-lambda-bedrock-cdk/cdk.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
{
"app": "npx ts-node --prefer-ts-exts bin/app.ts",
"watch": {
"include": ["**"],
"exclude": ["README.md", "cdk*.json", "**/*.d.ts", "**/*.js", "node_modules", "src"]
},
"context": {
"@aws-cdk/aws-lambda:recognizeLayerVersion": true,
"@aws-cdk/core:checkSecretUsage": true
}
}
61 changes: 61 additions & 0 deletions s3-vectors-lambda-bedrock-cdk/example-pattern.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
{
"title": "S3 Vectors with Lambda and Amazon Bedrock RAG",
"description": "Build a serverless RAG pipeline using Amazon S3 Vectors for cost-optimized vector storage, Lambda for orchestration, and Amazon Bedrock for embeddings and generation.",
"language": "TypeScript",
"level": "300",
"framework": "AWS CDK",
"introBox": {
"headline": "How it works",
"text": [
"This pattern deploys two Lambda functions backed by Amazon S3 Vectors and Amazon Bedrock to implement a serverless Retrieval-Augmented Generation (RAG) pipeline.",
"The Ingest function takes text documents, generates vector embeddings using Bedrock Titan Embeddings V2, and stores them in an S3 vector index with metadata. The Query function takes a natural language question, embeds it, performs a similarity search against S3 Vectors, and uses Bedrock Claude to generate an answer grounded in the retrieved context.",
"S3 Vectors provides purpose-built, cost-optimized vector storage with sub-second query latency \u2014 no vector database infrastructure to manage."
]
},
"gitHub": {
"template": {
"repoURL": "https://github.com/aws-samples/serverless-patterns/tree/main/s3-vectors-lambda-bedrock-cdk",
"templateURL": "serverless-patterns/s3-vectors-lambda-bedrock-cdk",
"projectFolder": "s3-vectors-lambda-bedrock-cdk",
"templateFile": "lib/s3-vectors-lambda-bedrock-stack.ts"
}
},
"resources": {
"bullets": [
{
"text": "Amazon S3 Vectors Documentation",
"link": "https://docs.aws.amazon.com/AmazonS3/latest/userguide/s3-vectors.html"
},
{
"text": "Getting started with S3 Vectors",
"link": "https://docs.aws.amazon.com/AmazonS3/latest/userguide/s3-vectors-getting-started.html"
},
{
"text": "Amazon Bedrock Titan Embeddings",
"link": "https://docs.aws.amazon.com/bedrock/latest/userguide/titan-embedding-models.html"
}
]
},
"deploy": {
"text": [
"cdk deploy"
]
},
"testing": {
"text": [
"See the GitHub repo for detailed testing instructions."
]
},
"cleanup": {
"text": [
"Delete the stack: <code>cdk destroy</code>."
]
},
"authors": [
{
"name": "Nithin Chandran R",
"bio": "Technical Account Manager at AWS",
"linkedin": "nithin-chandran-r"
}
]
}
140 changes: 140 additions & 0 deletions s3-vectors-lambda-bedrock-cdk/lib/s3-vectors-lambda-bedrock-stack.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,140 @@
import * as cdk from "aws-cdk-lib";
import * as lambda from "aws-cdk-lib/aws-lambda";
import * as iam from "aws-cdk-lib/aws-iam";
import * as logs from "aws-cdk-lib/aws-logs";
import * as cr from "aws-cdk-lib/custom-resources";
import { Construct } from "constructs";

export class S3VectorsLambdaBedrockStack extends cdk.Stack {
constructor(scope: Construct, id: string, props?: cdk.StackProps) {
super(scope, id, props);

const vectorBucketName = new cdk.CfnParameter(this, "VectorBucketName", {
type: "String",
default: "rag-knowledge-base-vectors",
description: "Name for the S3 vector bucket",
});

const indexName = "knowledge-base";

// S3 Vectors policy (shared by both functions and custom resource)
// Note: s3vectors does not support resource-level ARNs yet — wildcard required
const s3VectorsPolicy = new iam.PolicyStatement({
actions: [
"s3vectors:CreateVectorBucket",
"s3vectors:DeleteVectorBucket",
"s3vectors:CreateVectorIndex",
"s3vectors:DeleteVectorIndex",
"s3vectors:PutVectors",
"s3vectors:QueryVectors",
"s3vectors:GetVectors",
"s3vectors:DeleteVectors",
],
resources: ["*"],
});

const bedrockPolicy = new iam.PolicyStatement({
actions: ["bedrock:InvokeModel"],
resources: [
`arn:aws:bedrock:${this.region}::foundation-model/amazon.titan-embed-text-v2:0`,
`arn:aws:bedrock:${this.region}:${this.account}:inference-profile/us.anthropic.claude-sonnet-4-20250514-v1:0`,
"arn:aws:bedrock:*::foundation-model/*",
],
});

const sharedEnv = {
VECTOR_BUCKET_NAME: vectorBucketName.valueAsString,
INDEX_NAME: indexName,
EMBED_MODEL_ID: "amazon.titan-embed-text-v2:0",
GENERATION_MODEL_ID: "us.anthropic.claude-sonnet-4-20250514-v1:0",
};

// Ingest function — embeds text and stores in S3 Vectors
const ingestFn = new lambda.Function(this, "IngestFn", {
runtime: lambda.Runtime.NODEJS_20_X,
handler: "ingest.handler",
code: lambda.Code.fromAsset("src"),
timeout: cdk.Duration.minutes(5),
memorySize: 256,
environment: sharedEnv,
logRetention: logs.RetentionDays.ONE_WEEK,
});
ingestFn.addToRolePolicy(s3VectorsPolicy);
ingestFn.addToRolePolicy(bedrockPolicy);

// Query function — searches S3 Vectors and generates answer with Bedrock
const queryFn = new lambda.Function(this, "QueryFn", {
runtime: lambda.Runtime.NODEJS_20_X,
handler: "query.handler",
code: lambda.Code.fromAsset("src"),
timeout: cdk.Duration.minutes(2),
memorySize: 256,
environment: sharedEnv,
logRetention: logs.RetentionDays.ONE_WEEK,
});
queryFn.addToRolePolicy(s3VectorsPolicy);
queryFn.addToRolePolicy(bedrockPolicy);

// Custom resource to create vector bucket and index on deploy
const setupRole = new iam.Role(this, "SetupRole", {
assumedBy: new iam.ServicePrincipal("lambda.amazonaws.com"),
managedPolicies: [
iam.ManagedPolicy.fromAwsManagedPolicyName(
"service-role/AWSLambdaBasicExecutionRole"
),
],
});
setupRole.addToPolicy(s3VectorsPolicy);

const createBucket = new cr.AwsCustomResource(this, "CreateVectorBucket", {
onCreate: {
service: "S3Vectors",
action: "createVectorBucket",
parameters: { vectorBucketName: vectorBucketName.valueAsString },
physicalResourceId: cr.PhysicalResourceId.of("vector-bucket"),
},
onDelete: {
service: "S3Vectors",
action: "deleteVectorBucket",
parameters: { vectorBucketName: vectorBucketName.valueAsString },
},
role: setupRole,
policy: cr.AwsCustomResourcePolicy.fromStatements([s3VectorsPolicy]),
});

const createIndex = new cr.AwsCustomResource(this, "CreateVectorIndex", {
onCreate: {
service: "S3Vectors",
action: "createVectorIndex",
parameters: {
vectorBucketName: vectorBucketName.valueAsString,
indexName,
dimension: 1024,
distanceMetric: "cosine",
},
physicalResourceId: cr.PhysicalResourceId.of("vector-index"),
},
onDelete: {
service: "S3Vectors",
action: "deleteVectorIndex",
parameters: {
vectorBucketName: vectorBucketName.valueAsString,
indexName,
},
},
role: setupRole,
policy: cr.AwsCustomResourcePolicy.fromStatements([s3VectorsPolicy]),
});
createIndex.node.addDependency(createBucket);

new cdk.CfnOutput(this, "IngestFunctionName", {
value: ingestFn.functionName,
});
new cdk.CfnOutput(this, "QueryFunctionName", {
value: queryFn.functionName,
});
new cdk.CfnOutput(this, "VectorBucketNameOutput", {
value: vectorBucketName.valueAsString,
});
}
}
20 changes: 20 additions & 0 deletions s3-vectors-lambda-bedrock-cdk/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
{
"name": "s3-vectors-lambda-bedrock-cdk",
"version": "1.0.0",
"bin": {
"app": "bin/app.ts"
},
"scripts": {
"build": "tsc",
"cdk": "cdk"
},
"dependencies": {
"aws-cdk-lib": "2.180.0",
"constructs": "10.4.2"
},
"devDependencies": {
"@types/node": "^22.0.0",
"ts-node": "^10.9.0",
"typescript": "~5.7.0"
}
}
Loading