Kubernetes 上的大数据——在 Kubernetes 上的生成式人工智能

1,019 阅读35分钟

生成式人工智能(GenAI)已成为一种变革性技术,彻底改变了我们与人工智能的互动方式和利用方式。在本章中,我们将探索生成式人工智能的激动人心的世界,并学习如何在 Kubernetes 上发挥其力量。我们将深入了解生成式人工智能的基本原理,并理解它与传统人工智能的主要区别。

我们的重点将放在利用 Amazon Bedrock,这是一套全面的服务套件,旨在简化生成式人工智能应用程序的开发和部署。通过实际示例,你将获得在 Kubernetes 上使用 Streamlit 构建生成式人工智能应用的实践经验,Streamlit 是一个强大的 Python 库,用于创建交互式数据应用。我们将覆盖从开发到在 Kubernetes 集群上部署应用的整个过程。

此外,我们将探索检索增强生成(RAG)的概念,它结合了生成式人工智能与外部知识库的力量。

最后,我们将介绍 Amazon Bedrock 的 Agents 功能,这是一个强大的功能,允许你自动化任务并创建智能助手。你将学习如何构建一个代理,通过 OpenAPI 模式定义其能力,并创建作为代理后端的底层 Lambda 函数。

到本章结束时,你将对生成式人工智能、其应用以及在 Kubernetes 上构建和部署生成式人工智能应用所需的工具和技术有一个坚实的理解。

在本章中,我们将涵盖以下主要主题:

  • 什么是生成式人工智能,什么不是
  • 使用 Amazon Bedrock 处理基础模型
  • 在 Kubernetes 上构建生成式人工智能应用
  • 为 Amazon Bedrock 构建基于知识库的 RAG
  • 用代理构建动作模型

技术要求

对于本章,你将需要一个 AWS 账户和一个正在运行的 Kubernetes 集群。我们还将使用 LangChain 和 Streamlit 库。虽然在 Kubernetes 中部署应用程序时不必安装它们,但如果你想在本地测试代码并对其进行修改以进行自己的实验,建议安装。

此外,还需要安装 Beautiful Soup 库,以获取 RAG 练习(第四节)的数据。

本章的所有代码都可在 github.com/PacktPublis… 的 Chapter11 文件夹下找到。

什么是生成式人工智能,什么不是

生成式人工智能(Generative AI)本质上指的是能够生成新的、原创的内容的人工智能系统,如基于其接触过的训练数据生成文本、图像、音频或代码。生成式人工智能模型是在大量现有内容的数据集上进行训练的,它们学习数据中的模式和关系。当被提示时,这些模型可以生成类似于训练数据但不是任何特定示例的精确副本的新的、原创内容。

这与传统的机器学习模型形成对比,后者侧重于基于现有数据进行预测或分类。传统的机器学习模型,如用于图像识别、自然语言处理或预测分析的模型,旨在接收输入数据并根据该数据进行预测或分类。机器学习模型擅长执行分类(例如,识别图像中的对象或文本中的主题)、回归(例如,根据面积和位置预测房价)和聚类(例如,根据相似行为模式对客户进行分组)等任务。

例如,一个图像识别模型可能在一个大型的标记图像数据集上进行训练,以学习识别和分类新的、未见过的图像中的对象。同样,自然语言处理模型可能在文本数据语料库上进行训练,执行情感分析、命名实体识别或语言翻译等任务。

在信用风险评估场景中,机器学习模型将根据包含过去贷款申请者的信息(如收入、信用历史等相关特征)以及表明他们是否违约的标签的数据集进行训练。模型将学习这些特征与贷款违约结果之间的模式和关系。面对新的贷款申请时,训练有素的模型可以预测申请人违约的可能性。

在这些情况下,机器学习模型并不生成新内容;相反,它使用从训练数据中学到的模式和关系对新的、未见过的数据做出有根据的预测或决策。

相比之下,例如,一个在庞大的文本语料库上训练的生成式人工智能模型可以在任何给定的主题上或以任何所需的风格生成类似人类的写作。同样,训练有素的图像模型可以根据文本描述或其他输入数据创建全新的、逼真的图像。

尽管生成式人工智能的最终结果是创造新内容,但其底层机制仍基于机器学习的相同原则:进行预测。然而,与预测单一输出(如分类或数值)不同,生成式人工智能模型被训练用来预测序列中的下一个元素,无论该序列是单词序列、像素序列还是其他类型的数据序列。

大型神经网络的力量

虽然预测序列中下一个元素的概念相对简单,但生成式人工智能模型生成连贯、高质量内容的能力在于用来驱动这些模型的神经网络的规模和复杂性。

生成式人工智能模型通常采用具有数十亿甚至数万亿参数的大型、深层神经网络。这些神经网络在庞大的数据量上进行训练,通常涵盖数百万或数十亿的示例,使它们能够捕捉数据中极其细微的模式和关系。

例如,Anthropic的模型,如Claude,就是在覆盖广泛主题和领域的庞大文本数据语料库上进行训练的。这使得模型能够深入理解语言、上下文和领域特定知识,使它们能够生成不仅语法正确,而且在语义上连贯并与给定上下文相关的文本。

挑战和局限性

尽管生成式人工智能展示了显著的能力,但它也存在挑战和局限性。主要关注点之一是这些模型可能生成有偏见、有害或误导性内容的潜力,特别是当它们在反映社会偏见或包含不准确信息的数据集上进行训练时。

此外,生成式人工智能模型有时可能产生荒谬、不一致或事实上不正确的输出,尽管它们在表面上看起来连贯和可信。这被称为“幻觉”问题,即模型生成的内容没有根据事实知识或提供的上下文。

尽管存在这些挑战,生成式人工智能是一个快速发展的领域,研究人员和开发人员正在积极解决这些问题。正在探索的技术,如微调、提示工程和使用外部知识源(例如知识库或RAG),旨在提高生成式人工智能模型的可靠性、安全性和事实准确性。

在接下来的章节中,我们将深入探讨使用 Amazon Bedrock 及其基础模型、知识库和基于代理的架构构建和部署生成式人工智能应用的实践方面。

使用 Amazon Bedrock 处理基础模型

Amazon Bedrock 提供了一套基础模型,可以作为您生成式人工智能应用的构建模块。理解每个模型的能力和预期用例对于选择适合您应用的正确模型至关重要。

Amazon Bedrock 提供的模型包括语言模型、计算机视觉模型和多模态模型。语言模型擅长理解和生成类似人类的文本。它们可用于文本摘要、问答和内容生成等任务。另一方面,计算机视觉模型擅长分析和理解视觉数据,使它们非常适合于图像识别、对象检测和场景理解等应用。

多模态模型,顾名思义,可以同时处理多种模态。这使它适合于图像字幕、视觉问答和数据图表分析等任务。

值得注意的是,每个模型都有其自身的优势和局限性,模型的选择应由您的应用的具体需求来指导。例如,如果您的应用主要处理基于文本的任务,如 Llama 这样的语言模型可能是最合适的选择。然而,如果您需要同时处理文本和图像,像 Claude 这样的多模态模型会是更好的选择。

要有效地将 Amazon Bedrock 的基础模型整合到我们的生成式人工智能应用中,请按照以下步骤操作:

首先,我们需要激活 Amazon Bedrock 的可用基础模型。前往 AWS 控制台并搜索 Amazon Bedrock 页面。然后,点击修改模型访问权限(图 11.1)。

image.png

在下一页中,请选择 Claude 3 Sonnet 和 Claude 3 Haiku Anthropic 模型。这些是我们将用于生成 AI 应用的基础模型。如果您想要玩耍并尝试不同的模型,您可以选择所有可用的模型(见图 11.2)。

image.png

点击“下一步”,在接下来的页面中,审阅更改然后点击“提交”。这些模型可能需要几分钟时间才能获得访问权限。 一旦获得访问权限,我们就拥有了开发生成式 AI 应用所需的一切。让我们开始吧。

在 Kubernetes 上构建生成式 AI 应用

在这一节中,我们将使用 Streamlit 构建一个生成式 AI 应用。这个应用的架构示意图显示在图 11.3 中。在这个应用中,用户将能够选择他们将要交互的基础模型。

image.png

我们从应用的 Python 代码开始。完整的代码位于 GitHub 上的 Chapter 11/streamlit-claude/app 文件夹中。我们将逐块地浏览代码: 首先,创建一个名为 app 的文件夹,在其中创建一个名为 main.py 的代码文件。首先,我们导入必要的文件并创建一个客户端以访问 Amazon Bedrock 运行时 API:

import boto3
from langchain_community.chat_models import BedrockChat
from langchain.callbacks.streaming_stdout import StreamingStdOutCallbackHandler
bedrock = boto3.client(service_name='bedrock-runtime', region_name="us-east-1")

接下来,我们定义一个参数字典,这些参数对于使用 Claude 非常重要:

inference_modifier = {
    "max_tokens": 4096,
    "temperature": 0.5,
    "top_k": 250,
    "top_p": 1,
    "stop_sequences": ["\n\nHuman:"],
}

接下来,我们将配置一个函数,允许选择首选的基础模型。通过选择,我们将返回一个可以通过 Langchain 访问 Bedrock 的模型对象:

def choose_model(option):
    modelId = ""
    if option == "Claude 3 Haiku":
        modelId = "anthropic.claude-3-haiku-20240307-v1:0"
    elif option == "Claude 3 Sonnet":
        modelId = "anthropic.claude-3-sonnet-20240229-v1:0"
    model = BedrockChat(
        model_id=modelId,
        client=bedrock,
        model_kwargs=inference_modifier,
        streaming=True,
        callbacks=[StreamingStdOutCallbackHandler()],
    )
    return model

现在,我们将添加一个小函数来重置会话历史:

def reset_conversation():
    st.session_state.messages = []

接下来,我们将开始开发主函数,并在应用界面中添加一些小工具。以下代码创建了一个侧边栏。在其中,我们添加了一个选择框,选项为 Claude 3 Haiku 和 Claude 3 Sonnet,我们写下一个确认消息告诉用户他们正在与哪个模型交谈,并添加了一个重置聊天按钮。之后,我们运行 choose_model 函数返回连接到 Bedrock 的类,并写下应用的标题,与 Claude 3 聊天:

def main():
    with st.sidebar:
        option = st.selectbox(
            "What model do you want to talk to?",
            ("Claude 3 Haiku", "Claude 3 Sonnet")
        )
        st.write(f"You are talking to **{option}**")
        st.button('Reset Chat', on_click=reset_conversation)
    model = choose_model(option)
    st.title("Chat with Claude 3")

接下来,我们将初始化聊天历史为一个空列表,如果它还不存在于 st.session_state 中。st.session_state 是一个 Streamlit 对象,用于在应用重运行中保持数据。然后,我们遍历 st.session_state 中的消息列表,并在聊天消息容器中显示每条消息。st.chat_message 函数创建一个指定角色(例如,用户或助理)的聊天消息容器。st.markdown 函数在容器内显示消息内容:

if "messages" not in st.session_state:
    st.session_state.messages = []
for message in st.session_state.messages:
    with st.chat_message(message["role"]):
        st.markdown(message["content"])

接下来,我们处理用户输入并显示对话。st.chat_input 函数创建一个输入字段,用户可以在其中输入他们的提示。如果用户输入了一个提示,将执行以下步骤:(1) 用户的提示被添加到 st.session_state 的消息列表中,并设置为用户角色;(2) 用户的提示在用户角色的聊天消息容器中显示;(3) 调用 model.stream(prompt) 函数,该函数将用户的提示发送到 Bedrock 模型并实时流回响应。st.write_stream 函数实时显示流回的响应;(4) 助理的回答被添加到 st.session_state 的消息列表中,并设置为助理角色:

if prompt := st.chat_input("Enter your prompt here"):
    st.session_state.messages.append(
        {"role": "user", "content": prompt}
    )
    with st.chat_message("user"):
        st.markdown(prompt)
    with st.chat_message("assistant"):
        response = st.write_stream(
            model.stream(prompt)
        )
    st.session_state.messages.append(
        {"role": "assistant", "content": response}
    )

最后,我们调用 main 函数以启动 Streamlit 应用:

if __name__ == "__main__":
    main()

如果你想在本地运行这个应用,请参照这个 requirements.txt 文件: boto3==1.34.22 langchain-community==0.0.33 langchain==0.1.16 streamlit==1.34.0 使用以下命令安装必要的库:

pip install -r requirements.txt

如果你已经安装了这些库,请使用 aws configure 命令认证你的 AWS CLI,并使用以下命令在本地启动应用:

streamlit run main.py

这是在构建用于部署的容器映像之前测试应用的绝佳方式。你可以测试和修改应用,按照你的需求进行调整。 准备就绪后,现在,让我们为部署构建一个容器映像。 以下是构建映像的简单 Dockerfile:

