亚马逊AWS官方博客

基于 Bedrock 构建钉钉智能问答机器人

概述

随着科技的飞速发展,基于大语言模型(LLM)的智能问答机器人在提升工作效率、降低运营成本等方面展现出巨大潜力。将其与办公应用(如钉钉)集成,可进一步优化企业员工的办公体验。本文将介绍如何利用亚马逊云科技的 Amazon Bedrock 服务构建智能问答机器人,使用自然语言即可快速获取所需结果,常见应用场景包括内容创作、语言翻译、代码生成等。

整体架构

  • Amazon Bedrock
    • Amazon Bedrock 是一项完全托管的服务,使用单个 API 提供来自 AI21 Labs、Anthropic、Cohere、Meta、Stability AI 和 Amazon 等领先人工智能公司的高性能基础模型(FM),以及构建生成式人工智能应用程序所需的一系列广泛功能,在维护隐私和安全的同时简化开发。在本博客中我们通过配置的方式使用 Bedrock 来访问 Anthropic 的 Claude 模型。
  • ECS
    • Amazon Elastic Container Service(ECS)是一项完全托管的容器编排服务,可帮助您更有效地部署、管理和扩展容器化的应用程序。 在本博客中,我们使用 ECS 来部署 chatbot 服务端的代码,服务端代码通过钉钉 SDK 的 Listener 来监听并接受、处理消息请求,并以 webhook 的方式返回给钉钉。
  • DynamoDB
    • Amazon DynamoDB 是一种全托管 NoSQL 数据库服务,提供快速而可预测的性能,能够实现无缝扩展。DynamoDB 可以免除操作和扩展分布式数据库的管理工作负担,因而无需担心硬件预置、设置和配置、复制、软件修补或集群扩展等问题。在本博客中,我们使用 DynamoDB 来存储不同用户的会话相关的数据。
  • CloudWatch
    • Amazon CloudWatch 是一项针对应用程序的监控服务。本博客中,我们使用它来分析服务端等各个 service 的日志。
  • IAM
    • AWS IAM 提供涵盖整个 AWS 的精细访问控制。借助 IAM 可以控制在特定条件下对服务和资源的访问。使用 IAM policy 来管理用户和系统的权限,以确保最低权限。
  • Secrets Manager
    • AWS Secrets Manager 是一种密钥管理服务,可帮助保护对应用程序、服务和 IT 资源的访问。通过该项服务,可以在数据库凭证、API 密钥和其他密钥的整个生命周期内轻松地对其进行轮换、管理和检索,例如存放钉钉机器人应用的 credentials 信息。
  • S3(可选)
    • 可以配置 Bedrock 的 log 到 S3 和 CloudWatch log group,也可以只存在 log group 或 S3 里。

本博客中,我们选择了钉钉机器人应用的 stream 方式进行回复,用户体验会更好,stream 方式的原理如下:

Stream 方式的优势有:

  • 不需要依赖公网 IP 或域名,也不需要暴露公网 IP,减少了公网暴露服务的安全风险并降低了开发门槛。
  • 使用应用身份对连接进行鉴权,通过反向连接的方式与钉钉开放平台建立 TLS 加密连接,提供了快速、安全的通信体验。
  • Stream 模式下开发者无需向公网开放提供任何服务端口,无需部署防火墙和配置白名单。
  • 通过反向连接的方式建立通道,开发者只需保证运行环境具备公网访问能力即可,无需部署网关。
  • 开发者无需在本地搭建内网穿透工具,通过 Stream 模式在本地开发环境中即可接收卡片回调。

方案部署

前提条件

  1. 通过如下地址下载部署代码 https://github.com/aws-samples/dingtalk-chatbot/
  2. 部署使用的 IAM user 或者 role 有 IAM/CloudFormation/S3/SSM Parameter/SageMaker 的权限。

如果选择在您的本地常用电脑上进行部署请完成以下准备工作:

  1. 安装 Python,请确保在您的本地开发机或部署机上有高于 3.8 的 python 版本,如果没有请参考 https://www.python.org/downloads/ 进行下载和安装。
  2. 安装 AWS CLI,请参考 https://docs.aws.amazon.com/cli/latest/userguide/getting-started-install.html 进行安装,快速设置账号权限请参考 https://docs.aws.amazon.com/cli/latest/userguide/getting-started-quickstart.html
  3. 安装 AWS CDK
    # 安装 nvm node cdk
    curl -o nvm_install.sh https://raw.githubusercontent.com/nvm-sh/nvm/v0.37.2/install.sh
    sh nvm_install.sh
    . ~/.nvm/nvm.sh
    nvm install 16
    node -v 
    # 16.18.0
    npm -v
    npm install -g aws-cdk
    cdk --version
    

