Como dominar a geração controlada com o Gemini 1.5: adesão a esquemas para desenvolvedores

SET 03, 2024
Lewis Liu Group Product Manager Gemini
Terry Koo Research Scientist Google Deepmind

Grande parte da atual empolgação em relação à IA generativa se concentra em "possibilidades futuras", ou seja, os potenciais experimentos e avanços com modelos fundamentais. Mas, no Google, sempre tivemos o compromisso de fornecer um ecossistema de IA abrangente que ajude não só a experimentar os melhores modelos da categoria, mas também adotá-los em aplicações práticas.

Como parte dessa jornada, introduzimos a geração controlada para o Gemini 1.5 Pro durante o Google I/O deste ano, e foi incrível ver a rápida adoção e os feedbacks positivos que recebemos. Hoje, estamos dando mais um passo com a introdução da geração controlada para o Gemini 1.5 Flash e adicionando suporte a "Enum" (tipo enumerado). Isso proporciona aos desenvolvedores uma ferramenta robusta para a geração confiável de respostas que sigam um esquema definido. Além disso, a geração controlada é ativada automaticamente em QUALQUER modo quando você usa a chamada de funções no Gemini 1.5.


O que é geração controlada, e por que ela é importante?

Pense na geração controlada como uma forma de fornecer um plano para a saída do modelo. Ao definir um esquema de resposta, você determina o formato e a estrutura exatos das respostas da IA. Seja ao extrair entidades no formato JSON para processamento de downstream contínuo ou ao classificar artigos de notícias dentro de sua própria taxonomia, a geração controlada ajuda a garantir consistência e reduz a necessidade de pós-processamento, que é uma tarefa demorada.

Para integrar totalmente a IA ao desenvolvimento de software, duas coisas precisam acontecer: uma transferência fluida das equipes de ciência de dados e aprendizado de máquina para os desenvolvedores de aplicativos e uma integração perfeita da saída do modelo nos sistemas existentes. Com a geração controlada, você pode:

  • Permitir que a IA produza dados prontos para uso e legíveis por máquina, reduzindo a necessidade de realizar tarefas complexas de análise e pós-processamento.

  • Gerar saídas em formatos como JSON, tornando sua IA um recurso de primeira classe na economia de APIs, com integração total a fluxos de trabalho existentes.

  • Injetar alguma previsibilidade nas saídas de IA, prevendo, de maneira confiável, o formato e a estrutura dos dados produzidos pelo modelo de IA.

Segundo Chris Curro, engenheiro principal de aprendizado de máquina da The Estée Lauder Companies, um de nossos primeiros testadores: "Estamos projetando fluxos de trabalho de lógica complexa com base no Gemini 1.5 para criar experiências para consumidores e funcionários que seriam impossíveis de outra forma. A natureza de acessibilidade para desenvolvedores da geração controlada permitiu que nossa equipe fizesse a transição rapidamente e agregasse valor para os negócios."

O recurso foi criado com base no avanço recente desenvolvido pela equipe do Google, chamado decodificação controlada. Para saber mais sobre nossas técnicas subjacentes, consulte este artigo.

Na API Gemini e na API Vertex AI, introduzimos o conceito de "esquema de resposta". Um esquema de resposta atua como um modelo, determinando os elementos, os tipos de dados e a estrutura geral da saída da IA. O esquema é criado com base na definição de esquemas do OpenAPI 3.0 para que você sempre saiba que está criando em um padrão aberto e compatível. Ao incluir um esquema de resposta com o prompt, você instrui o modelo a seguir suas regras definidas, levando a resultados previsíveis e estruturados.


O diferencial do Google

  • A geração controlada do Gemini adiciona latência mínima às chamadas de API existentes, mesmo na primeira chamada de API.

  • O Gemini dá suporte a Enum como um tipo, e mais adições estão previstas.

  • O Gemini aplica esquemas sem precisar armazenar dados.


Como começar

O recurso de geração controlada está disponível no Gemini 1.5 Pro e no Gemini 1.5 Flash no Google AI Studio e na Vertex AI.


Exemplo: criação de um app de planejamento de refeições com o esquema JSON

Imagine que você esteja criando um app para sugerir receitas para diferentes cenários. As receitas devem ser geradas em formato estruturado para serem facilmente processadas pelo app e apresentadas visualmente ao usuário. O exemplo a seguir ilustra como a geração controlada pode ser usada para gerar um conjunto de receitas para uma refeição com vários pratos.

from vertexai.generative_models import GenerationConfig, GenerativeModel
vertexai.init(project=project_id, location="us-central1")
 
response_schema = {
    "type": "array",
    "items": {
        "type": "object",
        "properties": {
            "course": {
                "type": "string",
                "enum": [
                    "appetizer",
                    "salad",
                    "soup",
                    "main",
                    "dessert",
                ],
            },
            "name": {
                "type": "string",
            },
            "ingredients": {
                "type": "array",
                "items": {
                    "type": "object",
                    "properties": {
                        "unit": {
                            "type": "string",
                            "enum": [
                                "count",
                                "cup",
                                "tablespoon",
                                "teaspoon",
                                "pound",
                                "ounce",
                            ],
                        },
                        "amount": {
                            "type": "number",
                        },
                        "name": {
                            "type": "string",
                        },
                    },
                    "required": ["name"],
                },
            },
            "steps": {
                "type": "array",
                "items": {
                    "type": "string",
                },
            },
        },
        "required": ["course", "name"],
    },
}
 
prompt = (
    "Some friends are in town and I want to host them for dinner.  "
    "Can you plan a three-course meal for me?  "
    "I'm not an experienced cook so I need simple recipes."
)
 
