AWS CloudFormationを使用してAmazon Lexのバージョンを作成した際の挙動を確認してみた
はじめに
AWSドキュメントには、AWS CloudFormationを使用したAmazon Lexのバージョン管理に関する詳細な記載がなく、その挙動をイメージすることが難しかったです。そこで今回は、CloudFormationを使用してLexのバージョンを作成する際の挙動を実際に確認してみました。
Amazon Lexのバージョンとエイリアスについての詳細は、以下のリンクをご参照ください。
挙動を確認するため、以下のCloudFormationテンプレートを使用してLexボットを作成します。
このボットは、Amazon Connectから呼び出され、特定の製品カテゴリーを聞き取る機能を持っています。
また、音声をS3バケットに保存し、Lexでの文字起こし内容をCloudWatch Logsにログとして記録します。
バージョンは作成せず、エイリアスは作成するテンプレートです。
AWSTemplateFormatVersion: 2010-09-09
Description: Amazon Lex Bot with Intent creation (Japanese)
Parameters:
LexBotName:
Type: String
Default: cm-hirai-product-name
Description: The name of the Lex bot
SlotName:
Type: String
Default: name
Description: The name of the slot
CustomSlotTypeName:
Type: String
Default: productname
Description: The name of the custom slot type
AliasName:
Type: String
AllowedValues:
- dev
- prd
Default: dev
Description: The alias name for the Lex bot
Resources:
MyLexBot:
Type: AWS::Lex::Bot
Properties:
Name: !Ref LexBotName
Description: !Ref LexBotName
DataPrivacy:
ChildDirected: false
IdleSessionTTLInSeconds: 300
RoleArn: !GetAtt LexBotRole.Arn
BotLocales:
- LocaleId: ja_JP
NluConfidenceThreshold: 0.40
VoiceSettings:
VoiceId: Kazuha
Intents:
- Name: FallbackIntent
ParentIntentSignature: AMAZON.FallbackIntent
- Name: ProductName
SampleUtterances:
- Utterance: '{name}'
- Utterance: 商材名は、{name}です。
- Utterance: '{name}です。'
- Utterance: 聞きたいのは、{name}についてです。
Slots:
- Name: !Ref SlotName
SlotTypeName: !Ref CustomSlotTypeName
ValueElicitationSetting:
SlotConstraint: Required
PromptSpecification:
MaxRetries: 3
MessageGroupsList:
- Message:
PlainTextMessage:
Value: 商材名をお伝え下さい。
IntentConfirmationSetting:
PromptSpecification:
MaxRetries: 3
MessageGroupsList:
- Message:
PlainTextMessage:
Value: 商材名は、{name}、ですね。よろしければ、はい、と、異なる場合、いいえ、とお伝え下さい。
## 確認プロンプトに NOと伝えた場合のボットのプロンプト
# DeclinationResponse:
# MessageGroupsList:
# - Message:
# PlainTextMessage:
# Value: 正しく商材名を聞き取れず、申し訳ございません。
## 応答を閉じる
# IntentClosingSetting:
# ClosingResponse:
# MessageGroupsList:
# - Message:
# PlainTextMessage:
# Value: 担当者にお繋ぎします
SlotPriorities:
- Priority: 1
SlotName: !Ref SlotName
SlotTypes:
- Name: !Ref CustomSlotTypeName
ValueSelectionSetting:
ResolutionStrategy: ORIGINAL_VALUE
SlotTypeValues:
- SampleValue:
Value: Wifi
- SampleValue:
Value: ウォーターサーバー
- SampleValue:
Value: スマートホームデバイス
- SampleValue:
Value: 電動自転車
TestBotAliasSettings:
BotAliasLocaleSettings:
- LocaleId: ja_JP
BotAliasLocaleSetting:
Enabled: true
## Lambdaを利用する場合
# CodeHookSpecification:
# LambdaCodeHook:
# LambdaArn: !GetAtt LambdaFunction.Arn
ConversationLogSettings:
TextLogSettings:
- Enabled: true
Destination:
CloudWatch:
CloudWatchLogGroupArn: !Sub "arn:aws:logs:${AWS::Region}:${AWS::AccountId}:log-group:${CloudWatchLogGroup}"
LogPrefix: TestBotAlias/
AudioLogSettings:
- Enabled: true
Destination:
S3Bucket:
S3BucketArn: !GetAtt S3Bucket.Arn
LogPrefix: TestBotAlias/
# バージョンを利用する場合
# BotVersion1:
# Type: AWS::Lex::BotVersion
# Properties:
# BotId: !Ref MyLexBot
# BotVersionLocaleSpecification:
# - LocaleId: ja_JP
# BotVersionLocaleDetails:
# SourceBotVersion: DRAFT
MyLexBotAlias:
Type: AWS::Lex::BotAlias
Properties:
BotAliasName: dev
BotId: !Ref MyLexBot
# バージョンを利用する場合
# BotVersion: !GetAtt BotVersion1.BotVersion
ConversationLogSettings:
TextLogSettings:
- Enabled: true
Destination:
CloudWatch:
CloudWatchLogGroupArn: !Sub "arn:aws:logs:${AWS::Region}:${AWS::AccountId}:log-group:${CloudWatchLogGroup}"
LogPrefix: dev/
AudioLogSettings:
- Enabled: true
Destination:
S3Bucket:
S3BucketArn: !GetAtt S3Bucket.Arn
LogPrefix: dev/
LexBotRole:
Type: AWS::IAM::Role
Properties:
AssumeRolePolicyDocument:
Version: 2012-10-17
Statement:
- Effect: Allow
Principal:
Service: lexv2.amazonaws.com
Action: sts:AssumeRole
Policies:
- PolicyName: !Sub ${LexBotName}-policy
PolicyDocument:
Version: 2012-10-17
Statement:
- Effect: Allow
Action:
- polly:SynthesizeSpeech
Resource: '*'
- Effect: Allow
Action:
- s3:PutObject
Resource:
- !Sub "arn:aws:s3:::${S3Bucket}/*"
- Effect: Allow
Action:
- logs:CreateLogStream
- logs:PutLogEvents
Resource:
- !Sub "arn:aws:logs:${AWS::Region}:${AWS::AccountId}:log-group:${CloudWatchLogGroup}:*"
CloudWatchLogGroup:
Type: AWS::Logs::LogGroup
Properties:
LogGroupName: !Sub "/aws/lex/${LexBotName}"
RetentionInDays: 365
S3Bucket:
Type: AWS::S3::Bucket
Properties:
BucketName: !Ref LexBotName
パラメータは、以下の内容でスタックを作成します。
スタックを作成すると、バージョンは、テンプレートに記載していませんが、ドラフトバージョンは自動作成されます。
バージョンは作成していないため、エイリアスdevは作成されますが、バージョンには関連付けられてはいません。
先に結論
CloudFormationを使用してLexのバージョンを作成した際の主な挙動は、以下の通りです
- 新しいバージョンを追加しつつ、元のバージョンを残す場合は、テンプレートにリソースとしてボットバージョンを追加する必要がある
- テンプレートのコード量がどんどん増えてしまう
- 元のバージョンが不要な場合は、テンプレートのバージョンの論理名を変更するだけでよい
- CloudFormationでバージョンを作成する場合、ボットの構築(Build)が自動的に行われる
上記の実際の挙動を確認してみます。
CloudFormationでバージョン1を作成
CloudFormationでバージョンを作成してエイリアスdevを関連付けるには、テンプレートに以下のように変更を加える必要があります。
以下の通りコメントアウトしました。
# バージョンを利用する場合
- # BotVersion1:
- # Type: AWS::Lex::BotVersion
- # Properties:
- # BotId: !Ref MyLexBot
- # BotVersionLocaleSpecification:
- # - LocaleId: ja_JP
- # BotVersionLocaleDetails:
- # SourceBotVersion: DRAFT
+ BotVersion1:
+ Type: AWS::Lex::BotVersion
+ Properties:
+ BotId: !Ref MyLexBot
+ BotVersionLocaleSpecification:
+ - LocaleId: ja_JP
+ BotVersionLocaleDetails:
+ SourceBotVersion: DRAFT
MyLexBotAlias:
Type: AWS::Lex::BotAlias
Properties:
BotAliasName: dev
BotId: !Ref MyLexBot
# バージョンを利用する場合
- # BotVersion: !GetAtt BotVersion1.BotVersion
+ BotVersion: !GetAtt BotVersion1.BotVersion
この変更を適用してスタックを更新します。
変更セットのプレビューは以下のようになります
バージョン1が作成されました。
バージョン1がエイリアスdevに関連付けられました。
手動でのバージョン作成との違い
手動でバージョンを作成する場合、以下のような状況では、ドラフトバージョンを構築(Build)してからバージョンを作成する必要があります
- ボット作成直後にバージョンを作成する場合
- ボットを作成し構築後、設定変更をしたため、その変更内容を反映したバージョンを作成する場合
ドラフトバージョンを構築せずにバージョンを作成すると、そのバージョンには設定変更内容が反映されません。また、ボット作成直後に構築しない場合、ボット自体利用することができません。
一方、CloudFormationでバージョンを作成する場合、スタック更新中に自動で構築(Build)が行われます。
CloudFormationでボット作成時(バージョンは未作成)
CloudFormationでバージョンを作成するようスタック更新後、自動で構築される
CloudFormationでバージョン2を作成
Lexボットの設定(例えば、インテントや発話例)を修正したと仮定し、新しいバージョン2を作成してエイリアスdevに関連付けるには、テンプレートに以下の対応が必要です。
- 新しいリソース(BotVersion2)を追加します。
- エイリアスdevの関連付けを、バージョン1からバージョン2に変更します。
具体的には、CloudFormationテンプレートに以下のような変更を加えます。
BotVersion1:
Type: AWS::Lex::BotVersion
Properties:
BotId: !Ref MyLexBot
BotVersionLocaleSpecification:
- LocaleId: ja_JP
BotVersionLocaleDetails:
SourceBotVersion: DRAFT
+ BotVersion2:
+ Type: AWS::Lex::BotVersion
+ Properties:
+ BotId: !Ref MyLexBot
+ BotVersionLocaleSpecification:
+ - LocaleId: ja_JP
+ BotVersionLocaleDetails:
+ SourceBotVersion: DRAFT
MyLexBotAlias:
Type: AWS::Lex::BotAlias
Properties:
BotAliasName: dev
BotId: !Ref MyLexBot
# バージョンを利用する場合
- BotVersion: !GetAtt BotVersion1.BotVersion
+ BotVersion: !GetAtt BotVersion2.BotVersion
上記の変更を適用してスタックを更新します。
変更セットのプレビューは以下のようになります
バージョン2が作成されました。
バージョン2がエイリアスdevに関連付けられました。
CloudFormationでバージョン1を削除
次に、テンプレートからバージョン1を以下のように削除します。
- BotVersion1:
- Type: AWS::Lex::BotVersion
- Properties:
- BotId: !Ref MyLexBot
- BotVersionLocaleSpecification:
- - LocaleId: ja_JP
- BotVersionLocaleDetails:
- SourceBotVersion: DRAFT
上記の変更を適用してスタックを更新します。
変更セットのプレビューは以下のようになります
バージョン1が削除されました。
論理名を変える
Lexボットの設定を再度変更したと仮定し、CloudFormationテンプレート内のバージョン2の論理名を変更した場合、バージョン3が作成されます。この動作を確認してみましょう。
以下の通り、論理名を変更します。
+ BotVersion3:
- BotVersion2:
Type: AWS::Lex::BotVersion
Properties:
BotId: !Ref MyLexBot
BotVersionLocaleSpecification:
- LocaleId: ja_JP
BotVersionLocaleDetails:
SourceBotVersion: DRAFT
MyLexBotAlias:
Type: AWS::Lex::BotAlias
Properties:
BotAliasName: dev
BotId: !Ref MyLexBot
# バージョンを利用する場合
+ BotVersion: !GetAtt BotVersion3.BotVersion
- BotVersion: !GetAtt BotVersion2.BotVersion
上記の変更を適用してスタックを更新します。
変更セットのプレビューは以下のようになります
バージョン2が削除され、バージョン3が作成されエイリアスdevに関連付けされました。
以上の動作から、次のことが分かりました
- 新しいバージョンを追加しつつ、元のバージョンを残す場合は、テンプレートにリソースとしてボットバージョンを追加する必要がある
- テンプレートのコード量がどんどん増えてしまう
- 元のバージョンが不要な場合は、テンプレートのバージョンの論理名を変更するだけでよい
- CloudFormationでバージョンを作成する場合、ボットの構築(Build)が自動的に行われる
元のバージョンを残す必要がある場合、テンプレートのコード量がどんどん増えてしまいますので、今後、代替案を考えてみます。
最後に
本記事では、AWS CloudFormationを使用してAmazon Lexのバージョンを作成する際の挙動確認しました。
特に注意すべき点として、各バージョンを保持する必要がある場合は、CloudFormationテンプレートにコードを追加する必要があります。
これにより、テンプレートが複雑化する可能性があります。
参考になれば幸いです。
参考