在亚马逊云科技上用生成式AI提升代码质量并通过CICD开发部署代码修复服务

项目简介:

小李哥将继续每天介绍一个基于亚马逊云科技AWS云计算平台的全球前沿AI技术解决方案,帮助大家快速了解国际上最热门的云计算平台亚马逊云科技AWS AI最佳实践,并应用到自己的日常工作里。

本次介绍的是如何利用亚马逊云科技大模型托管服务Amazon Bedrock和云原生网站开发服务,利用亚马逊Titan和Mistral AI大模型,为开发者创建分析、提升代码质量并修复漏洞网页交互界面,本架构设计全部采用了云原生Serverless架构,提供可扩展和安全的AI解决方案。通过Amazon API Gateway和AWS Lambda将应用程序与AI模型集成。本方案的解决方案架构图如下:

方案所需基础知识 

什么是 Amazon Bedrock?

Amazon Bedrock 是亚马逊云科技提供的一项服务,旨在帮助开发者轻松构建和扩展生成式 AI 应用。Bedrock 提供了访问多种强大的基础模型(Foundation Models)的能力,支持多种不同大模型厂商的模型,如AI21 Labs, Anthropic, Cohere, Meta, Mistral AI, Stability AI, 和Amazon,用户可以使用这些模型来创建、定制和部署各种生成式 AI 应用程序,而无需从头开始训练模型。Bedrock 支持多个生成式 AI 模型,包括文本生成、图像生成、代码生成等,简化了开发流程,加速了创新。

什么是 Amazon CodeGuru Security?

Amazon CodeGuru Security 是亚马逊云科技推出的一项自动化代码分析服务,专注于帮助开发者识别并修复代码中的安全漏洞。它基于机器学习和自动化分析技术,能够深入扫描代码库,检测常见的安全问题,如 SQL 注入、数据泄露、身份验证漏洞等。CodeGuru Security 为开发团队提供了一个有效的工具,确保在代码开发和部署的早期阶段就能发现并解决安全隐患,从而提升应用的整体安全性。

如何利用 Amazon CodeGuru Security 提升代码质量?

自动检测安全漏洞

CodeGuru Security 自动扫描代码库,识别潜在的安全漏洞,并提供详细的报告。这使得开发者能够在代码开发的早期阶段就发现并修复问题,避免安全风险在生产环境中暴露。

提供修复建议

除了发现漏洞,CodeGuru Security 还会针对每个检测到的问题提供具体的修复建议。这些建议基于亚马逊云科技的最佳实践和机器学习模型,有助于开发者快速、准确地修复代码,提升代码质量。

持续集成与持续交付(CI/CD)集成

CodeGuru Security 可以无缝集成到现有的 CI/CD 流水线中,实现自动化的安全扫描。在每次代码提交或合并时,服务会自动检查新代码的安全性,确保在代码进入生产环境前解决潜在问题。

提升开发团队的安全意识

通过定期使用 CodeGuru Security,开发团队可以不断学习和了解常见的安全问题及其解决方法,逐步提升团队的安全意识和编码规范。

节省时间和资源

CodeGuru Security 自动化的漏洞检测和修复建议大幅减少了人工代码审查的时间和工作量,使开发者能够将更多精力投入到创新和核心业务功能的开发上。

本方案包括的内容

1. 通过亚马逊云科技云端IDE Cloud9上传代码到代码库CodeCommit

2. 利用Amazon CodeGuru对代码库中的代码进行质量扫描

3. 构建后端应用通过Amazon Bedrock API调用LLM AI大模型Amazon Titan和Mistral AI

4. 构建Streamlit Web应用,调用Bedrock上的大模型提供代码质量提升建议

项目搭建具体步骤:

1. 进入亚马逊云科技控制台,打开云端IDE Cloud9

2. 进入到Clodu 9命令行中,运行命令创建CodeCommit代码库“ code-review-repo”。

aws codecommit create-repository --repository-name code-review-repo

3. 得到创建成功的回复,复制响应中“cloneUrlHttp”的键值

4. 运行以下命令初始化新的Git仓库,并将CodeCommit远程代码库添加到本地。

git config --global init.defaultBranch main
git init
git remote add codecommit <code-review-uri>

 5. 运行以下命令为CodeCommit开启代码CodeGuru质量扫描。复制响应中的“AssociationArn”键值。

aws codeguru-reviewer associate-repository --repository 'CodeCommit={Name=code-review-repo}'

6. 下面我们将本地的测试代码添加并上传到CodeCommit代码库中

git add ./
git commit -a -m " adding code to the code repo"
git push --set-upstream codecommit main

测试代码如下:

#  Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
#  SPDX-License-Identifier: Apache-2.0

# {fact rule=code-injection@v1.0 defects=1}
from flask import app


@app.route("/")
def execute_input_noncompliant():
    from flask import request

    module_version = request.args.get("module_version")
    # Noncompliant: executes unsanitized inputs.
    exec("import urllib%s as urllib" % module_version)


# {/fact}


# {fact rule=code-injection@v1.0 defects=0}
from flask import app


