Anteckning
Åtkomst till den här sidan kräver auktorisering. Du kan prova att logga in eller ändra kataloger.
Åtkomst till den här sidan kräver auktorisering. Du kan prova att ändra kataloger.
GÄLLER FÖR: Alla API Management-nivåer
I den här artikeln importerar du ett API för Amazon Bedrock-språkmodell till DIN API Management-instans som ett API för genomströmning. Det här är ett exempel på en modell som finns på en annan slutsatsdragningsprovider än Azure AI-tjänster. Använd principer för AI-gatewayer och andra funktioner i API Management för att förenkla integrering, förbättra observerbarheten och förbättra kontrollen över modellsutgångspunkterna.
Läs mer om att hantera AI-API:er i API Management:
Läs mer om Amazon Bedrock:
Förutsättningar
- En befintlig API Management-instans. Skapa en om du inte redan har gjort det.
- Ett AWS-konto (Amazon Web Services) med åtkomst till Amazon Bedrock och tillgång till en eller flera Amazon Bedrock Foundation-modeller. Läs mer
Skapa IAM-användaråtkomstnycklar
För att autentisera din API Management-instans till Amazon API Gateway behöver du åtkomstnycklar för en AWS IAM-användare.
Information om hur du genererar det nödvändiga åtkomstnyckel-ID:t och den hemliga nyckeln med hjälp av AWS-hanteringskonsolen finns i Skapa en åtkomstnyckel för dig själv i AWS-dokumentationen.
Spara dina åtkomstnycklar på en säker plats. Du lagrar dem som namngivna värden i nästa steg.
Försiktighet
Åtkomstnycklar är långsiktiga autentiseringsuppgifter och du bör hantera dem lika säkert som ett lösenord. Läs mer om att skydda åtkomstnycklar
Lagra IAM-användaråtkomstnycklar som namngivna värden
Lagra de två IAM-användaråtkomstnycklarna på ett säkert sätt som hemliga namngivna värden i din Azure API Management-instans med hjälp av konfigurationen som rekommenderas i följande tabell.
| AWS-hemlighet | Namn | Hemligt värde |
|---|---|---|
| Åtkomstnyckel | accesskey | Åtkomstnyckel-ID som hämtats från AWS |
| Hemlig åtkomstnyckel | secretkey | Hemlig åtkomstnyckel som hämtats från AWS |
Importera ett Bedrock-API med hjälp av portalen
Så här importerar du ett Amazon Bedrock-API till API Management:
I Azure Portal navigerar du till din API Management-instans.
I den vänstra menyn går du till API:er och väljer API:er>+ Lägg till API.
Under Definiera ett nytt API väljer du Språkmodell-API.
På fliken Konfigurera API :
Ange ett visningsnamn och en valfri beskrivning för API:et.
Ange följande URL till standardslutpunkten för Amazon Bedrock:
https://bedrock-runtime.<aws-region>.amazonaws.com.Exempel:
https://bedrock-runtime.us-east-1.amazonaws.comDu kan också välja en eller flera produkter som ska associeras med API:et.
I Sökväg lägger du till en sökväg som din API Management-instans använder för att komma åt LLM API-slutpunkterna.
I Typ väljer du Skapa ett API för genomströmning.
Lämna värdena tomma i Åtkomstnyckeln .
På de återstående flikarna kan du välja att konfigurera principer för att hantera tokenförbrukning, semantisk cachelagring och AI-innehållssäkerhet. Mer information finns i Importera ett språkmodell-API.
Välj Granska.
När inställningarna har verifierats väljer du Skapa.
API Management skapar API- och (valfritt) principer som hjälper dig att övervaka och hantera API:et.
Konfigurera principer för att autentisera begäranden till Amazon Bedrock API
Konfigurera API Management-principer för att signera begäranden till Amazon Bedrock-API:et. Läs mer om att signera AWS API-begäranden
I följande exempel används accesskey och secretkey med namngivna värden som du skapade tidigare för AWS-åtkomstnyckeln och hemlighetsnyckeln. Ange variabeln till lämpligt värde för amazon bedrock-API:et region . Exemplet använder us-east-1 för regionen.
I Azure Portal navigerar du till din API Management-instans.
I den vänstra menyn går du till API:er och väljer API:er.
Välj det API som du skapade i föregående avsnitt.
I den vänstra menyn under Design väljer du Alla åtgärder.
Välj fliken Inkommande bearbetning .
I redigeraren för inkommande bearbetningsprinciper väljer du </> för att öppna principredigeraren.
Konfigurera följande principer:
<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>
Anropa Bedrock-API:et
Om du vill anropa Bedrock-API:et via API Management kan du använda AWS Bedrock SDK. I det här exemplet används .NET SDK, men du kan använda valfritt språk som stöder AWS Bedrock-API:et.
I följande exempel används en anpassad HTTP-klient som instansierar klasser som definierats i den medföljande filen BedrockHttpClientFactory.cs. Den anpassade HTTP-klienten dirigerar begäranden till API Management-slutpunkten och innehåller API Management-prenumerationsnyckeln (om det behövs) i begärandehuvudena.
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
Följande kod implementerar klasser för att skapa en anpassad HTTP-klient som dirigerar begäranden till Bedrock-API:et via API Management, inklusive en API Management-prenumerationsnyckel i rubrikerna.
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);
}
}
}