model = GenerativeModel("gemini-1.5-pro-001")
 
response = model.generate_content(
    prompt,
    generation_config=GenerationConfig(
        response_mime_type="application/json",
        response_schema=response_schema
    ),
)

A saída deste modelo realmente confirma o esquema especificado no corpo da solicitação e pode ser usada diretamente pelo aplicativo.

[
    {
        "course": "appetizer",
        "name": "Caprese Skewers",
        "ingredients": [
            {
                "name": "cherry tomatoes",
                "amount": 1,
                "unit": "cup"
            },
            {
                "name": "fresh mozzarella balls",
                "amount": 1,
                "unit": "cup"
            },
            {
                "name": "fresh basil leaves",
                "amount": 12,
                "unit": "count"
            },
            {
                "name": "olive oil",
                "amount": 2,
                "unit": "tablespoon"
            },
            {
                "name": "balsamic glaze",
                "amount": 2,
                "unit": "tablespoon"
            },
            {
                "name": "salt",
                "amount": 1,
                "unit": "teaspoon"
            },
            {
                "name": "black pepper",
                "amount": 1,
                "unit": "teaspoon"
            }
        ],
        "steps": [
            "Thread cherry tomatoes, mozzarella balls, and basil leaves onto skewers.",
            "Drizzle with olive oil and balsamic glaze.",
            "Season with salt and pepper to taste."
        ]
    },
    {
        "course": "main",
        "name": "One-Pan Lemon Herb Salmon",
        "ingredients": [
            {
                "name": "salmon fillets",
                "amount": 4,
                "unit": "count"
            },
            {
                "name": "asparagus",
                "amount": 1,
                "unit": "pound"
            },
            {
                "name": "cherry tomatoes",
                "amount": 1,
                "unit": "cup"
            },
            {
                "name": "lemon",
                "amount": 1,
                "unit": "count"
            },
            {
                "name": "dried oregano",
                "amount": 1,
                "unit": "teaspoon"
            },
            {
                "name": "dried thyme",
                "amount": 1,
                "unit": "teaspoon"
            },
            {
                "name": "salt",
                "amount": 1,
                "unit": "teaspoon"
            },
            {
                "name": "black pepper",
                "amount": 1,
                "unit": "teaspoon"
            },
            {
                "name": "olive oil",
                "amount": 2,
                "unit": "tablespoon"
            }
        ],
        "steps": [
            "Preheat oven to 400 degrees F (200 degrees C).",
            "Line a baking sheet with parchment paper.",
            "Place salmon fillets on one side of the baking sheet and spread asparagus and cherry tomatoes on the other side.",
            "Squeeze lemon juice over the salmon and vegetables.",
            "Sprinkle with oregano, thyme, salt, and pepper.",
            "Drizzle with olive oil.",
            "Bake for 15-20 minutes, or until salmon is cooked through and vegetables are tender."
        ]
    },
    {
        "course": "dessert",
        "name": "Fruit Salad with Honey Yogurt",
        "ingredients": [
            {
                "name": "strawberries",
                "amount": 1,
                "unit": "cup"
            },
            {
                "name": "blueberries",
                "amount": 1,
                "unit": "cup"
            },
            {
                "name": "raspberries",
                "amount": 1,
                "unit": "cup"
            },
            {
                "name": "greek yogurt",
                "amount": 1,
                "unit": "cup"
            },
            {
                "name": "honey",
                "amount": 2,
                "unit": "tablespoon"
            }
        ],
        "steps": [
            "In a large bowl, combine strawberries, blueberries, and raspberries.",
            "In a separate bowl, mix together greek yogurt and honey.",
            "Serve fruit salad with a dollop of honey yogurt."
        ]
    }
]

Como classificar a condição do produto com o esquema Enum

Para restringir a saída do modelo em um conjunto de valores predefinidos, você pode usar "text/x.enum".

import vertexai
from vertexai.generative_models import GenerationConfig, GenerativeModel
 
vertexai.init(project=project_id, location="us-central1")
model = GenerativeModel("gemini-1.5-flash-001")
 
response_schema = {
     "type": "STRING",
     "enum": ["new in package", "like new", "gently used", "used", "damaged", "soiled"]
}
 
prompt = [
     "Item description: The item is a long winter coat that has many tears all around the seams and is falling apart. It has large questionable stains on it."
]
 
 
response = model.generate_content(
     prompt,
     generation_config=GenerationConfig(
         response_mime_type="text/x.enum", response_schema=response_schema
     ),
)
print(response.candidates[0])

A saída do modelo contém a classificação simples do produto como "damaged" (danificado).

content {
  role: "model"
  parts {
    text: "damaged"
  }
}

Limitações

  • A geração controlada oferece suporte a um subconjunto do esquema do OpenAPI 3.0.

  • O conteúdo da saída ainda depende da capacidade de raciocínio e extração do modelo. O uso da geração controlada aplica o formato de saída, mas não a resposta real.

  • Se o prompt não tiver informações suficientes para um campo obrigatório, a geração controlada poderá gerar uma resposta com base nos dados em que foi treinada. Definir nullable como True no campo pode atenuar essa limitação.


Resumo

Com a geração controlada, agora você tem uma ferramenta robusta para gerar respostas que seguem um esquema definido. Você pode aplicá-lo a fluxos de trabalho existentes para torná-lo mais confiável e preditivo. Temos o compromisso de fornecer aos desenvolvedores recursos de API fáceis de usar para guiar e controlar melhor o comportamento de modelos. E a geração controlada é apenas o começo.

Leia mais na página de documentação do Google AI Studio ou da Vertex AI para começar a usar esse recurso.