Resultados estructurados

De forma predeterminada, Gemini genera texto no estructurado, pero puedes restringir el modelo para que responda con un resultado estructurado, ya sea JSON o un valor de una enumeración. Esta función de salida estructurada es particularmente útil cuando necesitas extraer información de datos no estructurados y, luego, procesarla para que la consuma una aplicación. Por ejemplo, puedes usar la función para extraer información estandarizada de los currículums y, luego, crear una base de datos con esa información. También puedes extraer ingredientes de las recetas y mostrar un vínculo a un sitio web de venta de comestibles para cada ingrediente.

En esta guía, se muestra cómo generar resultados estructurados con la API de Gemini.

Cómo generar JSON

Existen dos maneras de generar JSON con la API de Gemini:

  • Configura un esquema en el modelo
  • Proporciona un esquema en una instrucción de texto

La configuración de un esquema en el modelo es la forma recomendada de generar JSON, porque limita el modelo para que genere JSON.

Cómo configurar un esquema

Para restringir el modelo para que genere JSON, configura un responseSchema. Luego, el modelo responderá a cualquier instrucción con una salida en formato 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

El resultado podría verse de la siguiente manera:

[
  {
    "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"
    ]
  },
  ...
]

Proporciona un esquema en una instrucción de texto

En lugar de configurar un esquema, puedes proporcionar uno como lenguaje natural o pseudcódigo en una instrucción de texto. No se recomienda este método, ya que podría producir resultados de menor calidad y porque el modelo no está limitado a seguir el esquema.

Este es un ejemplo genérico de un esquema proporcionado en una instrucción de texto:

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>

Dado que el modelo obtiene el esquema del texto en la instrucción, es posible que tengas cierta flexibilidad en la forma en que representas el esquema. Sin embargo, cuando proporcionas un esquema intercalado como este, el modelo no está limitado a mostrar JSON. Para obtener una respuesta más determinista y de mejor calidad, configura un esquema en el modelo y no lo dupliques en la instrucción de texto.

Esquemas de JSON

Cuando configuras el modelo para que devuelva una respuesta JSON, usas un objeto Schema para definir la forma de los datos JSON. Schema representa un subconjunto selecto del objeto de esquema de OpenAPI 3.0 y también agrega un campo propertyOrdering.

Esta es una representación pseudo-JSON de todos los campos 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)
  }
}

El Type del esquema debe ser uno de los tipos de datos de OpenAPI o una unión de esos tipos (con anyOf). Solo un subconjunto de campos es válido para cada Type. En la siguiente lista, se asigna cada Type a un subconjunto de los campos que son válidos para ese tipo:

  • 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

Estos son algunos ejemplos de esquemas que muestran combinaciones válidas de tipo y campo:

{ "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"]
}

Para obtener la documentación completa de los campos del esquema tal como se usan en la API de Gemini, consulta la referencia del esquema.

Ordenamiento de propiedades

Cuando trabajas con esquemas JSON en la API de Gemini, el orden de las propiedades es importante. De forma predeterminada, la API ordena las propiedades alfabéticamente y no conserva el orden en el que se definen (aunque los SDKs de Google Gen AI pueden conservar este orden). Si proporcionas ejemplos al modelo con un esquema configurado y el orden de las propiedades de los ejemplos no es coherente con el orden de las propiedades del esquema, el resultado podría ser incoherente o inesperado.

Para garantizar un orden coherente y predecible de las propiedades, puedes usar el campo opcional propertyOrdering[].

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

propertyOrdering[], que no es un campo estándar en la especificación de OpenAPI, es un array de cadenas que se usa para determinar el orden de las propiedades en la respuesta. Si especificas el orden de las propiedades y, luego, proporcionas ejemplos con propiedades en ese mismo orden, es posible que mejores la calidad de los resultados. propertyOrdering solo se admite cuando creas types.Schema de forma manual.

Esquemas en Python

En esta sección, se proporciona orientación adicional para trabajar con esquemas JSON con la biblioteca de Python.

Cuando usas la biblioteca de Python, el valor de response_schema debe ser uno de los siguientes:

  • Un tipo, como lo usarías en una anotación de tipo (consulta el módulo typing de Python)
  • Una instancia de genai.types.Schema
  • El equivalente dict de genai.types.Schema

