【免费下载链接】aws-cdk-examples
Example projects using the AWS CDK
导读
本文基于 aws-cdk-examples 仓库中的 typescript/lexbot 示例,讲解如何用 AWS CDK 以纯代码方式创建一个可预订酒店与租车的 Amazon Lex 机器人(BookTrip)。示例完整演示了 Lex 机器人在 CloudFormation 资源层面(AWS::Lex::Bot、AWS::Lex::BotVersion、AWS::Lex::BotAlias)的声明式定义方式,以及 IAM 运行时角色的挂载、DRAFT 版本发布、别名绑定等关键流程。读完本文,你将掌握用 CDK(TypeScript)从零编排 Lex 机器人内联定义、槽位(Slot)、意图(Intent)、版本与别名,并完成构建、部署与模板合成的完整实战链路。
示例概述:以代码定义 Lex 机器人
Amazon Lex 通常通过控制台或 API 以交互方式构建对话机器人,而本示例展示了另一条路径:将整个机器人定义(包括语言区域、槽位类型、意图、提示语)内联写进 CDK 代码,随 CloudFormation 模板一次性部署。README 明确说明,该示例创建了一个用于预订酒店房间和租用汽车的机器人,其定义方式与 CloudFormation 官方文档中AWS::Lex::Bot的示例一致。
整个示例的核心逻辑集中在 lib/lexbot-stack.ts 的LexbotStack中,入口位于 bin/lexbot.ts,工程结构与运行方式记录在 cdk.json 和 package.json 中。
架构:四个资源与一条清晰的依赖链
README 将示例要创建的资源归纳为 4 项,这同时也是理解本示例架构的骨架:
- IAM Role:供 Lex 服务在运行时调用其他 AWS 服务使用;
- 内联机器人定义(Inline Bot Definition):依赖上述 IAM Role,机器人本体以代码内联形式定义;
- Bot 版本(Bot Version):依赖 Lex Bot 的 DRAFT 版本,为其创建可发布版本;
- Bot 别名(Bot Alias):通过绑定上面创建的 Bot 版本,为机器人提供稳定的调用入口。
这四个资源在源码中的对应关系如下表:
| 资源 | CDK 构造 | 源码位置 | 关键依赖 |
|---|---|---|---|
| IAM 运行时角色 | iam.Role | lib/lexbot-stack.ts#L11-L14 | lexv2.amazonaws.com服务主体 |
| 机器人本体 | lex.CfnBot | lib/lexbot-stack.ts#L17-L156 | roleArn引用 IAM Role |
| Bot 版本 | lex.CfnBotVersion | lib/lexbot-stack.ts#L158-L167 | botId与DRAFT源版本 |
| Bot 别名 | lex.CfnBotAlias | lib/lexbot-stack.ts#L170-L175 | botVersion引用版本资源属性 |
依赖方向为:Bot → IAM Role;BotVersion → Bot;BotAlias → BotVersion,形成一条自底向上的引用链,任何一步缺失都会导致机器人无法完整发布。
源码逐段拆解:从 IAM 角色到内联机器人
1. 为 Lex 服务创建 IAM 运行时角色
const botRuntimeRole = new iam.Role(this, 'BotRuntimeRole', { assumedBy: new iam.ServicePrincipal('lexv2.amazonaws.com'), managedPolicies: [iam.ManagedPolicy.fromAwsManagedPolicyName('AmazonLexFullAccess')] });代码见 lib/lexbot-stack.ts#L11-L14。这里有两个要点:
- 信任主体使用
lexv2.amazonaws.com,即 Amazon Lex V2 服务,使其能够代入该角色发起运行时调用; - 权限来源直接挂载 AWS 托管策略
AmazonLexFullAccess。在生产环境中建议按最小权限原则替换为自定义策略,仅授予机器人运行时实际需要调用的服务权限(如 Lambda、DynamoDB 等)。
2. 内联定义机器人本体(CfnBot)
机器人本体使用底层 L1 构造lex.CfnBot,将定义全部内联在botLocales中。基础属性如下:
const bookTripTemplateBot = new lex.CfnBot(this, 'BookTripTemplateBot', { roleArn: botRuntimeRole.roleArn, name: 'BookTripWithCFN', dataPrivacy: { ChildDirected : false }, idleSessionTtlInSeconds: 300, description: 'How to create a BookTrip bot with CDK', autoBuildBotLocales: false, botLocales: [ ... ] });关键参数含义(对应 lib/lexbot-stack.ts#L17-L23):
roleArn:绑定第 1 步创建的 IAM 角色,体现"Bot 依赖 IAM Role"这一关系;name:机器人名称BookTripWithCFN,用于在 Lex 控制台与 API 中标识;dataPrivacy:ChildDirected设为false,声明该机器人不面向儿童,符合 Lex 的数据隐私配置要求;idleSessionTtlInSeconds:会话空闲超时时间,示例为 300 秒(5 分钟),超过后会话状态将重置;autoBuildBotLocales:设为false,表示不自动构建语言区域,避免在每次代码变更时触发构建流程,改由显式控制构建时机。
3. Bot Locale:语言、语音与 NLU 阈值
{ localeId: 'en_US', description: 'Book a trip bot Locale', nluConfidenceThreshold: 0.40, voiceSettings: { voiceId: 'Ivy' }, ... }见 lib/lexbot-stack.ts#L25-L31。本示例为机器人配置了单一en_US区域:
nluConfidenceThreshold:NLU(自然语言理解)置信度阈值,设为 0.40。意图识别的置信度低于该值时,机器人会拒绝匹配(可配合兜底意图处理);voiceSettings.voiceId:语音 ID 设为Ivy,这是 Lex 提供的标准女声之一,用于语音交互场景的 TTS 播报。
4. 自定义槽位类型(Slot Type)
在区域定义中声明了两个自定义槽位类型,用于约束用户输入的可选值:
slotTypes: [ { name: 'CarTypeValues', slotTypeValues: [ { sampleValue: { value: 'economy' } }, { sampleValue: { value: 'standard' } }, { sampleValue: { value: 'midsize' } }, { sampleValue: { value: 'full size' } }, { sampleValue: { value: 'luxury' } }, { sampleValue: { value: 'minivan' } } ], valueSelectionSetting: { resolutionStrategy: 'ORIGINAL_VALUE' } }, { name: 'RoomTypeValues', slotTypeValues: [ { sampleValue: { value: 'queen' } }, { sampleValue: { value: 'king' } }, { sampleValue: { value: 'deluxe' } } ], valueSelectionSetting: { resolutionStrategy: 'ORIGINAL_VALUE' } } ]见 lib/lexbot-stack.ts#L32-L56:
CarTypeValues:租车场景的车型枚举,共 6 个取值(economy / standard / midsize / full size / luxury / minivan);RoomTypeValues:酒店场景的房型枚举,共 3 个取值(queen / king / deluxe);resolutionStrategy: 'ORIGINAL_VALUE':槽位解析策略,表示将用户原话直接作为槽位值返回,而不做同义词归一化。
除自定义槽位类型外,各意图还大量使用了 Amazon 内置槽位类型,如AMAZON.City、AMAZON.Date、AMAZON.Number,见 lib/lexbot-stack.ts#L97-L101 与 lib/lexbot-stack.ts#L142-L145,它们能自动完成城市名、日期与数字的识别与解析。
5. 意图(Intent)设计:BookCar 与 BookHotel
机器人定义了三个意图:BookCar(预订租车)、BookHotel(预订酒店)与FallbackIntent(兜底意图)。前两者的结构完全对称,均由示例话语、槽位、槽位优先级、确认提示与拒绝响应组成。
BookCar:租车意图
{ name: 'BookCar', description: 'Intent to book a car on StayBooker', sampleUtterances: [ { utterance: 'Book a car' }, { utterance: 'Reserve a car' }, { utterance: 'Make a car reservation' } ], slotPriorities: [ { priority: 4, slotName: 'DriverAge' }, { priority: 1, slotName: 'PickUpCity' }, { priority: 3, slotName: 'ReturnDate' }, { priority: 5, slotName: 'CarType' }, { priority: 2, slotName: 'PickUpDate' } ], ... }见 lib/lexbot-stack.ts#L57-L68。slotPriorities决定了对话过程中槽位的填充顺序:机器人会先询问优先级为 1 的PickUpCity(取车城市),随后是PickUpDate(取车日期)、ReturnDate(还车日期)、DriverAge(驾驶员年龄),最后是CarType(车型)。
五个槽位均配置了valueElicitationSetting,即槽位采集提示。以PickUpCity为例(lib/lexbot-stack.ts#L97):
{ name: 'PickUpCity', slotTypeName: 'AMAZON.City', valueElicitationSetting: { slotConstraint: 'Required', promptSpecification: { messageGroupsList: [ { message: { plainTextMessage: { value: 'In what city do you need to rent a car?' } } } ], maxRetries: 3, allowInterrupt: false } } }slotConstraint: 'Required'表示该槽位为必填项,机器人会持续追问直至获取有效值;maxRetries: 3表示同一问题最多重试 3 次;allowInterrupt: false表示在机器人播报提示时不允许用户打断。其余槽位(PickUpDate、ReturnDate、DriverAge、CarType)结构一致,只是提示语与槽位类型不同。
BookHotel:酒店意图
BookHotel的示例话语更加灵活,甚至包含槽位引用语法:
sampleUtterances: [ { utterance: 'Book a hotel' }, { utterance: 'I want a make hotel reservations' }, { utterance: 'Book a {Nights} night stay in {Location}' } ]见 lib/lexbot-stack.ts#L107。第三条话语Book a {Nights} night stay in {Location}展示了 Lex 的**槽位注入(slot in utterance)**能力:用户可以在同一句话中同时表达"住几晚"和"在哪个城市",NLU 会直接从话语中抽取对应槽位值,无需逐一追问。
该意图的四个槽位为Location(城市)、CheckInDate(入住日期)、Nights(晚数)、RoomType(房型),见 lib/lexbot-stack.ts#L141-L145。
确认设置:intentConfirmationSetting
两个意图都配置了intentConfirmationSetting,在收集完所有槽位后,机器人会复述订单信息并向用户确认(lib/lexbot-stack.ts#L69-L95):
intentConfirmationSetting: { promptSpecification: { messageGroupsList: [ { message: { plainTextMessage: { value: 'Okay, I have you down for a {CarType} rental in {PickUpCity} from {PickUpDate} to {ReturnDate}. Should I book the reservation?' } } } ], maxRetries: 3, allowInterrupt: false }, declinationResponse: { messageGroupsList: [ { message: { plainTextMessage: { value: 'Okay, I have cancelled your reservation in progress.' } } } ], allowInterrupt: false } }promptSpecification:确认提示语,通过{CarType}、{PickUpCity}等占位符动态回填已收集的槽位值,实现自然的订单复述;declinationResponse:用户否定确认时的响应文案,示例返回"已取消进行中的预订"。
注意一个细节差异:BookCar的declinationResponse.allowInterrupt为false(lib/lexbot-stack.ts#L93),而BookHotel的同一字段为true(lib/lexbot-stack.ts#L132),说明每个意图的交互细节都可以独立微调。
FallbackIntent:兜底意图
{ name: 'FallbackIntent', description: 'Default intent when no other intent matches', parentIntentSignature: 'AMAZON.FallbackIntent' }见 lib/lexbot-stack.ts#L148-L152。当用户输入无法匹配BookCar或BookHotel(或 NLU 置信度低于 0.40 的阈值)时,机器人会落入此意图,保证对话不会意外中断。
版本发布:BotVersion 与 BotAlias
机器人定义完成后,还需经过"版本化 + 别名绑定"两步才能对外提供稳定调用入口。
创建 Bot 版本(依赖 DRAFT)
const bookTripBotVersionWithCFN = new lex.CfnBotVersion(this, 'BookTripBotVersionWithCFN', { botId: bookTripTemplateBot.ref, botVersionLocaleSpecification: [ { localeId: 'en_US', botVersionLocaleDetails: { sourceBotVersion: 'DRAFT' } } ], description: 'BookTrip Version' });见 lib/lexbot-stack.ts#L158-L167。要点:
botId使用bookTripTemplateBot.ref引用机器人逻辑 ID,天然形成 CDK 层面的依赖关系;sourceBotVersion: 'DRAFT'表示以机器人的草稿版本(最新未发布改动)为源创建版本快照。这正对应 README 中"Bot 版本依赖 Lex Bot 的 DRAFT 版本"的说明;- 每次部署都会基于最新 DRAFT 生成一个新的版本号。
创建 Bot 别名(绑定版本)
new lex.CfnBotAlias(this, 'FirstBotAliasWithCFN', { botId: bookTripTemplateBot.ref, botAliasName: 'BookTripVersion1Alias', botVersion: bookTripBotVersionWithCFN.attrBotVersion, sentimentAnalysisSettings: { DetectSentiment: true } });见 lib/lexbot-stack.ts#L170-L175。别名是客户端调用机器人的固定入口:
botVersion通过attrBotVersion引用CfnBotVersion资源返回的版本号,形成"别名 → 版本"的依赖;botAliasName设为BookTripVersion1Alias,客户端 SDK 通过 BotId + BotAliasId 组合调用机器人;sentimentAnalysisSettings.DetectSentiment设为true,开启对话情绪分析,可在后续集成中获取每条用户消息的情感倾向。
至此,README 描述的 4 项资源全部落地,依赖链完整闭合。
工程结构与入口文件
项目采用标准 CDK TypeScript 布局:
typescript/lexbot/ ├── bin/lexbot.ts # 入口:实例化 LexbotStack ├── lib/lexbot-stack.ts # 核心栈:IAM 角色 + 机器人 + 版本 + 别名 ├── test/lexbot.test.ts # Jest 测试骨架 ├── cdk.json # CDK 应用配置 ├── package.json # 依赖与脚本 ├── jest.config.js # Jest 配置 └── tsconfig.json # TypeScript 编译配置入口文件 bin/lexbot.ts 创建cdk.App并实例化LexbotStack。默认未指定env,栈为环境无关(environment-agnostic)模板;如需绑定特定账号与区域,可取消env: { account: process.env.CDK_DEFAULT_ACCOUNT, region: process.env.CDK_DEFAULT_REGION }的注释(bin/lexbot.ts#L13)。
cdk.json 中的app字段声明了启动命令:
"app": "npx tsc && npx tsx bin/lexbot.ts"即先由tsc编译 TypeScript,再通过tsx直接运行入口。依赖版本见 package.json:aws-cdk-lib2.262.1、constructs^10、aws-cdkCLI 2.1133.0,build脚本对应tsc,test脚本对应jest。
构建、部署与模板合成
README 给出了完整的本地操作流程,须在示例根目录(typescript/lexbot)下执行。
1. 构建
npm install -g aws-cdk npm install npm run build依次完成:全局安装 CDK CLI → 安装示例依赖 → 编译 TypeScript 并生成 CloudFormation 模板。npm run build实际执行package.json中的tsc脚本,产物(含cdk.out目录)会被 tsconfig.json 的exclude排除在编译范围之外。
2. 部署
cdk deploy将LexbotStack部署(或重新部署)到当前 AWS CLI 配置对应的账号与区域。部署前请确认本地已配置 AWS 凭证。整个栈会按依赖顺序创建 IAM 角色、机器人、版本与别名。
3. 合成 CloudFormation 模板
cdk synth仅合成而不部署,生成的模板输出到cdk.out目录。可借此检查 Lex 机器人内联定义最终渲染成的AWS::Lex::Bot、AWS::Lex::BotVersion、AWS::Lex::BotAlias资源 JSON 结构,验证槽位、意图与依赖关系是否符合预期。
测试骨架说明
仓库附带了 test/lexbot.test.ts,目前内容整体注释,仅保留了一个测试骨架示例。从注释代码可以看出预期的测试模式:使用aws-cdk-lib/assertions的Template.fromStack(stack)将栈渲染为模板,再通过template.hasResourceProperties('AWS::SQS::Queue', ...)断言资源属性。读者可参照该模式,将断言对象替换为AWS::Lex::Bot、AWS::Lex::BotVersion与AWS::Lex::BotAlias,编写资源属性级回归测试。
总结与扩展方向
本示例以最简洁的资源组合展示了 CDK 声明式定义 Lex 机器人的完整范式:
- 单一栈、四个资源、一条依赖链:IAM 角色 → 内联机器人(
CfnBot)→ 版本(CfnBotVersion)→ 别名(CfnBotAlias); - 机器人定义全部内联:语言区域、NLU 阈值、语音、槽位类型、意图、示例话语、确认提示均在
botLocales中以代码表达,可随模板版本化、可审计、可复用; - 对话交互细节可编程:槽位优先级、必填约束、重试次数、打断开关、情绪分析等交互参数全部可配置。
后续扩展方向包括:将autoBuildBotLocales设为true以自动化区域构建;接入 Lambda 实现预订后端的实际执行业务逻辑;按最小权限替换AmazonLexFullAccess托管策略;以及为多个区域(如en_US与zh_CN)分别声明botLocales以实现多语言机器人。
【免费下载链接】aws-cdk-examples
Example projects using the AWS CDK
相关推荐
使用 AWS SDK for JavaScript v3 在 Web 应用中构建多语言 Amazon Lex 聊天机器人(lex-bot 示例)
使用 AWS SDK for JavaScript v3 在 Web 应用中构建多语言 Amazon Lex 聊天机器人(lex bot 示例) 导读 本文围绕
示例工程教程后端Zappa与AWS Lex:构建无服务器聊天机器人应用
Zappa与AWS Lex:构建无服务器聊天机器人应用 你是否还在为聊天机器人的服务器部署、扩展和维护而烦恼?本文将带你了解如何使用Zappa和AWS Lex构
云原生DevOps后端使用 AWS SDK for Java v2 构建多语言 Amazon Lex 聊天机器人并集成到 Spring Boot 应用
使用 AWS SDK for Java v2 构建多语言 Amazon Lex 聊天机器人并集成到 Spring Boot 应用 导读 本教程基于当前仓库 ja
示例工程教程后端
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考