Cloud Intelligence™Cloud Intelligence™

Cloud Intelligence™

Amazon Bedrock Starter Kit mit Go und EKS

By Paul O'BrienAug 11, 20247 min read

Diese Seite ist auch in English, Español, Français, Italiano, 日本語 und Português verfügbar.

Mit Amazon Bedrock generiertes Bild eines Kubernetes Starter Kits

Ein Large Language Model (LLM) in eine Anwendung einzubetten, kann diese deutlich leistungsfähiger und einfacher in der Nutzung machen. Das so umzusetzen, dass es sich sauber in eine bestehende Codebasis einfügt und dabei skalierbar bleibt, ist allerdings nicht trivial.

Dieser Artikel stellt ein Starter-Projekt vor, mit dem Sie schnell loslegen können.

Warum ein Starter Kit auf Basis von Go?

Die meisten Generative-AI-Beispiele, die einem begegnen, laufen in Python – das ergibt Sinn, denn Python ist die Lingua franca von Machine Learning und Data Science. Was aber, wenn Sie eine bestehende Anwendung lediglich über gängige API-Aufrufe um Machine-Learning-Modelle erweitern möchten und weder eigene Modelle bauen noch andere dedizierte Machine-Learning-Aufgaben umsetzen?

Go eignet sich hervorragend, um Web Services anzusprechen – darunter auch Machine-Learning-APIs wie Amazon Bedrock oder ChatGPT.

Das in diesem Artikel vorgestellte Starter Kit konzentriert sich auf Amazon Bedrock und ist hier zu finden:

https://github.com/p-obrien/bedrock-microservice-starter

Voraussetzung — Amazon-Bedrock-Modelle aktivieren

Um Amazon Bedrock nutzen zu können, müssen Sie die entsprechenden Foundational Models aktivieren. Das ist derzeit (Stand Juli 2024) leider nur über die AWS Console möglich.

Gehen Sie zur Aktivierung wie folgt vor:

1. Melden Sie sich in Ihrer AWS Console an und navigieren Sie zu Amazon Bedrock.

2. Klappen Sie die Navigationsleiste auf der linken Seite auf und scrollen Sie zu "Model access".

3. Suchen Sie im Dialog "Find model" nach dem gewünschten Modell – im Starter-Projekt verwenden wir "Claude 3 Sonnet". Falls es für Ihr Projekt noch nicht aktiviert ist, müssen Sie Zugriff anfordern. Klicken Sie dazu auf "request model access", wählen Sie die zu aktivierenden Modelle aus und folgen Sie den weiteren Schritten.

Nach der Aktivierung sollte es so aussehen:

AWS Bedrock Base Models

Hinweis: Die Modellverfügbarkeit unterscheidet sich je nach Region. Unter Umständen müssen Sie das Modell in einer anderen Region betreiben als Ihre üblichen workloads.

**Überblick über das Starter Kit**

Das Starter Kit ist als Referenz für Ihre eigene Lösung gedacht und übernimmt Folgendes:

  • Stellt einen Graviton-basierten EKS-Cluster mit einer Managed Node Group bereit
  • Stellt den AWS Load Balancer Controller bereit
  • Stellt EKS Pod Identity und Service Account bereit

Der Go-Code stellt einen Microservice bereit, der:

  • Aufrufer per API-Key authentifiziert
  • EKS Pod Identity zur Kommunikation mit Amazon Bedrock nutzt
  • Eine Konversation mit Amazon Bedrock zurückgibt – konkret mit dem Foundational Model Claude Sonnet, was sich aber leicht anpassen lässt

Wenn Sie bereits einen EKS-Cluster betreiben, können Sie den Code dort ausführen. Stellen Sie aber sicher, dass der Pod Identities Agent und der Service Account vorhanden sind.

**Infrastruktur**

Das Starter Kit nutzt Terraform oder OpenTofu, um einen frischen AWS-EKS-Cluster bereitzustellen. Details zur Verwendung finden Sie in der README.md im Infrastructure-Ordner.

Statt Access Keys im Container, Secrets oder anderen Authentifizierungsmethoden setzen wir auf ein AWS-EKS-Feature namens Pod Identities, um Zugriff auf Bedrock zu gewähren.

Bis vor Kurzem kam dafür EKS IRSA (IAM Roles for Service Accounts) zum Einsatz – das war jedoch ziemlich aufwendig einzurichten und brachte einige Einschränkungen mit sich. EKS Pod Identities umgeht diese Einschränkungen und bietet eine deutlich einfachere Lösung. Wer es genauer wissen will, findet die Details HIER.

EKS Pod Identity

Schritt 1 — EKS Pod Identity Add-on bereitstellen

Schritt 2 — Eine Rolle definieren und dem Pod Identity Add-on erlauben, sie zu übernehmen

Schritt 3 — Einen Kubernetes Service Account mit der Rolle verknüpfen

Schritt 4 — Sicherstellen, dass EKS einen passenden Service Account besitzt

Code

Die Kommunikation des Microservice mit Amazon Bedrock läuft über die Amazon Bedrock Go API.

Hinweis: Es sind weitaus komplexere Interaktionen möglich, als in diesem Starter-Projekt gezeigt werden.

Authentifizierung – ganz einfach

Der Vorteil von EKS Pod Identities: Sie sind für Ihre Anwendung weitgehend transparent. Der folgende Code nutzt etwa die Go Bedrock API, um einen Client anzulegen und sich per EKS Pod Identities zu authentifizieren:

func init() {
 cfg, err := config.LoadDefaultConfig(context.TODO())
 if err != nil {
  log.Fatalf("unable to load SDK config, %v", err)
 }

 brc = bedrockruntime.NewFromConfig(cfg)
}

Um das Laden eines Secrets müssen Sie sich nicht kümmern: Im Pod sind die Umgebungsvariablen für das AWS-Profil automatisch gesetzt. Sie können den Bedrock-Client also einfach mit den Defaults initialisieren.

REST-Server

Wir verwenden das Echo Framework, um einen authentifizierten REST-Endpunkt für eingehende Requests bereitzustellen. Im Starter-Projekt nutzen wir einen einfachen API-Key:

// Sample API Key please don't use this in production and consider something more robust
var apiKey string = "test-api-key"
var brc *bedrockruntime.Client

const modelID = "anthropic.claude-3-sonnet-20240229-v1:0"

func main() {

 cfg, err := config.LoadDefaultConfig(context.TODO())
 if err != nil {
  log.Fatal(err)
 }

 brc = bedrockruntime.NewFromConfig(cfg)

 e := echo.New()
 e.Use(middleware.Logger())
 e.Use(middleware.Recover())

 e.Use(middleware.KeyAuth(func(key string, c echo.Context) (bool, error) {
  return key == apiKey, nil
 }))

 e.POST("/converse", converseHandler)

 if err := e.Start(":8080"); err != http.ErrServerClosed {
  log.Fatal(err)
 }
}

Anschließend nehmen wir den Prompt aus dem Multipart-Form-Input entgegen, reichen ihn an Bedrock weiter und geben die Antwort an den Client zurück.

func converseHandler(c echo.Context) error {
 // Initialize the Bedrock ConverseInput with the model ID
 converseInput := &bedrockruntime.ConverseInput{
  ModelId: aws.String(modelID),
 }

 // Get the user input from the form value
 input := c.FormValue("message")

 // Create the user's message
 userMsg := types.Message{
  Role: types.ConversationRoleUser,
  Content: []types.ContentBlock{
   &types.ContentBlockMemberText{
    Value: input,
   },
  },
 }

 // Append the user's message to the conversation input
 converseInput.Messages = append(converseInput.Messages, userMsg)

 // Call the Bedrock Converse API
 output, err := brc.Converse(context.Background(), converseInput)
 if err != nil {
  log.Fatal("Error calling Converse API:", err)
  return c.String(http.StatusInternalServerError, "Internal Server Error")
 }

 // Extract the response from the assistant
 response, ok := output.Output.(*types.ConverseOutputMemberMessage)
 if !ok {
  return c.String(http.StatusInternalServerError, "Failed to parse response")
 }

 responseContentBlock := response.Value.Content[0]
 text, ok := responseContentBlock.(*types.ContentBlockMemberText)
 if !ok {
  return c.String(http.StatusInternalServerError, "Failed to parse response content")
 }

 // Create the assistant's message
 assistantMsg := types.Message{
  Role:    types.ConversationRoleAssistant,
  Content: response.Value.Content,
 }

 // Append the assistant's message to the conversation input
 converseInput.Messages = append(converseInput.Messages, assistantMsg)

 // Return the assistant's response to the client
 return c.JSON(http.StatusOK, text.Value)
}

Erweiterungsmöglichkeiten

Folgende Verbesserungen überlassen wir Ihnen als Übung:

  • Streaming Responses — Das Echo Framework unterstützt Streaming Responses, und es wäre praktisch, auch von Bedrock eine Streaming-Antwort zu erhalten
  • System Prompt — Ein System Prompt, der Amazon Bedrock vor der Verarbeitung der Client-Interaktionen mit einer bestimmten Vorgabe initialisiert

Abschließende Gedanken …

Vielen Dank fürs Lesen. Bei Fragen oder Feedback öffnen Sie gerne ein Issue in meinem Github-Repository.

Falls Sie DoiT International noch nicht kennen, sollten Sie uns unbedingt einen Besuch abstatten. Unser Team möchte mehr über Sie und Ihre Anforderungen im Cloud Engineering erfahren. Wir setzen ausschließlich auf Senior Engineers und sind auf anspruchsvolle Cloud-Beratung, Architekturdesign und Debugging spezialisiert. Kontaktieren Sie uns – sprechen wir miteinander!