Générer du contenu avec des modèles d'IA

Les modèles d'IA sont au cœur de l'IA générative. Actuellement, les deux exemples les plus marquants de modèles génératifs sont les grands modèles de langage (LLM) et les modèles de génération d'images. Ces modèles reçoivent une entrée, appelée invite (généralement du texte, une image ou une combinaison des deux), et produisent du texte, une image, voire de l'audio ou de la vidéo en sortie.

Le résultat de ces modèles peut être étonnamment convaincant: les LLM génèrent du texte qui semble avoir été écrit par un être humain, et les modèles de génération d'images peuvent produire des images très proches de vraies photographies ou d'œuvres d'art créées par des humains.

De plus, les LLM ont prouvé qu'ils pouvaient effectuer des tâches au-delà de la simple génération de texte:

  • Écrire des programmes informatiques
  • Planifier les sous-tâches nécessaires pour accomplir une tâche plus importante
  • Organiser des données désorganisées
  • Comprendre et extraire des données d'informations à partir d'un corpus de texte
  • Suivre et effectuer des activités automatisées en fonction d'une description textuelle de l'activité.

De nombreux modèles sont disponibles auprès de plusieurs fournisseurs. Chaque modèle présente ses propres forces et faiblesses. Un modèle peut exceller dans une tâche, mais être moins performant dans d'autres. Les applications qui utilisent l'IA générative peuvent souvent tirer parti de l'utilisation de plusieurs modèles différents en fonction de la tâche à accomplir.

En tant que développeur d'applications, vous n'interagissez généralement pas directement avec les modèles d'IA générative, mais via des services disponibles en tant qu'API Web. Bien que ces services présentent souvent des fonctionnalités similaires, ils les fournissent tous via des API différentes et incompatibles. Si vous souhaitez utiliser plusieurs services de modèles, vous devez utiliser chacun de leurs SDK propriétaires, potentiellement incompatibles les uns avec les autres. Et si vous souhaitez passer d'un modèle à un autre, le plus récent et le plus performant, vous devrez peut-être recréer cette intégration.

Genkit répond à ce défi en fournissant une interface unique qui élimine les détails d'accès à n'importe quel service de modèle d'IA générative, avec plusieurs implémentations prédéfinies déjà disponibles. Créer votre application optimisée par l'IA autour de Genkit simplifie le processus d'appel de votre premier modèle d'IA générative. Vous pouvez également combiner plusieurs modèles ou en remplacer un par un autre à mesure que de nouveaux modèles apparaissent.

Avant de commencer

Si vous souhaitez exécuter les exemples de code de cette page, suivez d'abord les étapes du guide Premiers pas. Tous les exemples supposent que vous avez déjà installé Genkit en tant que dépendance dans votre projet.

Modèles compatibles avec Genkit

Genkit est conçu pour être suffisamment flexible pour utiliser potentiellement n'importe quel service de modèle d'IA générative. Ses bibliothèques principales définissent l'interface commune pour travailler avec les modèles, et les plug-ins de modèle définissent les détails d'implémentation pour travailler avec un modèle spécifique et son API.

L'équipe Genkit gère des plug-ins pour travailler avec les modèles fournis par Vertex AI, Google Generative AI et Ollama:

Charger et configurer des plug-ins de modèle

Avant de pouvoir utiliser Genkit pour commencer à générer du contenu, vous devez charger et configurer un plug-in de modèle. Si vous venez du guide de démarrage, vous l'avez déjà fait. Sinon, consultez le guide de démarrage ou la documentation du plug-in individuel, puis suivez les étapes indiquées avant de continuer.

Fonction genkit.Generate()

Dans Genkit, la fonction genkit.Generate() est l'interface principale avec laquelle vous interagissez avec les modèles d'IA générative.

L'appel genkit.Generate() le plus simple spécifie le modèle que vous souhaitez utiliser et une invite de texte:

import (
    "context"
    "log"

    "github.com/firebase/genkit/go/ai"
    "github.com/firebase/genkit/go/genkit"
    "github.com/firebase/genkit/go/plugins/googlegenai"
)

func main() {
    ctx := context.Background()

    g, err := genkit.Init(ctx,
        genkit.WithPlugins(&googlegenai.GoogleAI{}),
        genkit.WithDefaultModel("googleai/gemini-2.0-flash"),
    )
    if err != nil {
        log.Fatal(err)
    }

    resp, err := genkit.Generate(ctx, g,
        ai.WithPrompt("Invent a menu item for a pirate themed restaurant."),
    )
    if err != nil {
        log.Fatal(err)
    }

    log.Println(resp.Text())
}

Lorsque vous exécutez cet exemple bref, des informations de débogage s'affichent, suivies de la sortie de l'appel genkit.Generate(), qui est généralement un texte Markdown, comme dans l'exemple suivant:

## The Blackheart's Bounty

**A hearty stew of slow-cooked beef, spiced with rum and molasses, served in a
hollowed-out cannonball with a side of crusty bread and a dollop of tangy
pineapple salsa.**

**Description:** This dish is a tribute to the hearty meals enjoyed by pirates
on the high seas. The beef is tender and flavorful, infused with the warm spices
of rum and molasses. The pineapple salsa adds a touch of sweetness and acidity,
balancing the richness of the stew. The cannonball serving vessel adds a fun and
thematic touch, making this dish a perfect choice for any pirate-themed
adventure.

Exécutez à nouveau le script pour obtenir un résultat différent.

L'exemple de code précédent a envoyé la requête de génération au modèle par défaut, que vous avez spécifié lorsque vous avez configuré l'instance Genkit.

Vous pouvez également spécifier un modèle pour un seul appel genkit.Generate():

resp, err := genkit.Generate(ctx, g,
    ai.WithModelName("googleai/gemini-2.5-pro"),
    ai.WithPrompt("Invent a menu item for a pirate themed restaurant."),
)

Un identifiant de chaîne de modèle se présente sous la forme providerid/modelid, où l'ID du fournisseur (dans ce cas, googleai) identifie le plug-in, et l'ID du modèle est un identifiant de chaîne spécifique au plug-in pour une version spécifique d'un modèle.

Ces exemples illustrent également un point important: lorsque vous utilisez genkit.Generate() pour effectuer des appels de modèle d'IA générative, il vous suffit de transmettre une valeur différente au paramètre du modèle pour modifier le modèle que vous souhaitez utiliser. En utilisant genkit.Generate() au lieu des SDK de modèle natif, vous avez la possibilité d'utiliser plus facilement plusieurs modèles différents dans votre application et de les modifier à l'avenir.

Jusqu'à présent, vous n'avez vu que des exemples des appels genkit.Generate() les plus simples. Toutefois, genkit.Generate() fournit également une interface pour des interactions plus avancées avec les modèles génératifs, comme vous le verrez dans les sections suivantes.

Requêtes système

Certains modèles permettent de fournir une invite système, qui donne au modèle des instructions sur la façon dont vous souhaitez qu'il réponde aux messages de l'utilisateur. Vous pouvez utiliser l'invite système pour spécifier un persona que vous souhaitez que le modèle adopte, le ton de ses réponses, le format de ses réponses, etc.

Si le modèle que vous utilisez est compatible avec les invites système, vous pouvez en fournir une avec l'option WithSystem():

resp, err := genkit.Generate(ctx, g,
    ai.WithSystem("You are a food industry marketing consultant."),
    ai.WithPrompt("Invent a menu item for a pirate themed restaurant."),
)

Pour les modèles qui ne sont pas compatibles avec les requêtes système, WithSystem() les simule en modifiant la requête pour qu'elle ressemble à une requête système.

Paramètres du modèle

La fonction genkit.Generate() accepte une option WithConfig(), via laquelle vous pouvez spécifier des paramètres facultatifs qui contrôlent la façon dont le modèle génère du contenu:

resp, err := genkit.Generate(ctx, g,
    ai.WithModelName("googleai/gemini-2.0-flash"),
    ai.WithPrompt("Invent a menu item for a pirate themed restaurant."),
    ai.WithConfig(&googlegenai.GeminiConfig{
        MaxOutputTokens: 500,
        StopSequences:   ["<end>", "<fin>"],
        Temperature:     0.5,
        TopP:            0.4,
        TopK:            50,
    }),
)

