Saída estruturada

Por padrão, o Gemini gera texto não estruturado, mas você pode restringir o modelo para responder com saída estruturada, seja JSON ou um valor de um tipo enumerado. Esse recurso de saída estruturada é particularmente útil quando você precisa extrair informações de dados não estruturados e processá-las para consumo por um aplicativo. Por exemplo, você pode usar o recurso para extrair informações padronizadas de currículos e criar um banco de dados com essas informações. Ou você pode extrair ingredientes de receitas e mostrar um link para um site de compras de alimentos para cada ingrediente.

Este guia mostra como gerar uma saída estruturada usando a API Gemini.

Geração de JSON

Há duas maneiras de gerar JSON usando a API Gemini:

  • Configurar um esquema no modelo
  • Fornecer um esquema em um comando de texto

Configurar um esquema no modelo é a maneira recomendada de gerar JSON, porque ele restringe o modelo a gerar JSON.

Como configurar um esquema

Para restringir o modelo a gerar JSON, configure um responseSchema. O modelo vai responder a qualquer comando com saída formatada em 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

A saída pode ser semelhante a esta:

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

Como fornecer um esquema em uma solicitação de texto

Em vez de configurar um esquema, você pode fornecer um esquema como linguagem natural ou pseudocódigo em um comando de texto. Esse método não é recomendado porque pode produzir uma saída de qualidade inferior e porque o modelo não é restrito a seguir o esquema.

Confira um exemplo genérico de um esquema fornecido em uma solicitação 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>

Como o modelo recebe o esquema do texto no comando, você pode ter alguma flexibilidade na representação do esquema. No entanto, quando você fornece um esquema inline como esse, o modelo não é limitado a retornar JSON. Para uma resposta mais determinística e de melhor qualidade, configure um esquema no modelo e não duplique o esquema no comando de texto.

Esquemas JSON

Ao configurar o modelo para retornar uma resposta JSON, você usa um objeto Schema para definir a forma dos dados JSON. O Schema representa um subconjunto selecionado do objeto de esquema da OpenAPI 3.0 e também adiciona um campo propertyOrdering.

Confira uma representação pseudo-JSON de todos os 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)
  }
}

O Type do esquema precisa ser um dos tipos de dados da OpenAPI ou uma união desses tipos (usando anyOf). Apenas um subconjunto de campos é válido para cada Type. A lista a seguir mapeia cada Type para um subconjunto dos campos válidos para esse 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

Confira alguns exemplos de esquemas que mostram combinações válidas de tipo e 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 conferir a documentação completa dos campos do esquema conforme eles são usados na API Gemini, consulte a Referência do esquema.

Ordenação de propriedades

Ao trabalhar com esquemas JSON na API Gemini, a ordem das propriedades é importante. Por padrão, a API ordena as propriedades em ordem alfabética e não preserva a ordem em que as propriedades são definidas, embora os SDKs do Google Gen AI possam preservar essa ordem. Se você estiver fornecendo exemplos ao modelo com um esquema configurado e a ordem das propriedades dos exemplos não for consistente com a ordem das propriedades do esquema, a saída poderá ser incoerente ou inesperada.

Para garantir uma ordenação consistente e previsível das propriedades, use o campo propertyOrdering[] opcional.

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

propertyOrdering[], que não é um campo padrão na especificação da OpenAPI, é uma matriz de strings usada para determinar a ordem das propriedades na resposta. Ao especificar a ordem das propriedades e fornecer exemplos com propriedades nessa mesma ordem, você pode melhorar a qualidade dos resultados. O propertyOrdering só é aceito quando você cria manualmente o types.Schema.

Esquemas em Python

Esta seção oferece orientações adicionais sobre como trabalhar com esquemas JSON usando a biblioteca Python.

Ao usar a biblioteca Python, o valor de response_schema precisa ser um destes:

  • Um tipo, como você usaria em uma anotação de tipo (consulte o módulo typing do Python).
  • Uma instância de genai.types.Schema
  • O dict equivalente a genai.types.Schema

A maneira mais fácil de definir um esquema é com um tipo Pydantic (como mostrado no exemplo anterior):

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

Quando você usa um tipo Pydantic, a biblioteca Python cria um esquema JSON para você e o envia à API. Para mais exemplos, consulte os documentos da biblioteca do Python.

A biblioteca Python oferece suporte a esquemas definidos com os seguintes tipos (em que AllowedType é qualquer tipo permitido):

  • int
  • float
  • bool
  • str
  • list[AllowedType]
  • AllowedType|AllowedType|...
  • Para tipos estruturados:
    • dict[str, AllowedType]. Essa anotação declara que todos os valores do dicionário são do mesmo tipo, mas não especifica quais chaves devem ser incluídas.
    • Modelos do Pydantic definidos pelo usuário. Essa abordagem permite especificar os nomes das chaves e definir tipos diferentes para os valores associados a cada uma das chaves, incluindo estruturas aninhadas.

Como gerar valores de tipo enumerado

Em alguns casos, talvez você queira que o modelo escolha uma única opção de uma lista de opções. Para implementar esse comportamento, transmita um tipo enumerado no esquema. É possível usar uma opção de tipo enumerado em qualquer lugar em que você possa usar um string no responseSchema, porque um tipo enumerado é uma matriz de strings. Assim como um esquema JSON, um enum permite restringir a saída do modelo para atender aos requisitos do aplicativo.

Por exemplo, suponha que você esteja desenvolvendo um aplicativo para classificar instrumentos musicais em uma das cinco categorias: "Percussion", "String", "Woodwind", "Brass" ou ""Keyboard"". Você pode criar um tipo enumerado para ajudar com essa tarefa.

No exemplo abaixo, você transmite um tipo enumerado como responseSchema, restringindo o modelo para escolher a opção mais adequada.

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

A biblioteca Python vai traduzir as declarações de tipo para a API. No entanto, a API aceita um subconjunto do esquema da OpenAPI 3.0 (Esquema).

Há duas outras maneiras de especificar uma enumeração. Você pode usar um Literal:

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

Também é possível transmitir o 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

Além de problemas básicos de múltipla escolha, você pode usar um tipo enumerado em qualquer lugar em um esquema JSON. Por exemplo, você pode pedir ao modelo uma lista de títulos de receitas e usar um tipo enumerado Grade para dar a cada título uma nota de popularidade:

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)

A resposta pode ser assim:

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

Considerações

Considere as seguintes considerações e práticas recomendadas ao usar um esquema de resposta:

  • O tamanho do esquema de resposta é contabilizado no limite de tokens de entrada.
  • Por padrão, os campos são opcionais, o que significa que o modelo pode preenchê-los ou pular. É possível definir campos conforme necessário para forçar o modelo a fornecer um valor. Se não houver contexto suficiente no comando de entrada associado, o modelo gera respostas principalmente com base nos dados em que foi treinado.
  • Um esquema complexo pode resultar em um erro InvalidArgument: 400. A complexidade pode vir de nomes de propriedades longos, limites de comprimento de matriz longos, enumerações com muitos valores, objetos com muitas propriedades opcionais ou uma combinação desses fatores.

    Se você receber esse erro com um esquema válido, faça uma ou mais das seguintes mudanças para resolver o problema:

    • Encurte os nomes de propriedades ou de tipos enumerados.
    • Nivelar matrizes aninhadas.
    • Reduza o número de propriedades com restrições, como números com limites mínimo e máximo.
    • Reduza o número de propriedades com restrições complexas, como propriedades com formatos complexos, como date-time.
    • Reduza o número de propriedades opcionais.
    • Reduza o número de valores válidos para tipos enumerados.
  • Se você não está vendo os resultados esperados, inclua mais contexto aos comandos de entrada ou revise seu esquema de resposta. Por exemplo, revise a resposta do modelo sem saída estruturada para conferir como o modelo responde. Depois, você pode atualizar o esquema de resposta para que ele se ajuste melhor à saída do modelo.

A seguir

Agora que você aprendeu a gerar saída estruturada, tente usar as ferramentas da API Gemini: