Sortie structurée

Vous pouvez configurer Gemini pour obtenir une sortie structurée plutôt qu'un texte non structuré, ce qui permet d'extraire et de normaliser précisément les informations pour un traitement ultérieur. Par exemple, vous pouvez utiliser une sortie structurée pour extraire des informations de CV, les normaliser afin de créer une base de données structurée.

Gemini peut générer du JSON ou des valeurs d'énumération en tant que sortie structurée.

Générer un fichier JSON

Il existe deux façons de générer du code JSON à l'aide de l'API Gemini:

  • Configurer un schéma sur le modèle
  • Fournir un schéma dans une requête textuelle

La configuration d'un schéma sur le modèle est la méthode recommandée pour générer du JSON, car elle contraint le modèle à générer du JSON.

Configurer un schéma (recommandé)

Pour contraindre le modèle à générer du code JSON, configurez un responseSchema. Le modèle répondra ensuite à toute requête avec une sortie au format JSON.

from google import genai
from pydantic import BaseModel

class Recipe(BaseModel):
    recipe_name: str
    ingredients: list[str]

client = genai.Client(api_key="GOOGLE_API_KEY")
response = client.models.generate_content(
    model="gemini-2.0-flash",
    contents="List a few popular cookie recipes, and include the amounts of ingredients.",
    config={
        "response_mime_type": "application/json",
        "response_schema": list[Recipe],
    },
)
# Use the response as a JSON string.
print(response.text)

# Use instantiated objects.
my_recipes: list[Recipe] = response.parsed
import { GoogleGenAI, Type } from "@google/genai";

const ai = new GoogleGenAI({ "GOOGLE_API_KEY" });

async function main() {
  const response = await ai.models.generateContent({
    model: "gemini-2.0-flash",
    contents:
      "List a few popular cookie recipes, and include the amounts of ingredients.",
    config: {
      responseMimeType: "application/json",
      responseSchema: {
        type: Type.ARRAY,
        items: {
          type: Type.OBJECT,
          properties: {
            recipeName: {
              type: Type.STRING,
            },
            ingredients: {
              type: Type.ARRAY,
              items: {
                type: Type.STRING,
              },
            },
          },
          propertyOrdering: ["recipeName", "ingredients"],
        },
      },
    },
  });

  console.log(response.text);
}

main();
package main

import (
    "context"
    "fmt"
    "log"

    "google.golang.org/genai"
)

func main() {
    ctx := context.Background()
    client, err := genai.NewClient(ctx, &genai.ClientConfig{
        APIKey:  "GOOGLE_API_KEY",
        Backend: genai.BackendGeminiAPI,
    })
    if err != nil {
        log.Fatal(err)
    }

    config := &genai.GenerateContentConfig{
        ResponseMIMEType: "application/json",
        ResponseSchema: &genai.Schema{
            Type: genai.TypeArray,
            Items: &genai.Schema{
                Type: genai.TypeObject,
                Properties: map[string]*genai.Schema{
                    "recipeName": {Type: genai.TypeString},
                    "ingredients": {
                        Type:  genai.TypeArray,
                        Items: &genai.Schema{Type: genai.TypeString},
                    },
                },
                PropertyOrdering: []string{"recipeName", "ingredients"},
            },
        },
    }

    result, err := client.Models.GenerateContent(
        ctx,
        "gemini-2.0-flash",
        genai.Text("List a few popular cookie recipes, and include the amounts of ingredients."),
        config,
    )
    if err != nil {
        log.Fatal(err)
    }
    fmt.Println(result.Text())
}
curl "https://generativelanguage.googleapis.com/v1beta/models/gemini-2.0-flash:generateContent?key=$GOOGLE_API_KEY" \
-H 'Content-Type: application/json' \
-d '{
      "contents": [{
        "parts":[
          { "text": "List a few popular cookie recipes, and include the amounts of ingredients." }
        ]
      }],
      "generationConfig": {
        "responseMimeType": "application/json",
        "responseSchema": {
          "type": "ARRAY",
          "items": {
            "type": "OBJECT",
            "properties": {
              "recipeName": { "type": "STRING" },
              "ingredients": {
                "type": "ARRAY",
                "items": { "type": "STRING" }
              }
            },
            "propertyOrdering": ["recipeName", "ingredients"]
          }
        }
      }
}' 2> /dev/null | head

