Hinweis
Für den Zugriff auf diese Seite ist eine Autorisierung erforderlich. Sie können versuchen, sich anzumelden oder das Verzeichnis zu wechseln.
Für den Zugriff auf diese Seite ist eine Autorisierung erforderlich. Sie können versuchen, das Verzeichnis zu wechseln.
GILT FÜR: Alle API Management-Ebenen
In diesem Artikel importieren Sie eine Amazon Bedrock-Sprachmodell-API als Passthrough-API in Ihre API-Verwaltungsinstanz. Dies ist ein Beispiel für ein Modell, das bei einem anderen Anbieter als den Azure AI Services gehostet wird. Verwenden Sie KI-Gatewayrichtlinien und andere Funktionen in der API-Verwaltung, um die Integration zu vereinfachen, die Observierbarkeit zu verbessern und die Kontrolle über die Modellendpunkte zu verbessern.
Weitere Informationen zum Verwalten von KI-APIs in der API-Verwaltung:
Erfahren Sie mehr über Amazon Bedrock:
Voraussetzungen
- Eine bestehende API Management-Instanz. Erstellen Sie bitte eine, falls noch nicht geschehen.
- Ein Amazon Web Services (AWS)-Konto mit Zugriff auf Amazon Bedrock und Zugriff auf ein oder mehrere Amazon Bedrock Foundation-Modelle. Weitere Informationen
Erstellen von IAM-Benutzerzugriffsschlüsseln
Um Ihre API Management-Instanz beim Amazon API Gateway zu authentifizieren, benötigen Sie Zugriffstasten für einen AWS IAM-Benutzer.
Informationen zum Generieren der erforderlichen Zugriffsschlüssel-ID und des geheimen Schlüssels mithilfe der AWS-Verwaltungskonsole finden Sie unter Erstellen eines Zugriffsschlüssels für sich selbst in der AWS-Dokumentation.
Speichern Sie Ihre Zugriffsschlüssel an einem sicheren Ort. Sie speichern sie im nächsten Schritt als benannte Werte.
Vorsicht
Zugriffsschlüssel sind langfristige Anmeldeinformationen, und Sie sollten sie so sicher wie ein Kennwort verwalten. Weitere Informationen zum Sichern von Zugriffsschlüsseln
Speichern von IAM-Benutzerzugriffsschlüsseln als benannte Werte
Speichern Sie die beiden IAM-Benutzerzugriffsschlüssel sicher als geheime benannte Werte in Ihrer Azure API Management-Instanz unter Verwendung der in der folgenden Tabelle empfohlenen Konfiguration.
| AWS-Geheimnis | Name | Geheimniswert |
|---|---|---|
| Zugriffsschüssel | Zugriffstaste | Zugriffsschlüssel-ID, die von AWS abgerufen wurde |
| Geheimer Zugriffsschlüssel | geheimer Schlüssel | Geheimer Zugriffsschlüssel, der von AWS abgerufen wurde |
Importieren einer Bedrock-API mithilfe des Portals
So importieren Sie eine Amazon Bedrock-API in api Management:
Navigieren Sie im Azure-Portal zu Ihrer API Management-Instanz.
Wählen Sie im linken Menü unter APIs die Option APIs>+ API hinzufügen aus.
Wählen Sie unter "Neue API definieren" die Sprachmodell-API aus.
Auf der Registerkarte "API konfigurieren ":
Geben Sie einen Anzeigenamen und optional eine Beschreibung für die API ein.
Geben Sie die folgende URL zum standardmäßigen Amazon Bedrock-Endpunkt ein:
https://bedrock-runtime.<aws-region>.amazonaws.com.Beispiel:
https://bedrock-runtime.us-east-1.amazonaws.comWählen Sie optional ein oder mehrere Produkte aus, die der API zugeordnet werden sollen.
Fügen Sie im Pfad einen Pfad an, den Ihre API-Verwaltungsinstanz für den Zugriff auf die LLM-API-Endpunkte verwendet.
Wählen Sie im Typdie Option "Passthrough-API erstellen" aus.
Lassen Sie Werte in Access-Schlüssel leer.
Konfigurieren Sie auf den verbleibenden Registerkarten optional Richtlinien zum Verwalten der Tokennutzung, der semantischen Zwischenspeicherung und der SICHERHEIT von KI-Inhalten. Ausführliche Informationen finden Sie unter Importieren einer Sprachmodell-API.
Wählen Sie Überprüfen aus.
Wählen Sie nach der Überprüfung Ihrer Einstellungen Erstellen aus.
Die API-Verwaltung erstellt die API- und (optional) Richtlinien, mit denen Sie die API überwachen und verwalten können.
Konfigurieren von Richtlinien zum Authentifizieren von Anforderungen an die Amazon Bedrock-API
Konfigurieren Sie API-Verwaltungsrichtlinien zum Signieren von Anforderungen an die Amazon Bedrock-API. Weitere Informationen zum Signieren von AWS-API-Anforderungen
Im folgenden Beispiel werden die Access Key und Secret Key benannten Werte verwendet, die Sie zuvor für den AWS-Zugriffsschlüssel und den geheimen Schlüssel erstellt haben. Legen Sie die region Variable auf den entsprechenden Wert für Ihre Amazon Bedrock-API fest. Im Beispiel wird für die Region verwendet us-east-1 .
Navigieren Sie im Azure-Portal zu Ihrer API Management-Instanz.
Wählen Sie im linken Menü unter APIs die Option APIs aus.
Wählen Sie die API aus, die Sie im vorherigen Abschnitt erstellt haben.
Wählen Sie im linken Menü unter "Entwurf" "Alle Vorgänge" aus.
Wählen Sie die Registerkarte "Eingehende Verarbeitung" aus .
Wählen Sie im Editor für eingehende Verarbeitungsrichtlinien die Option </> aus, um den Richtlinien-Editor zu öffnen.
Konfigurieren Sie die folgenden Richtlinien:
<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>
Aufrufen der Bedrock-API
Um die Bedrock-API über API Management aufzurufen, können Sie das AWS Bedrock SDK verwenden. In diesem Beispiel wird das .NET SDK verwendet, Sie können jedoch jede Sprache verwenden, die die AWS Bedrock-API unterstützt.
Im folgenden Beispiel wird ein benutzerdefinierter HTTP-Client verwendet, der Klassen instanziiert, die in der zugehörigen Datei BedrockHttpClientFactory.csdefiniert sind. Der benutzerdefinierte HTTP-Client leitet Anforderungen an den API-Verwaltungsendpunkt weiter und enthält den API-Verwaltungsabonnementschlüssel (falls erforderlich) in den Anforderungsheadern.
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
Der folgende Code implementiert Klassen zum Erstellen eines benutzerdefinierten HTTP-Clients, der Anforderungen an die Bedrock-API über die API-Verwaltung weiterleitet, einschließlich eines API-Verwaltungsabonnementschlüssels in den Headern.
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);
}
}
}