使用 Claude 3 on Amazon Bedrock 打造个性化智能编程助手

API
SDK
Amazon Bedrock
0
0
最近,随着人工智能技术的迅速发展,代码助手已经成为软件开发领域备受关注的工具。比如像 [Amazon CodeWhisperer](https://aws.amazon.com/cn/codewhisperer/?trk=cndc-detail) 这样的工具可以在集成开发环境中帮助用户自动生成代码,极大地提高了开发效率。然而,这些助手通常缺乏直接执行代码的能力,需要额外集成开发环境来执行代码。为了解决这一问题,很多软件又开发了一些工具,能够允许我们直接执行大型语言模型生成的代码。但是它们提供的的代码解释器主要以 Python 为主,对其他开发语言比如 Nodejs,Golang,Rust,PHP 支持得并不好。 在日常工作中,我们发现许多客户经常需要使用 Amazon SDK 进行开发,通常涉及多种编程语言如 Go、Node.js 和 Rust,为此我们创建了“[Bedrock-claude-codecoach](https://github.com/aws-samples/bedrock-claude-codecoach?trk=cndc-detail)”开源项目。 它是使用 [Amazon Bedrock](https://aws.amazon.com/cn/bedrock/?trk=cndc-detail)、Piston、LangChainJS 和 NextJS 开发的编程助手和代码解释器,支持 Anthropic Claude 2/2.1,Claude 3 和开源 Mistral 7B、Mixtral 8x7B 等模型。通过这个开源项目,我们旨在提供一个开箱即用的 Bedrock 编程助手,可以快速帮助用户进行 Amazon SDK 代码开发和调试。另外,我们还内置了一个提示词编辑工具,方便那些初次接触 [Amazon Bedrock](https://aws.amazon.com/cn/bedrock/?trk=cndc-detail) 的提示词工程师进行提示词调试。 ### 01 架构介绍 CodeCoach 架构图如下: ![image.png](https://dev-media.amazoncloud.cn/bf1cdabc351e477d88a90a45c0cc396d_image.png "image.png") 本项目最大的价值是提供方便快捷的部署方案,以较高的准确度生成代码并提供执行代码的各种运行环境。因此在项目中我们使用了 [Amazon Bedrock](https://aws.amazon.com/cn/bedrock/?trk=cndc-detail) 服务进行代码的生成。 [Amazon Bedrock](https://aws.amazon.com/cn/bedrock/?trk=cndc-detail) 是一个 MaaS 的平台,提供了各种业界翘楚的商业化模型(如:Anthropic 的 Claude)和开源模型(如:Llama/Mistral),最大程度地减少了客户选择和使用基础模型的试错成本和时间周期,并且 [Amazon Bedrock](https://aws.amazon.com/cn/bedrock/?trk=cndc-detail) 上的基础模型会不断迭代更新,确保客户能始终 enable 最新最强的模型的功能,如最近新上架的 Anthropic Claude v3 的模型,增加了多模态 VQA,Function Calling 等最新功能。 在本项目中,我们采用了 Claude 3 on [Amazon Bedrock](https://aws.amazon.com/cn/bedrock/?trk=cndc-detail) 和 Mistral 7B 模型进行代码生成,经测试其在各项代码生成中稳定性和功能均表现突出;用户验证信息和提示词模版等数据存储在 DynamoDB 中,支持多人访问;此外项目还集成了 Piston 多语言代码执行引擎,通过 Piston 我们可以打造自己开源的 code interpreter,目前 Piston 支持 30 多种执行环境,在 CodeCoach 里面我们选择了常见的几种开发语言:Python,Golang,JavaScript/TypeScript,PHP 和 Rust,并且已经预集成了 Amazon SDK 可以直接使用;同时为了简化部署过程,我们提供了 CloudFormation 一键部署模版(cf-template.yaml)。 ### 02 部署项目 CodeCoach 已经提供了 [CloudFormation 模版](https://github.com/aws-samples/bedrock-claude-codecoach/blob/main/cf-template.yaml?trk=cndc-detail),可以直接下载到本地后进行部署。 #### 方法一:通过 CloudFormation 服务控制界面进行部署 首先请登陆亚马逊云科技控制台,进入 CloudFormation 界面,点击创建 Stack ![image.png](https://dev-media.amazoncloud.cn/d35525620a0a4ab4a94e766cc1c1552f_image.png "image.png") 选择上传模版文件, 上传 cf-template.yaml 模版 ![image.png](https://dev-media.amazoncloud.cn/193ddf028e52481196bb43e47598a202_image.png "image.png") 设置 EC2 密钥对的名字,这样就可以直接登陆到 EC2 进行调试 ![image.png](https://dev-media.amazoncloud.cn/d25398bd8a66479fb2218ca00037f073_image.png "image.png") ![image.png](https://dev-media.amazoncloud.cn/0da54d71a3594982b271b1deb2deac3f_image.png "image.png") #### 方法二:使用命令行工具部署 CodeCoach ```js #请替换<你的 KeyPair 名字> 为实际使用的 Key Pair 名字 aws cloudformation create-stack --region us-west-2 \\ --stack-name codecoach \\ --template-body file://cf-template.yaml \\ --parameters ParameterKey=SSHKeyName,ParameterValue=<你的 KeyPair 名字> \\ --capabilities CAPABILITY_IAM ``` CloudFormation Stack 创建完成后会输出 Cloudfront 地址(下图红框提示处即访问地址),直接访问即可。 ![image.png](https://dev-media.amazoncloud.cn/5913a6aab6ad44acb01f49075cb17e7d_image.png "image.png") 访问该网页点击 Get Start 即可登录,初始用户密码( admin@demo.com/123456!@# ),首次登录后请点击右上角设置(齿轮图标),立即修改用户密码。 ![image.png](https://dev-media.amazoncloud.cn/29c18de48e6649cbb57d474fe36d6313_image.png "image.png") ![image.png](https://dev-media.amazoncloud.cn/9d8a10ec82af4b1fb932698df9a5a37d_image.png "image.png") 选择助手,点击模型下拉列表,选择合适的模型然后点击测试,测试通过后点击保存,项目默认是 Claude2,推荐使用最新的 Claude3 Sonnet。 ![image.png](https://dev-media.amazoncloud.cn/7d169c794c3b4104b51b2044fef4ffb4_image.png "image.png") ### 03 CodeCoach 功能介绍 #### 3.1 使用 Amazon SDK 进行程序开发 我们在日常工作中可能会需要使用各种语言的 Amazon SDK 代码,比如 Python (boto3),Golang,JavaScript/TypeScript,PHP,Rust 等。下面我们就以 Python (boto3) /Golang 为例来演示如何使用 CodeCoach 进行 Amazon SDK 开发。 ##### 3.1.1 使用 boto3 进行开发,打印某个区域的 EC2 实例列表,并可以返回运行状态 首先我们输入“使用 boto3 列出 us-east-1 的 ec2 实例”,然后等待 CodeCoach 返回,点击执行。 ![image.png](https://dev-media.amazoncloud.cn/f388600a859b4ee99c571b434e7daa81_image.png "image.png") UI 就会调出代码编辑界面,在这个界面点击执行即可,在 output 显示框我们可以看见 Amazon SDK 的返回结果,如果代码有问题,会出现“fix”按钮,我们可以要求 CodeCoach 修复错误,并进行说明。 ![image.png](https://dev-media.amazoncloud.cn/15d518ede2d24a6c9717d08a180e6604_image.png "image.png") ##### 3.1.2 使用亚马逊 Golang SDK 打印 S3 桶列表 输入“使用 Amazon Golang SDK 编写一个 list s3 bucket 代码”,点击执行,因为 Golang 需要编译,所以执行的时候需要比 Python 更久的时间,点击后请耐心等待。 ![image.png](https://dev-media.amazoncloud.cn/2a669e10594f42838fadfde624026197_image.png "image.png") ![image.png](https://dev-media.amazoncloud.cn/412cdf2255034185bc515e8fb458d123_image.png "image.png") #### 3.2 错误修复 如果生成的代码出现了错误,我们可以直接点击“修复助手”,CodeCoach 会调用大语言模型给出修复方法和说明。 ![image.png](https://dev-media.amazoncloud.cn/89f984f496b040ef91e6e4eab34fcd85_image.png "image.png") ![image.png](https://dev-media.amazoncloud.cn/457ee8b659f142498a9fed5f80c7d8de_image.png "image.png") 可以看到 Claude3 不仅帮助我们纠正了错误,而且还给出了关于错误的解释:返回值“没有 Instances”这个 Key,需要使用 “Reservations”。 #### 3.3 提示词模版工具 CodeCoach 支持自定义提示词,直接打开提示词,可以编写加载自己的提示词,我们分别使用 Claude2,Claude3 来编写一个翻译助手。 ##### 3.3.1 编写 Claude3 提示词 Claude3 不再需要 Human,Assistant 限定格式,可以直接进行编写,可以参考 [Anthropic Claude Message API 文档](https://docs.aws.amazon.com/bedrock/latest/userguide/model-parameters-anthropic-claude-messages.html?trk=cndc-detail)。 下面我们以 Claude3 为例编写一个翻译助手。 **1)不使用 System Role,直接在用户提示词里面编写任务** ```js 你是一个中英文翻译专家,你先要判断我的问题是中文还是英文 1.如果是英文请转换成中文 2.如果是中文请转换成英文 这里是我的问题: {query} 请返回 {"input": "question", "output":"你的答案“} ``` ![image.png](https://dev-media.amazoncloud.cn/e8a71abe05e04a8087a92ec53492c3e4_image.png "image.png") 点击提交,Claude3 会返回{“input”: “我想买一辆车.”, “output”: “I want to buy a car.”} ,完全符合我们的预期。 后台查看 Message API 格式如下: ![image.png](https://dev-media.amazoncloud.cn/f1e55ea67bb84bf590ce43cc832b35ba_image.png "image.png") **2)使用 Claude3 的 System Role,我们将原始提示词里面任务的定义填写到 Claude3 System Role 里面** ![image.png](https://dev-media.amazoncloud.cn/691e144042444c8bbb36d2c8454660bd_image.png "image.png") 注意,这里整个 payload 就多了一个新 key “system”,这个就是 Claude3 最新的 Message API 定义 system role 的方法。 ##### 3.3.2 编写 Claude2 提示词,Human,Assistant 分别代表了输入和模型的输出 ```js Human: 你是一个中英文翻译专家,你先要判断我的问题是中文还是英文 1.如果是英文请转换成中文 2.如果是中文请转换成英文 这里是我的问题: {query} 请返回 {"input": "question", "output":"你的答案“} Assistant: ``` ![image.png](https://dev-media.amazoncloud.cn/c78ddb58896a4eee9ee02c9a7d6061cc_image.png "image.png") Mistral 7B 使用方式类似,在这里我们就不再赘述了。 其次在提示词调试工具里面我们可以定义任意的{变量}, 变量会自动生成文本输入框,通过 LangChainJS Prompt Template 进行加载,点击提交即可测试你的提示词,点击保存就可以将模版保存在 [Amazon DynamoDB](https://aws.amazon.com/cn/dynamodb/?trk=cndc-detail) 中方便下次使用。 ### 04 如何自定义 Piston 执行环境 Piston 的开源地址为 https://github.com/engineer-man/piston?trk=cndc-detail ,目前已经集成了 112 种运行环境,参考 https://github.com/engineer-man/piston/releases/download/pkgs/index?trk=cndc-detail 。官方的 repo 中仅提供每种语言基础的运行环境,但是在实际的使用过程中,我们需要丰富运行环境,安装额外的依赖,例如我们需要为 python 环境增加 boto3 的 SDK,或者为 Bash 环境增加 Amazon CLI 等,因此我们需要在官方 repo 的基础上自定义 Piston 环境。 #### 4.1 复制全量执行环境(可选) 为了拥有全量的执行环境,我们先将官方的 repo 中的所有运行环境迁移到自己的 github 仓库中,我们可以 Fork 官方 git 仓库之后通过以下脚本批量的迁移 Release 中发布的所有环境。 ```js #!/bin/bash repo="piston" # GitHub Token token="xxxxxxx" # github owner code owner="xxx" # Release名 release_name="Packages" # 本地附件目录 attach_dir="/opt/pkgs" # ReleaseId release_id="" upload_assets(){ release_id=\$1 file=\$2 echo "-----" echo \$release_id \$file # 上传文件 upload_url=\$(curl -H "Authorization: token \$token" \\ -H "Content-Type: application/gzip" \\ https://uploads.github.com/repos/\$owner/\$repo/releases/\$release_id/assets?name=\$(basename \$file) \\ --data-binary @\$file > /dev/null) # 添加为Release附件 curl -X POST -s -H "Authorization: token \$token" \\ -H "Content-Type: application/json" \\ -d '{"name":"'\$(basename \$file)'","url":"'\$upload_url'"}' \\ https://api.github.com/repos/\$owner/\$repo/releases/\$release_id/assets > /dev/null } release_to_github(){ # 获取 release_id if [ "x"\${release_id} == "x" ]; then # 判断release是否存在 release_exist=\$(curl -s -H "Authorization: token \$token" https://api.github.com/repos/\$owner/\$repo/releases/tags/\$release_name | jq '.id') if [ -z "\$release_exist" ]; then # 不存在则创建 release_id=\$(curl -s -X POST -H "Authorization: token \$token" \\ -d '{"tag_name":"'"\$release_name"'","name":"'"\$release_name"'"}' \\ https://api.github.com/repos/\$owner/\$repo/releases | jq '.id') else # 存在则直接使用 release_id=\$release_exist fi fi # 遍历附件目录上传文件 for file in \$attach_dir/*.tar.gz; do echo "release: \$file" upload_assets \$release_id \$file done } download_from_source(){ cd \$attach_dir rm -fr index && curl -s -L https://github.com/engineer-man/piston/releases/download/pkgs/index -o index count=1 while read line; do if [ "x"\$line == "x" ];then continue fi # 分割CSV字段 IFS=',' read -ra fields <<< "\$line" # 下载文件 url="\${fields[3]}" echo "\${count}:\${url}" filename=\$(basename \$url) curl -s -L -o "\$filename" "\$url" release_to_github rm -fr \$filename ((count++)) done < ./index sed -i 's!https://github.com/engineer-man/piston/releases/download/pkgs/!https://github.com/yanjun-ios/piston/releases/download/Packages/!g' index # 合并index文件 mv index index_1 && curl -s -L https://github.com/\$owner/piston/releases/download/Packages/index -o index_2 cat index_1 index_2 | sort | uniq > index echo "upload the index file !" # 上传 index 文件 upload_assets \$release_id \$attach_dir/index } download_from_source ``` #### 4.2 修改执行环境,重新构建执行环境的安装包 在 Piston 的工程中的 piston/packages/ 目录下存放了所有执行环境的构建代码,每个执行环境主要包括 build.sh, environment, metadata.json, run, test 五个文件,其中 build.sh 中定义了执行环境的安装过程,environment 中定义了我们要暴露的环境变量,在自定义执行环境的时候我们需要修改这两个文件。 ![image.png](https://dev-media.amazoncloud.cn/98f51885aed847d2b74782b056577a03_image.png "image.png") 我们以 Bash 执行环境中添加 awscli 为例,将 piston/packages/bash/5.2.0/build.sh 中内容改成下代码: ```js #!/usr/bin/env bash # Put instructions to build your package in here PREFIX=\$(realpath \$(dirname \$0)) mkdir -p build cd build curl "https://ftp.gnu.org/gnu/bash/bash-5.2.tar.gz" -o bash.tar.gz tar xzf bash.tar.gz --strip-components=1 # === autoconf based === ./configure --prefix "\$PREFIX" make -j\$(nproc) make install -j\$(nproc) cd ../ rm -rf build # install aws cli PREFIX=\$PWD curl "https://awscli.amazonaws.com/awscli-exe-linux-x86_64-2.0.30.zip" -o "awscliv2.zip" unzip awscliv2.zip ./aws/install -i \$PREFIX/aws-cli -b \$PREFIX/bin rm -fr awscliv2.zip rm -fr ./aws ``` 在 environment 中添加 awscli 的环境变量 ```js #!/usr/bin/env bash # Put 'export' statements here for environment variables export PATH=\$PWD/bin:\$PATH export PATH=\$PWD/aws-cli:\$PATH ``` 修改完执行环境,我们修改 piston/docker-compose.yaml 文件,从本地代码构建 docker 镜像,并启动容器 ```js version: '3.2' services: api: build: api container_name: piston_api cap_add: - CAP_SYS_ADMIN restart: always ports: - 2000:2000 volumes: - ./data/piston/packages:/piston/packages environment: - PISTON_REPO_URL=https://github.com/@owner/piston/releases/download/Packages/index - PISTON_DISABLE_NETWORKING=false - PISTON_RUN_TIMEOUT=300000 - PISTON_OUTPUT_MAX_SIZE=102400 tmpfs: - /piston/jobs:exec,uid=1000,gid=1000,mode=711 ``` 启动并进入容器中,构建自定义执行环境 ```js docker compose up -d docker exec -it piston_repo bash cd piston/repo/ # 执行构建命令 sh build_package.sh bash=5.2.0 # 将构建好的安装包发布到github sh build_package.sh release ``` 其中 build_package.sh 代码如下: ```js #!/bin/bash #set -x # usage: sh build_package.sh python or sh build_package.sh python=2.7.18 repo="piston" # GitHub Token token="xxxxx" # github owner code owner="xxxx" # Release名 release_name="Packages" # 本地附件目录 attach_dir="/piston/repo/" # ReleaseId release_id="" all_assets=() upload_assets(){ release_id=\$1 file=\$2 echo "-----" echo "Upload File, Release Id: \$release_id file name : \$file" # 上传文件 upload_url=\$(curl -H "Authorization: token \$token" \\ -H "Content-Type: application/gzip" \\ https://uploads.github.com/repos/\$owner/\$repo/releases/\$release_id/assets?name=\$(basename \$file) \\ --data-binary @\$file > /dev/null) # 添加为Release附件 curl -X POST -s -H "Authorization: token \$token" \\ -H "Content-Type: application/json" \\ -d '{"name":"'\$(basename \$file)'","url":"'\$upload_url'"}' \\ https://api.github.com/repos/\$owner/\$repo/releases/\$release_id/assets > /dev/null } # 获取所有的asset get_all_assets() { page=1 #release_id=128663575 assets_url="https://api.github.com/repos/\$owner/\$repo/releases/\${release_id}/assets?per_page=100" while : do local assets assets=\$(curl -fsS -H "Authorization: token \${token}" "\${assets_url}&page=\${page}" | jq -r '.[] | "\\(.name)-\\(.id)"') name=\$(echo \${assets[@]}| grep "pkg.tar.gz") # result=\$(echo \$name | grep "=") if [ \$? -ne 0 ];then break; fi # 将当前页面的assets添加到数组中 #mapfile -t assets < <(echo "\$assets") for i in \${assets[*]} do # echo "this is i: "\$i all_assets[\${#all_assets[*]}]=\${i} done ((page++)) done echo "全量数组长度:\${#all_assets[@]}" } # 根据文件名删除附件 delete_release_asset(){ release_id=\$1 file_name=\$2 if [ \${#all_assets[@]} -eq 0 ]; then echo "assets 为空,请求全量assets" get_all_assets fi asset_id="" for element in "\${all_assets[@]}"; do if [[ \$element == *"\$file_name"* ]]; then asset_id=\$(echo \$element | awk -F '-' '{print \$NF}') break fi done echo "Delete File, file Name : \$file_name asset_id :\$asset_id" if [ "\$asset_id" == "" ]; then echo "Delete failed, No asset found with filename: \$filename" return 1 fi asset_url="https://api.github.com/repos/\$owner/\${repo}/releases/assets/\${asset_id}" response=\$(curl -s -X DELETE -H "Authorization: token \${token}" \${asset_url}) if echo "\$response" | grep -q '204 No Content'; then echo "Failed to delete asset: \$response" else echo "Asset deleted successfully" fi } # 发布到github release中 release_to_github(){ cd \$attach_dir if [ ! -f *.tar.gz ];then echo "there is no packages to be released , exit 1" exit 1 fi # 获取 release_id if [ "x"\${release_id} == "x" ]; then # 判断release是否存在 release_exist=\$(curl -s -H "Authorization: token \$token" https://api.github.com/repos/\$owner/\$repo/releases/tags/\$release_name | jq '.id') if [ -z "\$release_exist" ]; then # 不存在则创建 release_id=\$(curl -s -X POST -H "Authorization: token \$token" \\ -d '{"tag_name":"'"\$release_name"'","name":"'"\$release_name"'"}' \\ https://api.github.com/repos/\$owner/\$repo/releases | jq '.id') else # 存在则直接使用 release_id=\$release_exist fi fi # 遍历 tar.gz 附件目录上传文件 for file in *.tar.gz; do echo "release: \$file" delete_release_asset \$release_id \$file upload_assets \$release_id \$file done # 合并index文件 mv index index_1 && curl -s -L https://github.com/@owner/piston/releases/download/Packages/index -o index_2 if [ \$? -ne 0 ];then echo "download index file failed,exit 1" exit 1 fi for file in *.tar.gz; do sed -i "/\${file}\$/d" index_2 done cat index_1 index_2 | sort | uniq > index echo "upload the index file !" # 上传 index 文件 delete_release_asset \$release_id index upload_assets \$release_id index } # 构建安装包 build_package(){ cd /piston/packages echo "build packages from args..." for pkg in "\$@" do shift if [ ! -d `echo \$pkg | awk -F'=' '{print \$1}'` ];then echo "Packages not found for \$pkg" continue fi result=\$(echo \$pkg | grep "=") if [ \$? -eq 0 ];then echo "install \$pkg" pkgname=\$(echo \${pkg/=/-}) echo \$pkgname make -j16 \$pkgname.pkg.tar.gz PLATFORM=docker-debian else if [ -d "\$pkg" ];then echo "install all version for \$pkg" for version in \$pkg/*;do version=\$(echo \$version | awk -F '/' '{print \$2}') pkgname=\${pkg}"-"\${version} echo \$pkgname make -j16 \$pkgname.pkg.tar.gz PLATFORM=docker-debian done fi fi done if [ ! -f *.tar.gz ];then echo "there is no packages to be released , exit 1" exit 1 fi cd /piston/repo echo "Creating index" ./mkindex.sh echo "Index created" } if [ \$1 == "release" ];then release_to_github else build_package \$@ # release_to_github fi ``` 至此,我们已经在自己的 github 中拥有一个完全独立的 Piston 的 repo,在使用时,我们只需要进入 CloudFormation 启动的 EC2,修改/root/bedrock-claude-codecoach/docker-compose.yaml 文件,通过环境变量的方式指定我们自定义 piston repo 中的 index 文件,重新执行 init.sh 即可。docker-compose 示例如下图: ![image.png](https://dev-media.amazoncloud.cn/8c7817c9d9c6498283161ab4ad318b20_image.png "image.png") - Piston 启动配置请参考:https://github.com/engineer-man/piston/blob/master/docs/configuration.md?trk=cndc-detail - 完整的 Piston自定义环境参考:https://github.com/yanjun-ios/piston/tree/master?trk=cndc-detail ### 05 总结 我们可以通过 Claude 3 on [Amazon Bedrock](https://aws.amazon.com/cn/bedrock/?trk=cndc-detail),Mistral 7B 打造自己的代码助手,同时通过扩展 Piston 提供自定义安全可靠的执行环境,并且始终保持整个数据访问限定在企业内部,满足数据合规要求。项目后续考虑加入 Agent 和文档检索增强,利用 Amazon SDK 文档进一步提高 CodeCoach 的代码正确率,通过 Agent 来实现自动化测试。 ### 附录 - [Anthropic’s Claude on Amazon Bedrock](https://aws.amazon.com/bedrock/claude/?trk=cndc-detail) - [Mistral AI on Amazon Bedrock](https://aws.amazon.com/bedrock/mistral/?trk=cndc-detail) - [Piston](https://github.com/engineer-man/piston?trk=cndc-detail)
0
目录
关闭