Le résultat peut ressembler à ceci:

[
  {
    "recipeName": "Chocolate Chip Cookies",
    "ingredients": [
      "1 cup (2 sticks) unsalted butter, softened",
      "3/4 cup granulated sugar",
      "3/4 cup packed brown sugar",
      "1 teaspoon vanilla extract",
      "2 large eggs",
      "2 1/4 cups all-purpose flour",
      "1 teaspoon baking soda",
      "1 teaspoon salt",
      "2 cups chocolate chips"
    ]
  },
  ...
]

Fournir un schéma dans une requête textuelle

Au lieu de configurer un schéma, vous pouvez fournir un schéma en langage naturel ou en pseudo-code dans une invite de texte. Cette méthode n'est pas recommandée, car elle peut produire une sortie de moins bonne qualité et parce que le modèle n'est pas contraint de suivre le schéma.

Voici un exemple générique de schéma fourni dans une requête textuelle:

List a few popular cookie recipes, and include the amounts of ingredients.

Produce JSON matching this specification:

Recipe = { "recipeName": string, "ingredients": array<string> }
Return: array<Recipe>

Étant donné que le modèle obtient le schéma à partir du texte de l'invite, vous pouvez avoir une certaine flexibilité dans la façon de représenter le schéma. Toutefois, lorsque vous fournissez un schéma intégré comme celui-ci, le modèle n'est pas contraint de renvoyer du JSON. Pour une réponse plus déterministe et de meilleure qualité, configurez un schéma sur le modèle et ne dupliquez pas le schéma dans la requête textuelle.

Générer des valeurs d'énumération

Dans certains cas, vous pouvez souhaiter que le modèle ne choisisse qu'une seule option parmi une liste. Pour implémenter ce comportement, vous pouvez transmettre une énumération dans votre schéma. Vous pouvez utiliser une option d'énumération partout où vous pouvez utiliser un string dans le responseSchema, car une énumération est un tableau de chaînes. Comme un schéma JSON, un énumérateur vous permet de contraindre la sortie du modèle pour répondre aux exigences de votre application.

Par exemple, supposons que vous développiez une application permettant de classer les instruments de musique dans l'une des cinq catégories suivantes: "Percussion", "String", "Woodwind", "Brass" ou ""Keyboard"". Vous pouvez créer une énumération pour vous aider dans cette tâche.

Dans l'exemple suivant, vous transmettez un énumération en tant que responseSchema, ce qui contraint le modèle à choisir l'option la plus appropriée.

Python
from google import genai
import enum

class Instrument(enum.Enum):
  PERCUSSION = "Percussion"
  STRING = "String"
  WOODWIND = "Woodwind"
  BRASS = "Brass"
  KEYBOARD = "Keyboard"

client = genai.Client(api_key="GEMINI_API_KEY")
response = client.models.generate_content(
    model='gemini-2.0-flash',
    contents='What type of instrument is an oboe?',
    config={
        'response_mime_type': 'text/x.enum',
        'response_schema': Instrument,
    },
)

print(response.text)
# Woodwind

La bibliothèque Python traduit les déclarations de type pour l'API. Toutefois, l'API accepte un sous-ensemble du schéma OpenAPI 3.0 (Schéma).

Il existe deux autres façons de spécifier une énumération. Vous pouvez utiliser un Literal:

Python
Literal["Percussion", "String", "Woodwind", "Brass", "Keyboard"]

Vous pouvez également transmettre le schéma au format JSON:

Python
from google import genai

client = genai.Client(api_key="GEMINI_API_KEY")
response = client.models.generate_content(
    model='gemini-2.0-flash',
    contents='What type of instrument is an oboe?',
    config={
        'response_mime_type': 'text/x.enum',
        'response_schema': {
            "type": "STRING",
            "enum": ["Percussion", "String", "Woodwind", "Brass", "Keyboard"],
        },
    },
)

print(response.text)
# Woodwind

En plus des problèmes de choix multiples de base, vous pouvez utiliser une énumération n'importe où dans un schéma JSON. Par exemple, vous pouvez demander au modèle une liste de titres de recettes et utiliser une énumération Grade pour attribuer à chaque titre un niveau de popularité:

Python
from google import genai

import enum
from pydantic import BaseModel

class Grade(enum.Enum):
    A_PLUS = "a+"
    A = "a"
    B = "b"
    C = "c"
    D = "d"
    F = "f"

class Recipe(BaseModel):
  recipe_name: str
  rating: Grade

client = genai.Client(api_key="GEMINI_API_KEY")
response = client.models.generate_content(
    model='gemini-2.0-flash',
    contents='List 10 home-baked cookie recipes and give them grades based on tastiness.',
    config={
        'response_mime_type': 'application/json',
        'response_schema': list[Recipe],
    },
)

print(response.text)

La réponse peut ressembler à ceci:

[
  {
    "recipe_name": "Chocolate Chip Cookies",
    "rating": "a+"
  },
  {
    "recipe_name": "Peanut Butter Cookies",
    "rating": "a"
  },
  {
    "recipe_name": "Oatmeal Raisin Cookies",
    "rating": "b"
  },
  ...
]

À propos des schémas JSON

La configuration du modèle pour la sortie JSON à l'aide du paramètre responseSchema repose sur l'objet Schema pour définir sa structure. Cet objet représente un sous-ensemble spécifique de l'objet de schéma OpenAPI 3.0 et ajoute également un champ propertyOrdering.

Voici une représentation pseudo-JSON de tous les champs Schema:

{
  "type": enum (Type),
  "format": string,
  "description": string,
  "nullable": boolean,
  "enum": [
    string
  ],
  "maxItems": integer,
  "minItems": integer,
  "properties": {
    string: {
      object (Schema)
    },
    ...
  },
  "required": [
    string
  ],
  "propertyOrdering": [
    string
  ],
  "items": {
    object (Schema)
  }
}

Le Type du schéma doit être l'un des types de données OpenAPI ou une union de ces types (à l'aide de anyOf). Seul un sous-ensemble de champs est valide pour chaque Type. La liste suivante met en correspondance chaque Type avec un sous-ensemble des champs valides pour ce type:

  • string -> enum, format, nullable
  • integer -> format, minimum, maximum, enum, nullable
  • number -> format, minimum, maximum, enum, nullable
  • boolean -> nullable
  • array -> minItems, maxItems, items, nullable
  • object -> properties, required, propertyOrdering, nullable

Voici quelques exemples de schémas illustrant des combinaisons de type et de champ valides:

{ "type": "string", "enum": ["a", "b", "c"] }

{ "type": "string", "format": "date-time" }

{ "type": "integer", "format": "int64" }

{ "type": "number", "format": "double" }

{ "type": "boolean" }

{ "type": "array", "minItems": 3, "maxItems": 3, "items": { "type": ... } }

{ "type": "object",
  "properties": {
    "a": { "type": ... },
    "b": { "type": ... },
    "c": { "type": ... }
  },
  "nullable": true,
  "required": ["c"],
  "propertyOrdering": ["c", "b", "a"]
}

Pour obtenir une documentation complète sur les champs de schéma tels qu'ils sont utilisés dans l'API Gemini, consultez la référence du schéma.

Commande de propriétés

Lorsque vous travaillez avec des schémas JSON dans l'API Gemini, l'ordre des propriétés est important. Par défaut, l'API trie les propriétés par ordre alphabétique et ne conserve pas l'ordre dans lequel elles sont définies (bien que les SDK Google Gen AI puissent conserver cet ordre). Si vous fournissez des exemples au modèle avec un schéma configuré et que l'ordre des propriétés des exemples n'est pas cohérent avec l'ordre des propriétés du schéma, la sortie peut être décousue ou inattendue.

