创建与 Amazon Bedrock Guardrails 集成的代理

在此文件夹中,我们提供了一个示例,用于创建一个与 Amazon Bedrock 和 Amazon Bedrock Guardrails 集成的代理,以及与 Amazon Bedrock Knowledge Base 和操作组的集成。

通过此集成,代理将能够通过采取一系列操作来响应用户查询,咨询知识库以获取更多信息,和/或使用与操作组连接的 Lambda 函数执行任务。对于每次交互,Amazon Bedrock 的 Guardrail 都为应用程序提供了额外的安全层,验证用户输入和代理输出是否符合 Guardrail 中定义的主题拒绝,并阻止必要的请求。

用例

在此示例中,我们将创建一个银行助理代理,允许用户:

  • 查看账户余额,
  • 预约新的银行约见,
  • 回答一般问题

此助理不会向用户提供投资建议,为了更好地验证此要求,我们在应用程序中添加了拒绝投资建议主题的 Guardrail。

“CustomerSupportActionGroup"操作组提供了检查账户余额和预约预订的功能,而 Amazon Bedrock 的知识库为 OpenSearch Serverless 矢量数据库编制了包含常见问题的文档索引。

对于此用例,我们将使用一个假设的场景,即意外地将一些投资建议数据添加到了知识库中编制的常见问题文档中。

作为银行,我们的代理不应该提供任何投资建议,因此定义了一个 Guardrail 来阻止投资建议主题。它的定义如下:

response = bedrock_client.create_guardrail(
    name='BankingAssistantGuardrail',
    description='Guardrail for online banking assistant to help users with banking and account related questions',
    topicPolicyConfig={
        'topicsConfig': [
            {
                'name': 'Investment Advice',
                'definition': 'Investment advice refers to professional guidance or recommendations provided to individuals or entities regarding the management and allocation of their financial assets.',
                'examples': [
                    'Should I buy gold?',
                    'Is investing in stocks better than bonds?',
                    'When is it a good idea to invest in gold?',
                ],
                'type': 'DENY'
            },
        ]
    },
    blockedInputMessaging='Sorry, your query violates our usage policies. We do not provide investment advices. To discuss the best investment advice for your current situation, please contact us on (XXX) XXX-XXXX and we will be happy to support you.',
    blockedOutputsMessaging='Sorry, I am unable to reply. Please contact us on (XXX) XXX-XXXX and we will be happy to support you.',
)

代理架构


在此示例中创建的操作组使用 function details 来定义 check_balancebook_appointment 的功能。操作组执行连接到 Lambda 函数。此代理没有实现任何真正的功能,并且在 Lambda 函数中使用的函数返回硬编码值。对于真实的应用程序,我们应该实现 check_balancebook_appointment 函数,以连接到可用的数据库。

1. 导入所需的库

第一步是安装先决条件包

!pip install --upgrade -q -r requirements.txt
import os
import time
import boto3
import logging
import pprint
import json

from knowledge_base import KnowledgeBasesForAmazonBedrock
from agent import AgentsForAmazonBedrock
#Clients
s3_client = boto3.client('s3')
sts_client = boto3.client('sts')
session = boto3.session.Session()
region = session.region_name
account_id = sts_client.get_caller_identity()["Account"]
bedrock_agent_client = boto3.client('bedrock-agent')
bedrock_agent_runtime_client = boto3.client('bedrock-agent-runtime')
bedrock_client = boto3.client('bedrock')
logging.basicConfig(format='[%(asctime)s] p%(process)s {%(filename)s:%(lineno)d} %(levelname)s - %(message)s', level=logging.INFO)
logger = logging.getLogger(__name__)
region, account_id
suffix = f"{region}-{account_id}"
agent_name = 'banking-assistant1q11'
knowledge_base_name = f'{agent_name}-kb'
knowledge_base_description = "Knowledge Base that provides FAQ documentation for the banking assistant agent"
agent_alias_name = "banking-agent-alias"
bucket_name = f'{agent_name}-{suffix}'
agent_bedrock_allow_policy_name = f"{agent_name}-ba"
agent_role_name = f'AmazonBedrockExecutionRoleForAgents_{agent_name}'
agent_foundation_model = "anthropic.claude-3-sonnet-20240229-v1:0"

agent_description = "Online Banking assistant agents"
agent_instruction = """
You are an agent designed to assist customers from the ANY_BANK Corporation with online banking queries. 
You ALWAYS reply politely and concise using ONLY the available information in the ba_kb knowledge base or the data retrieved via the banking-assistant action group.

You also add the name ANY_BANK Corporation to your first answer in a session. You should start with an acknowledgement of the customer's query and thanking the customer for contacting you.

Introduce yourself as the "ANY_BANK Corporation AI Assistant".

NEVER provide account balances or book appointments without first confirming the customer's user_id
"""

2. 创建 Amazon Bedrock 知识库

让我们从创建 Amazon Bedrock 知识库 开始,以存储餐厅菜单。知识库允许我们与不同的矢量数据库集成,包括 Amazon OpenSearch ServerlessAmazon AuroraPinecone 。对于此示例,我们将与 Amazon OpenSearch Serverless 集成知识库。为此,我们将使用助手类 BedrockKnowledgeBase,它将创建知识库及其所有先决条件:

  1. IAM 角色和策略
  2. S3 存储桶
  3. Amazon OpenSearch Serverless 加密、网络和数据访问策略
  4. Amazon OpenSearch Serverless 集合
  5. Amazon OpenSearch Serverless 矢量索引
  6. 知识库
  7. 知识库数据源
knowledge_base = KnowledgeBasesForAmazonBedrock()
kb_id, ds_id = knowledge_base.create_or_retrieve_knowledge_base(
    knowledge_base_name, knowledge_base_description, data_bucket_name=bucket_name
)

