在亚马逊云科技上利用生成式AI和LangChain开发代码生成服务

项目简介:

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

本次介绍的是如何利用亚马逊云科技大模型托管服务Amazon Bedrock和LangChain提示词模板生成代码、对代码解释和代码版本转换,从而加速代码开发效率,本架构设计全部采用了云原生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 Titan 模型?

Amazon Titan 是亚马逊云科技推出的基础模型之一,专为处理复杂生成任务而设计。Titan 模型经过大规模数据训练,具备强大的自然语言理解和生成能力,适用于多种应用场景,包括文本创作、对话生成、代码生成等。开发者可以通过 Amazon Bedrock 直接访问 Titan 模型,进行轻松的定制和部署,满足特定业务需求。

利用生成式 AI 应用到代码开发的常见场景

提高开发效率

生成式 AI 可以自动生成代码片段、函数和模块,帮助开发者减少重复性工作,加快开发进程,从而更专注于解决复杂问题和实现业务逻辑。

减少错误和漏洞

通过生成式 AI 自动生成和审查代码,能够减少人为错误的发生,提升代码质量,降低漏洞风险。

智能代码补全

生成式 AI 可提供智能代码补全和建议,根据上下文自动补全代码,帮助开发者更快地编写代码,并保持一致性。

代码优化和重构

生成式 AI 可以建议代码优化和重构方案,帮助开发者改进代码性能,减少技术债务,提升代码的可维护性。最常见的就是将代码语言从Java8升级到Java17。

本方案包括的内容

1. 通过API调用Amazon Bedrock上的AI大模型生成动态SQL查询语句

2. 通过LangChain的提示词模板对代码进行解释

3. 利用Amazon Bedrock和LangChain将旧语言版本代码升级为新版本语言代码

项目搭建具体步骤:

1. 首先我们打开亚马逊云科技控制台,进入到Amazon Bedrock服务。

2. 在模型管理功能“Manage Access”中,点击”Enable Specific Models“开启所需要的模型。

3. 这里我们开启Amazon自研模型”Titan Text G1 - Premier“

4. 下面我们进入亚马逊云科技的云原生计算服务Lambda,创建一个Lambda函数”bedrock_function“,用于利用LangChain构建提示词模板与Amazon Bedrock上的AI大模型交互,并将生成内容返回给客户端,添加如下Python代码。

# Import necessary libraries
import json
import boto3
import os
import re
import logging

from langchain.prompts import ChatPromptTemplate, HumanMessagePromptTemplate
from template import generate_code_template, generate_translate_template, generate_analyze_code_template, ask_question_template


# Set up logging
logger = logging.getLogger()
logger.setLevel(logging.INFO)


# Create a Bedrock Runtime client
bedrock_client = boto3.client('bedrock-runtime')


# Define Lambda function
def lambda_handler(event, context):
    # Log the incoming event in JSON format
    logger.info('Event: %s', json.dumps(event))

    request_body = json.loads(event['body'])
    prefix = request_body.get('prefix')
    content  = request_body.get('content')
        
    # Generate the prompt based on the prefix
    if prefix == 'generate_code':
        template_generator = generate_code_template
    elif prefix == 'translate_code':
        template_generator = generate_translate_template
    elif prefix == 'analyze_code':
        template_generator = generate_analyze_code_template
    elif prefix == 'ask_question':
        template_generator = ask_question_template

    template = template_generator(context=content)
    
    prompt_template = ChatPromptTemplate(
        messages=[HumanMessagePromptTemplate.from_template(template)],
        input_variables=["context"],
    )
    
    prompt = prompt_template.format(context=content)
    
    # Prepare the input data for the model
    input_data = {
        "inputText": prompt,
        "textGenerationConfig": {
            "temperature": 0.7,
            "topP": 0.95,
            "maxTokenCount": 1000,
            "stopSequences": []
        }
    }
    
    # Log the input data
    logger.info('Input data: %s', json.dumps(input_data))

    # Invoke the Bedrock Runtime with the cleaned body as payload
    response = bedrock_client.invoke_model(
        modelId=os.environ['BEDROCK_MODEL_ID'],
        body=json.dumps(input_data).encode("utf-8"),
        accept='application/json',
        contentType='application/json'
    )

    # Load the response body and decode it
    result = json.loads(response["body"].read().decode())
    
    # Log the response payload
    logger.info('Response payload: %s', json.dumps(result))
    
    # Extract the generated text from the response
    generated_text = ""
    if "results" in result and result["results"]:
        generated_text = result["results"][0].get("outputText", "").replace("\\n", "\n")
    
    # Return the result with status code 200 and the necessary headers
    return {
        'statusCode': 200,
        'headers': {
            'Access-Control-Allow-Headers': 'Content-Type',
            'Access-Control-Allow-Origin': '*',
            'Access-Control-Allow-Methods': 'OPTIONS,POST'
        },
        'body': generated_text
    }

