Cloud Intelligence™Cloud Intelligence™

Cloud Intelligence™

Un Starter Kit Amazon Bedrock basé sur Go et EKS

By Paul O'BrienAug 11, 20247 min read

Cette page est également disponible en English, Deutsch, Español, Italiano, 日本語 et Português.

Image d'un Starter Kit Kubernetes générée par Amazon Bedrock

Intégrer un Large Language Model (LLM) à une application la rend plus puissante et plus simple à utiliser. Le faire de façon à s'inscrire dans une base de code existante tout en restant scalable peut toutefois s'avérer délicat.

Cet article présente un projet de démarrage qui vous permettra de vous lancer rapidement.

Pourquoi bâtir un starter kit sur Go ?

La plupart des exemples d'IA générative que l'on rencontre tournent en Python, ce qui est logique puisque Python est la lingua franca du Machine Learning et de la Data Science. Mais que faire lorsque vous disposez d'une application existante que vous souhaitez simplement enrichir avec des modèles de Machine Learning via de simples appels d'API, sans construire vos propres modèles ni mener d'autres tâches dédiées au Machine Learning ?

Go est un langage idéal pour effectuer des appels vers des Web Services, y compris vers des API de Machine Learning telles qu'Amazon Bedrock ou ChatGPT.

Le Starter Kit présenté dans cet article est centré sur Amazon Bedrock et est disponible ici :

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

Prérequis — activer les modèles Amazon Bedrock

Pour utiliser Amazon Bedrock, vous devez activer les Foundational Models concernés. À ce jour (juillet 2024), cela n'est malheureusement possible que via la console AWS.

Pour activer le foundational model, suivez ces étapes :

1. Connectez-vous à votre console AWS et accédez à Amazon Bedrock.

2. Déployez le panneau de navigation à gauche et faites défiler jusqu'à Model access.

3. Dans la boîte de dialogue Find model, recherchez le modèle à activer ; pour le starter project, nous utilisons Claude 3 Sonnet. S'il n'est pas activé pour votre projet, vous devrez en demander l'accès. Cliquez sur le lien request model access, sélectionnez les modèles à activer et parcourez les écrans suivants.

Une fois activé, l'écran devrait ressembler à ceci :

Modèles de base AWS Bedrock

Remarque : la disponibilité des modèles varie selon les régions ; il peut être nécessaire d'exécuter le modèle dans une région différente de celle de vos workloads habituels.

**Vue d'ensemble du Starter Kit**

Le starter kit a été pensé comme un point de référence à reprendre dans votre propre solution. Il effectue les opérations suivantes :

  • Déploie un cluster EKS basé sur Graviton avec un managed node group
  • Déploie l'AWS Load Balancer Controller
  • Déploie EKS Pod Identity et le service account

Le code Go déploie un microservice qui :

  • Exige une API Key pour authentifier les appelants
  • S'appuie sur EKS Pod Identity pour communiquer avec Amazon Bedrock
  • Renvoie une conversation avec Amazon Bedrock, plus précisément le foundational model Claude Sonnet, que vous pouvez facilement personnaliser

Si vous disposez déjà d'un cluster EKS, vous pouvez exécuter le code dans un cluster existant, à condition que le Pod Identities Agent et le Service Account aient bien été déployés.

**Infrastructure**

Le starter kit s'appuie sur Terraform ou OpenTofu pour déployer un cluster AWS EKS entièrement neuf. Le fichier README.md du dossier Infrastructure détaille la marche à suivre.

Plutôt que d'utiliser des Access Keys dans un conteneur, des secrets ou d'autres méthodes d'authentification, nous nous appuierons sur une fonctionnalité d'AWS EKS appelée Pod Identities pour autoriser l'accès à Bedrock.

Jusqu'à récemment, EKS IRSA (IAM Roles for Service Accounts) remplissait ce rôle, mais sa configuration restait complexe et présentait certaines limites. EKS Pod Identities lève ces limites et propose une solution simple à mettre en œuvre. Pour les curieux, les détails se trouvent ICI.

EKS Pod Identity

Étape 1 — Déployer l'add-on EKS Pod Identity

Étape 2 — Définir un rôle et autoriser l'add-on Pod Identity à l'assumer

Étape 3 — Associer un Service Account Kubernetes au rôle

Étape 4 — Vérifier qu'EKS dispose d'un service account correspondant

Code

La communication avec Amazon Bedrock depuis le microservice passe par l'API Go d'Amazon Bedrock.

Remarque : des interactions bien plus poussées sont possibles que celles présentées dans ce starter project.

L'authentification en toute simplicité

L'avantage d'EKS Pod Identities, c'est que le mécanisme reste largement transparent pour votre application. Le code ci-dessous s'appuie par exemple sur l'API Go Bedrock pour créer un client et tirer parti de l'authentification EKS Pod Identities :

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

 brc = bedrockruntime.NewFromConfig(cfg)
}

Plutôt que d'avoir à charger un secret, le pod dispose automatiquement des variables d'environnement définies pour le profil AWS. Il suffit donc d'initialiser le client Bedrock avec les valeurs par défaut.

Serveur REST

Nous utilisons le framework Echo pour créer un endpoint REST authentifié, capable de recevoir les requêtes des appelants. Pour le starter project, nous nous contentons d'une simple 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)
 }
}

Nous récupérons ensuite le prompt depuis le Multipart Form et le transmettons à Bedrock avant de renvoyer la réponse au client.

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

Améliorations

Quelques pistes laissées en exercice au lecteur :

  • Réponses en streaming — le framework Echo prend en charge le streaming, et il serait intéressant d'obtenir une réponse en streaming depuis Bedrock
  • System Prompt — ajouter un system prompt pour initialiser Amazon Bedrock avec une consigne précise avant de traiter les interactions avec le client

Pour conclure…

Merci de votre lecture. Pour toute question ou retour, n'hésitez pas à ouvrir une issue sur mon dépôt GitHub.

Si vous ne connaissez pas encore DoiT International, c'est le moment de nous découvrir. Notre équipe est à votre écoute pour comprendre vos besoins en cloud engineering. Composée exclusivement d'ingénieurs seniors, elle est spécialisée dans le conseil cloud avancé, la conception d'architectures et l'aide au débogage. Contactez-nous, et discutons-en !