Amazon Bedrock geçiş dil modeli API'sini içeri aktarma

UYGULANANLAR: Tüm API Management katmanları

Bu makalede, amazon bedrock dil modeli API'sini GEÇIŞ API'si olarak API Management örneğinize aktaracaksınız. Bu örnekte, Foundry Tools dışında bir çıkarım sağlayıcısında barındırılan bir model gösterilmektedir. Tümleştirmeyi basitleştirmek, gözlemlenebilirliği geliştirmek ve model uç noktaları üzerinde denetimi geliştirmek için API Management'taki yapay zeka ağ geçidi ilkelerini ve diğer özellikleri kullanın.

API Management'ta yapay zeka API'lerini yönetme hakkında daha fazla bilgi için bkz:

Amazon Bedrock hakkında daha fazla bilgi için bkz:

Önkoşullar

IAM kullanıcı erişim anahtarları oluşturma

API Management örneğinizin kimliğini Amazon API Gateway'de doğrulamak için AWS IAM kullanıcısına yönelik erişim anahtarları gerekir.

AWS Yönetim Konsolu'nu kullanarak gerekli erişim anahtarı kimliğini ve gizli anahtarı oluşturmak için AWS belgelerinde Kendiniz için erişim anahtarı oluşturma bölümüne bakın.

Erişim anahtarlarınızı güvenli bir konuma kaydedin. Bunları bir sonraki adımda adlandırılmış değerler olarak depolayacaksınız.

Dikkat

Erişim anahtarları uzun vadeli kimlik bilgileridir ve bunları parola gibi güvenli bir şekilde yönetmeniz gerekir. Erişim anahtarlarının güvenliğini sağlama hakkında daha fazla bilgi edinin.

IAM kullanıcı erişim anahtarlarını adlandırılmış değerler olarak depolama

Aşağıdaki tabloda önerilen yapılandırmayı kullanarak iki IAM kullanıcı erişim anahtarını Azure API Management örneğinizde gizli olarak adlandırılmış değerler şeklinde güvenli bir şekilde depolayın.

AWS gizli anahtarı İsim Gizli değer
Erişim anahtarı accesskey AWS'den alınan erişim anahtarı kimliği
Gizli dizi erişim anahtarı gizli anahtar AWS'den alınan gizli erişim anahtarı

Portalı kullanarak Bir Bedrock API'sini içeri aktarma

Amazon Bedrock API'sini API Management'a aktarmak için:

  1. Azure portalında API Management örneğine gidin.

  2. Soldaki menüde, API'ler'in altında API'ler>+ API Ekle'yi seçin.

  3. Yeni API tanımla'nın altında Dil Modeli API'sini seçin.

    Portalda geçiş dili modeli API'sini oluşturma işleminin ekran görüntüsü.

  4. API'yi Yapılandır sekmesinde:

    1. Görünen ad ve isteğe bağlı açıklama girin.

    2. Varsayılan Amazon Bedrock uç noktasının URL'sini girin: https://bedrock-runtime.<aws-region>.amazonaws.com.

      Örnek: https://bedrock-runtime.us-east-1.amazonaws.com

    3. İsteğe bağlı olarak, API ile ilişkilendirilecek bir veya daha fazla Ürün seçin.

    4. Path bölümüne, API Management instance'ınızın LLM API uç noktalarına erişmek için kullandığı bir yol ekleyin.

    5. Tür'deGeçiş API'sini oluştur'u seçin.

    6. Access anahtarını boş bırakın.

    Portalda dil modeli API yapılandırmasının ekran görüntüsü.

  5. Kalan sekmelerde isteğe bağlı olarak belirteç tüketimini, anlamsal önbelleğe almayı ve yapay zeka içerik güvenliğini yönetmek için ilkeleri yapılandırın. Ayrıntılar için bkz. Dil modeli API'sini içeri aktarma.

  6. İncele'yi seçin.

  7. Portal ayarları doğruladıktan sonra Oluştur'u seçin.

API Management, API'yi izlemenize ve yönetmenize yardımcı olmak için API'yi ve (isteğe bağlı olarak) ilkeleri oluşturur.

Amazon Bedrock API'sine yönelik isteklerin kimliğini doğrulamak için ilkeleri yapılandırma

Api Management ilkelerini, Amazon Bedrock API'sine yönelik istekleri imzalamak için yapılandırın. AWS API isteklerini imzalama hakkında daha fazla bilgi edinin.

Önceden oluşturduğunuz AWS erişim anahtarı ve gizli anahtarı için adlandırılmış olan accesskey ve secretkey değerleri aşağıdaki örnekte kullanılır. Değişkenini region Amazon Bedrock API'niz için uygun değere ayarlayın. Örnek, us-east-1 kullanır.

  1. Azure portalında API Management örneğine gidin.

  2. Soldaki menüde, API'ler'in altında API'ler'i seçin.

  3. Önceki bölümde oluşturduğunuz API'yi seçin.

  4. Soldaki menüde, Tasarım'ın altında Tüm işlemler'i seçin.

  5. Gelen işleme sekmesini seçin.

  6. Gelen işleme ilkesi düzenleyicisinde ilke düzenleyicisini açmak için </> seçeneğini seçin.

  7. Aşağıdaki ilkeleri yapılandırın:

    <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>
    

Bedrock API'sini çağırma

API Management aracılığıyla Bedrock API'sini çağırmak için AWS Bedrock SDK'sını kullanabilirsiniz. Bu örnekte .NET SDK kullanılır ancak AWS Bedrock API'sini destekleyen herhangi bir dil kullanılır.

Aşağıdaki örnek, eşlik eden dosyasında BedrockHttpClientFactory.cstanımlanan sınıfların örneğini oluşturan özel bir HTTP istemcisi kullanır. Özel HTTP istemcisi istekleri API Management uç noktasına yönlendirir ve istek üst bilgilerinde API Management abonelik anahtarını (gerekirse) içerir.

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

Aşağıdaki kod, üst bilgilerde API Management abonelik anahtarı da dahil olmak üzere istekleri API Management aracılığıyla Bedrock API'sine yönlendiren özel bir HTTP istemcisi oluşturmak için sınıfları uygular.

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);
        }
    }
}