使用亚马逊 Bedrock 进行跨区域推理入门

通过亚马逊 Bedrock 的推理配置文件,我们可以以完全托管、安全和私密的方式进行跨区域推理,无需进行任何设置。推理配置文件是构建在亚马逊 Bedrock 之上的托管功能,为生成式 AI 应用程序构建者提供了一个无缝的解决方案,用于管理流量高峰并确保最佳可用性和性能。通过利用这一功能,构建者不再需要花费时间和精力来构建复杂的弹性结构。相反,推理配置文件会智能地将流量路由到多个选定的区域,自动适应峰值使用率激增。通过推理配置文件进行的任何推理都将动态利用任何配置区域中可用的按需容量,最大化可用性和吞吐量。

主要功能和优势

主要功能包括:

  • 可以访问不同区域的容量,允许生成式 AI 工作负载根据需求进行扩展。
  • 可以访问独立于区域的模型,以实现更高的吞吐量。
  • 能够抵御任何流量高峰。
  • 能够选择适合应用程序需求的预定义区域集。
  • 与现有 API 兼容。
  • 无额外费用。
  • 与源区域相同的模型定价。

最终用户体验不受影响,因为跨区域推理背后的模型保持不变,构建者可以专注于编写差异化应用程序的逻辑。

Bedrock 是构建和扩展生成式 AI 应用程序的最简单方法。跨区域推理进一步增强了可用性。

# 首先安装依赖项,确保我们有最新版本
#!pip install --quiet --upgrade --force-reinstall boto3 botocore awscli

辅助方法

  1. 允许假设角色功能(如果需要)
  2. 利用为 boto3 客户端设置的配置文件
import warnings

from io import StringIO
import sys
import textwrap
import os
from typing import Optional

# 外部依赖项:
import boto3
from botocore.config import Config

warnings.filterwarnings('ignore')

def print_ww(*args, width: int = 100, **kwargs):
    """像 print()一样,但将输出包装到 `width` 个字符(默认 100)"""
    buffer = StringIO()
    try:
        _stdout = sys.stdout
        sys.stdout = buffer
        print(*args, **kwargs)
        output = buffer.getvalue()
    finally:
        sys.stdout = _stdout
    for line in output.splitlines():
        print("\n".join(textwrap.wrap(line, width=width)))
        



def get_boto_client(
    assumed_role: Optional[str] = None,
    region: Optional[str] = None,
    runtime: Optional[bool] = True,
    service_name: Optional[str] = None,
):
    """为亚马逊 Bedrock 创建一个 boto3 客户端,并可选择配置覆盖

    参数
    ----------
    assumed_role :
        可选的 AWS IAM 角色 ARN,用于调用 Bedrock 服务。如果未指定,将使用当前活动的凭证。
    region :
        可选的 AWS 区域名称,服务应在其中调用(例如"us-east-1")。
        如果未指定,将使用 AWS_REGION 或 AWS_DEFAULT_REGION 环境变量。
    runtime :
        可选择获取不同的客户端来执行与亚马逊 Bedrock 服务相关的操作。
    """
    if region is None:
        target_region = os.environ.get("AWS_REGION", os.environ.get("AWS_DEFAULT_REGION"))
    else:
        target_region = region

    print(f"Create new client\n  Using region: {target_region}")
    session_kwargs = {"region_name": target_region}
    client_kwargs = {**session_kwargs}

    profile_name = os.environ.get("AWS_PROFILE")
    if profile_name:
        print(f"  Using profile: {profile_name}")
        session_kwargs["profile_name"] = profile_name

    retry_config = Config(
        region_name=target_region,
        retries={
            "max_attempts": 10,
            "mode": "standard",
        },
    )
    session = boto3.Session(**session_kwargs)

    if assumed_role:
        print(f"  Using role: {assumed_role}", end='')
        sts = session.client("sts")
        response = sts.assume_role(
            RoleArn=str(assumed_role),
            RoleSessionName="langchain-llm-1"
        )
        print(" ... successful!")
        client_kwargs["aws_access_key_id"] = response["Credentials"]["AccessKeyId"]
        client_kwargs["aws_secret_access_key"] = response["Credentials"]["SecretAccessKey"]
        client_kwargs["aws_session_token"] = response["Credentials"]["SessionToken"]

    if not service_name:
        if runtime:
            service_name='bedrock-runtime'
        else:
            service_name='bedrock'

    bedrock_client = session.client(
        service_name=service_name,
        config=retry_config,
        **client_kwargs
    )

    print("boto3 Bedrock client successfully created!")
    print(bedrock_client._endpoint)
    return bedrock_client
import boto3
print(boto3.__version__)

os.environ["AWS_PROFILE"] = '<replace with your profile>'
boto3_client =  get_boto_client(region='us-east-1', runtime=False) # 切换到我们选择的区域
boto3_client.list_foundation_models()

🔴 重要❗🔴

注意: 此 notebook 示例使用 us-east-1 区域和该区域中可用的推理配置文件作为示例。 根据我们所在的区域以及该区域中可用的推理配置文件,更改下面单元格中的 region_name 和推理配置文件 ID。

# 确保我们已设置 AWS 凭证或 AWS 配置文件,然后再运行此单元格

#boto3_client =  get_bedrock_client(region='us-east-1', runtime=False)

region_name = 'us-east-1' # 切换到我们选择的区域
account_id = get_boto_client(service_name='sts', region=region_name).get_caller_identity().get('Account')
bedrock_client = get_boto_client(service_name='bedrock', region=region_name)
bedrock_runtime = get_boto_client(service_name='bedrock-runtime', region=region_name)

print(account_id, bedrock_client, bedrock_client)

了解推理配置文件

