AWS Machine Learning Blog

Building a restaurant telephony AI host with Amazon Bedrock AgentCore and Amazon Nova 2 Sonic

6.9内容质量
Building a restaurant telephony AI host with Amazon Bedrock AgentCore and Amazon Nova 2 Sonic

TL;DR · AI 摘要

Building a restaurant telephony AI host with Amazon Bedrock AgentCore and Amazon Nova 2 Sonic Artificial Intelligence Bu...

核心要点

  • 主题聚焦:Building a restaurant telephony AI host with Ama
  • 来源:AWS Machine Learning Blog,建议结合原文判断细节。
  • AI 分析暂不可用,本条为保底评分与摘要。
#AI#编程#后端#云计算#安全
打开原文

使用 Amazon Bedrock AgentCore 和 Amazon Nova 2 Sonic 构建餐厅电话 AI 主持人 | 人工智能

使用 Amazon Bedrock AgentCore 和 Amazon Nova 2 Sonic 构建餐厅电话 AI 主持人

餐厅每月平均会错过每个地点约 150 通电话,其中约 60% 是顾客试图下单或预订餐桌。这些电话大多在晚餐时段涌入,此时正是主持人接待客人、服务员翻台的关键时刻,电话却往往被忽视。让员工离开岗位去接听电话并不能解决问题,反而会同时损害顾客体验和员工体验。添加应用程序或网站虽然能帮助偏好在线下单的顾客,但对只想打电话的顾客毫无帮助。

在本文中,我们将展示如何构建一个语音下单系统,该系统能够接听电话号码并从问候到确认完成整个下单流程。该系统使用 Amazon Bedrock AgentCore 托管和运行代理,通过 Model Context Protocol (MCP) 与餐厅后端连接,采用 Amazon Nova 2 Sonic 实现实时语音交互。操作指南涵盖使用 AWS Cloud Development Kit (AWS CDK) 部署完整堆栈,通过 Amazon Elastic Container Service (Amazon ECS) 和 AWS Fargate 上的 Session Initiation Protocol (SIP) 网关将电话呼叫接入代理。系统在电话仍在响铃时预热代理会话,确保呼叫者永远不会听到死线。

解决方案概述

该系统包含三层架构。电话层处理与电话相关的特殊需求。音频通过电话网络而非浏览器传输,系统通过电话号码而非登录信息识别来电者。SIP 网关通过签名的 WebSocket 连接将音频流传输到代理层,代理层使用 Amazon Nova 2 Sonic 与用户进行对话。代理通过 MCP 工具与后端层通信。后端层存储菜单、购物车、订单和位置信息。将这些层分离意味着下单逻辑可以独立于调用它的渠道。新的渠道(如移动应用或自助终端)可以连接到相同的代理而无需重写后端。由于 MCP 是连接代理与外部工具的开放标准,后端可以更改而无需修改代理。代理支持文本和音频作为输入和输出,通过单向双向流处理转录、对话轮次和中断。

该解决方案部署了以下组件:

在电话侧,Amazon Chime SDK Voice Connector 提供 SIP 中继和免费电话号码以接收来电。AWS Fargate 上的 Amazon ECS 在网络负载均衡器后运行 SIP 网关。对于代理层,AgentCore Runtime 主持对话逻辑,每个通话在独立的微虚拟机中运行以实现隔离。Amazon Nova 2 Sonic 处理语音到语音的交互。AgentCore Gateway 将后端 API 暴露为代理可按名称发现和调用的 MCP 工具。后端层使用 Amazon API Gateway 提供受 AWS Identity and Access Management (IAM) 保护的 REST 端点。AWS Lambda 运行菜单、购物车、订单和位置查询的业务逻辑。Amazon DynamoDB 存储数据,Amazon Location Service 处理地理编码和路线计算。Amazon Elastic Container Registry (Amazon ECR)、AWS CodeBuild 和 Amazon Simple Storage Service (Amazon S3) 用于构建和存储代理容器镜像。

架构图

以下图表展示了该解决方案,分为四个部分。

在A部分中,餐厅的后端基础设施首先部署。Amazon DynamoDB 存储客户、订单、菜单、购物车和位置数据,Amazon Location Service 处理地址和路线。AWS Lambda 运行业务逻辑,Amazon API Gateway 通过 IAM 授权对外暴露接口。资源按照依赖顺序部署。