3. 将数据集上传到 Amazon S3

现在我们已经创建了知识库,让我们用菜单数据集填充它。知识库数据源希望数据可用于与之连接的 S3 存储桶,并且可以使用 StartIngestionJob API 调用将对数据的更改同步到知识库。在此示例中,我们将使用 boto3 抽象 来调用 API,通过我们的助手类。

让我们首先将 dataset 文件夹中可用的菜单数据上传到 s3

def upload_directory(path, bucket_name):
        for root,dirs,files in os.walk(path):
            for file in files:
                file_to_upload = os.path.join(root,file)
                print(f"uploading file {file_to_upload} to {bucket_name}")
                s3_client.upload_file(file_to_upload,bucket_name,file)

upload_directory("dataset", bucket_name)

现在我们启动摄取作业

# ensure that the kb is available
time.sleep(30)
# sync knowledge base
knowledge_base.synchronize_data(kb_id, ds_id)

3.1 测试知识库

现在知识库可用,我们可以使用 <strong>retrieve</strong><strong>retrieve_and_generate</strong> 函数对其进行测试。

使用 Retrieve 和 Generate API 测试知识库

让我们首先使用 retrieve 和 generate API 测试知识库。使用此 API,Bedrock 负责从知识库中检索必要的引用,并使用 Bedrock 的 LLM 模型生成最终答案

time.sleep(30)

response = bedrock_agent_runtime_client.retrieve_and_generate(
    input={
        "text": "Should I invest in bitcoin"
    },
    retrieveAndGenerateConfiguration={
        "type": "KNOWLEDGE_BASE",
        "knowledgeBaseConfiguration": {
            'knowledgeBaseId': kb_id,
            "modelArn": "arn:aws:bedrock:{}::foundation-model/{}".format(region, agent_foundation_model),
            "retrievalConfiguration": {
                "vectorSearchConfiguration": {
                    "numberOfResults":1
                } 
            }
        }
    }
)

print(response['output']['text'],end='\n'*2)

如我们所见,使用 retrieve 和 generate API,我们直接获得了最终响应,我们没有看到用于生成此响应的不同来源。现在让我们使用 retrieve API 从知识库中检索源信息。

使用 Retrieve API 测试知识库

如果我们需要额外的控制层,我们可以使用 retrieve API 检索最匹配我们查询的块。在此设置中,我们可以配置所需的结果数量,并使用我们自己的应用程序逻辑控制最终答案。该 API 然后提供我们与内容匹配的内容、其 S3 位置、相似度分数和块元数据

response_ret = bedrock_agent_runtime_client.retrieve(
    knowledgeBaseId=kb_id, 
    nextToken='string',
    retrievalConfiguration={
        "vectorSearchConfiguration": {
            "numberOfResults":5,
        } 
    },
    retrievalQuery={
        'text': 'What is my account value?'
    }
)

def response_print(retrieve_resp):
#structure 'retrievalResults': list of contents. Each list has content, location, score, metadata
    for num,chunk in enumerate(response_ret['retrievalResults'],1):
        print(f'Chunk {num}: ',chunk['content']['text'],end='\n'*2)
        print(f'Chunk {num} Location: ',chunk['location'],end='\n'*2)
        print(f'Chunk {num} Score: ',chunk['score'],end='\n'*2)
        print(f'Chunk {num} Metadata: ',chunk['metadata'],end='\n'*2)

response_print(response_ret)

4. 创建 Amazon Bedrock 代理

在本节中,我们将介绍创建带有 Guardrail 的 Amazon Bedrock 代理的所有步骤。

这些是要完成的步骤:

  1. 创建代理
  2. 创建代理操作组
    1. 创建 AWS Lambda 函数
    2. 允许代理调用操作组 Lambda
  3. 将知识库与代理关联
    1. 准备没有 Guardrail 的代理
    2. 测试没有 Guardrail 的代理

创建所需的权限

现在让我们也创建 lambda 角色及其所需的策略。对于这种情况,我们需要 lambda 能够访问 DynamoDB,这就是为什么我们还创建了一个 DynamoDB 策略并将其附加到我们的 Lambda 上。为此,我们将使用支持函数 create_lambda_role

创建函数

现在我们有了 Lambda 函数代码及其执行角色,让我们将其打包到一个 Zip 文件中并创建 Lambda 资源

4.1 - 创建代理

现在我们已经创建了知识库和用于执行代理任务的 Lambda 函数,让我们开始创建我们的代理。

首先需要创建允许 bedrock 模型调用和知识库查询的代理策略,以及与代理关联的 IAM 角色。我们将允许此代理调用 Claude Sonnet 模型。然后我们需要实际创建代理,同时使用 (https://boto3.amazonaws.com/v1/documentation/api/latest/reference/services/bedrock-agent/client/create_agent.html) boto3 API 将该角色与代理关联。它需要一个代理名称、基础模型和指令。我们还可以提供代理描述。

这里我们使用 agent.py 中的 [create_agent] 函数来创建 IAM 角色和代理本身

请注意,创建的代理尚未准备就绪。我们将重点关注准备代理,然后使用它来调用操作并使用其他 API

kb_arn =  f"arn:aws:bedrock:{region}:{account_id}:knowledge-base/{kb_id}"
agents = AgentsForAmazonBedrock()
agent_id = agents.create_agent(agent_name, agent_description, agent_instruction, [agent_foundation_model], kb_arns=[kb_arn])
print(agent_id)

4.2 创建代理操作组

我们现在将创建一个使用前面创建的 lambda 函数的代理操作组。 [create_agent_action_group](https://boto3.amazonaws.com/v1/documentation/api/latest/reference/services/bedrock-agent