Nota
O acesso a esta página requer autorização. Pode tentar iniciar sessão ou alterar os diretórios.
O acesso a esta página requer autorização. Pode tentar alterar os diretórios.
APLICA-SE A: Todas as camadas de gerenciamento de API
Neste artigo, você importa uma API de modelo de linguagem do Amazon Bedrock para sua instância de gerenciamento de API como uma API de passagem. Este é um exemplo de um modelo hospedado em um provedor de inferência diferente dos serviços de IA do Azure. Use políticas de gateway de IA e outros recursos no Gerenciamento de API para simplificar a integração, melhorar a observabilidade e aprimorar o controle sobre os pontos de extremidade do modelo.
Saiba mais sobre como gerenciar APIs de IA no Gerenciamento de API:
Saiba mais sobre o Amazon Bedrock:
Pré-requisitos
- Uma instância de gerenciamento de API existente. Crie um, caso ainda não o tenha feito.
- Uma conta da Amazon Web Services (AWS) com acesso ao Amazon Bedrock e acesso a um ou mais modelos de fundação do Amazon Bedrock. Mais informações
Criar chaves de acesso de usuário do IAM
Para autenticar sua instância de gerenciamento de API no Amazon API Gateway, você precisa de chaves de acesso para um usuário do AWS IAM.
Para gerar o ID da chave de acesso e a chave secreta necessários usando o Console de Gerenciamento da AWS, consulte Criar uma chave de acesso para você mesmo na documentação da AWS.
Guarde as suas chaves de acesso num local seguro. Você os armazenará como valores nomeados na próxima etapa.
Atenção
As chaves de acesso são credenciais de longo prazo, e você deve gerenciá-las com a mesma segurança com que faria com uma senha. Saiba mais sobre como proteger chaves de acesso
Armazenar chaves de acesso de usuário do IAM como valores nomeados
Armazene com segurança as duas chaves de acesso de usuário do IAM como valores nomeados secretos em sua instância de Gerenciamento de API do Azure usando a configuração recomendada na tabela a seguir.
Segredo da AWS | Nome | Valor secreto |
---|---|---|
Chave de acesso | chave de acesso | ID da chave de acesso recuperado da AWS |
Chave de acesso secreta | chave secreta | Chave de acesso secreta recuperada da AWS |
Importar uma API Bedrock usando o portal
Para importar uma API do Amazon Bedrock para o Gerenciamento de API:
No portal do Azure, navegue até sua instância de Gerenciamento de API.
No menu à esquerda, em APIs, selecione APIs>+ Add API.
Em Definir uma nova API, selecione Language Model API.
Na aba Configurar API:
Insira um Nome para exibição e uma Descrição opcional para a API.
Insira o seguinte URL para o endpoint padrão do Amazon Bedrock:
https://bedrock-runtime.<aws-region>.amazonaws.com
.Exemplo:
https://bedrock-runtime.us-east-1.amazonaws.com
Opcionalmente, selecione um ou mais Produtos para associar à API.
Em Caminho, acrescente um caminho que sua instância de Gerenciamento de API usa para acessar os pontos de extremidade da API LLM.
Em Tipo, selecione Criar uma API de passagem.
Deixe os valores na chave de acesso em branco.
Nas guias restantes, opcionalmente, configure políticas para gerenciar o consumo de tokens, cache semântico e segurança de conteúdo de IA. Para obter detalhes, consulte Importar uma API de modelo de idioma.
Selecione Revisão.
Depois que as configurações forem validadas, selecione Criar.
O Gerenciamento de API cria a API e (opcionalmente) políticas para ajudá-lo a monitorar e gerenciar a API.
Configurar políticas para autenticar solicitações para a API do Amazon Bedrock
Configure políticas de gestão de API para autenticar solicitações à API Amazon Bedrock. Saiba mais sobre como assinar solicitações de API da AWS
O exemplo a seguir usa os valores nomeados accesskey e secretkey que você criou anteriormente para a chave de acesso da AWS e a chave secreta. Defina a region
variável com o valor apropriado para sua API do Amazon Bedrock. O exemplo usa us-east-1
para a região.
No portal do Azure, navegue até sua instância de Gerenciamento de API.
No menu à esquerda, em APIs, selecione APIs.
Selecione a API que você criou na seção anterior.
No menu à esquerda, em Design, selecione Todas as operações.
Selecione a guia Processamento de entrada .
No editor de políticas de processamento de entrada , selecione </> para abrir o editor de políticas.
Configure as seguintes políticas:
<policies> <inbound> <base /> <set-variable name="now" value="@(DateTime.UtcNow)" /> <set-header name="X-Amz-Date" exists-action="override"> <value>@(((DateTime)context.Variables["now"]).ToString("yyyyMMddTHHmmssZ"))</value> </set-header> <set-header name="X-Amz-Content-Sha256" exists-action="override"> <value>@{ var body = context.Request.Body.As<string>(preserveContent: true); using (var sha256 = System.Security.Cryptography.SHA256.Create()) { var hash = sha256.ComputeHash(System.Text.Encoding.UTF8.GetBytes(body)); return BitConverter.ToString(hash).Replace("-", "").ToLowerInvariant(); } }</value> </set-header> <set-header name="Authorization" exists-action="override"> <value>@{ var accessKey = "{{accesskey}}"; var secretKey = "{{secretkey}}"; var region = "us-east-1"; var service = "bedrock"; var method = context.Request.Method; var uri = context.Request.Url; var host = uri.Host; // Create canonical path var path = uri.Path; var modelSplit = path.Split(new[] { "model/" }, 2, StringSplitOptions.None); var afterModel = modelSplit.Length > 1 ? modelSplit[1] : ""; var parts = afterModel.Split(new[] { '/' }, 2); var model = System.Uri.EscapeDataString(parts[0]); var remainder = parts.Length > 1 ? parts[1] : ""; var canonicalPath = $"/model/{model}/{remainder}"; var amzDate = ((DateTime)context.Variables["now"]).ToString("yyyyMMddTHHmmssZ"); var dateStamp = ((DateTime)context.Variables["now"]).ToString("yyyyMMdd"); // Hash the payload var body = context.Request.Body.As<string>(preserveContent: true); string hashedPayload; using (var sha256 = System.Security.Cryptography.SHA256.Create()) { var hash = sha256.ComputeHash(System.Text.Encoding.UTF8.GetBytes(body)); hashedPayload = BitConverter.ToString(hash).Replace("-", "").ToLowerInvariant(); } // Create canonical query string var queryDict = context.Request.Url.Query; var canonicalQueryString = ""; if (queryDict != null && queryDict.Count > 0) { var encodedParams = new List<string>(); foreach (var kvp in queryDict) { var encodedKey = System.Uri.EscapeDataString(kvp.Key); var encodedValue = System.Uri.EscapeDataString(kvp.Value.First() ?? ""); encodedParams.Add($"{encodedKey}={encodedValue}"); } canonicalQueryString = string.Join("&", encodedParams.OrderBy(p => p)); } // Create signed headers and canonical headers var headers = context.Request.Headers; var canonicalHeaderList = new List<string[]>(); // Add content-type if present var contentType = headers.GetValueOrDefault("Content-Type", "").ToLowerInvariant(); if (!string.IsNullOrEmpty(contentType)) { canonicalHeaderList.Add(new[] { "content-type", contentType }); } // Always add host canonicalHeaderList.Add(new[] { "host", host }); // Add x-amz-* headers (excluding x-amz-date, x-amz-content-sha256) foreach (var header in headers) { var name = header.Key.ToLowerInvariant(); if (string.Equals(name, "x-amz-content-sha256", StringComparison.OrdinalIgnoreCase) || string.Equals(name, "x-amz-date", StringComparison.OrdinalIgnoreCase)) { continue; } if (name.StartsWith("x-amz-")) { var value = header.Value.First()?.Trim(); canonicalHeaderList.Add(new[] { name, value }); } } canonicalHeaderList.Add(new[] { "x-amz-content-sha256", hashedPayload }); canonicalHeaderList.Add(new[] { "x-amz-date", amzDate }); var canonicalHeadersOrdered = canonicalHeaderList.OrderBy(h => h[0]); var canonicalHeaders = string.Join("\n", canonicalHeadersOrdered.Select(h => $"{h[0]}:{h[1].Trim()}")) + "\n"; var signedHeaders = string.Join(";", canonicalHeadersOrdered.Select(h => h[0])); // Create and hash the canonical request var canonicalRequest = $"{method}\n{canonicalPath}\n{canonicalQueryString}\n{canonicalHeaders}\n{signedHeaders}\n{hashedPayload}"; string hashedCanonicalRequest = ""; using (var sha256 = System.Security.Cryptography.SHA256.Create()) { var hash = sha256.ComputeHash(System.Text.Encoding.UTF8.GetBytes(canonicalRequest)); hashedCanonicalRequest = BitConverter.ToString(hash).Replace("-", "").ToLowerInvariant(); } // Build string to sign var credentialScope = $"{dateStamp}/{region}/{service}/aws4_request"; var stringToSign = $"AWS4-HMAC-SHA256\n{amzDate}\n{credentialScope}\n{hashedCanonicalRequest}"; // Sign it using secret key byte[] kSecret = System.Text.Encoding.UTF8.GetBytes("AWS4" + secretKey); byte[] kDate, kRegion, kService, kSigning; using (var h1 = new System.Security.Cryptography.HMACSHA256(kSecret)) { kDate = h1.ComputeHash(System.Text.Encoding.UTF8.GetBytes(dateStamp)); } using (var h2 = new System.Security.Cryptography.HMACSHA256(kDate)) { kRegion = h2.ComputeHash(System.Text.Encoding.UTF8.GetBytes(region)); } using (var h3 = new System.Security.Cryptography.HMACSHA256(kRegion)) { kService = h3.ComputeHash(System.Text.Encoding.UTF8.GetBytes(service)); } using (var h4 = new System.Security.Cryptography.HMACSHA256(kService)) { kSigning = h4.ComputeHash(System.Text.Encoding.UTF8.GetBytes("aws4_request")); } // Auth header string signature; using (var hmac = new System.Security.Cryptography.HMACSHA256(kSigning)) { var sigBytes = hmac.ComputeHash(System.Text.Encoding.UTF8.GetBytes(stringToSign)); signature = BitConverter.ToString(sigBytes).Replace("-", "").ToLowerInvariant(); } return $"AWS4-HMAC-SHA256 Credential={accessKey}/{credentialScope}, SignedHeaders={signedHeaders}, Signature={signature}"; }</value> </set-header> <set-header name="Host" exists-action="override"> <value>@(context.Request.Url.Host)</value> </set-header> </inbound> <backend> <base /> </backend> <outbound> <base /> </outbound> <on-error> <base /> </on-error> </policies>
Chame a Bedrock API
Para chamar a API Bedrock por meio do Gerenciamento de API, você pode usar o AWS Bedrock SDK. Este exemplo usa o SDK do .NET, mas você pode usar qualquer linguagem compatível com a API do AWS Bedrock.
O exemplo a seguir usa um cliente HTTP personalizado que instancia classes definidas no arquivo BedrockHttpClientFactory.cs
que acompanha o arquivo . O cliente HTTP personalizado roteia solicitações para o ponto de extremidade do Gerenciamento de API e inclui a chave de assinatura do Gerenciamento de API (se necessário) nos cabeçalhos de solicitação.
using Amazon;
using Amazon.BedrockRuntime;
using Amazon.BedrockRuntime.Model;
using Amazon.Runtime;
using BedrockClient;
// Leave accessKey and secretKey values as empty strings. Authentication to AWS API is handled through policies in API Management.
var accessKey = "";
var secretKey = "";
var credentials = new BasicAWSCredentials(accessKey, secretKey);
// Create custom configuration to route requests through API Management
// apimUrl is the API Management endpoint, such as https://apim-hello-word.azure-api.net/bedrock
var apimUrl = "<api-management-endpoint">;
// Provide name and value for the API Management subscription key header.
var apimSubscriptionHeaderName = "api-key";
var apimSubscriptionKey = "<your-apim-subscription-key>";
var config = new AmazonBedrockRuntimeConfig()
{
HttpClientFactory = new BedrockHttpClientFactory(apimUrl, apimSubscriptionHeaderName, apimSubscriptionKey),
// Set the AWS region where your Bedrock model is hosted.
RegionEndpoint = RegionEndpoint.USEast1
};
var client = new AmazonBedrockRuntimeClient(credentials, config);
// Set the model ID, e.g., Claude 3 Haiku. Find the supported models in Amazon Bedrock documentation: https://docs.aws.amazon.com/bedrock/latest/userguide/models-supported.html.
var modelId = "us.anthropic.claude-3-5-haiku-20241022-v1:0";
// Define the user message.
var userMessage = "Describe the purpose of a 'hello world' program in one line.";
// Create a request with the model ID, the user message, and an inference configuration.
var request = new ConverseRequest
{
ModelId = modelId,
Messages = new List<Message>
{
new Message
{
Role = ConversationRole.User,
Content = new List<ContentBlock> { new ContentBlock { Text = userMessage } }
}
},
InferenceConfig = new InferenceConfiguration()
{
MaxTokens = 512,
Temperature = 0.5F,
TopP = 0.9F
}
};
try
{
// Send the request to the Bedrock runtime and wait for the result.
var response = await client.ConverseAsync(request);
// Extract and print the response text.
string responseText = response?.Output?.Message?.Content?[0]?.Text ?? "";
Console.WriteLine(responseText);
}
catch (AmazonBedrockRuntimeException e)
{
Console.WriteLine($"ERROR: Can't invoke '{modelId}'. Reason: {e.Message}");
throw;
}
BedrockHttpClientFactory.cs
O código a seguir implementa classes para criar um cliente HTTP personalizado que roteia solicitações para a API Bedrock por meio do Gerenciamento de API, incluindo uma chave de assinatura do Gerenciamento de API nos cabeçalhos.
using Amazon.Runtime;
namespace BedrockClient
{
public class BedrockHttpClientFactory : HttpClientFactory
{
readonly string subscriptionKey;
readonly string subscriptionHeaderName;
readonly string rerouteUrl;
public BedrockHttpClientFactory(string rerouteUrl, string subscriptionHeaderName, string subscriptionKey)
{
this.rerouteUrl = rerouteUrl;
this.subscriptionHeaderName = subscriptionHeaderName;
this.subscriptionKey = subscriptionKey;
}
public override HttpClient CreateHttpClient(IClientConfig clientConfig)
{
var handler = new RerouteHandler(rerouteUrl)
{
InnerHandler = new HttpClientHandler()
};
var httpClient = new HttpClient(handler);
httpClient.DefaultRequestHeaders.Add(this.subscriptionHeaderName, this.subscriptionKey);
return httpClient;
}
}
public class RerouteHandler : DelegatingHandler
{
readonly string rerouteUrl;
readonly string host;
public RerouteHandler(string rerouteUrl)
{
this.rerouteUrl = rerouteUrl;
this.host = rerouteUrl.Split("/")[2].Split(":")[0];
}
protected override Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
{
var originalUri = request.RequestUri;
request.RequestUri = new Uri($"{this.rerouteUrl}{originalUri.PathAndQuery}");
request.Headers.Host = this.host;
return base.SendAsync(request, cancellationToken);
}
}
}