@app.route("/")
def execute_input_compliant():
    from flask import request

    module_version = request.args.get("module_version")
    # Compliant: executes sanitized inputs.
    exec("import urllib%d as urllib" % int(module_version))


# {/fact}

7. 接下来我们利用CodeGuru对我们上传到代码库的代码进行质量扫描,这里的“AssociationArn”用我们刚刚复制的键值替代,这里的ARN使我们CodeCommit代码库的ID。

aws codeguru-reviewer create-code-review \
 --name codereview0011 \
 --type '{"RepositoryAnalysis": {"RepositoryHead": {"BranchName": "main"}}}' \
 --repository-association-arn <AssociationArn>

8. 我们进入到CodeGuru服务主页,点击左侧的Code Reviews,可以看到我们刚刚完成的代码质量分析扫描,点击进入。

9. 我们可以看到代码质量分析运行的结果和建议,其中一条是在hashlib_constructor.py文件第12行的hashlib 模块关于构造函数new(),CodeGuru建议它建议使用 hashlib 模块的构造函数(如 hashlib.sha256())而不是使用 new() 方法,因为构造函数在性能上更快。

10. 接下来我们开始为我们进入亚马逊云科技的Jenkis服务CodeBuild,用于构建部署Streamlit应用的CICD。

我们可以通过以下脚本创建CodeBuild项目“streamlit-codebuild-project”,在CICD中构建我们的代码。这段脚本基于我们的应用源代码,打包了一个Docker镜像,并上传到了亚马逊云科技镜像库ECR中。

{
  "version": "0.2",
  "phases": {
    "pre_build": {
      "commands": [
        "echo 'Downloading container image from S3 bucket'",
        "aws s3 cp s3://lab-code-4b5aab50/Dockerfile .",
        "aws s3 cp s3://lab-code-4b5aab50/requirements.txt .",
        "aws s3 cp s3://lab-code-4b5aab50/app.py ."
      ]
    },
    "build": {
      "commands": [
        "echo 'Loading container image'",
        "aws ecr get-login-password --region us-east-1 | docker login --username AWS --password-stdin 903982278766.dkr.ecr.us-east-1.amazonaws.com",
        "docker build -t streamlit-container-image .",
        "echo 'Tagging and pushing container image to ECR'",
        "docker tag streamlit-container-image:latest 903982278766.dkr.ecr.us-east-1.amazonaws.com/streamlit-repo:latest",
        "docker push 903982278766.dkr.ecr.us-east-1.amazonaws.com/streamlit-repo:latest"
      ]
    }
  },
  "artifacts": {
    "base-directory": ".",
    "files": [
      "Dockerfile"
    ]
  }
}

11. 我们进入到ECR主页,可以看到我们刚构建的Docker镜像。

12. 接下来我们需要将Docker镜像部署运行在亚马逊云科技云原生容器管理服务ECS中。首先我们需要创建一个ECS容器任务定义模板。

我们根据如下的JSON配置文件,创建一个任务定义模板“streamlit-task-definition”。

{
    "taskDefinitionArn": "arn:aws:ecs:us-east-1:903982278766:task-definition/streamlit-task-definition:1",
    "containerDefinitions": [
        {
            "name": "StreamlitContainer",
            "image": "903982278766.dkr.ecr.us-east-1.amazonaws.com/streamlit-repo:latest",
            "cpu": 0,
            "links": [],
            "portMappings": [
                {
                    "containerPort": 8501,
                    "hostPort": 8501,
                    "protocol": "tcp"
                }
            ],
            "essential": true,
            "entryPoint": [],
            "command": [],
            "environment": [],
            "environmentFiles": [],
            "mountPoints": [],
            "volumesFrom": [],
            "secrets": [],
            "dnsServers": [],
            "dnsSearchDomains": [],
            "extraHosts": [],
            "dockerSecurityOptions": [],
            "dockerLabels": {},
            "ulimits": [],
            "systemControls": [],
            "credentialSpecs": []
        }
    ],
    "family": "streamlit-task-definition",
    "taskRoleArn": "arn:aws:iam::903982278766:role/ecs_cluster_role",
    "executionRoleArn": "arn:aws:iam::903982278766:role/ecs_cluster_role",
    "networkMode": "awsvpc",
    "revision": 1,
    "volumes": [],
    "status": "ACTIVE",
    "requiresAttributes": [
        {
            "name": "com.amazonaws.ecs.capability.ecr-auth"
        },
        {
            "name": "com.amazonaws.ecs.capability.docker-remote-api.1.17"
        },
        {
            "name": "com.amazonaws.ecs.capability.task-iam-role"
        },
        {
            "name": "ecs.capability.execution-role-ecr-pull"
        },
        {
            "name": "com.amazonaws.ecs.capability.docker-remote-api.1.18"
        },
        {
            "name": "ecs.capability.task-eni"
        }
    ],
    "placementConstraints": [],
    "compatibilities": [
        "EC2",
        "FARGATE"
    ],
    "requiresCompatibilities": [
        "FARGATE"
    ],
    "cpu": "512",
    "memory": "2048",
    "runtimePlatform": {
        "cpuArchitecture": "X86_64",
        "operatingSystemFamily": "LINUX"
    },
    "registeredAt": "2024-08-11T04:51:21.621Z",
    "registeredBy": "arn:aws:sts::903982278766:assumed-role/AWSLabs-Provisioner-v2-CjDTNtCaQDT/LPS-States-CreateStack",
    "tags": []
}