Les paramètres exacts compatibles dépendent du modèle et de l'API de modèle. Toutefois, les paramètres de l'exemple précédent sont communs à presque tous les modèles. Voici une explication de ces paramètres:

Paramètres qui contrôlent la longueur de la sortie

MaxOutputTokens

Les LLM fonctionnent sur des unités appelées jetons. Un jeton est généralement mappé sur une séquence de caractères spécifique, mais ce n'est pas nécessairement le cas. Lorsque vous transmettez une requête à un modèle, l'une des premières étapes consiste à tokeniser votre chaîne de requête en une séquence de jetons. Le LLM génère ensuite une séquence de jetons à partir de l'entrée tokenisée. Enfin, la séquence de jetons est convertie à nouveau en texte, qui est votre sortie.

Le paramètre "max_output_tokens" définit simplement une limite sur le nombre de jetons à générer à l'aide du LLM. Chaque modèle utilise potentiellement un tokenizer différent, mais une bonne règle d'or est de considérer qu'un seul mot anglais est composé de deux à quatre jetons.

Comme indiqué précédemment, il est possible que certains jetons ne soient pas mappés sur des séquences de caractères. Par exemple, il existe souvent un jeton qui indique la fin de la séquence : lorsqu'un LLM génère ce jeton, il cesse de générer d'autres jetons. Par conséquent, il est possible et souvent le cas qu'un LLM génère moins de jetons que le maximum, car il a généré le jeton "stop".

StopSequences

Vous pouvez utiliser ce paramètre pour définir les jetons ou les séquences de jetons qui, lorsqu'ils sont générés, indiquent la fin de la sortie LLM. Les valeurs correctes à utiliser ici dépendent généralement de la façon dont le modèle a été entraîné et sont généralement définies par le plug-in du modèle. Toutefois, si vous avez demandé au modèle de générer une autre séquence d'arrêt, vous pouvez la spécifier ici.

Notez que vous spécifiez des séquences de caractères, et non des jetons en tant que tels. Dans la plupart des cas, vous spécifiez une séquence de caractères que le tokenizer du modèle mappe à un seul jeton.

Paramètres qui contrôlent la "créativité"

Les paramètres température, top-p et top-k contrôlent ensemble le niveau de créativité que vous souhaitez pour le modèle. Vous trouverez ci-dessous une brève explication de la signification de ces paramètres. Toutefois, le point le plus important à retenir est le suivant: ces paramètres servent à ajuster le caractère de la sortie d'un LLM. Les valeurs optimales pour ces paramètres dépendent de vos objectifs et de vos préférences, et ne peuvent être déterminées qu'à l'aide de tests.

Température

Les LLM sont fondamentalement des machines de prédiction de jetons. Pour une séquence de jetons donnée (comme la requête), un LLM prédit, pour chaque jeton de son vocabulaire, la probabilité que le jeton soit le suivant dans la séquence. La température est un facteur de mise à l'échelle par lequel ces prédictions sont divisées avant d'être normalisées pour obtenir une probabilité comprise entre 0 et 1.

Les valeurs de température basse (entre 0,0 et 1,0) amplifient la différence de probabilités entre les jetons, ce qui fait que le modèle est encore moins susceptible de produire un jeton qu'il a déjà évalué comme peu probable. Cela est souvent perçu comme un résultat moins créatif. Bien que 0, 0 ne soit techniquement pas une valeur valide, de nombreux modèles le considèrent comme indiquant que le modèle doit se comporter de manière déterministe et ne prendre en compte que le jeton le plus probable.

Les valeurs de température élevée (supérieures à 1,0) compressent les différences de probabilités entre les jetons, ce qui augmente la probabilité que le modèle produise des jetons qu'il avait précédemment évalués comme peu probables. Cela est souvent perçu comme un résultat plus créatif. Certaines API de modèle imposent une température maximale, souvent 2,0.

TopP

Top-p est une valeur comprise entre 0,0 et 1,0 qui contrôle le nombre de jetons possibles que vous souhaitez que le modèle prenne en compte, en spécifiant la probabilité cumulée des jetons. Par exemple, une valeur de 1,0 signifie que vous devez prendre en compte tous les jetons possibles (mais toujours en tenant compte de la probabilité de chaque jeton). Une valeur de 0,4 signifie que seuls les jetons les plus probables, dont les probabilités s'additionnent à 0,4, sont pris en compte, et que les jetons restants sont exclus.

TopK

Top-k est une valeur entière qui contrôle également le nombre de jetons possibles que vous souhaitez que le modèle prenne en compte, mais cette fois en spécifiant explicitement le nombre maximal de jetons. Spécifier une valeur de 1 signifie que le modèle doit se comporter de manière déterministe.

Tester les paramètres du modèle

Vous pouvez tester l'effet de ces paramètres sur la sortie générée par différentes combinaisons de modèle et d'invite à l'aide de l'UI du développeur. Démarrez l'interface utilisateur du développeur avec la commande genkit start. Elle chargera automatiquement tous les modèles définis par les plug-ins configurés dans votre projet. Vous pouvez rapidement essayer différentes invites et valeurs de configuration sans avoir à effectuer ces modifications à plusieurs reprises dans le code.

Associer le modèle à sa configuration

Étant donné que chaque fournisseur ou même un modèle spécifique peut avoir son propre schéma de configuration ou nécessiter certains paramètres, il peut être sujet à des erreurs de définir des options distinctes à l'aide de WithModelName() et WithConfig(), car ce dernier n'est pas fortement typé par rapport au premier.

Pour associer un modèle à sa configuration, vous pouvez créer une référence de modèle que vous pouvez transmettre à l'appel de génération à la place:

model := googlegenai.GoogleAIModelRef("gemini-2.0-flash", &googlegenai.GeminiConfig{
    MaxOutputTokens: 500,
    StopSequences:   ["<end>", "<fin>"],
    Temperature:     0.5,
    TopP:            0.4,
    TopK:            50,
})

resp, err := genkit.Generate(ctx, g,
    ai.WithModel(model),
    ai.WithPrompt("Invent a menu item for a pirate themed restaurant."),
)
if err != nil {
    log.Fatal(err)
}

Le constructeur de la référence du modèle s'assurera que le type de configuration approprié est fourni, ce qui peut réduire les incohérences.

Sortie structurée

Lorsque vous utilisez l'IA générative comme composant dans votre application, vous souhaitez souvent obtenir une sortie dans un format autre que le texte brut. Même si vous ne générez que du contenu à afficher à l'utilisateur, vous pouvez bénéficier d'une sortie structurée simplement pour le présenter de manière plus attrayante. Toutefois, pour les applications plus avancées de l'IA générative, telles que l'utilisation programmatique de la sortie du modèle ou l'alimentation de la sortie d'un modèle dans un autre, une sortie structurée est indispensable.

Dans Genkit, vous pouvez demander une sortie structurée à partir d'un modèle en spécifiant un type de sortie lorsque vous appelez genkit.Generate():

type MenuItem struct {
    Name        string   `json:"name"`
    Description string   `json:"description"`
    Calories    int      `json:"calories"`
    Allergens   []string `json:"allergens"`
}

resp, err := genkit.Generate(ctx, g,
    ai.WithPrompt("Invent a menu item for a pirate themed restaurant."),
    ai.WithOutputType(MenuItem{}),
)
if err != nil {
  log.Fatal(err) // One possible error is that the response does not conform to the type.
}

Les types de sortie du modèle sont spécifiés sous forme de schéma JSON à l'aide du package invopop/jsonschema. Cela fournit une vérification de type d'exécution, qui comble l'écart entre les types Go statiques et la sortie imprévisible des modèles d'IA générative. Ce système vous permet d'écrire du code qui peut s'appuyer sur le fait qu'un appel de génération réussi renverra toujours une sortie conforme à vos types Go.

Lorsque vous spécifiez un type de sortie dans genkit.Generate(), Genkit effectue plusieurs opérations en coulisses:

  • Ajoute des instructions supplémentaires sur le format de sortie souhaité. Cela a également pour effet secondaire de spécifier au modèle le contenu exact que vous souhaitez générer (par exemple, non seulement suggérer un élément de menu, mais aussi générer une description, une liste d'allergènes, etc.).
  • Vérifie que la sortie est conforme au schéma.
  • Convertit la sortie du modèle en type Go.

Pour obtenir une sortie structurée à partir d'un appel de génération réussi, appelez Output() sur la réponse du modèle avec une valeur vide de type:

var item MenuItem
if err := resp.Output(&item); err != nil {
    log.Fatalf(err)
}

log.Printf("%s (%d calories, %d allergens): %s\n",
    item.Name, item.Calories, len(item.Allergens), item.Description)

Vous pouvez également utiliser genkit.GenerateData() pour un appel plus succinct:

item, resp, err := genkit.GenerateData[MenuItem](ctx, g,
    ai.WithPrompt("Invent a menu item for a pirate themed restaurant."),
)
if err != nil {
  log.Fatal(err)
}

log.Printf("%s (%d calories, %d allergens): %s\n",
    item.Name, item.Calories, len(item.Allergens), item.Description)

Cette fonction nécessite le paramètre de type de sortie, mais définit automatiquement l'option WithOutputType() et appelle resp.Output() avant de renvoyer la valeur.

Traiter les erreurs

Notez dans l'exemple précédent que l'appel genkit.Generate() peut entraîner une erreur. Une erreur peut se produire lorsque le modèle ne parvient pas à générer une sortie conforme au schéma. La meilleure stratégie pour gérer ces erreurs dépend de votre cas d'utilisation exact, mais voici quelques conseils généraux:

  • Essayez un autre modèle. Pour que la sortie structurée aboutisse, le modèle doit être capable de générer une sortie au format JSON. Les LLM les plus puissants, comme Gemini, sont suffisamment polyvalents pour ce faire. Toutefois, les modèles plus petits, comme certains des modèles locaux que vous utiliseriez avec Ollama, ne pourront peut-être pas générer de sortie structurée de manière fiable, sauf s'ils ont été spécifiquement entraînés pour ce faire.

  • Simplifiez le schéma. Les LLM peuvent avoir du mal à générer des types complexes ou profondément imbriqués. Essayez d'utiliser des noms clairs, moins de champs ou une structure plate si vous ne parvenez pas à générer des données structurées de manière fiable.

  • Réessayez l'appel genkit.Generate(). Si le modèle que vous avez choisi ne parvient que rarement à générer une sortie conforme, vous pouvez traiter l'erreur comme vous le feriez pour une erreur réseau, et simplement relancer la requête à l'aide d'une stratégie d'intervalle exponentiel entre les tentatives.

Streaming

Lorsque vous générez de grandes quantités de texte, vous pouvez améliorer l'expérience pour vos utilisateurs en présentant la sortie au fur et à mesure de sa génération (streaming de la sortie). Un exemple familier de streaming en action peut être observé dans la plupart des applications de chat LLM: les utilisateurs peuvent lire la réponse du modèle à leur message au fur et à mesure de sa génération, ce qui améliore la réactivité perçue de l'application et renforce l'illusion de discuter avec un homologue intelligent.

Dans Genkit, vous pouvez diffuser la sortie à l'aide de l'option WithStreaming():

resp, err := genkit.Generate(ctx, g,
    ai.WithPrompt("Suggest a complete menu for a pirate themed restaurant."),
    ai.WithStreaming(func(ctx context.Context, chunk *ai.ModelResponseChunk) error {
        // Do something with the chunk...
        log.Println(chunk.Text())
        return nil
    }),
)
if err != nil {
    log.Fatal(err)
}

log.Println(resp.Text())

Entrée multimodale

Les exemples que vous avez vus jusqu'à présent utilisaient des chaînes de texte comme requêtes du modèle. Bien que ce soit le moyen le plus courant d'inviter des modèles d'IA générative, de nombreux modèles peuvent également accepter d'autres supports comme des requêtes. Les requêtes multimédias sont le plus souvent utilisées avec des requêtes textuelles qui indiquent au modèle d'effectuer une opération sur le contenu multimédia, par exemple pour ajouter des sous-titres à une image ou transcrire un enregistrement audio.

La possibilité d'accepter des entrées multimédias et les types de contenus multimédias que vous pouvez utiliser dépendent entièrement du modèle et de son API. Par exemple, la série de modèles Gemini 2.0 peut accepter des images, des vidéos et des contenus audio comme requêtes.

Pour fournir une requête multimédia à un modèle qui la prend en charge, au lieu de transmettre une requête textuelle simple à genkit.Generate(), transmettez un tableau composé d'une partie multimédia et d'une partie textuelle:

resp, err := genkit.Generate(ctx, g,
    ai.WithModelName("googleai/gemini-2.0-flash"),
    ai.WithMessages(
        NewUserMessage(
            NewMediaPart("image/jpeg", "https://example.com/photo.jpg"),
            NewTextPart("Compose a poem about this image."),
        ),
    ),
)

Dans l'exemple ci-dessus, vous avez spécifié une image à l'aide d'une URL HTTPS accessible au public. Vous pouvez également transmettre des données multimédias directement en les encodant en tant qu'URL de données. Exemple :

image, err := ioutil.ReadFile("photo.jpg")
if err != nil {
    log.Fatal(err)
}

resp, err := genkit.Generate(ctx, g,
    ai.WithModelName("googleai/gemini-2.0-flash"),
    ai.WithMessages(
        NewUserMessage(
            NewMediaPart("image/jpeg", "data:image/jpeg;base64," + base64.StdEncoding.EncodeToString(image)),
            NewTextPart("Compose a poem about this image."),
        ),
    ),
)

Tous les modèles compatibles avec l'entrée multimédia acceptent à la fois les URL de données et les URL HTTPS. Certains plug-ins de modèle sont compatibles avec d'autres sources multimédias. Par exemple, le plug-in Vertex AI vous permet également d'utiliser des URL Cloud Storage (gs://).

Étapes suivantes

En savoir plus sur Genkit

  • En tant que développeur d'applications, le principal moyen d'influencer les résultats des modèles d'IA générative est de les inviter à effectuer des actions. Consultez Gérer les requêtes avec Dotprompt pour découvrir comment Genkit vous aide à développer des requêtes efficaces et à les gérer dans votre base de code.
  • Bien que genkit.Generate() soit le noyau de chaque application optimisée par l'IA générative, les applications du monde réel nécessitent généralement des tâches supplémentaires avant et après l'appel d'un modèle d'IA générative. Pour refléter cela, Genkit introduit le concept de flux, qui sont définis comme des fonctions, mais qui ajoutent des fonctionnalités supplémentaires telles que l'observabilité et le déploiement simplifié. Pour en savoir plus, consultez la section Définir des workflows d'IA.

Utilisation avancée du LLM

  • Pour améliorer les fonctionnalités des LLM, vous pouvez leur fournir une liste de façons de vous demander des informations supplémentaires ou de vous demander d'effectuer une action. C'est ce qu'on appelle l'appel d'outil ou l'appel de fonction. Les modèles entraînés pour prendre en charge cette fonctionnalité peuvent répondre à une invite avec une réponse au format spécial, qui indique à l'application appelante qu'elle doit effectuer une action et renvoyer le résultat au LLM avec l'invite d'origine. Genkit dispose de fonctions de bibliothèque qui automatisent à la fois la génération d'invites et les éléments de boucle d'appel-réponse d'une implémentation d'appel d'outil. Pour en savoir plus, consultez la section Appel d'outils.
  • La génération augmentée de récupération (RAG) est une technique utilisée pour introduire des informations spécifiques au domaine dans la sortie d'un modèle. Pour ce faire, insérez les informations pertinentes dans une invite avant de les transmettre au modèle de langage. Une implémentation complète du RAG nécessite de combiner plusieurs technologies: modèles de génération d'embeddings textuels, bases de données vectorielles et grands modèles de langage. Consultez la page Génération augmentée par récupération (RAG) pour découvrir comment Genkit simplifie la coordination de ces différents éléments.