もっと早い人がいます。めちゃくちゃ早い!
こちらの記事でLambdaをSAMでデプロイする方法を紹介しました。
APIがかなりスピーディに作成できますので、一度お試しください!!
このSAMプロジェクトを修正して ほぼ一撃 でデプロイできることを確認しましたので紹介します。
サンプルプロジェクトの取得
AWS Lambda Web Adapterのサンプルを使用します。
git clone https://github.com/awslabs/aws-lambda-web-adapter.git
examplesフォルダー内にあるbedrock-agent-fastapi-zip
に対して修正を行います。
サンプルには以下の3つのAPIが含まれています。
パス | メソッド | 内容 |
---|---|---|
/s3_bucket_count | GET | S3バケットの数を返却 |
/s3_object_count | GET | 指定したS3バケットの中のオブジェクトの数を返却 |
/s3_object | GET | 指定したバケットとオブジェクトキーの最終更新日を返却 |
手順
OpenAPIスキーマを作る
app
フォルダー内で以下のコマンドを実行してOpenAPIスキーマを生成します。
pip install -r requirements.txt
pip install boto3
python -c "import main;import json; print(json.dumps(main.app.openapi()))" > openapi.json
openapi.json
が作成されます。
template.yamlを修正する
もともとあるものを含め、以下のリソースを作成します。
-
Lambda Function
AWS Lambda Web Adapterを使って、FastAPIのAPI作成だけでBedrockに対応できるすぐれものです。
BedrockAgentFastAPIFunction: Type: AWS::Serverless::Function Properties: CodeUri: ./app Runtime: python3.12 Handler: run.sh MemorySize: 1024 Environment: Variables: AWS_LAMBDA_EXEC_WRAPPER: /opt/bootstrap AWS_LWA_READINESS_CHECK_PROTOCOL: TCP PORT: 8000 Layers: - !Sub arn:aws:lambda:${AWS::Region}:753240598075:layer:LambdaAdapterLayerX86:20 Policies: AmazonS3ReadOnlyAccess
-
Lambda Permission
BedrockAgentPermission: Type: AWS::Lambda::Permission Properties: FunctionName: !Ref BedrockAgentFastAPIFunction Action: lambda:InvokeFunction Principal: bedrock.amazonaws.com SourceAccount: !Ref "AWS::AccountId" SourceArn: !Sub arn:aws:bedrock:${AWS::Region}:${AWS::AccountId}:agent/*
-
IAMロール(Bedrockの実行ロール) ☆☆☆追加☆☆☆
ロール名はAmazonBedrockExecutionRoleForAgents_
で始まる必要があるようです。
BedrockモデルをInvokeする権限と、アクションのLambdaをInvokeする権限が必要です。BedrockAgentResourceRole: Type: AWS::IAM::Role Properties: RoleName: AmazonBedrockExecutionRoleForAgents_FastAPISample AssumeRolePolicyDocument: Version: 2012-10-17 Statement: - Effect: Allow Principal: Service: bedrock.amazonaws.com Action: sts:AssumeRole Condition: StringEquals: aws:SourceAccount: !Sub ${AWS::AccountId} ArnLike: aws:SourceArn: !Sub arn:aws:bedrock:${AWS::Region}:${AWS::AccountId}:agent/* Policies: - PolicyName: AmazonBedrockExecutionRoleForAgents_FastAPISamplePolicy PolicyDocument: Version: 2012-10-17 Statement: - Effect: Allow Action: bedrock:InvokeModel Resource: !Sub arn:aws:bedrock:${AWS::Region}::foundation-model/anthropic.claude-v2:1 - Effect: Allow Action: lambda:InvokeFunction Resource: !GetAtt BedrockAgentFastAPIFunction.Arn
-
BedrockAgent ☆☆☆追加☆☆☆
BedrockAgent。Payloadに先ほど出力したOpenAPIスキーマを貼り付ける。
文字列で指定するので、JSON文字列をシングルクオートで囲います。BedrockAgent: Type: AWS::Bedrock::Agent Properties: AgentName: BedrockAgentFastAPISample Description: Query S3 information agent. AgentResourceRoleArn: !GetAtt BedrockAgentResourceRole.Arn Instruction: This agent allows you to query the S3 information in your AWS account. FoundationModel: anthropic.claude-v2:1 ActionGroups: - ActionGroupName: action-group ActionGroupExecutor: Lambda: !GetAtt BedrockAgentFastAPIFunction.Arn ApiSchema: Payload: 'ここにOpenAPIスキーマのJSONを丸ごと貼り付ける'
ここだけ手作業。。惜しい!!
外部ファイルの文字列をCloudFormationテンプレートの一部に、自動で埋め込む方法をご存じの方いらっしゃいましたら教えて下さい。
必須項目はAgentName
だけなのですが、AgentResourceRoleArn
やInstruction
、FoundationModel
を指定せずに作成してしまうと、CloudFormationの更新も削除もできなくなります。さらにAgents for Amazon Bedrockの管理画面からも消せなくなってしまいますので、注意してください。
-
BedrockAgentのエイリアス ☆☆☆追加☆☆☆
BedrockAgentRelease: Type: AWS::Bedrock::AgentAlias Properties: AgentAliasName: v1 AgentId: !Ref BedrockAgent
最終的にこのようなtemplate.yaml
となります。
AWSTemplateFormatVersion: "2010-09-09"
Transform: AWS::Serverless-2016-10-31
Description: >
bedrock-agent-fastapi
FastAPI app that work with Agents for Amazon Bedrock
# More info about Globals: https://github.com/awslabs/serverless-application-model/blob/master/docs/globals.rst
Globals:
Function:
Timeout: 60
Resources:
BedrockAgentFastAPIFunction:
Type: AWS::Serverless::Function
Properties:
CodeUri: ./app
Runtime: python3.12
Handler: run.sh
MemorySize: 1024
Environment:
Variables:
AWS_LAMBDA_EXEC_WRAPPER: /opt/bootstrap
AWS_LWA_READINESS_CHECK_PROTOCOL: TCP
PORT: 8000
Layers:
- !Sub arn:aws:lambda:${AWS::Region}:753240598075:layer:LambdaAdapterLayerX86:20
Policies: AmazonS3ReadOnlyAccess
BedrockAgentPermission:
Type: AWS::Lambda::Permission
Properties:
FunctionName: !Ref BedrockAgentFastAPIFunction
Action: lambda:InvokeFunction
Principal: bedrock.amazonaws.com
SourceAccount: !Ref "AWS::AccountId"
SourceArn: !Sub arn:aws:bedrock:${AWS::Region}:${AWS::AccountId}:agent/*
BedrockAgentResourceRole:
Type: AWS::IAM::Role
Properties:
RoleName: AmazonBedrockExecutionRoleForAgents_FastAPISample
AssumeRolePolicyDocument:
Version: 2012-10-17
Statement:
- Effect: Allow
Principal:
Service: bedrock.amazonaws.com
Action: sts:AssumeRole
Condition:
StringEquals:
aws:SourceAccount: !Sub ${AWS::AccountId}
ArnLike:
aws:SourceArn: !Sub arn:aws:bedrock:${AWS::Region}:${AWS::AccountId}:agent/*
Policies:
- PolicyName: AmazonBedrockExecutionRoleForAgents_FastAPISamplePolicy
PolicyDocument:
Version: 2012-10-17
Statement:
- Effect: Allow
Action: bedrock:InvokeModel
Resource: !Sub arn:aws:bedrock:${AWS::Region}::foundation-model/anthropic.claude-v2:1
- Effect: Allow
Action: lambda:InvokeFunction
Resource: !GetAtt BedrockAgentFastAPIFunction.Arn
BedrockAgent:
Type: AWS::Bedrock::Agent
Properties:
AgentName: BedrockAgentFastAPISample
Description: Query S3 information agent.
AgentResourceRoleArn: !GetAtt BedrockAgentResourceRole.Arn
Instruction: This agent allows you to query the S3 information in your AWS account.
FoundationModel: anthropic.claude-v2:1
ActionGroups:
- ActionGroupName: action-group
ActionGroupExecutor:
Lambda: !GetAtt BedrockAgentFastAPIFunction.Arn
ApiSchema:
Payload: '{"openapi": "3.0.2", "info": {"title": "FastAPI", "description": "This agent allows you to query the S3 information in your AWS account.", "version": "0.1.0"}, "paths": {"/s3_bucket_count": {"get": {"summary": "Get S3 Bucket Count", "description": "This method returns the number of S3 buckets in your AWS account.\n\nReturn:\n S3BucketCountResponse: A json object containing the number of S3 buckets in your AWS account.", "operationId": "get_s3_bucket_count_s3_bucket_count_get", "responses": {"200": {"description": "Successful Response", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/S3BucketCountResponse"}}}}}}}, "/s3_object_count": {"get": {"summary": "Get S3 Object Count", "description": "This method returns the number of S3 objects in your specified bucket.\n\nReturn:\n S3ObjectCountResponse: A json object containing the number of S3 objects in your specified bucket.", "operationId": "get_s3_object_count_s3_object_count_get", "parameters": [{"name": "bucket_name", "in": "query", "required": true, "schema": {"type": "string", "description": "Bucket name", "title": "Bucket Name"}, "description": "Bucket name"}], "responses": {"200": {"description": "Successful Response", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/S3ObjectCountResponse"}}}}, "422": {"description": "Validation Error", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/HTTPValidationError"}}}}}}}, "/s3_object": {"post": {"summary": "Get S3 Object", "description": "This method returns the last modified date of S3 object.\n\nReturn:\n S3GetObjectResponse: A json object containing the last modified date of S3 objects.", "operationId": "get_s3_object_s3_object_post", "requestBody": {"content": {"application/json": {"schema": {"$ref": "#/components/schemas/S3GetObjectRequest"}}}, "required": true}, "responses": {"200": {"description": "Successful Response", "content": {"application/json": {"schema": {}}}}, "422": {"description": "Validation Error", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/HTTPValidationError"}}}}}}}}, "components": {"schemas": {"HTTPValidationError": {"properties": {"detail": {"items": {"$ref": "#/components/schemas/ValidationError"}, "type": "array", "title": "Detail"}}, "type": "object", "title": "HTTPValidationError"}, "S3BucketCountResponse": {"properties": {"count": {"type": "integer", "title": "Count", "description": "the number of S3 buckets"}}, "type": "object", "required": ["count"], "title": "S3BucketCountResponse"}, "S3GetObjectRequest": {"properties": {"bucket_name": {"type": "string", "title": "Bucket Name", "description": "Bucket name"}, "object_key": {"type": "string", "title": "Object Key", "description": "Object key"}}, "type": "object", "required": ["bucket_name", "object_key"], "title": "S3GetObjectRequest"}, "S3ObjectCountResponse": {"properties": {"count": {"type": "integer", "title": "Count", "description": "the number of S3 objects"}}, "type": "object", "required": ["count"], "title": "S3ObjectCountResponse"}, "ValidationError": {"properties": {"loc": {"items": {"anyOf": [{"type": "string"}, {"type": "integer"}]}, "type": "array", "title": "Location"}, "msg": {"type": "string", "title": "Message"}, "type": {"type": "string", "title": "Error Type"}}, "type": "object", "required": ["loc", "msg", "type"], "title": "ValidationError"}}}}'
BedrockAgentRelease:
Type: AWS::Bedrock::AgentAlias
Properties:
AgentAliasName: v1
AgentId: !Ref BedrockAgent
Outputs:
BedrockAgentFastAPIFunction:
Description: "BedrockAgentFastAPIFunction Lambda Function ARN"
Value: !GetAtt BedrockAgentFastAPIFunction.Arn
BedrockAgent:
Description: "BedrockAgent ID"
Value: !Ref BedrockAgent
BedrockAgentAlias:
Description: "BedrockAgentAlias ID"
Value: !Ref BedrockAgentRelease
ビルド、デプロイ
通常のコマンドです。
sam build
sam deploy
動作確認
AWS CLIはInvokeAgentに未対応のためPythonスクリプトで確認
agentIdとagentAliasIdはCfnのOutputから取得できます。(agentAliasIdは、agentIdとagentAliasIdをパイプで繋いだ文字列が出力されています。)
Key BedrockAgentAlias
Description BedrockAgentAlias ID
Value YGTJ0VMR7O|LZAELUEUPI
Key BedrockAgent
Description BedrockAgent ID
Value YGTJ0VMR7O
import uuid
import boto3
client = boto3.client("bedrock-agent-runtime")
response = client.invoke_agent(
agentId="YGTJ0VMR7O",
agentAliasId="LZAELUEUPI",
sessionId=str(uuid.uuid4()),
inputText="S3バケットの数を教えて下さい。",
)
for event in response.get("completion"):
chunk = event["chunk"]
print(chunk["bytes"].decode(), flush=None)
print()
あなたのAWSアカウントには14個のS3バケットがあります。
うまくいきました