5. 同时我们在Lambda中新建一个Python函数template.py, 复制以下内容到Python文件中。分别定义了四个不同特定任务的提示词模板,分别用于代码生成、将Java代码转为Python、分析代码、回答代码相关问题。根据上一个Python文件31-38行中HTTPS请求体中的Prefix值,调用本文件中对用的提示词模板。

def generate_code_template(context):
    template = f"""
    Anime Island AI has a database with a table named `content_library` containing information about their anime content. The table has the following columns:
    - `release_date` (YYYY-MM-DD)
    - `content_id`
    - `episode_count`
    - `view_count`

    Generate SQL queries based on the following context: {{context}}
    """
    return template 

def generate_translate_template(context):
    template = f"""
    You are a highly skilled software engineer tasked with translating the following legacy Java code to Python.
    1. Please provide the translated Python code, ensuring that it maintains the same functionality and behavior as the original Java code.
    2. Include comments explaining any significant changes, optimizations, or improvements made during the translation process.
    3. Your translation should follow best practices and modern coding standards for Python.
    
    Review the provided legacy code snippet in context: {{context}}
    """
    return template

def generate_analyze_code_template(context):
    template = f"""
    Please provide a detailed explanation and interpretation for the following code snippet. Your explanation should cover:
    1. The purpose and functionality of the code
    2. How the code works, step-by-step
    3. Any important data structures, algorithms, or design patterns used
    4. Potential improvements, optimizations, or alternative approaches
    5. Any external dependencies or libraries used, and their roles
    6. Any potential challenges, gotchas, or pitfalls to be aware of
    
    Review the provided code snippet in context: {{context}}
    """
    return template

def ask_question_template(context):
    template = f"""
    Your task is to answer the question as asked.
    Review the provided request in context: {{context}}
    """
    return template
    

6. 接下来我们利用API Gateway服务创建一个API对外暴露的接口,获取后端API的URL。

 7. 我们通过亚马逊云科技的CDN服务CloudFront访问前端UI界面

8. 接下来我们开始测试我们刚刚构建的代码生成AI应用。首先测试的是动态SQL代码生成功能。我们浏览器中打开CloudFront的URL,可以看到我们自己开发的前端UI。我们点击”Generate SQL Queries“功能,提示词已经自动填充,这时我们输入问题:”请识别本年度观看次数最多的前5部动漫作品,并计算每部在本年度发布的动漫每集的平均观看次数。”

 9. 我们可以得到通过AI生成的SQL语句代码。

10. 接下来我们测试将Java代码翻译成 Python代码功能。我们先点击“Legacy Code Translation”,再将测试代码复制到输入框。

测试代码如下:

public class AnimationRenderer {
    private static final int FRAME_WIDTH = 640;
    private static final int FRAME_HEIGHT = 480;

    public static void renderAnimation(List<Frame> frames, String outputPath) {
        try (FileOutputStream outputStream = new FileOutputStream(outputPath)) {
            outputStream.write(ByteBuffer.allocate(4).putInt(frames.size()).array());

            for (Frame frame : frames) {
                outputStream.write(ByteBuffer.allocate(4).putInt(FRAME_WIDTH).array());
                outputStream.write(ByteBuffer.allocate(4).putInt(FRAME_HEIGHT).array());

                for (int y = 0; y < FRAME_HEIGHT; y++) {
                    for (int x = 0; x < FRAME_WIDTH; x++) {
                        Color color = frame.getPixel(x, y);
                        outputStream.write(ByteBuffer.allocate(4)
                                .putInt((color.getRed() << 16) | (color.getGreen() << 8) | color.getBlue())
                                .array());
                    }
                }
            }
        } catch (IOException e) {
            System.err.println("Error writing animation file: " + e.getMessage());
        }
    }
}

11. 我们得到了大模型的如下回复。我们看到大模型把Java代码转换成了Python,并且按照我们提示词的提示提供了代码的具体解释。

```python
import io
from PIL import Image, ImageColor

class AnimationRenderer:
    # Class constants, same as in Java code
    FRAME_WIDTH = 640
    FRAME_HEIGHT = 480

    @staticmethod
    def render_animation(frames, output_path):
        try:
            # Open the output file in binary mode
            with open(output_path, 'wb') as output_file:
                # Write the number of frames to the file
                output_file.write(bytes([len(frames)]))

                # Iterate through each frame
                for frame in frames:
                    # Write the frame dimensions to the file
                    output_file.write(bytes([AnimationRenderer.FRAME_WIDTH]))
                    output_file.write(bytes([AnimationRenderer.FRAME_HEIGHT]))

                    # Convert the frame to an image and resize it
                    img = Image.new('RGB', (AnimationRenderer.FRAME_WIDTH, AnimationRenderer.FRAME_HEIGHT))
                    img.putdata([
                        ImageColor.getrgb(color.getRed(), color.getGreen(), color.getBlue())
                        for y in range(AnimationRenderer.FRAME_HEIGHT)
                        for x in range(AnimationRenderer.FRAME_WIDTH)
                        for color in frame.get_pixel(x, y)
                    ])

                    # Save the image to the output file
                    img.save(output_file, 'PNG')

        except IOError as e:
            print(f"Error writing animation file: {e}")
```

