在此文件夹中,我们提供了一个示例,用于创建一个与 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_balance
、book_appointment
的功能。操作组执行连接到 Lambda 函数。此代理没有实现任何真正的功能,并且在 Lambda 函数中使用的函数返回硬编码值。对于真实的应用程序,我们应该实现 check_balance
和 book_appointment
函数,以连接到可用的数据库。
第一步是安装先决条件包
!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
"""
让我们从创建 Amazon Bedrock 知识库
开始,以存储餐厅菜单。知识库允许我们与不同的矢量数据库集成,包括 Amazon OpenSearch Serverless
、Amazon Aurora
和 Pinecone
。对于此示例,我们将与 Amazon OpenSearch Serverless 集成知识库。为此,我们将使用助手类 BedrockKnowledgeBase
,它将创建知识库及其所有先决条件:
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
)
现在我们已经创建了知识库,让我们用菜单数据集填充它。知识库数据源希望数据可用于与之连接的 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)
现在知识库可用,我们可以使用 <strong>retrieve</strong> 和 <strong>retrieve_and_generate</strong> 函数对其进行测试。
让我们首先使用 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 检索最匹配我们查询的块。在此设置中,我们可以配置所需的结果数量,并使用我们自己的应用程序逻辑控制最终答案。该 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)
在本节中,我们将介绍创建带有 Guardrail 的 Amazon Bedrock 代理的所有步骤。
这些是要完成的步骤:
现在让我们也创建 lambda 角色及其所需的策略。对于这种情况,我们需要 lambda 能够访问 DynamoDB,这就是为什么我们还创建了一个 DynamoDB 策略并将其附加到我们的 Lambda 上。为此,我们将使用支持函数 create_lambda_role
。
现在我们有了 Lambda 函数代码及其执行角色,让我们将其打包到一个 Zip 文件中并创建 Lambda 资源
现在我们已经创建了知识库和用于执行代理任务的 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)
我们现在将创建一个使用前面创建的 lambda 函数的代理操作组。 [create_agent_action_group
](https://boto3.amazonaws.com/v1/documentation/api/latest/reference/services/bedrock-agent