FROM python:3.9-slim
WORKDIR /app
RUN apt-get update && apt-get install -y \
    build-essential \
    curl \
    software-properties-common \
    git \
    && rm -rf /var/lib/apt/lists/*
COPY app /app/
EXPOSE 8501
HEALTHCHECK CMD curl --fail http://localhost:8501/_stcore/health
RUN pip3 install -r requirements.txt
ENTRYPOINT ["streamlit", "run", "main.py", "--server.port=8501", "--server.address=0.0.0.0"]

这个 Dockerfile 从 Python 3.9 slim 基础镜像开始,设置工作目录为 /app。然后安装应用所需的各种系统包,如 build-essential, curl, software-properties-common 和 git。应用代码被复制到 /app 目录中,容器公开 8501 端口。设置了一个健康检查,检查 Streamlit 应用是否在 http://localhost:8501/_stcore/health 上正确运行。根据 requirements.txt 文件使用 pip3 安装所需的 Python 包。最后,ENTRYPOINT 命令通过运行 streamlit run main.py 并指定服务器端口和地址来启动 Streamlit 应用。 要在本地构建映像,请输入以下命令:

docker build --platform linux/amd64 -t <YOUR_USERNAME>/chat-with-claude:v1 .

记得将 <YOUR_USERNAME> 更改为你的实际 Docker Hub 用户名。然后,使用以下命令推送映像:

docker push <YOUR_USERNAME>/chat-with-claude:v1

请记住,这个映像将在 Docker Hub 上公开。不要在代码中或作为环境变量放置任何认证凭证或敏感数据! 现在,让我们在 Kubernetes 上部署我们的应用。

部署 Streamlit 应用

正如我们之前看到的,要在 Kubernetes 上部署我们的应用,我们需要一个 Deployment 和一个 Service 的 .yaml 定义文件。我们可以在一个文件中提供这两个定义: 首先,创建一个名为 deploy_chat_with_claude.yaml 的文件,文件内容如下: deploy_chat_with_claude.yaml

apiVersion: apps/v1
kind: Deployment
metadata:
  name: chat-with-claude
spec:
  replicas: 1
  selector:
    matchLabels:
      app: chat-with-claude
  template:
    metadata:
      labels:
        app: chat-with-claude
    spec:
      containers:
      - name: chat-with-claude
        image: docker.io/neylsoncrepalde/chat-with-claude:v1
        ports:
        - containerPort: 8501
        env:
        - name: AWS_ACCESS_KEY_ID
          valueFrom:
            secretKeyRef:
              name: aws-credentials
              key: aws_access_key_id
        - name: AWS_SECRET_ACCESS_KEY
          valueFrom:
            secretKeyRef:
              name: aws-credentials
              key: aws_secret_access_key

代码的第一部分定义了一个名为 chat-with-claude 的 Deployment 资源。它使用之前构建的镜像(你可以更改为你自己的新镜像),并在容器中打开端口 8501,以便从 Pod 外部访问。spec.template.spec.containers.env 块将 AWS 凭证作为环境变量挂载到名为 aws-credentials 的秘密中的容器。

代码的第二部分定义了一个用于 Deployment 中定义的 Pod 的 LoadBalancer 服务,它监听端口 8501,并将流量引导到容器中的端口 8501。不要忘记在单个文件中分隔几个资源所必需的 ---:

---
apiVersion: v1
kind: Service
metadata:
  name: chat-with-claude
spec:
  type: LoadBalancer
  ports:
  - port: 8501
    targetPort: 8501
  selector:
    app: chat-with-claude

现在,我们将创建命名空间和秘密,并使用以下命令部署应用程序:

kubectl create namespace genai
kubectl create secret generic aws-credentials --from-literal=aws_access_key_id=<YOUR_ACCESS_KEY_ID> --from-literal=aws_secret_access_key="<YOUR_SECRET_ACCESS_KEY>" -n genai
kubectl apply -f deploy_chat_with_claude.yaml -n genai

就这样。等待几分钟让 LoadBalancer 启动并运行,并使用以下命令检查其 URL:

kubectl get svc -n genai

现在,在 URL 后面加上 :8501 来定义正确的端口,瞧!(见图 11.4)。

image.png

现在,与助理玩一玩。尝试 Haiku 和 Sonnet,注意它们在响应速度和答案质量上的差异。经过几次尝试,你会注意到向基础模型提出具体问题会导致产生幻觉。例如,问模型,你是谁。你会有一个惊喜(和一些笑声)。这个模型需要上下文。 在下一节中,我们将使用 RAG 提供一些上下文。

使用亚马逊 Bedrock 的知识库构建 RAG RAG 是一种在生成过程中为基础模型提供额外上下文和知识的生成 AI 模型技术。它首先从知识库或文档语料库中检索相关信息,然后使用这些检索到的信息增强生成模型的输入。

RAG 是为生成 AI 模型提供上下文的一个好选择,因为它允许模型访问和利用外部知识源,这可以显著提高生成输出的质量、准确性和相关性。没有 RAG,模型将仅限于在训练期间学习的知识和模式,这可能并不总是足够的或最新的,特别是对于特定领域或快速发展的主题。

RAG 的一个关键优势是它使模型能够利用大型知识库或文档集合,这在模型的训练数据中包含这些内容是不切实际或不可能的。这使得模型能够生成更有信息量和知识性的输出,因为它可以汲取大量相关信息。此外,RAG 可以帮助缓解幻觉和偏见问题,因为模型可以访问权威和事实性的来源。

然而,RAG 也有一些局限性。生成输出的质量在很大程度上取决于检索信息的相关性和准确性,这可能会受到知识库的质量、检索机制的有效性以及模型整合检索信息的能力的影响。此外,RAG 可能会引入计算开销和延迟,因为它需要在生成过程之前增加一个额外的检索步骤。

为了构建具有 RAG 的 AI 助手,我们将使用亚马逊 Bedrock 的知识库功能,这是 Bedrock 中的一个功能,允许您无缝创建和管理知识库。让我们开始吧。 在我们的练习中,我们将构建一个能够提供关于 AWS Competency Program 的信息的 AI 助手。这个助手的架构示意图显示在图 11.5 中:

image.png

AWS Competency Program 是 AWS 提供的一项验证程序,用于认可那些在专门解决方案领域展示了技术熟练度和经过验证的客户成功的合作伙伴。AWS Competencies 授予那些经历了与特定 AWS 服务或工作负载相关的技术验证的 AWS 合作伙伴网络(APN)成员,确保他们具备提供一致、高质量 AWS 解决方案的专业知识。这些能力覆盖了各种领域,如 DevOps、迁移、数据与分析、机器学习和安全等。每个能力都有自己的规则文档,并且理解起来可能相当具有挑战性。

首先,我们将收集一些关于该计划的背景信息。在 GitHub 上,位于 Chapter 11/claude-kb/knowledge-base/ 文件夹下,你会找到一个 Python 代码,该代码将收集关于对话 AI、数据与分析、DevOps、教育、能源、金融服务、机器学习和安全计划的信息。将这个代码保存到本地后,安装 Beautiful Soup 库,使用以下命令:

pip install "beautifulsoup4==4.12.2"

然后,使用以下命令运行代码:

python get_competency_data.py

几秒钟后,数据应该会被保存在你的机器上。

接下来,创建一个 S3 桶并上传这些文件。这将成为我们 RAG 层的基础。

接下来,转到 AWS 控制台中的 Bedrock 页面。在侧边菜单中,点击 Knowledge Bases,然后点击 Create knowledge base(见图 11.6)。

image.png

在下一页中,为您的知识库选择一个名称,并在 IAM 权限部分选择“创建并使用新的服务角色”。然后,点击“下一步”。

接下来,您将配置数据源。根据您的愿望选择一个数据源名称。对于“数据源位置”,确保选中“This AWS account”框选项。然后,在“S3 URI”部分,点击“浏览 S3”以搜索包含 AWS Competency 数据集的 S3 桶(我们在第二步中创建的桶)。该配置的示例显示在图 11.7 中。选择 S3 桶后,点击“下一步”。

image.png

接下来,我们将选择嵌入模型。这个嵌入模型负责将文本或图像文件转换成称为嵌入的向量表示。这些嵌入捕捉输入数据的语义和上下文信息,允许进行高效的相似性比较和检索操作。Bedrock 的一个嵌入模型,Amazon Titan,默认应该是可用的。如果不可用,可以在控制台进行相同的访问请求过程。

在下一页的嵌入模型部分,选择 Titan Embeddings G1 - Text。在向量数据库部分,确保选中“快速创建新的向量存储”选项。这个快速创建选项基于 OpenSearch Serverless 创建一个向量数据库。保留其他选项不选,点击“下一步”。

注意

OpenSearch 是一个基于 Apache Lucene 构建的开源分布式搜索和分析引擎,源自 Elasticsearch。它是 RAG 向量数据库的绝佳选项,因为它提供了高效的全文搜索和最近邻搜索功能,适用于向量嵌入。OpenSearch 支持密集向量的索引和检索,适合存储和查询大量的向量嵌入集合,这对 RAG 模型的检索组件至关重要。

接下来,复查信息以确认是否正确提供。如果一切看起来都好,点击“创建知识库”。请耐心等待。这个创建过程将需要几分钟时间完成。

在知识库建立并运行之后,返回 Bedrock 的知识库页面,点击你刚创建的知识库。在下一页,滚动到你看到数据源部分(如图 11.8 所示)。选择数据源并点击“同步”开始嵌入文本内容的过程。这同样需要几分钟时间。

image.png

在“同步”准备好之后,我们就拥有了使用 RAG 运行我们的生成式 AI 助理所需的一切。现在是时候调整代码,让 Claude 与知识库一起工作了。

调整代码以用于 RAG 检索

我们将从之前开发的与纯 Claude 模型一起工作的代码开始。由于我们只需要一些小修改,我们不会再次走遍整个代码。我们将仔细看看必要的修改。RAG 应用的完整代码可在 github.com/PacktPublis… 文件夹中找到。如果你不想自定义你的代码,你可以使用我为这个示例提供的现成的 docker 镜像。

首先,我们需要额外的导入:

import os
from botocore.client import Config
from langchain.prompts import PromptTemplate
from langchain.retrievers.bedrock import AmazonKnowledgeBasesRetriever
from langchain.chains import RetrievalQA

这里,我们导入 os 库以获取环境变量。Config 类将帮助构建一个配置对象来访问 bedrock-agent API。所有其他的导入都与访问知识库和将检索到的文档与 AI 响应合并有关。

接下来,我们将从环境变量中获取 Amazon Bedrock 服务的知识库 ID。这可以是一个非常有用的方法。如果将来需要更改知识库,无需重建镜像。我们只需更改环境变量。然后,我们设置一些配置并创建一个 bedrock-agent-runtime API 的客户端(用于知识库):

kb_id = os.getenv("KB_ID")
bedrock_config = Config(connect_timeout=120, read_timeout=120, retries={'max_attempts': 0})
bedrock_agent_client = boto3.client(
    "bedrock-agent-runtime", config=bedrock_config, region_name = "us-east-1"
)

接下来,我们将配置一个提示模板,帮助我们将知识库中检索到的文档和用户问题链接起来。最后,我们实例化一个对象,该对象将持有模板,并接收文档和用户问题作为输入:

PROMPT_TEMPLATE = """
Human: You are a friendly AI assistant and provide answers to questions about AWS competency program for partners.
Use the following pieces of information to provide a concise answer to the question enclosed in <question> tags.
Don't use tags when you generate an answer. Answer in plain text, use bullets or lists if needed.
If you don't know the answer, just say that you don't know, don't try to make up an answer.
<context>
{context}
</context>
<question>
{question}
</question>
The response should be specific and use statistics or numbers when possible.
Assistant:"""
claude_prompt = PromptTemplate(template=PROMPT_TEMPLATE,
                               input_variables=["context","question"])

设置好 choose_model() 函数后,我们需要实例化一个检索类,它将从知识库中拉取文档:

retriever = AmazonKnowledgeBasesRetriever(
        knowledge_base_id=kb_id,
        retrieval_config={
            "vectorSearchConfiguration": {
                "numberOfResults": 4
            }
        },
        client=bedrock_agent_client
    )

现在,在 main 函数中,我们将添加 RetrievalQA。这个类用于构建可以从知识库检索相关信息的问答系统:

qa = RetrievalQA.from_chain_type(
        llm=model,
        chain_type="stuff",
        retriever=retriever,
        return_source_documents=False,
        chain_type_kwargs={"prompt": claude_prompt}
    )

最后,我们将修改响应以给出完整的答案:

with st.chat_message("assistant"):
    response = qa.invoke(prompt)['result']
    st.write(response)

就这样。代码已准备好构建新镜像。您可以通过创建一个新的 Dockerfile 并使用之前的代码来重新构建它。运行 docker build 命令时,记得选择一个不同的镜像名称(或至少是不同的版本)。

接下来,我们将开始部署。.yaml 文件也与上一节中的非常相似(但记得更改部署、服务、容器和标签的所有名称为 rag-with-claude)。这段代码的完整版本可在 GitHub 仓库中找到。我们只需要声明知识库 ID 的环境变量。由于这不是敏感凭证,我们不需要使用 Kubernetes secret。我们将使用 ConfigMap。您的 .yaml 文件的 spec.template.spec.container.env 部分应该如下所示:

env:
  - name: AWS_ACCESS_KEY_ID
    valueFrom:
      secretKeyRef:
        name: aws-credentials
        key: aws_access_key_id
  - name: AWS_SECRET_ACCESS_KEY
    valueFrom:
      secretKeyRef:
        name: aws-credentials
        key: aws_secret_access_key
  - name: KB_ID
    valueFrom:
      configMapKeyRef:
        name: kb-config
        key: kb_id

注意我们添加了一个名为 KB_ID 的新环境变量,它将从 ConfigMap 中导入。

要部署新应用,我们运行以下命令:

kubectl create configmap kb-config --from-literal=kb_id=<YOUR_KB_ID> -n genai

我们先前运行的是创建知识库 ID 的 ConfigMap,然后我们运行:

kubectl apply -f deploy_chat_with_claude.yaml -n genai

我们运行先前的命令来部署应用。等待几分钟让 LoadBalancer 启动并使用以下命令:

kubectl get svc -n genai

使用先前的命令获取 LoadBalancer 的 URL。复制并粘贴名为 rag-with-claude 的服务在浏览器中,并添加 :8501 来连接到暴露的端口。瞧!你应该能看到你的新应用运行,如图 11.9 所示。

image.png

尝试稍微玩一下这个应用程序。你会发现,如果你提出与其范围(AWS 资质计划)无关的问题,助手会说它无法回答。 现在,我们将进入本章的最后一部分,学习如何使用代理让生成式AI模型执行操作。

构建具备操作能力的生成式AI模型

代理是生成式AI领域最新的功能。它们是强大的工具,通过允许生成式AI模型代表我们执行操作来实现任务自动化。代理充当生成式AI模型与外部系统或服务之间的中介,促进现实世界中任务的执行。

在后台,代理“理解”用户的需求并调用执行该操作的后端函数。代理的操作范围由OpenAPI架构定义,该架构既用于“理解”代理的职责范围,也用于正确调用后端函数。

总结来说,构建一个代理我们需要OpenAPI架构、后端函数和知识库。知识库是可选的,但它可以大大提升用户与AI助手的互动体验。

在本节的练习中,我们将构建一个“了解”AWS资质计划相关信息的代理。图11.10展示了该代理应用程序架构的可视化表示。

image.png

这个代理将会创建一个包含用例信息的简单工作表,将其保存到Amazon S3,并在DynamoDB表中注册这些信息以供查询。让我们开始吧:

首先,我们需要一个定义了代理可用方法的OpenAPI架构。在这个案例中,我们将定义两个方法。第一个方法,generateCaseSheet,用于注册用例信息并创建工作表。第二个方法,checkCase,用于根据用例ID返回相关信息。由于这是一个很长的JSON文件,我们这里不展示。完整代码可以在此处找到。复制该代码并将其保存到S3存储桶中。

接下来,我们将定义一个Lambda函数,作为代理的后端。函数的完整Python代码可以在本书的GitHub库Chapter 11/agent/function文件夹中找到。在你的机器上,创建一个名为function的文件夹,并将代码保存为function文件夹中的lambda_function.py。该代码定义了一个Lambda函数,作为Bedrock代理的后端。该函数处理两个不同的API路径:/generateCaseSheet和/checkCase。让我们逐块解析代码。

导入必要的模块后,我们定义了两个辅助函数来从事件对象中提取参数值(get_named_parameter和get_named_property)。generateCaseSheet函数负责根据提供的信息创建新的用例表。它从事件对象中提取所需参数,生成唯一ID,使用CaseTemplate类创建新的Excel工作簿,用提供的参数填充模板,将工作簿保存到临时文件,上传到S3存储桶,并将用例信息存储在DynamoDB表中。最后,它返回包含用例详细信息的响应对象。checkCase函数根据提供的caseSheetId参数从DynamoDB表中检索用例信息,并返回包含用例详细信息的响应对象。lambda_handler函数是Lambda函数的入口点。它根据事件对象中的apiPath值确定适当的操作。函数根据操作构建适当的响应对象并返回。

接下来,在function文件夹内创建一个新文件lambda_requirements.txt,在其中列出Lambda函数代码的依赖项。在lambda_requirements.txt文件中,输入openpyxl==3.0.10并保存。

在部署函数之前,我们需要创建一个IAM角色,赋予Lambda必要的权限。在AWS控制台上,进入IAM页面,选择侧边菜单中的Roles,然后点击Create a new role。

在下一页,选择Trusted entity类型中的AWS service,并在Use case中选择Lambda(如图11.11所示)。点击Next。

image.png

现在,我们将选择一个权限策略。选择“Administrator Access”并点击“Next”。请记住,在生产环境中使用如此开放的权限并不是一个好做法。你应该仅为所需的操作和资源设置权限。

接着,为你的IAM角色选择一个名称(例如,BDOK-Lambda-service-role),然后点击“Create role”。

随后,你会再次看到IAM Roles页面。搜索你创建的角色并点击它(如图11.12所示)。

image.png

在角色页面,你会看到该角色的Amazon Resource Name (ARN)。复制它并保存以备后用。我们需要这个名称来部署Lambda函数。

接下来,在你创建的function文件夹中,创建一个名为worksheet的新文件夹。从此处复制两个文件,第一个名为__init__.py,第二个名为template.py,并将这些代码文件放置在worksheet文件夹中。这些代码包含一个名为CaseTemplate的类,该类使用openpyxl Python库构建Excel工作表。

接下来,从此处复制另外两个文件,分别名为build_lambda_package.sh和create_lambda_function.sh。这些文件包含安装Lambda函数依赖项并将其部署到AWS的bash代码。

现在,我们将部署我们的Lambda函数。这是检查你的项目结构是否正确的好时机。文件夹和文件结构应如下所示:

├── app
│   └── main.py
├── function
│   ├── lambda_function.py
│   ├── lambda_requirements.txt
│   ├── test_event.json
│   └── worksheet
│       ├── __init__.py
│       └── template.py
├── openapi_schema.json
└── scripts
    ├── build_lambda_package.sh
    └── create_lambda_function.sh

如果你的项目结构不同,请更正以获得此确切结构,否则bash代码将无法正常工作。

现在,进入scripts文件夹并运行以下命令:

sh build_lambda_package.sh
sh create_lambda_function.sh "<YOUR_ROLE_ARN>"

记得将<YOUR_ROLE_ARN>替换为你的Lambda IAM角色的实际ARN。现在,我们还有一些工作要做。接下来,我们将创建一个DynamoDB表来存储用例信息。

创建DynamoDB表

DynamoDB是一种完全托管的NoSQL数据库服务。它是一种键值和文档数据库,可以在任何规模下提供毫秒级的性能。DynamoDB针对无服务器应用程序进行了优化,设计上可以根据需求自动扩展或缩减,无需预置或管理服务器。它特别适用于需要在任何规模下对数据进行低延迟读写访问的应用程序。其极低的延迟使其成为AI助手应用程序的一个非常好的选择。让我们开始吧:

在AWS控制台,导航到DynamoDB页面。在侧边菜单中,点击“Tables”,然后点击“Create table”。

在下一个页面中,在“Table name”字段中填写“case-sheets”,在“Partition key”字段中填写“caseSheetId”。记得选择“Number”以表示该条目是一个数字,如图11.13所示。将其他所有配置保持默认,然后点击“Create table”。

image.png

几秒钟后,你的DynamoDB表应该就准备好使用了。现在,我们将配置Bedrock代理。

配置代理

在本节的最后部分,我们将配置一个Bedrock代理,并将其链接到后端Lambda函数和知识库数据库。让我们开始吧:

首先,在AWS控制台中,搜索Bedrock,然后在侧边菜单中点击“Agents”。

在弹出框中,输入你的代理名称(例如aws-competency-agent),然后点击“Create”。

接下来,你会看到代理配置页面。向下滚动到“Select model”部分,选择Anthropic模型Claude 3 Haiku(你也可以根据需要试用其他可用模型)。

在“Instructions for the agent”字段中,设置初始指令,以指导基础模型的行为。你可以输入,例如:

You are a friendly AI assistant. Your main goal is to help AWS partner companies build case sheets for the AWS Competency program, register those cases, and tell the user the information about the registered cases. When you generate a case sheet, always show back to the user the ID of the case sheet (id), the client's name (client), and the name of the case (casename) and confirm that the case was successfully created. Also, answer the questions of the user about what you can do and how you can help. This is a very important part of the agent configuration. Play with these instructions as much as you like.

该屏幕的示例如图11.14所示。

image.png

之后,点击页面顶部的“Save”按钮,以便AWS创建必要的权限策略。

接着,向下滚动到“Action groups”部分,并点击“Add”。

在下一个页面,为你的操作组选择一个名称。在“Action group type”中,选择“Define with API schemas”。在“Action group invocation”中,选择“Select an existing Lambda function”,并选择我们刚刚创建的Lambda函数(如图11.15所示)。

image.png

现在,在“Action group schema”部分,选择“Select an existing API schema”,然后点击“Browse S3”搜索我们保存在S3上的OpenAPI架构(如图11.16所示)。然后,点击“Create”。

image.png

接下来,在“Knowledge base”部分,点击“Add”。

选择我们之前创建的知识库,并为代理输入一些使用说明。例如:

This knowledge base contains information on the following AWS Competency programs: conversational AI, data and analytics, DevOps, education, energy, financial services, machine learning, and security.

确保“Knowledge base status”设置为“Enabled”(如图11.17所示)。点击“Save and exit”。

image.png

现在,你回到代理的编辑页面。这里不需要再进行其他操作,所以你可以点击顶部的“Prepare”按钮,让你的代理准备运行,然后点击“Save and exit”。

现在,你会被带回到代理的主页面。向下滚动到“Aliases”部分并点击“Create”。

输入一个别名名称(例如aws-competency),然后点击“Create Alias”。

image.png

现在,最后一件事是为代理在Lambda上注册权限,以触发函数执行。在代理的主页面,复制代理的ARN。

接着,转到Lambda页面,点击我们为此练习创建的函数。在函数的主页面,向下滚动,点击“Configuration”,然后在侧边菜单中点击“Permissions”(如图11.19所示)。

image.png

再次向下滚动到“Resource-based policy statements”部分,点击“Add permissions”。

在下一页中,填写“Statement ID”框。在“Principal”字段中,粘贴从Bedrock代理复制的代理ARN。在“Action”字段中,选择“lambda”(如图11.20所示)。然后,点击“Save”。

image.png

这就是我们让代理运行所需的全部配置。现在,是时候进行部署了。让我们将我们的Streamlit应用程序部署到Kubernetes上。

在Kubernetes上部署应用程序

将代理Streamlit应用程序部署到Kubernetes的过程与之前部署的其他两个应用程序相同。唯一不同的是我们必须创建一个包含代理ID及其别名ID的新配置映射(configmap):

  1. 转到AWS控制台中的代理页面,复制代理的ID(在顶部部分)和别名ID(在底部部分)。

  2. 现在,使用以下命令创建包含这些参数的configmap:

    kubectl create configmap agent-config --from-literal=agent_alias_id=<YOUR_ALIAS_ID> --from-literal=agent_id=<YOUR_AGENT_ID> -n genai
    

    请记得将<YOUR_ALIAS_ID>和<YOUR_AGENT_ID>占位符替换为实际值。

  3. 如果你想自定义应用程序,可以构建自定义镜像。如果不需要,可以使用DockerHub上的现成镜像(链接)。

  4. 接下来,我们将为应用程序和服务部署定义一个deploy_agent.yaml文件。该文件的内容可在此处找到。

  5. 将该文件复制到本地,然后运行以下命令:

    kubectl apply -f deploy_agent.yaml -n genai
    
  6. 等待几秒钟以启动LoadBalancer。然后,运行以下命令获取LoadBalancer的URL:

    kubectl get svc -n genai
    
  7. 将URL粘贴到浏览器中,并添加正确的端口(:8501)以查看应用程序的运行效果(如图11.21所示)。

image.png

尝试输入一个创建新用例的提示,如图11.18所示。此外,你还可以通过传递用例的ID来检查该用例的具体信息(如图11.22所示)。

image.png

多玩一下,提出有关资质计划的问题,并尝试注册不同的用例。你还可以检查AWS DynamoDB,查看我们创建的表中输入的信息,并检查S3以查看代理创建的Excel文件。

就是这样!恭喜你!你刚刚部署了一个完整的生成式AI代理应用程序,该应用程序可以在Kubernetes上使用自然语言为你执行任务。

总结

在本章中,我们探索了生成式AI的精彩世界,并学习了如何在Kubernetes上利用其强大功能。我们首先了解了生成式AI的基本概念,其基本机制,以及它与传统机器学习方法的区别。

然后,我们利用Amazon Bedrock这一全面的服务套件来构建和部署生成式AI应用程序。我们学习了如何使用Bedrock的基础模型,如Claude 3 Haiku和Claude 3 Sonnet,并将它们集成到Streamlit应用程序中,以实现交互式用户体验。

接下来,我们深入研究了RAG的概念,它结合了生成式AI和外部知识库的力量。我们使用Amazon Bedrock的知识库构建了一个RAG系统,使我们的应用程序能够访问并利用大量结构化数据,从而提高生成输出的准确性和相关性。

最后,我们探索了Amazon Bedrock的代理功能,这是一项强大的功能,允许生成式AI模型自动化任务并代表我们采取行动。我们学习了如何构建代理,通过OpenAPI架构定义其能力,并创建作为代理后端的Lambda函数。

在本章中,我们通过实际操作获得了在Kubernetes上构建和部署生成式AI应用程序的经验。在当今快速发展的技术环境中,掌握这些技能和知识是无价的。生成式AI正在改变各行各业,并彻底改变我们与AI的互动和利用方式。通过掌握本章介绍的工具和技术,你将能够构建创新和智能的应用程序,这些应用程序可以生成类似人类的内容,利用外部知识源并自动化任务。

在下一章中,我们将讨论生产就绪的Kubernetes环境所需的一些重要点,这些内容在整本书中未能详细讨论。