Amazon Bedrockが登場！コイツでAWSのサーバレスAPIを簡単に作成できるのか？！

# はじめに

ChatGPTがリリースされてからすでに１年近くが経過し、日々の業務に広く取り入れられていると思います。
もはや特別な存在ではなく、多くの方々が利用されているのではないでしょうか？

AWSが提供する新サービス、Amazon Bedrockがプレビューフェーズを経て一般公開されました。


[AWS、生成系 AI のイノベーションを加速する新しい強力なサービス / 機能の提供を発表](https://aws.amazon.com/jp/about-aws/whats-new/2023/09/aws-announces-general-availability-of-amazon-bedrock/)

Amazon Bedrockとは、生成系AIではなく生成系AIをさえる**基盤サービス**です。
このBedrockという基盤を使用することで、様々な生成系AIを単一のAPIで利用可能とし、セキュリティを重視した環境も構築できるのです。

ですので、タイトルを正確に書くと
「Amazon BedrockでAWSのサーバレスAPIを作成」
ではなく
「Amazon Bedrock上に展開されている生成系AIでAWSのサーバレスAPIを作成」
というのが正しいタイトルになります。

## ChatGPTへの依頼

ChatGPTのモデルGPT-4がリリースされた直後「AWSのサーバレスAPIの作成を依頼してみたらどうなるか？」という事について検証しました。

生成された結果には、当時、大きな衝撃を受けました。それにより、エンジニアの働き方、存在意義、そして役割そのものが大きく変わっていくことを確信しました。同時に、このようなAI技術が日常的になった世の中で、「人間」は今後どう進んでいけばいいのか、と深く考えさせられるようになりました。

https://qiita.com/takuma818t/items/ff89ed5ba7c41ae7f2e5

今回Bedrock上で現在使えるモデルに同じ依頼をしてみてどうなるか試してみました。

記事の構成上プロンプトと応答を分かりやすくする為、以下プロンプトは以下スタイルで書きます。

:::note 
入力のプロンプトはこのスタイルで書きます。
:::

## プロンプト

以前ChatGPTに依頼したプロンプトと同じこちらのプロンプトを利用しました。

:::note 
AWS以下構成でAPIを実装したいです。
IaCとプログラムのコードを教えてください。

API
　UserNameとUserLocationをパラメータとして受け取る

Lambda
　put_Function
　　APIからリクエストを受け取りDynamoDBに書き込む
　Get_Function
　　APIからリクエストを受け取りDynamoDBのすべてのデータを返却

DynamoDB
　プライマリーキー：UserName
　パーティションキー　：UserLocation
:::


# 検証結果

## モデル　Claude v2

### モデル Claudev2 応答

*****
以下はいくつかの例です。

```
import boto3
import json

ddb = boto3.client('dynamodb')

def put_Function(event, context):
    data = json.loads(event['body'])
    ddb.put_item(
        TableName='users',
        Item={
            'UserName': data['UserName'],
            'UserLocation': data['UserLocation']
        }
    )

    return {
        'statusCode': 200,
        'body': json.dumps({})
    }

```

:::note 
続きをお願いします。
:::


Unfortunately, I do not have that information.

*****

### モデル Claudev2 結果

putのLambdaのソースのみ生成され、IaCコードや他のリソースはそれ以上は、生成されませんでした。

コードはChatGPT割と似ていましたが、ChatGPTは、テーブル名は環境変数として外だししたり、リターンされるメッセージきちんと出力するなど配慮されているのに対して、必要最低限という感じでした。
（ここまで生成されるのもすごいですが）

この後検証するモデル「Jurassic-2 Ultra」に対して、分かる所だけ回答するのは潔い？
また、応答文が途中で切れたとしても続きを生成しにくいのかもしれません。


## モデル Jurassic-2 Ultra

###  モデル Jurassic-2 Ultra 応答

*****
 AWSでAPI GatewayとLambda、DynamoDBを使って上記の要件を実装するIaCとコードは以下のようになります。

IaC (CloudFormationやCDKなど)

```
// API Gateway

Resource: MyApi 
  Type: AWS::ApiGateway::RestApi
  Properties: 
    Name: UserApi
    
Resource: UsersResource 
  Type: AWS::ApiGateway::Resource 
  Properties:
    ParentId: !Ref MyApi
    PathPart: users
    RestApiId: !Ref MyApi

Resource: UsersPostMethod
  Type: AWS::ApiGateway::Method
  Properties: 
    AuthorizationType: NONE
    HttpMethod: POST 
    ResourceId: !Ref UsersResource
    RestApiId: !Ref MyApi
    Integration:
      Type: AWS_PROXY
      IntegrationHttpMethod: POST 
      Uri: !GetAtt PutFunction.Arn
      
Resource: UsersGetMethod
  Type: AWS::ApiGateway::Method
  Properties: 
   AuthorizationType: NONE
   HttpMethod: GET
   ResourceId: !Ref UsersResource
   RestApiId: !Ref MyApi  
   Integration:
     Type: AWS_PROXY
     IntegrationHttpMethod: POST
     Uri: !GetAtt GetFunction.Arn
     
// Lambda

Resource: PutFunction
  Type: AWS::Lambda::Function
  Properties:
    Handler: index.putHandler    
    Runtime: nodejs

```
:::note 
続きをお願いします。
:::
```
 IaCの続き

// DynamoDB 

Resource: UsersTable 
  Type: AWS::DynamoDB::Table
  Properties:
    AttributeDefinitions:
      - AttributeName: "UserName"
        AttributeType: "S"
        
      - AttributeName: "UserLocation"
        AttributeType: "S"
        
    KeySchema:
      - AttributeName: "UserName"
        KeyType: "HASH"
        
      - AttributeName: "UserLocation" 
        KeyType: "RANGE"

Lambda関数のコード

// index.js

exports.putHandler = async (event) => {

  const userName = event.queryStringParameters.UserName;
  const userLocation = event.queryStringParameters.UserLocation;

  // DynamoDBに保存  
  await dynamoDb.put({
    TableName: "UsersTable",
    Item: {
      UserName: userName,
      UserLocation: userLocation  
    }
  }).promise();

  return {
    statusCode: 200,
    body: JSON.stringify('Added user.')
  };

};

exports.getHandler = async (event) => {

  const data = await dynamoDb.scan({ 
    TableName: "UsersTable"
  }).promise();

  return {
    statusCode: 200,
    body: JSON.stringify(data.Items)
  };

};

このようにAPI Gateway、Lambda
```

:::note 
続きをお願いします。
:::

```
 IaCの続き

// Lambda

Resource: GetFunction
  Type: AWS::Lambda::Function  
  Properties:
    Handler: index.getHandler    
    Runtime: nodejs

// API GatewayのLambda関数へのマッピング

Resource: UsersPostMethod
  Type: AWS::ApiGateway::Method
  Properties: 
    // (前のコードを省略)
    Integration:
      Type: AWS_PROXY
      IntegrationHttpMethod: POST  
      Uri: !GetAtt PutFunction.Arn 
      
Resource: UsersGetMethod
  Type: AWS::ApiGateway::Method
  Properties:
   // (前のコードを省略)  
   Integration:
     Type: AWS_PROXY 
     IntegrationHttpMethod: POST
     Uri: !GetAtt GetFunction.Arn

Lambda関数のコード

// index.js

// putHandler関数 (前のコード省略)

exports.getHandler = async (event) => {

  const data = await dynamoDb.scan({ 
    TableName: "UsersTable" 
  }).promise();

  return {
    statusCode: 200, 
    body: JSON.stringify(data.Items)
  };

};

このようにAPI Gateway、Lambda、DynamoDBを連携してCRUD APIを実装できます。
IaCではリソース定
```
:::note 
続きをお願いします。
:::

```
 IaCの続き

// Lambda

Resource: GetFunction
  Type: AWS::Lambda::Function  
  Properties:
    Handler: index.getHandler    
    Runtime: nodejs

// API GatewayのLambda関数へのマッピング

Resource: UsersPostMethod
  Type: AWS::ApiGateway::Method
  Properties: 
    // (前のコードを省略)
    Integration:
      Type: AWS_PROXY
      IntegrationHttpMethod: POST  
      Uri: !GetAtt PutFunction.Arn 
      
Resource: UsersGetMethod
  Type: AWS::ApiGateway::Method
  Properties:
   // (前のコードを省略)  
   Integration:
     Type: AWS_PROXY 
     IntegrationHttpMethod: POST
     Uri: !GetAtt GetFunction.Arn

Lambda関数のコード

// index.js

// putHandler関数 (前のコード省略)

exports.getHandler = async (event) => {

  const data = await dynamoDb.scan({ 
    TableName: "UsersTable" 
  }).promise();

  return {
    statusCode: 200, 
    body: JSON.stringify(data.Items)
  };

};

このようにAPI Gateway、Lambda、DynamoDBを連携してCRUD APIを実装できます。
IaCではリソース定
```
:::note 
続きをお願いします。
:::

```
 分かりました。IaCの続きです。

リソース定義だけではなく、ストレージなどの設定も必要です。

// S3バケットの定義

Resource: DeploymentBucket
  Type: AWS::S3::Bucket
  Properties:
    BucketName: ${self:custom.bucketName}

// バケットポリシーの設定    

Resource: DeploymentBucketPolicy
  Type: AWS::S3::BucketPolicy
  Properties: 
    Bucket: !Ref DeploymentBucket
    PolicyDocument:
      Version: 2012-10-17  
      Statement:
        - Sid: PublicReadForGetBucketObjects
          Effect: Allow
          Principal: '*'
          Action: s3:GetObject
          Resource: !Join 
            - ''
            - - 'arn:aws:s3:::'
              - !Ref DeploymentBucket
              - /*

// デプロイ設定

Resources: 
  WebAppDeployment:
    Type: AWS::CodeDeploy::DeploymentGroup
    Properties:
      ApplicationName: !Ref CodeDeployApplication
      DeploymentConfigName: !Ref CodeDeployDeploymentConfig
      Ec2TagFilters:
        - Key: Name
          Value: !Ref EC2InstanceTag
      ServiceRoleArn: !GetAtt CodeDeployRole.Arn

このようにS3バケットや
```
:::note 
続きをお願いします。
:::

```
 はい、IaCの続きですね。

S3バケットやバケットポリシー、CodeDeployなどのデプロイ設定も重要な部分です。

IaCのその他の部分としては、ロールやポリシーの設定も必要になります。

// IAMロール

Resource: LambdaRole  
  Type: AWS::IAM::Role
  Properties:
    AssumeRolePolicyDocument:
      Version: '2012-10-17'
      Statement:
        - Effect: Allow
          Principal:
            Service:
              - lambda.amazonaws.com
          Action:
            - sts:AssumeRole
    Policies:
      - PolicyName: LambdaPolicy
        PolicyDocument:
          Version: '2012-10-17'
          Statement:
            - Effect: Allow
              Action:
                - logs:CreateLogGroup
                - logs:CreateLogStream
                - logs:PutLogEvents
              Resource: arn:aws:logs:*:*:*

// IAMポリシー

Resource: DynamoDBPolicy
  Type: AWS::IAM::Policy
  Properties:
    PolicyName: DynamoDBPolicy
    PolicyDocument:
      Version: '2012-10-17'
      Statement:
        - Effect: Allow
          Action:
            - dynamodb:GetItem
           
```
:::note 
続きをお願いします。
:::

```
 はい、IaCの続きですね。

S3バケットやバケットポリシー、CodeDeployなどのデプロイ設定も重要な部分です。

IaCのその他の部分としては、ロールやポリシーの設定も必要になります。

// IAMロール

Resource: LambdaRole  
  Type: AWS::IAM::Role
  Properties:
    AssumeRolePolicyDocument:
      Version: '2012-10-17'
      Statement:
        - Effect: Allow
          Principal:
            Service:
              - lambda.amazonaws.com
          Action:
            - sts:AssumeRole
    Policies:
      - PolicyName: LambdaPolicy
        PolicyDocument:
          Version: '2012-10-17'
          Statement:
            - Effect: Allow
              Action:
                - logs:CreateLogGroup
                - logs:CreateLogStream
                - logs:PutLogEvents
              Resource: arn:aws:logs:*:*:*

// IAMポリシー

Resource: DynamoDBPolicy
  Type: AWS::IAM::Policy
  Properties:
    PolicyName: DynamoDBPolicy
    PolicyDocument:
      Version: '2012-10-17'
      Statement:
        - Effect: Allow
          Action:
            - dynamodb:GetItem
           
```
:::note 
続きをお願いします。
:::

```
 はい、IaCの続きですね。

IAMロールとポリシーはアクセス制御の観点から非常に重要です。

// IAMポリシー(続き)

Resource: DynamoDBPolicy  
  Properties:
    PolicyDocument:
      Statement:
        - Effect: Allow
          Action:
            - dynamodb:GetItem
            - dynamodb:PutItem
            - dynamodb:UpdateItem
            - dynamodb:DeleteItem
          Resource:
            - !GetAtt UsersTable.Arn 

// API Gateway実行ロール      

Resource: APIGatewayRole 
  Type: AWS::IAM::Role
  Properties:
    AssumeRolePolicyDocument: 
      Version: '2012-10-17'
      Statement:
        - Effect: Allow
          Principal:
            Service:
              - apigateway.amazonaws.com
          Action:
            - sts:AssumeRole
    Policies:
      - PolicyName: APIGatewayPolicy
        PolicyDocument:
          Version: '2012-10-17'
          Statement:
            - Effect: Allow
              Action:
                - logs:CreateLogGroup
                - logs:CreateLogStream
                - logs:DescribeLogGroups
                - logs:DescribeLogStreams
                - logs:PutLogEvents
                - logs:GetLogEvents
                - logs:FilterLogEvents
              Resource:
```
:::note 
続きをお願いします。
:::
```
 はい、IAMの設定は非常に重要ですね。

IaCのIAM設定の続きとして、API Gatewayの実行ロールも定義する必要があります。

// API Gateway実行ロール(続き)

Resource: APIGatewayRole
  // 中略
  Properties:
    Policies:
      - PolicyName: APIGatewayPolicy  
        PolicyDocument:
          Statement:
            - Effect: Allow
              Action:
               // 中略
              Resource:
                - arn:aws:logs:*:*:*
                - !Ref MyApi
                
// Lambda関数への実行ロールのアタッチ              
                
Resource: PutFunction
  DependsOn: LambdaRole
  Properties:
    Role: !GetAtt LambdaRole.Arn
    
Resource: GetFunction
  DependsOn: LambdaRole  
  Properties:
    Role: !GetAtt LambdaRole.Arn

このように、IAMのロールとポリシーを定義し、Lambda関数などにアタッチすることで、最小限のアクセス権限を与えることができます。

IaCは非常に重要なベストプラクティスで、インフラ全体の見通
```
:::note 
続きをお願いします。
:::
```
 はい、IaCはインフラの可視化やセキュリティ管理などにおいて重要なベストプラクティスですね。

IaCのメリットとして以下の点があげられます。

- インフラのコード化により、インフラの状態がコードで明確に定義されるため、インフラの可視化がしやすくなる

- コードでインフラを定義するため、バージョン管理ができ、変更履歴を追跡できる

- コードからインフラを自動プロビジョニングできるため、インフラの構築/変更がスピーディーに

- 設定のドリフト(コードと実際の設定のギャップ)を防げる

- コードレビューにより、セキュリティや運用面のベストプラクティスをチェックできる

- コードからインフラ全体を
```
:::note 
続きをお願いします。
:::
```
 はい、IaCのメリットですね。

IaCのメリットとして、以下の点もあげられます。

- コードからインフラ全体を再現・破棄できるので、環境の再構築が容易

- テストやステージング環境をコードで構築できるので、開発効率が向上

- コードのドライラン(実際にデプロイせず検証)ができるので、リスクが低減

- インフラをコードで定義するので、インフラ全体の構成がドキュメント化される

- インフラの変更履歴がコードで残るので、監査・遵守機能が向上

- コード化することで、インフラ全体の設定データが一元管理できる

このように、IaCはインフラ運用における非常に重要なベストプラクティスとなっています。コード
```
:::note 
続きをお願いします。
:::
```
 はい、IaCのメリットについて補足します。

IaCを導入することで、インフラ運用に次のようなメリットがあります。

- インフラの変更手順がコードとして明確に文書化されるので、運用標準化が図れる
- 設定の自動化により、人為的ミスが減少し、インフラの信頼性が向上する
- インフラ構成がコード化されるので、クラウドマイグレーションが容易になる
- コードレビューにより、セキュリティやコンプライアンスの確認がしやすくなる
- インフラの構成変更履歴がコードで追跡できるので、障害対応がスムーズ
- デプロイ・運用工数が削減され、コストが最適化される

このように、IaCはアジャイルなインフラ運用
```
:::note 
続きをお願いします。
:::
```
 はい、IaCのメリットについてもう少し補足させていただきます。

- IaCではインフラ全体の依存関係がコードで明示されるため、インフラ構成の理解が深まる

- 設定の変更履歴が追跡できるので、インフラの要件変更対応がスムーズ

- 設定データをコードで保管できるので、複数の環境での設定統一が図れる 

- 設定をコードから生成できるので、設定ミスによるインシデントが減少する

- コードレビューにより、セキュリティ強化やコスト最適化を推進できる

- コードベースのインフラなので、継続的デリバリやDevOpsの実現がしやすい

このように、IaCはアジャイルなインフラ運用、エンジニアリング、ガバナンスを実現する上
```

*****

####  モデル Jurassic-2 Ultra 結果

それっぽい不完全なyamlが生成されたと思ったら、Lambdaのコードを生成。

そして、また、Cloudformationで依頼していない、S3バケットやCodedeployを作り出す。その後はIaCのメリットを語り出し途中で切れたので続きを依頼すると、メリットの文章を最初から語り出すループにというような支離滅裂な感じでした。


# 所感

今回依頼した「AWSのサーバレスAPIの作成」というタスクにおいては、利用した2つのモデルが残念ながらChatGPTには遠く及ばない結果となりました。

しかしながら、Amazon Bedrockを使用することで、モデルの切り替えが非常に容易にできたのが印象的でした。
通常、現存する生成系AIを利用する場合、各モデルのサービスを個別に契約し、環境を構築し、それぞれのAPIを別々に利用する必要があります。これにはかなりのオーバーヘッドがあり、モデルの切り替えも大変です。

Bedrockは、これらのプロセスを単一の基盤で管理でき、更にセキュリティにも配慮した環境を提供してくれます。
これにより、今後増えてくるであろう生成系AIを、それぞれの強みや適用範囲に応じて柔軟に使い分けることができると感じました。

そして、もしかしたら、モデルGPT-4も近いうちにBedrock上で利用可能になる日が来るかもしれません

## 最後に

ここまで読んで頂いてありがとうございます。これを読んで頂いているあなたにとって一つでも参考になる情報があれば幸いです。

もし参考になったら「いいね」やストックしてもらえたら励みになりますのでよろしくお願いします。