跨区域推理功能附带了 Bedrock 客户端 SDK 中的两个额外 API:

  • list_inference_profiles() -> 此 API 告诉我们所有配置在推理配置文件后面的模型。
  • get_inference_profile(inferenceProfileIdentifier) -> 此 API 提供有关某个推理配置文件的特定详细信息。
bedrock_client.list_inference_profiles()['inferenceProfileSummaries']

需要注意的是,跨区域推理提供两种形式:

源区域中的基础模型

在此模式下,推理配置文件仅配置了存在于源区域的模型。对于此类模型,将存在一个故障转移机制,允许请求被重新路由到推理配置文件中配置的履行区域。默认情况下,请求将转到源区域资源,只有当该区域繁忙或我们达到配额限制时,请求才会路由到另一个区域。为了确定请求应该转到哪个区域,亚马逊 Bedrock 会实时检查哪个区域有冗余容量可用。按需原则仍然适用,如果没有任何区域有能力处理请求,则会被限制。

在此模式下,如果源区域没有某个特定的模型可用,我们将无法通过跨区域推理功能访问该模型。

通过推理配置文件提供

选定的一些模型通过跨区域推理提供,在这种情况下,亚马逊 Bedrock 抽象掉区域细节并自动管理托管和推理路由。这些基础模型然后存在于预定义的区域集中,构建者可以构建与区域设置无关的应用程序。这允许可靠的吞吐量、访问领先的基础模型以及吞吐量方面的可扩展性。

bedrock_client.get_inference_profile(
    inferenceProfileIdentifier='us.anthropic.claude-3-5-sonnet-20240620-v1:0'
)

使用 get_inference_profile API,我们可以观察推理配置文件的 status 是否为 ACTIVE,以及为推理路由配置了哪些区域。

使用推理配置文件

推理配置文件的使用方式与使用基础模型相同,使用模型的 modelIdarn。推理配置文件也有自己的 id 和 arn,不同之处在于前缀。对于推理配置文件,我们可以期望在模型 id 后面看到区域前缀,如 us.eu.。在 arn 中,我们可以看到从 :<region>::foundation-model/<model-id>:<region>::inference-profile/<region-set-prefix>.<model-id> 的区别。

我们可以将 arnmodelIdConverse API 一起使用,而只能使用 modelIdInvokeModel API。

Converse API

亚马逊 Bedrock 现在支持统一的消息传递 API,提供无缝的应用程序构建体验。在此处 阅读有关通过此 API 支持的所有模型的信息。

让我们向基础模型和推理配置文件发送一个请求,以观察变化。

from time import time
system_prompt = "You are an expert on AWS services and always provide correct and concise answers."
input_message = "Should I be storing documents in Amazon S3 or EFS for cost effective applications?"
modelId = ('Foundation Model', 'anthropic.claude-3-haiku-20240307-v1:0')
inferenceProfileId = ('Inference Profile', 'us.anthropic.claude-3-haiku-20240307-v1:0')

for inference_type, id in [modelId, inferenceProfileId]:
    start = time()
    response = bedrock_runtime.converse(
        modelId=id,
        system=[{"text": system_prompt}],
        messages=[{
            "role": "user",
            "content": [{"text": input_message}]
        }]
    )
    end = time()
    print(f"::{inference_type}::Response time: {int(end-start)} second(s)")
    print(f"::model:id:{id}::Response time: {int(end-start)} second(s)")
    print(f"::{inference_type}::Response output: {response['output']['message']['content']}")

我们可以观察到,使用相同的 API 并仅更改模型 ID,我们可以期望类似的行为。

也可以使用完整的 ARN 代替模型 ID:

inference_profile_id = "us.anthropic.claude-3-sonnet-20240229-v1:0"
inference_profile_arn = f"arn:aws:bedrock:{region_name}:{account_id}:inference-profile/{inference_profile_id}"
print(inference_profile_arn)

response = bedrock_runtime.converse(
    modelId=inference_profile_arn,
    system=[{"text": system_prompt}],
    messages=[{
        "role": "user",
        "content": [{"text": input_message}]
    }]
)
print(response['output']['message']['content'][0]['text'])

InvokeModel API

大多数生成式 AI 应用程序在生产中都是基于 InvokeModel API 构建的,即使是第三方工具也使用此 API 来使用模型。跨区域推理功能也与此 API 兼容。Converse API 只支持选定的模型,而 InvokeModel API 可以利用亚马逊 Bedrock 中可用的所有模型。

让我们通过基础模型 id 和推理配置文件 id 发送一个请求,以观察通过此 API 的变化。

import json
body = json.dumps({
    "anthropic_version": "bedrock-2023-05-31",
    "max_tokens": 1024,
    "temperature": 0.1,
    "top_p": 0.9,
    "system": system_prompt,
    "messages": [
        {
            "role": "user",
            "content": [
                {
                    "type": "text",
                    "text": f"{input_message}",
                }
            ]
        }
    ]
})
accept = 'application/json'
contentType = 'application/json'
modelId = ('Foundation Model', 'anthropic.claude-3-sonnet-20240229-v1:0')
inferenceProfileId = ('Inference Profile', 'us.anthropic.claude-3-sonnet-20240229-v1:0')
for inference_type, id in [modelId, inferenceProfileId]:
    start = time()
    response = bedrock_runtime.invoke_model(body=body, modelId=id, accept=accept, contentType=contentType)
    end = time()
    response_body = json.loads(response.get('body').read())
    print(f"::{inference_type}::Response time: {int(end-start)} second(s)")
    print(f"::{inference_type}::Response output: {response_body['content'][0]['text']}")

LangChain

以下是如何将新的跨区域推理功能与流行的开源框架 [LangChain](https://python.langchain.com/v