13. 接下来我们创建一个ECS集群“Streamlit-cluster”,用于运行我们的容器微服务。

14. 在集群内我们点击“Create”创建一个用streamlit开发代码分析应用微服务

15. 我们选择创建类型为“FARGATE”无服务器形式,无服务器架构可以让我们的应用有更好的扩展性并减轻运维压力。

 16. 创建类型选择“Service”微服务,在微服务创建模板选择我们刚创建的“streamlit-task-definition”,版本选择LATEST最新版本,并为微服务起名“streamlitservice”,维服务类型为“Replica”,表示在微服务内可以有多个副本任务同时运行提高可用性

17.接下来我们配置微服务部署的网络环境。选择LabVPC和双区高可用Public子网,并且添加Security Group防火墙。

18.  我们再为ECS微服务添加负载均衡器,选择“Application Load Balancer”应用层负载均衡器,并将微服务的8501端口挂载到负载均衡器。同时我们创建一个新的应用层负载均衡器“streamlit-lb”,健康检测生效时间为部署后30秒。

19. 最后我们为应用层负载均衡器开启HTTP 80端口作为对外暴露端口,创建新的后端目标组,用于托管ECS微服务,配置保持默认。

 20. ECS微服务部署完成后,我们可以获得我们应用层负载均衡器对外暴露的URL链接

21. 我们确认Amazon Bedrock上的“Titan Text G1 - Premier”大模型是开启的

 22. 接下来我们创建一个无服务器计算资源Lambda函数“bedrock_function”,并复制以下代码到函数中。

import json
import traceback

import boto3

region = boto3.session.Session().region_name


def lambda_handler(event, context):
    print(f"Event is: {event}")
    event_body = json.loads(json.dumps(event["body"]))
    prompt = event_body["query"]
    temperature = event_body["temperature"]
    max_tokens = event_body["max_tokens"]
    model_id = event_body["model_id"]
    top_p = event_body["top_p"]

    response = ""
    status_code = 200

    try:
        if model_id == "mistral.mistral-7b-instruct-v0:2":
            response = invoke_mistral_7b(
                model_id, prompt, temperature, max_tokens, top_p
            )
        elif model_id == "amazon.titan-text-premier-v1:0":
            response = invoke_titan(model_id, prompt, temperature, max_tokens, top_p)

        return ""+str(response)+""

    except Exception as e:
        print(f"An unexpected error occurred: {str(e)}")
        stack_trace = traceback.format_exc()
        print(stack_trace)
        return str(e)

def invoke_titan(model_id, prompt, temperature, max_tokens, top_p):
    try:

        bedrock_runtime_client = boto3.client(
            service_name="bedrock-runtime", region_name=region
        )
        body = {
            "inputText": prompt,
            "textGenerationConfig": {
                "maxTokenCount": max_tokens,
                "stopSequences": ["User:"],
                "temperature": temperature,
                "topP": top_p,
            },
        }

        response = bedrock_runtime_client.invoke_model(
            modelId=model_id, body=json.dumps(body)
        )

        response_body = json.loads(response["body"].read())
        outputs = response_body.get("results")
        print(f"response: {outputs}")
        outputText = outputs[0].get("outputText")
        return outputText
    except Exception as e:
        raise


def invoke_mistral_7b(model_id, prompt, temperature, max_tokens, top_p):
    try:

        instruction = f"<s>[INST] {prompt} [/INST]"
        bedrock_runtime_client = boto3.client(
            service_name="bedrock-runtime", region_name=region
        )

        body = {
            "prompt": instruction,
            "max_tokens": max_tokens,
            "temperature": temperature,
            "top_p": top_p,
        }

        response = bedrock_runtime_client.invoke_model(
            modelId=model_id, body=json.dumps(body)
        )
        response_body = json.loads(response["body"].read())
        outputs = response_body.get("outputs")
        print(f"response: {outputs}")

        completions = [output["text"] for output in outputs]
        return ""+str(completions[0])+""
    except Exception as e:
        raise

23. 我们打开应用层负载均衡器对外暴露的URL,进入到我们的部署的streamlit web应用微服务界面。复制我们在代码质量分析中发现的有关hashlib构造函数问题代码,配置大模型回复参数“Temperature”, “Top P”和“Max Tokens“,添加大模型提示词向大模型提问:”基于代码质量分析结果中发现的问题,将上面的代码重构返回修复后的代码,并附上解释,说明该修复是如何解决问题的”。

24. 我们就可以得到大模型重构后的修复代码和相应的解释分析

以上就是在亚马逊云科技上利用生成式AI提升代码质量并通过CICD开发部署问题修复web服务,提供问题修复建议的全部步骤。欢迎大家未来与我一起,未来获取更多国际前沿的生成式AI开发方案。

评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值