diff --git a/bedrock-prompt-management-lambda-sam/README.md b/bedrock-prompt-management-lambda-sam/README.md new file mode 100644 index 000000000..fba4214ed --- /dev/null +++ b/bedrock-prompt-management-lambda-sam/README.md @@ -0,0 +1,88 @@ +# Manage and version GenAI prompts with Amazon Bedrock Prompt Management + +This pattern defines an Amazon Bedrock managed prompt and a published version as native CloudFormation resources, and invokes the prompt from AWS Lambda through the Bedrock Converse API. The prompt text lives in Bedrock, not in the function, so you can update or roll back the prompt by publishing a new version, with no function code change. + +Learn more about this pattern at Serverless Land Patterns: https://serverlessland.com/patterns/bedrock-prompt-management-lambda-sam + +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. + +## How it works + +``` + {"input": "..."} Converse (modelId = prompt version ARN, + | promptVariables = {...}) + v | + AWS Lambda --------------------------------> Amazon Bedrock + (no prompt text, managed prompt + published version + only the version ARN) (template, variables, model) +``` + +- `AWS::Bedrock::Prompt` defines the prompt: template text with `{{variables}}`, the target model, and inference settings. +- `AWS::Bedrock::PromptVersion` publishes an immutable version of that prompt. +- The Lambda function calls `Converse` with the prompt version ARN as `modelId` and supplies `promptVariables`. Bedrock fetches the managed prompt, fills the variables, and runs the model. +- To change behaviour, publish a new version and repoint the function (a configuration value), or roll back to an older version - the function code never changes. + +## Requirements + +- An AWS account with permissions for AWS Lambda and Amazon Bedrock, and access to the chosen Bedrock model in your Region. +- [AWS CLI](https://docs.aws.amazon.com/cli/latest/userguide/install-cliv2.html) v2. +- [AWS SAM CLI](https://docs.aws.amazon.com/serverless-application-model/latest/developerguide/serverless-sam-cli-install.html). + +## Deployment + +```bash +sam build +sam deploy --guided +# - Stack Name : bedrock-prompt-management +# - AWS Region : us-east-1 (or a Region where the model is available) +# - ModelId : us.amazon.nova-lite-v1:0 (default; any Converse-compatible model or inference profile) +``` + +Note the `InvokePromptFunctionName` and `PromptArn` outputs. + +## Testing + +### 1. Invoke the managed prompt + +```bash +FN= +echo {\"input\":\"AWS Lambda runs code in response to events and scales automatically.\"} > event.json +aws lambda invoke --function-name $FN --cli-binary-format raw-in-base64-out --payload file://event.json out.json +cat out.json +``` + +You get a one-sentence summary, produced by the managed prompt (the function holds no prompt text). + +### 2. Change the prompt without changing code + +Edit the prompt, publish a new version, and repoint the function. The output changes; `handler.py` does not. + +```bash +PID= + +# Update the draft template (here: bullet points instead of one sentence) +aws bedrock-agent update-prompt --prompt-identifier $PID --name bedrock-prompt-management-summary-prompt \ + --default-variant v1 --variants "[{\"name\":\"v1\",\"templateType\":\"TEXT\",\"modelId\":\"us.amazon.nova-lite-v1:0\",\"templateConfiguration\":{\"text\":{\"text\":\"Rewrite the following as exactly three concise bullet points:\\n\\n{{input}}\",\"inputVariables\":[{\"name\":\"input\"}]}}}]" + +# Publish version 2 and note its ARN +V2=$(aws bedrock-agent create-prompt-version --prompt-identifier $PID --query arn --output text) + +# Repoint the function to v2 (configuration, not code) and re-invoke +aws lambda update-function-configuration --function-name $FN --environment "Variables={PROMPT_VERSION_ARN=$V2}" +sleep 6 +aws lambda invoke --function-name $FN --cli-binary-format raw-in-base64-out --payload file://event.json out2.json; cat out2.json +``` + +The response is now bullet points. Roll back by pointing `PROMPT_VERSION_ARN` at the earlier version ARN. + +## Cleanup + +```bash +sam delete +``` + +---- + +Author: Manish S + +Copyright 2026 Amazon.com, Inc. or its affiliates. All Rights Reserved. SPDX-License-Identifier: MIT-0 diff --git a/bedrock-prompt-management-lambda-sam/example-pattern.json b/bedrock-prompt-management-lambda-sam/example-pattern.json new file mode 100644 index 000000000..4461dcdf2 --- /dev/null +++ b/bedrock-prompt-management-lambda-sam/example-pattern.json @@ -0,0 +1,49 @@ +{ + "title": "Manage and version GenAI prompts with Amazon Bedrock Prompt Management", + "description": "Define an Amazon Bedrock managed prompt and a published version as CloudFormation resources, and invoke it from AWS Lambda through the Converse API. Update or roll back the prompt by publishing a new version, with no function code change.", + "language": "Python", + "level": "200", + "framework": "AWS SAM", + "patternArch": { + "icon1": { "x": 30, "y": 50, "service": "lambda", "label": "AWS Lambda (invoke by version ARN)" }, + "icon2": { "x": 70, "y": 50, "service": "bedrock", "label": "Bedrock managed prompt + version" }, + "line1": { "from": "icon1", "to": "icon2", "label": "Converse" } + }, + "introBox": { + "headline": "How it works", + "text": [ + "Teams building on Amazon Bedrock often hardcode prompt text inside their application code. Changing a prompt then means a code change and a redeploy, and there is no built-in versioning or rollback. Amazon Bedrock Prompt Management solves this by storing prompts as managed, versioned resources, and this pattern shows how to define and invoke them entirely as infrastructure as code.", + "The pattern defines two native CloudFormation resources: an AWS::Bedrock::Prompt (the prompt template, its input variables, the target model, and inference settings) and an AWS::Bedrock::PromptVersion (an immutable published version of that prompt). Because the prompt lives in Bedrock rather than in the function, prompt authors can iterate on wording independently of the application code.", + "At runtime, an AWS Lambda function calls the Bedrock Converse API and passes the prompt version ARN as the modelId, along with promptVariables for the template placeholders. Converse recognises the ARN, fetches the managed prompt, substitutes the variables, and runs it against the configured model, returning the result. The function contains no prompt text at all - only the version ARN it was given.", + "To change the prompt, you publish a new version in Bedrock and repoint the function to that version ARN (a configuration value, not code). Rolling back is just pointing at an older version. Invoking a pinned, immutable version keeps production behaviour deterministic while still allowing safe iteration - the same idea as feature flags, applied to GenAI prompts.", + "IAM permissions follow least privilege: the function may call bedrock:GetPrompt and bedrock:RenderPrompt only on this prompt, and bedrock:InvokeModel on the foundation model or inference profile the prompt uses. The target model is a template parameter, so the same pattern works with any Converse-compatible Bedrock model or cross-region inference profile. Good use cases include support and FAQ assistants, summarisation and classification, and any workload where prompts must be iterated, versioned, or rolled back without redeploying application code." + ] + }, + "gitHub": { + "template": { + "repoURL": "https://github.com/aws-samples/serverless-patterns/tree/main/bedrock-prompt-management-lambda-sam", + "templateURL": "serverless-patterns/bedrock-prompt-management-lambda-sam", + "projectFolder": "bedrock-prompt-management-lambda-sam", + "templateFile": "template.yaml" + } + }, + "resources": { + "headline": "Additional resources", + "bullets": [ + { "text": "Amazon Bedrock Prompt Management - documentation", "link": "https://docs.aws.amazon.com/bedrock/latest/userguide/prompt-management.html" }, + { "text": "AWS::Bedrock::Prompt - CloudFormation resource", "link": "https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-bedrock-prompt.html" }, + { "text": "AWS::Bedrock::PromptVersion - CloudFormation resource", "link": "https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-bedrock-promptversion.html" }, + { "text": "Amazon Bedrock Converse API reference", "link": "https://docs.aws.amazon.com/bedrock/latest/APIReference/API_runtime_Converse.html" } + ] + }, + "deploy": { "text": [ "sam build", "sam deploy --guided" ] }, + "testing": { + "headline": "Testing", + "text": [ "Invoke the Lambda function to run the managed prompt, then publish a new prompt version and repoint the function to see the output change with no code change. See the README for detailed instructions." ] + }, + "cleanup": { + "headline": "Cleanup", + "text": [ "1. Delete the stack: sam delete." ] + }, + "authors": [ { "name": "Manish S", "image": "", "bio": "AWS Support Engineer, trying to build things", "linkedin": "https://www.linkedin.com/in/manish-s-84199221b", "twitter": "" } ] +} diff --git a/bedrock-prompt-management-lambda-sam/src/handler.py b/bedrock-prompt-management-lambda-sam/src/handler.py new file mode 100644 index 000000000..372d65392 --- /dev/null +++ b/bedrock-prompt-management-lambda-sam/src/handler.py @@ -0,0 +1,29 @@ +"""Invoke a managed, versioned Amazon Bedrock prompt via the Converse API. + +The prompt template and its variables live in Amazon Bedrock (Prompt Management), not in +this code. Converse accepts the prompt version ARN as its modelId, fetches the managed +prompt, substitutes the promptVariables, and runs it against the configured model. To change +the prompt, publish a new version in Bedrock and repoint PROMPT_VERSION_ARN - no code change. +""" +import os +import boto3 + +bedrock = boto3.client("bedrock-runtime") + +PROMPT_VERSION_ARN = os.environ["PROMPT_VERSION_ARN"] +DEFAULT_TEXT = ( + "Amazon S3 is object storage built to store and retrieve any amount of data " + "from anywhere, offering industry-leading scalability, availability, and durability." +) + + +def handler(event, context): + text = (event or {}).get("input") or DEFAULT_TEXT + response = bedrock.converse( + modelId=PROMPT_VERSION_ARN, + promptVariables={"input": {"text": text}}, + ) + summary = response["output"]["message"]["content"][0]["text"] + print("Invoked prompt version: " + PROMPT_VERSION_ARN) + print("Summary: " + summary) + return {"summary": summary} diff --git a/bedrock-prompt-management-lambda-sam/src/requirements.txt b/bedrock-prompt-management-lambda-sam/src/requirements.txt new file mode 100644 index 000000000..3f3a4385f --- /dev/null +++ b/bedrock-prompt-management-lambda-sam/src/requirements.txt @@ -0,0 +1 @@ +boto3>=1.35.0 diff --git a/bedrock-prompt-management-lambda-sam/template.yaml b/bedrock-prompt-management-lambda-sam/template.yaml new file mode 100644 index 000000000..f18483f14 --- /dev/null +++ b/bedrock-prompt-management-lambda-sam/template.yaml @@ -0,0 +1,104 @@ +AWSTemplateFormatVersion: "2010-09-09" +Transform: AWS::Serverless-2016-10-31 +Description: > + Manage and version Amazon Bedrock prompts as infrastructure. A managed Bedrock prompt and a + published version are defined as native CloudFormation resources; an AWS Lambda function + invokes the prompt by its version ARN through the Bedrock Converse API. Update or roll back + the prompt by publishing a new version - the function code never changes. + (bedrock-prompt-management-lambda-sam) + +Parameters: + ModelId: + Type: String + Default: us.amazon.nova-lite-v1:0 + Description: Bedrock model or inference profile the prompt runs against (Converse-compatible). + +Resources: + # A managed, versionable Bedrock prompt. The template text and its input variables live here + # in Bedrock - not hardcoded in the function - so prompts can be iterated independently of code. + SummaryPrompt: + Type: AWS::Bedrock::Prompt + Properties: + Name: !Sub "${AWS::StackName}-summary-prompt" + Description: Summarize input text in one sentence. + DefaultVariant: v1 + Variants: + - Name: v1 + TemplateType: TEXT + ModelId: !Ref ModelId + TemplateConfiguration: + Text: + Text: "Summarize the following text in exactly one clear sentence:\n\n{{input}}" + InputVariables: + - Name: input + InferenceConfiguration: + Text: + Temperature: 0.5 + MaxTokens: 300 + + # An immutable published version. Production code invokes a pinned version ARN, so prompt + # changes are deliberate: publish a new version and repoint, or roll back to an older one. + SummaryPromptVersion: + Type: AWS::Bedrock::PromptVersion + Properties: + PromptArn: !GetAtt SummaryPrompt.Arn + Description: First published version. + + InvokePromptFunctionRole: + Type: AWS::IAM::Role + Properties: + AssumeRolePolicyDocument: + Version: "2012-10-17" + Statement: + - Effect: Allow + Principal: + Service: lambda.amazonaws.com + Action: sts:AssumeRole + ManagedPolicyArns: + - arn:aws:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole + Policies: + - PolicyName: InvokeManagedPrompt + PolicyDocument: + Version: "2012-10-17" + Statement: + - Sid: RenderManagedPrompt + Effect: Allow + Action: + - bedrock:GetPrompt + - bedrock:RenderPrompt + Resource: + - !GetAtt SummaryPrompt.Arn + - !Sub "${SummaryPrompt.Arn}:*" + - Sid: InvokeModel + Effect: Allow + Action: bedrock:InvokeModel + Resource: + - !Sub "arn:aws:bedrock:*::foundation-model/*" + - !Sub "arn:aws:bedrock:*:${AWS::AccountId}:inference-profile/*" + + InvokePromptFunction: + Type: AWS::Serverless::Function + Properties: + FunctionName: !Sub "${AWS::StackName}-invoke-prompt" + CodeUri: src/ + Handler: handler.handler + Runtime: python3.13 + Architectures: + - arm64 + Timeout: 30 + MemorySize: 128 + Role: !GetAtt InvokePromptFunctionRole.Arn + Environment: + Variables: + PROMPT_VERSION_ARN: !GetAtt SummaryPromptVersion.Arn + +Outputs: + PromptArn: + Description: ARN of the managed Bedrock prompt (draft). + Value: !GetAtt SummaryPrompt.Arn + PromptVersionArn: + Description: ARN of the published prompt version the function invokes. + Value: !GetAtt SummaryPromptVersion.Arn + InvokePromptFunctionName: + Description: Lambda function that invokes the managed prompt via Converse. + Value: !Ref InvokePromptFunction