B部分创建 AgentCore 网关,设置其 IAM 权限,并配置网关将后端端点作为代理可访问的 MCP 工具暴露。这是将代理与后端解耦的层级。没有它,添加或更改工具将需要重新部署代理本身。

C部分负责代理的配置。它创建 Amazon ECR 仓库,并使用 Amazon S3 和 AWS CodeBuild 构建并推送容器镜像。随后部署 AgentCore 运行时。同时部署支持代理个性化每个呼叫的组件,包括一个用于渲染提示的 Lambda 函数,以及一组 AWS Systems Manager Parameter Store 条目,其中存储了提示模板和用于呼叫者身份验证的密钥。

D部分配置电话路径。它设置 Amazon Chime SDK 语音连接器和一个免费电话号码,一个决定如何处理来电的 SIP 媒体应用 Lambda,一个共享的 Amazon 虚拟私有云(Amazon VPC),以及 SIP 网关(drachtio-server),该网关在 AWS Fargate 上通过网络负载均衡器后运行于 Amazon ECS。网关在 Chime SDK 语音连接器和 AgentCore 运行时之间桥接呼叫。

上图中的编号注释追踪了整个解决方案的端到端流程:

  • 电话呼叫通过 Amazon Chime SDK 配置的电话号码发起,由客户直接拨打或从其他线路转接而来。
  • Amazon Chime SDK 接听呼叫并调用 AWS Lambda 以建立桥接。
  • Lambda 创建会话标识符,并连接到 AgentCore 运行时以预热微虚拟机,从而避免媒体流开始时的冷启动。
  • Lambda 成功响应后,Amazon Chime SDK 通过 TCP 5060 端口发送 SIP 邀请,向网络负载均衡器发起桥接操作。
  • 运行在 AWS Fargate 上的 SIP 服务接受邀请,并在相同容器的实时传输协议(RTP)服务中分配一个空闲端口,用于接收指定公共 IP 地址的媒体流。
  • RTP 服务通过 UDP 端口从语音连接器接收媒体,并连接到 AgentCore 运行时的 WebSocket 以开始媒体转换,使用 SIP 媒体应用处理器创建的相同会话标识符。
  • AgentCore 运行时调用 AWS Lambda 函数,基于会话标识符和客户在 Amazon DynamoDB 中的记录,从 AWS Systems Manager Parameter Store 构建系统提示。
  • AgentCore 运行时与 Amazon Nova 2 Sonic 建立会话,并通过已建立的连接按照系统提示指令向客户问候。
  • AgentCore 运行时通过 MCP 协议从 AgentCore 网关列出并调用可用工具。
  • AWS CDK 将解决方案部署到 Amazon S3,触发 AWS CodeBuild 构建容器镜像并存储在 Amazon ECR 中。AgentCore 运行时和 AWS Fargate 使用这些镜像部署代理以及 SIP 和 RTP 服务器。
  • Amazon CloudWatch 提供跨所有服务的集中监控、日志记录和告警功能,所有静态数据均使用 AWS 密钥管理服务(AWS KMS)进行加密。

呼出项 1–9 发生在单次通话过程中,呼出项 10 说明解决方案如何部署 SIP 服务器和 AgentCore Runtime,呼出项 11 说明其监控和安全机制。以下部分将部署和运维内容暂时搁置,更聚焦于通话本身。

通话流程

本节从呼叫者的视角追踪一次通话,从首次响铃到语音回复。其运行时路径与前文架构图中呼出项 1–9 的路径相同。下图以序列形式展示该流程,使事件顺序更直观。

上图中编号步骤对应通话的以下阶段:

  • 呼叫者拨打免费电话号码,Amazon Chime SDK Voice Connector 接听来电。
  • Voice Connector 调用 SIP 媒体应用 Lambda,该 Lambda 为通话计算会话标识符。
  • Lambda 向 AgentCore Runtime 发送预热请求,使代理在电话仍在响铃时准备其会话。
  • Lambda 指示 Voice Connector 将通话桥接到运行在 AWS Fargate 上的 Amazon ECS 上的 SIP 网关,并传递会话标识符。
  • SIP 网关使用相同的会话标识符向 AgentCore Runtime 打开 SigV4 签名的 WebSocket。通话连接到预热会话,呼叫者音频传输给代理,代理音频回传给呼叫者。
  • 代理通过 AgentCore Gateway 调用后端工具,与 Amazon Nova 2 Sonic 进行对话,以获取菜单、购物车、订单或位置数据。

先决条件

开始之前,请确认已具备以下条件:

  • AWS 账户。
  • 在部署的 AWS 区域中,已通过 Amazon Bedrock 控制台的模型访问页面申请了 Amazon Nova 2 Sonic 的 Amazon Bedrock 模型访问权限。
  • Amazon Chime SDK PSTN 音频访问权限,如果在该账户中从未订购过号码,需在 Amazon Chime SDK 控制台中申请增加电话号码配额。
  • Node.js 24.x 或更高版本。
  • 已配置 AWS 命令行界面(AWS CLI)2.x 并设置凭证。
  • 使用 git 克隆仓库。
  • 在目标账户和区域中已安装 AWS CDK(通过命令 npx cdk bootstrap aws://<ACCOUNT_ID>/<REGION> 完成引导)。

代理容器使用 Python 构建,但构建过程在 AWS CodeBuild 中运行,因此您本地无需安装 Python。请在 Amazon Nova 2 Sonic、Amazon Chime SDK PSTN 音频和 AgentCore Runtime 均可用的区域进行部署。US East (N. Virginia) 区域(us-east-1)是理想的起点。

使用 AWS CDK 部署解决方案

完整解决方案可在 GitHub 的示例仓库中找到。克隆仓库并进入项目目录。

code
git clone https://github.com/aws-samples/sample-restaurant-telephony-ai-host-using-amazon-bedrock-agentcore-nova-sonic.git
cd sample-restaurant-telephony-ai-host-using-amazon-bedrock-agentcore-nova-sonic

运行预检脚本。该脚本将确认 Node.js、AWS CLI、git、AWS CDK 引导工具和 Amazon Bedrock 模型访问权限是否已就绪,并报告缺失项。

code
./scripts/preflight-check.sh

然后使用部署前缀运行部署脚本。该前缀会添加到所有资源名称中,您可借此在同一账户中多次部署解决方案。

code
./scripts/deploy-all.sh --deploymentPrefix qsr-tel

该脚本按顺序部署每个AWS CDK堆栈,并将一个堆栈的输出传递给后续堆栈。它首先构建后端,然后在后端API前面添加AgentCore网关。接下来,它使用AWS CodeBuild构建并推送代理容器镜像,并在AgentCore运行时部署代理。最后,它在AWS Fargate上的Amazon ECS上启动SIP网关,并配置Amazon Chime SDK语音连接器和免费电话号码。它还会预加载示例菜单和位置数据,这样您可以在部署完成后立即下单测试。代理容器镜像的首次构建需要几分钟时间,因此在AWS CodeBuild运行期间,脚本会暂停等待。

当脚本执行完成后,它会打印出需要拨打的号码:

code
您的电话代理已上线,号码为+1XXXXXXXXXX。请拨号测试。

SIP网关的工作原理

电话层只有一个任务:将电话呼叫转换为代理可读写的媒体流。这很重要,因为电话网络和代理使用不同的协议。电话通过UDP传输RTP音频包,而代理期望通过WebSocket传输Amazon Nova 2 Sonic格式的音频帧。如果没有中间的转换层,代理需要了解SIP协议、编解码器协商和网络级媒体路由,这会将代理绑定到单一通道。两个组件负责完成这个转换。

Amazon Chime SDK语音连接器接收来电并调用SIP媒体应用Lambda。该Lambda负责将呼叫路由到SIP网关,并携带会话标识符以便下一跳知道该呼叫属于哪个会话。

SIP网关运行在AWS Fargate上的Amazon ECS上。它使用drachtio-server处理SIP信令,并使用Node.js桥接音频。网关接听来电,并在电话网络使用的音频格式和Amazon Nova 2 Sonic期望的格式之间进行转换。为了实现高可用性(HA),网关在两个可用区(AZ)中运行两个任务,这提供了冗余,并可以将呼叫计数指标发布到Amazon CloudWatch用于扩展。呼叫的信令通过网络负载均衡器传递,但音频本身直接在Voice Connector和Fargate任务之间传输,这样负载均衡器就不会处于媒体路径上。

电话响铃时预热代理

语音呼叫对静音非常敏感。如果来电者连接后几秒钟内听不到任何声音,即使系统正常工作,通话也会感觉中断。启动通话的缓慢部分是一次性设置。代理需要为来电者解析系统提示,打开Amazon Nova 2 Sonic流,并发现可用的MCP工具。

为了避免让来电者等待,SIP媒体应用Lambda在电话响铃时就开始预热。当呼叫到达时,Lambda会使用该呼叫的会话标识符向AgentCore运行时发送预热请求。AgentCore运行时会分配一个微虚拟机(microVM),并在响铃期间执行设置。片刻之后,当SIP网关使用相同的会话标识符打开WebSocket连接时,AgentCore运行时会将其路由到已经预热的微虚拟机,代理就准备好通话了。

会话标识符是连接两个请求的关键。Lambda 会根据通话本身计算出该标识符,因此预热请求和后续的音频连接可以解析到相同的微虚拟机,无需额外状态跟踪。下图展示了这一过程如何与响铃窗口重叠,使代理在通话连接时能够及时准备就绪。

存储菜单、购物车和订单

五个 Amazon DynamoDB 表覆盖了点餐工作流程。客户表存储包括姓名、电话和忠诚度信息在内的用户资料,代理通过这些信息识别回头客。订单表保存订单历史及取餐位置信息。菜单表包含商品、价格和库存情况,不同地点的信息可能有所差异。购物车表保存正在进行中的购物车,并使用生存时间(TTL)值实现被遗弃购物车的自动清理。地点表存储餐厅详细信息,如坐标、营业时间和税率,代理会利用这些信息计算总金额并提供建议。DynamoDB 的按需容量会根据流量自动扩展,因此无需管理吞吐量。

确定取餐位置

Amazon Location Service 帮助来电者在无需输入任何内容的情况下找到便捷的取餐地点。由于电话来电者没有浏览器可以共享位置,代理会询问邮政编码或交叉街道,并通过 Amazon Location Service 将其转换为坐标。之后,后端可以利用这些坐标执行多项操作:可以查找最近的餐厅,按驾驶时间而非直线距离进行排序,优先选择来电者路线上的短途绕行,或者对特定地址进行地理编码。这使代理能够提供来电者可采取行动的信息,例如告知“最近的门店位于主街,大约五分钟车程”,而不是简单读取内部编码。

使用 Amazon Bedrock AgentCore 和 Amazon Nova 2 Sonic 处理语音

代理在 AgentCore 运行时上运行。每个通话都在独立的微虚拟机中运行,因此一个用户的会话不会影响其他用户的会话。AgentCore 运行时负责扩展管理,并提供双向传输音频的 WebSocket 连接。

在代理内部,代理框架定义了系统提示、可调用的工具以及对话流程。Amazon Nova 2 Sonic 负责通话中的语音处理。它能够识别多种口音的语音,并处理电话线路带来的音频质量差异。它以低延迟双向流式传输音频,并通过异步调用工具而不停止对话(参见 Amazon Nova Sonic 中的异步工具调用),因此来电者在数据获取期间不会被要求等待。它还支持中断处理,使来电者可以像人与人通话一样在代理说话时插话。

一个特别针对电话通话的细节是:后端查询可能需要几秒钟时间,而 Amazon Nova 2 Sonic 会终止在服务器端闲置过久的会话。为了在缓慢的工具调用期间保持会话连接,代理会以较短的时间间隔发送静音帧。会话保持活跃状态,而来电者不会听到任何异常声音。

通过 MCP 将代理连接到后端工具

代理从不直接调用后端 Lambda 函数。AgentCore 网关位于两者之间,将后端端点作为 MCP 工具呈现,代理通过名称发现并调用这些工具,涵盖菜单查询、购物车操作、订单创建、客户和订单历史记录、地理编码以及位置搜索。这意味着代理无需知道特定操作背后的 Lambda 函数位置,也无需了解如何对其进行身份验证。

这一分层设计实现了系统的松耦合。当代理调用 PlaceOrder 等工具时,网关会将其转换为对 Amazon API Gateway 的 REST 请求,由 API Gateway 路由到对应的 AWS Lambda 函数。由于代理与命名工具通信而非具体函数,因此可以更改后端处理程序或添加新工具而无需修改代理。同一后端也可以为其他渠道提供服务,因为所有渠道都通过相同工具和数据进行订单操作。

下图展示了单个工具调用如何从代理传递到后端。

无需登录即可识别来电者

电话来电者无需登录,系统使用来电者的电话号码作为身份基础。系统将号码与 AWS Systems Manager Parameter Store 中存储的密钥值进行哈希运算,结果成为会话标识符。原始电话号码不会出现在日志或会话状态中。这种哈希方法通过确保敏感来电信息从不以明文形式存储或传输,有助于满足个人身份信息(PII)处理要求。

如果该标识符匹配已知客户,代理将通过姓名问候来电者,并可提供其最近订单。如果不匹配,来电者将作为访客下单,订单仍会被创建和存储。每个订单都会记录其来源渠道以及来电者是否为访客,以便后续识别电话订单。

这种方法可以在不请求登录的情况下识别回头客,但它不是身份验证,电话号码哈希不应被视为证明来电者身份的证据。任何拥有相同电话号码的人都可以以该身份下单。需要验证身份的生产环境部署可以在代理打开来电者账户历史记录前添加额外步骤,例如通过短信发送一次性验证码。

下单流程演示

从部署输出中拨打该号码。代理会向您问候并询问需求。您可以通过语音自然表达,询问菜单,提供自提的邮政编码,并确认订单,整个过程无需停顿。在来电者讲话时,代理会在后台调用后端工具,因此数据加载时不会出现等待。以下视频展示了从问候到确认的典型订单流程。

通话结束后,您可以在 Amazon CloudWatch Logs 中追踪完整路径。SIP 网关日志显示通话如何建立并连接到代理。代理日志显示对话过程中每个代理事件和工具调用。订单确认后,它会以总金额和预估准备时间记录在 DynamoDB 订单表中。

成本

您需要为系统使用的AWS服务付费。免费电话每分钟费用和全天候运行的Fargate任务是两项最大的支出项。如果符合您的需求,可以降低这两项费用。本地直拨号码的每分钟费用低于免费电话号码,而在非工作时间减少Fargate任务规模可以降低计算费用(前提是您了解流量情况)。请查看每个服务的定价页面获取当前费率,并在AWS成本分析器中设置预算以跟踪支出。

清理资源

为避免持续产生费用,请在完成使用后删除相关资源。全天候运行的Fargate任务和免费电话号码无论是否有来电都会持续产生费用。清理脚本会按逆序删除堆栈,确保每个堆栈在它所依赖的堆栈之前被删除。

code
# 预览将被删除的内容,而不会实际删除任何内容。
./scripts/cleanup-all.sh --dry-run

# 删除部署过程中创建的所有堆栈。
./scripts/cleanup-all.sh

清理操作具有破坏性。它会释放免费电话号码,删除Amazon DynamoDB中的订单历史记录,从AWS Systems Manager Parameter Store中移除密钥,并删除Amazon ECR中的容器镜像。请先备份需要保留的任何数据。脚本执行完成后,请在AWS CloudFormation控制台确认堆栈已删除(参见AWS管理控制台上的查看AWS CloudFormation堆栈数据和资源),并在Amazon Chime SDK控制台确认免费电话号码已被释放(参见Amazon Chime SDK中的电话号码管理)。

结论

在本文中,我们演示了一个从部署到完成订单的电话语音订餐系统的完整流程。该架构将电话、代理和后端保持独立,使每个组件都能独立演进。这种分离使得系统更易于操作,因为您可以更新菜单数据、更换语音模型或添加新渠道,而无需协调整个堆栈的变更。

对于餐厅而言,这意味着电话订单可以顺利进入系统,而无需占用柜台员工的精力。来电者会立即听到问候语而非等待音乐,代理会大声确认每个订单项以减少错误,系统可以在不增加人手的情况下处理高峰时段。由于代理通过MCP工具连接到后端,您可以通过注册新工具来添加预订或积分等功能,而无需更改代理或电话层。

要开始使用,请从GitHub克隆示例代码库并运行预检以确认环境已就绪。然后,将DynamoDB表定义中的种子数据替换为自己的菜单项、位置和定价信息。更新Parameter Store条目中的系统提示模板,以反映餐厅名称、问候风格和任何订餐规则。最后运行部署脚本,即可在自己的免费电话号码上启用该系统。

作者简介

'"`