如果选择在 AWS Cloud9 上进行部署,请在 AWS 控制台上启动一个用户部署的 Cloud9 环境,具体步骤如下:

  1. 在 AWS console 上使用搜索栏搜索 “Cloud9″,或者在 “服务” 下拉菜单的 “开发人员工具” 部分找到 “Cloud9” 服务。
  2. 单击 “创建环境” 创建一个新的 Cloud9 环境。
  3. 在 “创建环境” 向导中,为您的环境提供一个名称,填写在 “名称” 字段中。
  4. 选择您喜欢的环境类型。您可以创建一个全新的环境。
  5. 选择 Cloud9 环境的实例类型,这里我们选择 m5.large 即可。
  6. 平台保持默认 Amazon Linux2 即可,下方的超时自动停止实例时间保持 30mins 即可,在您没有在 IDE 上操作 30mins 之后,这个实例将会被停止,以免产生不必要的费用。
  7. 如果需要打 Tags,可以进行填写,其他部分保持默认,点击“创建”即可。
  8. Cloud9 环境将被创建,这可能需要一些时间。一旦准备就绪,可以打开 Cloud9 集成开发环境(IDE),在这里您可以开始工作。

配置钉钉机器人

  1. 创建一个钉钉的机器人应用,创建好后取到 Client ID(App Key)和 Client Secret(App Secret)。
  2. 打开 https://open.dingtalk.com/ 点击右上角的“开发者后台”, 使用钉钉 APP 扫描二维码登录,选择你所在的组织。
  1. 为应用添加机器人应用能力
  1. 如果需要加入测试群,可以在点击发布,点击“确认发布”之后,再“点击调试”,扫描二维码加入测试群。
  1. 检查机器人应用状态变成已上线即可
  1. 查看 Client ID 和 Client Secret 进行存储,我们会在后面部署中用到,查看方式如下
  1. 在 AWS 管理控制台打开 Secrets Manager,点击右上角的“Store a new  secret”, 将第 1 步生成的 ID 和 secret 进行存储。请注意直接将下方第 4 步的文本复制粘贴,修改 your-client-id,your-client-secret 为您在第 1 步生成的 ID 和 secret,其他不用改。
  1. {“AppKey”:”your-client-id”,
    “AppSecret”:”your-client-secret”}
  2. 为这个 secret 取一个名字,比如:dingtalk_app_credential,这个名字我们将会在后面的 cdk 配置中用到,代码里会通过这个 secret 来访问钉钉机器人应用的 Client ID 和 Client Secret。
  1. 点下一步,其他配置不用更改,最后点保存即可。

部署

  1. 在 Cloud9 的 IDE 中打开一个 Terminal,使用以下命令下载代码到当前目录,执行以下命令创建 python 运行环境
    cd dingtalk_bedrock
    # 创建 python 环境
    python3 -m venv env
    source env/bin/activate
    # 安装依赖
    pip3 install -r  requirements.txt
    
  2. 修改配置,在IDE中打开 dingtalk_bedrock/params-config.json
    {
      "construct_id": "DingTalk-with-Bedrock",  #这个 CDK stack 的 ID
      "enable_bedrock_log": true,  # 是否打开 bedrock 的 log,建议保持默认配置打开即可
      "dingtalk_app_credential_secret_name": "dingtalk_app_credential",
      "bedrock_model_id": "anthropic.claude-v2:1", 
      "input_history_conversation_count": "2"
    }
    
  3. 执行 cdk 命令进行部署
    cdk bootstrap
    cdk deploy
    # 因为在 Dockerfile 中需要下载和安装 Python3.11.4,因此部署需要的时间比较久,大约 30mins 左右
    # cdk deploy 执行完成之后,output 中会有为 Bedrock 创建的 log group 等信息
    
  4. 等待部署完成之后,可以通过钉钉搜索机器人应用的名称,发送消息进行测试

打开 Bedrock Log