Here's a breakdown of the changes made:

* Changed the class name to `AnimationRenderer` to follow Python naming conventions.
* Imported the necessary modules: `io`, `PIL`, and `ImageColor`.
* Changed the class constants to class variables.
* Changed the method name to `render_animation` to follow Python naming conventions.
* Used the `with` statement to ensure that the output file is properly closed after writing.
* Used the `bytes` function to write integers to the file in binary format.
* Used a list comprehension to create the pixel data for the image.
* Used the `Image.new` function to create a new image with the specified dimensions.
* Used the `putdata` method to set the pixel data for the image.
* Used the `Image.save` method to save the image to the output file.
* Used a try-except block to handle any IO errors that may occur during the writing process.
* Used an f-string to format the error message.

12.  最后我们通过点击UI中的“Code Analysis”界面,对我们输入的代码进行分析。

代码如下:

import cv2
from collections import deque

def detect_anime_character(frame, character_cascade, pts):
    gray = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY)
    characters = character_cascade.detectMultiScale(gray, scaleFactor=1.1, minNeighbors=5, minSize=(30, 30))

    for (x, y, w, h) in characters:
        center = (x + w // 2, y + h // 2)
        pts.appendleft(center)

        for i in range(1, len(pts)):
            thickness = int(np.sqrt(64 / float(i + 1)) * 2.5)
            cv2.line(frame, pts[i - 1], pts[i], (0, 0, 255), thickness)

        cv2.circle(frame, center, 5, (0, 0, 255), -1)
        cv2.rectangle(frame, (x, y), (x + w, y + h), (0, 255, 0), 2)

    return frame, pts

character_cascade = cv2.CascadeClassifier('anime_character_detector.xml')
pts = deque(maxlen=64)

cap = cv2.VideoCapture('anime_video.mp4')
while True:
    ret, frame = cap.read()
    if not ret:
        break

    frame, pts = detect_anime_character(frame, character_cascade, pts)
    cv2.imshow('Anime Character Tracker', frame)

    if cv2.waitKey(1) & 0xFF == ord('q'):
        break

cap.release()
cv2.destroyAllWindows()

12. 我们得到了大模型根据我们提示词提示如下的代码具体分析。

 输出结果为:可以看到大模型帮我们分析了我们的代码的功能、使用的库、代码每一步具体实现的功能,代码评估及优化建议。

The code snippet is a video tracker for anime characters, using a pre-trained Haar cascade classifier for object detection and OpenCV for video processing. The primary purpose of the code is to locate and track anime characters in a video, drawing bounding boxes and connecting detected character positions with lines.

The code works in the following way:

1. It imports the necessary libraries, including OpenCV and the deque data structure from the collections module.
2. The `detect_anime_character` function takes in a frame, a Haar cascade classifier, and a deque as arguments. It performs the following steps:
a. Converts the input frame to grayscale.
b. Detects anime characters in the grayscale image using the cascade classifier and the `detectMultiScale` function.
c. For each detected character, it calculates the center point, appends it to the deque, and connects the center points with lines.
d. Draws a bounding box and a circle around the detected character.
3. The cascade classifier and deque are initialized.
4. The video is read using the `VideoCapture` class from OpenCV.
5. The video is processed in a while loop, breaking when the video ends or the 'q' key is pressed.
6. The processed frame and deque are passed to the `detect_anime_character` function.
7. The processed frame is displayed using the `imshow` function.
8. The video capture and all windows are released after the loop.

The code uses a deque data structure with a maximum length of 64 to store the most recent character positions, allowing for the creation of lines between character positions. The Haar cascade classifier, which is a machine learning-based object detection algorithm, is used to detect anime characters in the video.

Potential improvements or optimizations include:

* Training a custom Haar cascade classifier for better accuracy.
* Using a more advanced object detection algorithm, such as YOLO or Faster R-CNN.
* Implementing a more efficient algorithm for connecting character positions with lines.
* Using a more efficient data structure for storing character positions.

The code relies on the OpenCV library for video processing and the Haar cascade classifier. It also uses the deque data structure from the collections module for storing character positions.

Some potential challenges or pitfalls to be aware of include:

* The accuracy of the Haar cascade classifier may be affected by the quality and resolution of the input video.
* The code may not work well with videos that have a high frame rate or that contain a large number of characters.
* The code may be slow or resource-intensive for videos with a high resolution or a long duration.
* The code may not work well with videos that contain characters that are not in the training data for the Haar cascade classifier.

以上就是在亚马逊云科技上利用大模型托管服务上的生成式GenAI模型和LangChain加速代码开发的全部步骤。欢迎大家未来与我一起,未来获取更多国际前沿的生成式AI开发方案。

评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值