はじめに
ChatGPTがリリースされてからすでに1年近くが経過し、日々の業務に広く取り入れられていると思います。
もはや特別な存在ではなく、多くの方々が利用されているのではないでしょうか?
AWSが提供する新サービス、Amazon Bedrockがプレビューフェーズを経て一般公開されました。
AWS、生成系 AI のイノベーションを加速する新しい強力なサービス / 機能の提供を発表
Amazon Bedrockとは、生成系AIではなく生成系AIをさえる基盤サービスです。
このBedrockという基盤を使用することで、様々な生成系AIを単一のAPIで利用可能とし、セキュリティを重視した環境も構築できるのです。
ですので、タイトルを正確に書くと
「Amazon BedrockでAWSのサーバレスAPIを作成」
ではなく
「Amazon Bedrock上に展開されている生成系AIでAWSのサーバレスAPIを作成」
というのが正しいタイトルになります。
ChatGPTへの依頼
ChatGPTのモデルGPT-4がリリースされた直後「AWSのサーバレスAPIの作成を依頼してみたらどうなるか?」という事について検証しました。
生成された結果には、当時、大きな衝撃を受けました。それにより、エンジニアの働き方、存在意義、そして役割そのものが大きく変わっていくことを確信しました。同時に、このようなAI技術が日常的になった世の中で、「人間」は今後どう進んでいけばいいのか、と深く考えさせられるようになりました。
今回Bedrock上で現在使えるモデルに同じ依頼をしてみてどうなるか試してみました。
記事の構成上プロンプトと応答を分かりやすくする為、以下プロンプトは以下スタイルで書きます。
入力のプロンプトはこのスタイルで書きます。
プロンプト
以前ChatGPTに依頼したプロンプトと同じこちらのプロンプトを利用しました。
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({})
}
続きをお願いします。
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
続きをお願いします。
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
続きをお願いします。
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ではリソース定
続きをお願いします。
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ではリソース定
続きをお願いします。
分かりました。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バケットや
続きをお願いします。
はい、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
続きをお願いします。
はい、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
続きをお願いします。
はい、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:
続きをお願いします。
はい、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は非常に重要なベストプラクティスで、インフラ全体の見通
続きをお願いします。
はい、IaCはインフラの可視化やセキュリティ管理などにおいて重要なベストプラクティスですね。
IaCのメリットとして以下の点があげられます。
- インフラのコード化により、インフラの状態がコードで明確に定義されるため、インフラの可視化がしやすくなる
- コードでインフラを定義するため、バージョン管理ができ、変更履歴を追跡できる
- コードからインフラを自動プロビジョニングできるため、インフラの構築/変更がスピーディーに
- 設定のドリフト(コードと実際の設定のギャップ)を防げる
- コードレビューにより、セキュリティや運用面のベストプラクティスをチェックできる
- コードからインフラ全体を
続きをお願いします。
はい、IaCのメリットですね。
IaCのメリットとして、以下の点もあげられます。
- コードからインフラ全体を再現・破棄できるので、環境の再構築が容易
- テストやステージング環境をコードで構築できるので、開発効率が向上
- コードのドライラン(実際にデプロイせず検証)ができるので、リスクが低減
- インフラをコードで定義するので、インフラ全体の構成がドキュメント化される
- インフラの変更履歴がコードで残るので、監査・遵守機能が向上
- コード化することで、インフラ全体の設定データが一元管理できる
このように、IaCはインフラ運用における非常に重要なベストプラクティスとなっています。コード
続きをお願いします。
はい、IaCのメリットについて補足します。
IaCを導入することで、インフラ運用に次のようなメリットがあります。
- インフラの変更手順がコードとして明確に文書化されるので、運用標準化が図れる
- 設定の自動化により、人為的ミスが減少し、インフラの信頼性が向上する
- インフラ構成がコード化されるので、クラウドマイグレーションが容易になる
- コードレビューにより、セキュリティやコンプライアンスの確認がしやすくなる
- インフラの構成変更履歴がコードで追跡できるので、障害対応がスムーズ
- デプロイ・運用工数が削減され、コストが最適化される
このように、IaCはアジャイルなインフラ運用
続きをお願いします。
はい、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上で利用可能になる日が来るかもしれません
最後に
ここまで読んで頂いてありがとうございます。これを読んで頂いているあなたにとって一つでも参考になる情報があれば幸いです。
もし参考になったら「いいね」やストックしてもらえたら励みになりますのでよろしくお願いします。