Bedrock 模型调用日志可以用于检查调用的输入和输出数据。默认情况下,它是禁用的(https://docs.aws.amazon.com/bedrock/latest/userguide/model-invocation-logging.html)。

我们使用 CDK 创建了必要的资源,当 enable_bedrock_log 设置为 True 时,CDK 创建 CloudWatch 的 log group 和对应的 S3 bucket(当前默认的日志保留设置是 7 天)。但由于 Bedrock 服务比较新,最终的配置和设置必须手动完成

前往 Amazon Bedrock 控制台,在左侧面板选择“设置”,使用 CDK 的输出填写相应的信息。

时间分析

在 CloudWatch 中对 Bedrock log 进行分析

在 CloudWatch 控制台,选择日志洞察(Logs Insight),运行以下命令并查看 Bedrock 性能。

fields @timestamp, input.inputTokenCount as inputTokenCount, output.outputTokenCount as outputTokenCount
| stats sum(inputTokenCount) as total_input_tokens, sum(outputTokenCount) as total_output_tokens  by  bin(15m)
| sort @timestamp desc

fields @timestamp, 
| parse @message '"invocationLatency":*,' as invocationLatency
| stats avg(firstByteLatency) as averageFirstByteLatency, avg(invocationLatency) as averageInvocationLatency by bin(15m)
| sort @timestamp desc

ECS 配置手动修改

在 ECS 中手动修改环境变量的步骤如下:

  1. 登录 AWS 管理控制台并打开 ECS 控制台。
  2. 在左侧导航栏中,选择你的集群。
  3. 在集群详情页面中,选择你的服务(service)。
  4. 在服务详情页面中,选择你的任务定义(task definition)。
  5. 在任务定义详情页面中,找到 “容器定义” 部分,并点击你要修改环境变量的容器的名称。
  6. 在容器定义页面中,向下滚动至 “环境” 部分。
  7. 在 “环境” 部分,你可以看到当前定义的环境变量列表。
    • 若要修改现有环境变量,请点击对应环境变量的 “编辑” 按钮(铅笔图标)。
    • 若要添加新的环境变量,请点击 “添加环境变量” 按钮。
  8. 在编辑环境变量或添加环境变量的窗口中,输入环境变量的名称和值,并点击 “保存”。
  9. 返回到任务定义详情页面后,点击 “更新” 按钮以更新任务定义。
  10. 在更新任务定义页面中,选择 “创建新版本” 并点击 “更新”。

完成上述步骤后,你的任务定义将被更新,并且在下次部署任务时将使用新的环境变量配置。

请注意,修改任务定义的环境变量可能会影响正在运行的任务实例。如果你希望应用环境变量的更改,你可以手动停止并重新启动与任务定义关联的服务,以创建新的任务实例,并使用更新后的环境变量配置。

安全建议

  1. Cloud watch log group 加密。
  2. 每次会话尽量不要超过 20 个问题,可以使用“重置”清理当前的会话, 如果会话的所有文本及数据结构超过 400K,会达到 DynamoDB item 的大小限制。
  3. 考虑保证网络安全,可以打开 VPC flow log,示例的 CDK 代码如下:
    from aws_cdk import core
    from aws_cdk import aws_ec2 as ec2
    
    # 创建 VPC flow log
    flow_log = ec2.FlowLog(self, 'MyFlowLog',
       resource_type=ec2.FlowLogResourceType.from_vpc(vpc),
       traffic_type=ec2.FlowLogTrafficType.ALL,
       destination=ec2.FlowLogDestination.to_cloud_watch_logs(),
       destination_type=ec2.FlowLogDestinationType.CLOUD_WATCH_LOGS
    )
    

附录

  1. https://aws.amazon.com/cn/cdk/
  2. https://www.anthropic.com/index/releasing-claude-instant-1-2
  3. https://open.dingtalk.com/document/resourcedownload/introduction-to-stream-mode
  4. https://python.langchain.com/docs/integrations/memory/aws_dynamodb

本篇作者

陈汉卿

亚马逊云科技解决方案架构师,负责基于亚马逊云科技云计算方案的咨询、架构设计及落地,拥有多年移动互联网研发及技术团队管理经验,在云原生微服务以及云迁移等方向有丰富的实践经验。

贾婷

亚马逊云科技快速原型解决方案架构师,致力于帮助客户设计和开发大数据方向的快速原型方案,有游戏、汽车等行业的大数据开发经验。

洪丹

亚马逊云科技原型解决方案架构师,负责机器学习应用场景的快速构建,为客户提供高效、精准的解决方案,以满足他们独特的业务需求和挑战。

刘幸园

亚马逊云科技客户技术经理。主要负责游戏、互联网行业客户的架构优化、成本管理、技术咨询等工作。拥有 10 年以上的数据库优化、项目管理与技术支持经验。