摘要:在花费大量时间将 Amazon Bedrock 集成到应用程序中并构建基于 RAG 的聊天机器人后,我想—为什么不尝试一些更简单的东西呢?我决定创建一个由人工智能驱动的 Discord 机器人,它可以实时回答小组成员的问题。
在花费大量时间将 Amazon Bedrock 集成到应用程序中并构建基于 RAG 的聊天机器人后,我想—为什么不尝试一些更简单的东西呢?我决定创建一个由人工智能驱动的 Discord 机器人,它可以实时回答小组成员的问题。
我首先在 Amazon Bedrock 上启用 Llama 3.2——我之所以做出这个选择,是因为它是一个支持文本和视觉功能的多模态模型。这意味着我们的机器人不仅可以回答问题——它实际上可以分析用户上传的图像并回答有关它们的特定问题。
Amazon Bedrock 特别吸引人的地方在于它为开发人员提供了开箱即用的推理端点。无需处理服务器配置、API 公开或负载平衡。我们可以直接进入开发阶段,这正是我想要的。
Discord 方面的事情出奇地简单。如果你正在关注:
前往 Discord 开发者平台,创建新应用程序。
在设置中的 OAuth2 部分下生成令牌:
确保将其设置为公共机器人 - 如果你想邀请它加入你的服务器,这一点至关重要
实际的集成代码非常干净。我使用了 Bedrock Converse API,这是实现此功能的关键。基本实现如下所示:
import boto3from botocore.Exceptions import ClientErrorclient = boto3.client("bedrock-runtime", region_name="region_goes_here")model_id = "model_id_goes_here"user_message = "Describe the purpose of a 'hello world' program in one line."conversation = [{"role": "user","content": [{"text": user_message}],}]try:response = client.converse(modelId=model_id,messages=conversation,inferenceConfig={"maxTokens": 512, "temperature": 0.5, "topP": 0.9},)response_text = response["output"]["message"]["content"][0]["text"]print(response_text)except (ClientError, Exception) as e:print(f"ERROR: Can't invoke '{model_id}'. Reason: {e}")exit(1)4、处理图像处理由于 Llama 3.2 支持多模式交互,我确保实现图像处理功能。机器人现在可以处理用户上传的图像,但有一个问题 — Llama 3.2 有特定的图像大小限制。为了解决这个问题,我在将图像发送到 Bedrock Converse API 之前实现了图像大小调整和 base64 编码。
import pathlibfrom PIL import Image as PILImageimport base64import iofrom typing import Tuple, Optional, Unionimport magic # for mime type detectionclass ImageUtils:@staticmethoddef resize_img(b64imgstr: str, size: Tuple[int, int] = (256, 256)) -> str:"""Resize a base64 encoded image to the specified size.Args:b64imgstr (str): Base64 encoded image stringsize (tuple): Target size as (width, height)Returns:str: Base64 encoded resized image"""buffer = io.BytesIOimg = base64.b64decode(b64imgstr)img = PILImage.open(io.BytesIO(img))rimg = img.resize(size, PILImage.LANCZOS)rimg.save(buffer, format=img.format)return base64.b64encode(buffer.getvalue).decode("utf-8")@staticmethoddef img2base64(image_path: Union[str, pathlib.Path], resize: bool = False) -> str:"""Convert an image file to base64 string.Args:image_path (str or Path): Path to the image fileresize (bool): Whether to resize the image to 256x256Returns:str: Base64 encoded image"""with open(image_path, "rb") as img_f:img_data = base64.b64encode(img_f.read)if resize:return ImageUtils.resize_img(img_data.decode)else:return img_data.decode@staticmethoddef get_image(image_path: Union[str, pathlib.Path]) -> bytes:"""Read an image file and return its bytes.Args:image_path (str or Path): Path to the image fileReturns:bytes: Raw image data"""with open(image_path, "rb") as img_f:return img_f.read@staticmethoddef process_image_bytes(image_bytes: bytes, resize: bool = True) -> Tuple[bytes, str]:"""Process image bytes - optionally resize and detect format.Args:image_bytes (bytes): Raw image bytesresize (bool): Whether to resize the imageReturns:tuple: (processed image bytes, image format)"""# Detect image format using python-magicmime = magic.Magic(mime=True)image_format = mime.from_buffer(image_bytes).split('/')[-1]if resize:# Convert to base64, resize, and back to bytesb64_str = base64.b64encode(image_bytes).decoderesized_b64 = ImageUtils.resize_img(b64_str)return base64.b64decode(resized_b64), image_formatreturn image_bytes, image_format@staticmethoddef validate_image(image_bytes: bytes) -> bool:"""Validate if the bytes represent a valid image.Args:image_bytes (bytes): Raw image bytesReturns:bool: True if valid image, False otherwise"""try:img = PILImage.open(io.BytesIO(image_bytes))img.verifyreturn Trueexcept Exception:return False我甚至添加了一个巧妙的功能,如果有人在没有任何提示的情况下上传图像,机器人会自动使用默认提示来描述它在图像中看到的内容。
5、有趣的实验为了好玩,我甚至启动了两个机器人,让它们互相交谈——尽管我不得不承认,它们的聊天并没有真正产生任何意义!不过,观看它们还是很有趣的。
我的下一个项目更加令人兴奋——我计划使用 Amazon Bedrock 构建一个 AI 代理,该代理使用 RAG 模型连接到知识库。目标是让它使用我们自己的领域知识来回答特定问题,而不是仅仅依赖基础模型的训练数据。敬请期待!
来源:郑州楼盘