LoginSignup
16
17

【速報】Agents for Amazon BedrockがCloudFormationに対応しました(ほぼ一撃)

Posted at

もっと早い人がいます。めちゃくちゃ早い!


こちらの記事で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だけなのですが、AgentResourceRoleArnInstructionFoundationModelを指定せずに作成してしまうと、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バケットがあります。

うまくいきました

ちなみに、マネジメントコンソールでも確認できました。

16
17
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
16
17