Pour garantir un classement cohérent et prévisible des propriétés, vous pouvez utiliser le champ propertyOrdering[] facultatif.

"propertyOrdering": ["recipeName", "ingredients"]

propertyOrdering[] (qui n'est pas un champ standard dans la spécification OpenAPI) est un tableau de chaînes utilisé pour déterminer l'ordre des propriétés dans la réponse. En spécifiant l'ordre des propriétés, puis en fournissant des exemples avec des propriétés dans cet ordre, vous pouvez potentiellement améliorer la qualité des résultats. propertyOrdering n'est compatible que lorsque vous créez manuellement types.Schema.

Schémas en Python

Lorsque vous utilisez la bibliothèque Python, la valeur de response_schema doit être l'une des suivantes:

  • Un type, comme vous le feriez dans une annotation de type (voir le module typing Python)
  • Instance de genai.types.Schema
  • Équivalent dict de genai.types.Schema

Le moyen le plus simple de définir un schéma consiste à utiliser un type Pydantic (comme illustré dans l'exemple précédent):

Python
config={'response_mime_type': 'application/json',
        'response_schema': list[Recipe]}

Lorsque vous utilisez un type Pydantic, la bibliothèque Python crée un schéma JSON pour vous et l'envoie à l'API. Pour obtenir d'autres exemples, consultez la documentation de la bibliothèque Python.

La bibliothèque Python est compatible avec les schémas définis avec les types suivants (AllowedType étant un type autorisé):

  • int
  • float
  • bool
  • str
  • list[AllowedType]
  • AllowedType|AllowedType|...
  • Pour les types structurés :
    • dict[str, AllowedType]. Cette annotation déclare que toutes les valeurs du dictionnaire sont du même type, mais ne spécifie pas les clés à inclure.
    • Modèles Pydantic définis par l'utilisateur. Cette approche vous permet de spécifier les noms de clé et de définir différents types pour les valeurs associées à chacune des clés, y compris les structures imbriquées.

Bonnes pratiques

Tenez compte des considérations et des bonnes pratiques suivantes lorsque vous utilisez un schéma de réponse:

  • La taille de votre schéma de réponse est comptabilisée dans la limite des jetons d'entrée.
  • Par défaut, les champs sont facultatifs, ce qui signifie que le modèle peut les renseigner ou les ignorer. Vous pouvez définir les champs selon vos besoins pour forcer le modèle à fournir une valeur. Si le contexte de la requête d'entrée associée est insuffisant, le modèle génère des réponses principalement basées sur les données sur lesquelles il a été entraîné.
  • Un schéma complexe peut entraîner une erreur InvalidArgument: 400. La complexité peut provenir de noms de propriétés longs, de limites de longueur de tableau longues, d'énumérations avec de nombreuses valeurs, d'objets avec de nombreuses propriétés facultatives ou d'une combinaison de ces facteurs.

    Si vous rencontrez cette erreur avec un schéma valide, effectuez une ou plusieurs des modifications suivantes pour résoudre le problème:

    • Raccourcissez les noms de propriétés ou d'énumérations.
    • Aplatissez les tableaux imbriqués.
    • Réduisez le nombre de propriétés avec des contraintes, telles que les nombres avec des limites minimales et maximales.
    • Réduisez le nombre de propriétés avec des contraintes complexes, telles que les propriétés avec des formats complexes comme date-time.
    • Réduisez le nombre de propriétés facultatives.
    • Réduire le nombre de valeurs valides pour les énumérations
  • Si les résultats ne sont pas ceux escomptés, ajoutez plus de contexte à vos requêtes d'entrée ou modifiez votre schéma de réponse. Par exemple, examinez la réponse du modèle sans sortie structurée pour voir comment le modèle réagit. Vous pouvez ensuite mettre à jour le schéma de réponse afin qu'il corresponde mieux à la sortie du modèle.

Étape suivante

Maintenant que vous avez appris à générer une sortie structurée, vous pouvez essayer d'utiliser les outils de l'API Gemini: