Skip to content

Commit

Permalink
Initial commit of CDK and Bedrock Agents template
Browse files Browse the repository at this point in the history
  • Loading branch information
stephenVertex committed May 30, 2024
0 parents commit 35c5124
Show file tree
Hide file tree
Showing 20 changed files with 787 additions and 0 deletions.
10 changes: 10 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
*.swp
package-lock.json
__pycache__
.pytest_cache
.venv
*.egg-info

# CDK asset staging directory
.cdk.staging
cdk.out
134 changes: 134 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,134 @@

# Welcome to your CDK and Bedrock Agents Project

## Layout

The core of the stack is seen in the `cdk_lambda_bedrock/cdk_lambda_bedrock_stack.py` folder.
This stack contains:

+ A single Agent
+ A reference to an existing Lambda Layer for AWS Power Tools
+ Two **Action Groups**
+ For each **Action Group**, a `PythonFunction`
+ The `PythonFunction`'s share a common Lambda Layer.
This is [provided here](https://docs.powertools.aws.dev/lambda/python/latest/#lambda-layer).

``` mermaid
graph TD;
A[Stack] --> B[Agent]
B --> C[AgentActionGroup - TimeFunctions]
B --> D[AgentActionGroup - TodoListManagementFunctions]
C --> E[LambdaFunction - TimeFunctions<br/><code>lambda/app.py</code>]
D --> F[LambdaFunction - TodoListManagementFunctions<br/><code>lambda_two/app.py</code>]
E --> G[AWSLambdaPowertoolsPythonV2 Layer]
F --> G
subgraph Lambda Functions
E
F
end
subgraph Agent Action Groups
C
D
end
subgraph Bedrock Foundation Model
B
end
subgraph Layers
G
end
```

## Prerequisites

- Python 3
- AWS users with permission to create required resources. See [Sample IAM Policy](./sample_iam_policy.json)
- Install [aws-cdk]( https://github.com/aws/aws-cdk)
- Install [Docker](https://www.docker.com/)

## Steps to get started

1. Clone the repository

``` shell
git clone [email protected]:stephenVertex/cdk-lambda-bedrock-template.git
cd cdk-lambda-bedrock-template/
```
**NOTE:** Make sure that you change the stack name.

``` python
CdkLambdaBedrockStack(app, "CdkLambdaBedrockStack", ## <-- Change this to your desired stack name
```

2. Make a virtual environment.

``` shell
python3 -m venv .venv
source .venv/bin/activate
```
and install the dependencies

``` shell
pip3 install -r requirements.txt
```

3. Make sure Docker is running. THe `docker ps` command should work.

``` shell
❯ docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
```

4. You need to add the following policy to your user.

``` json
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": [
"sts:AssumeRole",
"iam:PassRole"
],
"Resource": [
"arn:aws:iam::{ACCT_NUMBER}:role/cdk-hnb659fds-deploy-role-*",
"arn:aws:iam::{ACCT_NUMBER}:role/cdk-hnb659fds-file-publishing-*",
"arn:aws:iam::{ACCT_NUMBER}:role/cdk-hnb659fds-lookup-role-*",
"arn:aws:iam::{ACCT_NUMBER}:role/cdk-readOnlyRole"
]
}
]
}
```
Note that `hnb659fds` is the default value of the all resources in the CDK "bootstrap stack."
If you need to change this, you will know what to do.

5. Run `./deploy`
The deployment script makes sure that the API specifications are nice.
``` shell
cd lambda
python3 app.py > openapi.json
cd ..

cd lambda_two
python3 app.py > openapi.json
cd ..

cdk deploy

```

# CDK General Advice
## Useful commands

* `cdk ls` list all stacks in the app
* `cdk synth` emits the synthesized CloudFormation template
* `cdk deploy` deploy this stack to your default AWS account/region
* `cdk diff` compare deployed stack with current state
* `cdk docs` open CDK documentation

Enjoy!
28 changes: 28 additions & 0 deletions app.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
#!/usr/bin/env python3
import os

import aws_cdk as cdk

from cdk_lambda_bedrock.cdk_lambda_bedrock_stack import CdkLambdaBedrockStack


app = cdk.App()
CdkLambdaBedrockStack(app, "CdkLambdaBedrockStack",
# If you don't specify 'env', this stack will be environment-agnostic.
# Account/Region-dependent features and context lookups will not work,
# but a single synthesized template can be deployed anywhere.

# Uncomment the next line to specialize this stack for the AWS Account
# and Region that are implied by the current CLI configuration.

#env=cdk.Environment(account=os.getenv('CDK_DEFAULT_ACCOUNT'), region=os.getenv('CDK_DEFAULT_REGION')),

# Uncomment the next line if you know exactly what Account and Region you
# want to deploy the stack to. */

#env=cdk.Environment(account='123456789012', region='us-east-1'),

# For more information, see https://docs.aws.amazon.com/cdk/latest/guide/environments.html
)

app.synth()
69 changes: 69 additions & 0 deletions cdk.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
{
"app": "python3 app.py",
"watch": {
"include": [
"**"
],
"exclude": [
"README.md",
"cdk*.json",
"requirements*.txt",
"source.bat",
"**/__init__.py",
"**/__pycache__",
"tests"
]
},
"context": {
"@aws-cdk/aws-lambda:recognizeLayerVersion": true,
"@aws-cdk/core:checkSecretUsage": true,
"@aws-cdk/core:target-partitions": [
"aws",
"aws-cn"
],
"@aws-cdk-containers/ecs-service-extensions:enableDefaultLogDriver": true,
"@aws-cdk/aws-ec2:uniqueImdsv2TemplateName": true,
"@aws-cdk/aws-ecs:arnFormatIncludesClusterName": true,
"@aws-cdk/aws-iam:minimizePolicies": true,
"@aws-cdk/core:validateSnapshotRemovalPolicy": true,
"@aws-cdk/aws-codepipeline:crossAccountKeyAliasStackSafeResourceName": true,
"@aws-cdk/aws-s3:createDefaultLoggingPolicy": true,
"@aws-cdk/aws-sns-subscriptions:restrictSqsDescryption": true,
"@aws-cdk/aws-apigateway:disableCloudWatchRole": true,
"@aws-cdk/core:enablePartitionLiterals": true,
"@aws-cdk/aws-events:eventsTargetQueueSameAccount": true,
"@aws-cdk/aws-iam:standardizedServicePrincipals": true,
"@aws-cdk/aws-ecs:disableExplicitDeploymentControllerForCircuitBreaker": true,
"@aws-cdk/aws-iam:importedRoleStackSafeDefaultPolicyName": true,
"@aws-cdk/aws-s3:serverAccessLogsUseBucketPolicy": true,
"@aws-cdk/aws-route53-patters:useCertificate": true,
"@aws-cdk/customresources:installLatestAwsSdkDefault": false,
"@aws-cdk/aws-rds:databaseProxyUniqueResourceName": true,
"@aws-cdk/aws-codedeploy:removeAlarmsFromDeploymentGroup": true,
"@aws-cdk/aws-apigateway:authorizerChangeDeploymentLogicalId": true,
"@aws-cdk/aws-ec2:launchTemplateDefaultUserData": true,
"@aws-cdk/aws-secretsmanager:useAttachedSecretResourcePolicyForSecretTargetAttachments": true,
"@aws-cdk/aws-redshift:columnId": true,
"@aws-cdk/aws-stepfunctions-tasks:enableEmrServicePolicyV2": true,
"@aws-cdk/aws-ec2:restrictDefaultSecurityGroup": true,
"@aws-cdk/aws-apigateway:requestValidatorUniqueId": true,
"@aws-cdk/aws-kms:aliasNameRef": true,
"@aws-cdk/aws-autoscaling:generateLaunchTemplateInsteadOfLaunchConfig": true,
"@aws-cdk/core:includePrefixInUniqueNameGeneration": true,
"@aws-cdk/aws-efs:denyAnonymousAccess": true,
"@aws-cdk/aws-opensearchservice:enableOpensearchMultiAzWithStandby": true,
"@aws-cdk/aws-lambda-nodejs:useLatestRuntimeVersion": true,
"@aws-cdk/aws-efs:mountTargetOrderInsensitiveLogicalId": true,
"@aws-cdk/aws-rds:auroraClusterChangeScopeOfInstanceParameterGroupWithEachParameters": true,
"@aws-cdk/aws-appsync:useArnForSourceApiAssociationIdentifier": true,
"@aws-cdk/aws-rds:preventRenderingDeprecatedCredentials": true,
"@aws-cdk/aws-codepipeline-actions:useNewDefaultBranchForCodeCommitSource": true,
"@aws-cdk/aws-cloudwatch-actions:changeLambdaPermissionLogicalIdForLambdaAction": true,
"@aws-cdk/aws-codepipeline:crossAccountKeysDefaultValueToFalse": true,
"@aws-cdk/aws-codepipeline:defaultPipelineTypeToV2": true,
"@aws-cdk/aws-kms:reduceCrossAccountRegionPolicyScope": true,
"@aws-cdk/aws-eks:nodegroupNameAttribute": true,
"@aws-cdk/aws-ec2:ebsDefaultGp3Volume": true,
"@aws-cdk/aws-ecs:removeDefaultDeploymentAlarm": true
}
}
Empty file added cdk_lambda_bedrock/__init__.py
Empty file.
73 changes: 73 additions & 0 deletions cdk_lambda_bedrock/cdk_lambda_bedrock_stack.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
from aws_cdk import (
Stack,
)
from aws_cdk.aws_lambda import Runtime, LayerVersion
from aws_cdk.aws_lambda_python_alpha import PythonFunction
from cdklabs.generative_ai_cdk_constructs.bedrock import Agent, AgentActionGroup, ApiSchema, BedrockFoundationModel
from constructs import Construct

class CdkLambdaBedrockStack(Stack):

def __init__(self, scope: Construct, construct_id: str, **kwargs) -> None:
super().__init__(scope, construct_id, **kwargs)

# THis is where the magic happens
agent = Agent(
self,
"Agent",
foundation_model=BedrockFoundationModel.ANTHROPIC_CLAUDE_INSTANT_V1_2,
instruction="You are a helpful and friendly agent that answers questions about insurance claims.",
)

lambda_layer = LayerVersion.from_layer_version_arn(
self, "AWSLambdaPowertoolsPythonV2",
# "arn:aws:lambda:us-west-2:017000801446:layer:AWSLambdaPowertoolsPythonV2:71" # for us-west-2
"arn:aws:lambda:us-east-1:017000801446:layer:AWSLambdaPowertoolsPythonV2:71"
)

action_group_function = PythonFunction(
self,
"LambdaFunction",
runtime=Runtime.PYTHON_3_12,
entry="./lambda",
index="app.py",
handler="lambda_handler",
layers=[lambda_layer]
)


action_group = AgentActionGroup(
self,
"ActionGroup",
action_group_name="TimeFunctions",
description="Functions for getting the current time and other time related functions",
action_group_executor=action_group_function,
action_group_state="ENABLED",
api_schema=ApiSchema.from_asset("./lambda/openapi.json"),
)

# 2nd function
mytodo_group_function = PythonFunction(
self,
"2LambdaFunction",
runtime=Runtime.PYTHON_3_12,
entry="./lambda_two",
index="app.py",
handler="lambda_handler",
layers=[lambda_layer]
)
# 2nd action group
mytodo_group = AgentActionGroup(
self,
"MytodoGroup",
action_group_name="TodoListManagementFunctions",
description="Use this action group to manage a TODO list",
action_group_executor=mytodo_group_function,
action_group_state="ENABLED",
api_schema=ApiSchema.from_asset("./lambda_two/openapi.json"),
)


# Associate actiong roup to the bla
agent.add_action_group(action_group)
agent.add_action_group(mytodo_group)
16 changes: 16 additions & 0 deletions deploy.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
#!/bin/bash

cd lambda
python3 app.py > openapi.json
cd ..

cd lambda_two
python3 app.py > openapi.json
cd ..

cdk deploy

## TODO Prompt me for a note. Log it somewhere.

## TODO Generate the AWS Management Console URL for the Bedrock Agent,
## https://us-east-1.console.aws.amazon.com/bedrock/home?region=us-east-1#/agents/{AGENT_ID}
29 changes: 29 additions & 0 deletions lambda/app.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
from time import time

from aws_lambda_powertools import Logger, Tracer
from aws_lambda_powertools.event_handler import BedrockAgentResolver
from aws_lambda_powertools.utilities.typing import LambdaContext

tracer = Tracer()
logger = Logger()
app = BedrockAgentResolver()


@app.get("/current_time", description="Gets the current time in seconds")
@tracer.capture_method
def current_time() -> int:
return int(time())

@app.get("/tomorrow_time", description="Gets the time tomorrow")
@tracer.capture_method
def tomorrow_time() -> int:
return int(time()) + 86400


@logger.inject_lambda_context
@tracer.capture_lambda_handler
def lambda_handler(event: dict, context: LambdaContext):
return app.resolve(event, context)

if __name__ == "__main__":
print(app.get_openapi_json_schema())
Loading

0 comments on commit 35c5124

Please sign in to comment.