La forma más sencilla de definir un esquema es con un tipo Pydantic (como se muestra en el ejemplo anterior):

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

Cuando usas un tipo Pydantic, la biblioteca de Python compila un esquema JSON por ti y lo envía a la API. Para obtener más ejemplos, consulta la documentación de la biblioteca de Python.

La biblioteca de Python admite esquemas definidos con los siguientes tipos (en los que AllowedType es cualquier tipo permitido):

  • int
  • float
  • bool
  • str
  • list[AllowedType]
  • AllowedType|AllowedType|...
  • Para tipos estructurados:
    • dict[str, AllowedType]. Esta anotación declara que todos los valores del diccionario son del mismo tipo, pero no especifica qué claves se deben incluir.
    • Modelos de Pydantic definidos por el usuario Este enfoque te permite especificar los nombres de las claves y definir diferentes tipos para los valores asociados con cada una de las claves, incluidas las estructuras anidadas.

Cómo generar valores de enum

En algunos casos, es posible que desees que el modelo elija una sola opción de una lista de opciones. Para implementar este comportamiento, puedes pasar una enum en tu esquema. Puedes usar una opción de enumeración en cualquier lugar en el que puedas usar un string en responseSchema, ya que una enumeración es un array de cadenas. Al igual que un esquema JSON, una enumeración te permite restringir el resultado del modelo para que cumpla con los requisitos de tu aplicación.

Por ejemplo, supongamos que estás desarrollando una aplicación para clasificar los instrumentos musicales en una de cinco categorías: "Percussion", "String", "Woodwind", "Brass" o “"Keyboard"”. Podrías crear una enumeración para ayudar con esta tarea.

En el siguiente ejemplo, pasas una enumeración como responseSchema, lo que restringe el modelo para que elija la opción más apropiada.

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 biblioteca de Python traducirá las declaraciones de tipo para la API. Sin embargo, la API acepta un subconjunto del esquema de OpenAPI 3.0 (esquema).

Existen otras dos formas de especificar una enumeración. Puedes usar un Literal:

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

También puedes pasar el esquema como 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

Además de los problemas básicos de opción múltiple, puedes usar una enumeración en cualquier parte de un esquema JSON. Por ejemplo, puedes pedirle al modelo una lista de títulos de recetas y usar una enumeración Grade para asignarle a cada título una calificación de popularidad:

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 respuesta podría ser similar a la siguiente:

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

Consideraciones

Ten en cuenta las siguientes consideraciones y prácticas recomendadas cuando uses un esquema de respuesta:

  • El tamaño del esquema de respuesta se considera para el límite de tokens de entrada.
  • De forma predeterminada, los campos son opcionales, lo que significa que el modelo puede propagarlos o omitarlos. Puedes configurar los campos según sea necesario para forzar al modelo a proporcionar un valor. Si no hay suficiente contexto en la instrucción de entrada asociada, el modelo genera respuestas principalmente en función de los datos con los que se entrenó.
  • Un esquema complejo puede generar un error InvalidArgument: 400. La complejidad puede provenir de nombres de propiedades largos, límites de longitud de array largos, enums con muchos valores, objetos con muchas propiedades opcionales o una combinación de estos factores.

    Si recibes este error con un esquema válido, realiza uno o más de los siguientes cambios para resolverlo:

    • Acorta los nombres de las propiedades o enums.
    • Compacta los arrays anidados.
    • Reduce la cantidad de propiedades con restricciones, como números con límites mínimos y máximos.
    • Reduce la cantidad de propiedades con restricciones complejas, como las propiedades con formatos complejos, como date-time.
    • Reduce la cantidad de propiedades opcionales.
    • Reduce la cantidad de valores válidos para las enums.
  • Si no ves los resultados que esperas, agrega más contexto a tus instrucciones de entrada o revisa tu esquema de respuesta. Por ejemplo, revisa la respuesta del modelo sin resultado estructurado para ver cómo responde. Luego, puedes actualizar el esquema de respuesta para que se adapte mejor al resultado del modelo.

¿Qué sigue?

Ahora que aprendiste a generar resultados estructurados, te recomendamos que pruebes las siguientes herramientas de la API de Gemini: