Como gerar conteúdo com modelos de IA

A IA generativa é baseada em modelos de IA. Os dois exemplos mais importantes de modelos generativos são modelos de linguagem grandes (LLMs) e modelos de geração de imagens. Esses modelos recebem uma entrada, chamada de comando (mais comumente texto, imagem ou uma combinação de ambos) e produzem como saída texto, imagem ou até áudio ou vídeo.

A saída desses modelos pode ser surpreendentemente convincente: os LLMs geram texto que parece ter sido escrito por um ser humano, e os modelos de geração de imagens podem produzir imagens muito próximas de fotografias reais ou artes criadas por humanos.

Além disso, os LLMs provaram ser capazes de realizar tarefas além da geração de texto simples:

  • Escrever programas de computador.
  • Planejar subtarefas necessárias para concluir uma tarefa maior.
  • Organizar dados desorganizados.
  • Entender e extrair dados de informações de um corpus de texto.
  • Seguir e realizar atividades automatizadas com base em uma descrição de texto da atividade.

Há muitos modelos disponíveis de vários provedores. Cada modelo tem pontos fortes e fracos, e um modelo pode se destacar em uma tarefa, mas ter um desempenho inferior em outras. Os apps que usam a IA generativa podem se beneficiar do uso de vários modelos diferentes, dependendo da tarefa em questão.

Como desenvolvedor de apps, você normalmente não interage diretamente com modelos de IA generativa, mas sim por meio de serviços disponíveis como APIs da Web. Embora esses serviços geralmente tenham funcionalidades semelhantes, todos eles as fornecem por APIs diferentes e incompatíveis. Se você quiser usar vários modelos de serviços, precisará usar cada um dos SDKs reservados, que podem ser incompatíveis entre si. E se você quiser fazer upgrade de um modelo para o mais recente e mais capaz, talvez seja necessário criar essa integração de novo.

O Genkit resolve esse desafio fornecendo uma única interface que abstrai os detalhes de acesso a qualquer serviço de modelo de IA generativa, com várias implementações predefinidas já disponíveis. Criar seu app com tecnologia de IA com o Genkit simplifica o processo de fazer a primeira chamada de IA generativa e facilita a combinação de vários modelos ou a troca de um modelo por outro à medida que novos modelos surgem.

Antes de começar

Se você quiser executar os exemplos de código nesta página, primeiro conclua as etapas no guia Primeiros passos. Todos os exemplos partem do princípio que você já instalou o Genkit como uma dependência no seu projeto.

Modelos com suporte do Genkit

O Genkit foi projetado para ser flexível o suficiente para usar qualquer serviço de modelo de IA generativa. As bibliotecas principais definem a interface comum para trabalhar com modelos, e os plug-ins de modelo definem os detalhes de implementação para trabalhar com um modelo específico e a API dele.

A equipe do Genkit mantém plug-ins para trabalhar com modelos fornecidos pela Vertex AI, IA generativa do Google e Ollama:

Como carregar e configurar plug-ins de modelo

Antes de usar o Genkit para começar a gerar conteúdo, é necessário carregar e configurar um plug-in de modelo. Se você veio do guia "Começar agora", então você já fez isso. Caso contrário, consulte o guia Comece já ou a documentação do plug-in individual e siga as etapas antes de continuar.

A função genkit.Generate()

No Genkit, a interface principal pela qual você interage com modelos de IA generativa é a função genkit.Generate().

A chamada genkit.Generate() mais simples especifica o modelo que você quer usar e um comando de texto:

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())
}

Quando você coloca em prática esse breve exemplo, ele mostra algumas informações de depuração seguidas pela saída da chamada genkit.Generate(), que geralmente é texto Markdown, como no exemplo a seguir:

## 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.

Execute o script novamente e você vai receber uma saída diferente.

O exemplo de código anterior enviou a solicitação de geração para o modelo padrão, especificado ao configurar a instância do Genkit.

Também é possível especificar um modelo para uma única chamada 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."),
)

Um identificador de string de modelo tem a aparência de providerid/modelid, em que o ID do provedor (neste caso, googleai) identifica o plug-in, e o ID do modelo é um identificador de string específico do plug-in para uma versão específica de um modelo.

Esses exemplos também ilustram um ponto importante: quando você usa genkit.Generate() para fazer chamadas de modelo de IA generativa, mudar o modelo que você quer usar é uma questão de transmitir um valor diferente ao parâmetro do modelo. Ao usar genkit.Generate() em vez dos SDKs de modelo nativo, você tem a flexibilidade de usar vários modelos diferentes no app com mais facilidade e mudar de modelo no futuro.

Até agora, você só viu exemplos das chamadas genkit.Generate() mais simples. No entanto, genkit.Generate() também oferece uma interface para interações mais avançadas com modelos generativos, que você vai encontrar nas seções a seguir.

Comandos do sistema

Alguns modelos oferecem suporte a um comando do sistema, que fornece ao modelo instruções sobre como você quer que ele responda às mensagens do usuário. É possível usar o comando do sistema para especificar características, como um perfil que você quer que o modelo adote, o tom e o formato das respostas.

Se o modelo que você está usando for compatível com comandos do sistema, forneça um com a opção 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."),
)

Para modelos que não oferecem suporte a comandos do sistema, WithSystem() faz a simulação modificando a solicitação para que ela pareça um comando do sistema.

Parâmetros do modelo

A função genkit.Generate() usa uma opção WithConfig(), em que é possível especificar configurações opcionais que controlam como o modelo gera conteúdo:

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,
    }),
)

Os parâmetros exatos que são aceitos dependem do modelo e da API de modelo. No entanto, os parâmetros no exemplo anterior são comuns a quase todos os modelos. Confira a seguir uma explicação desses parâmetros:

Parâmetros que controlam o comprimento da saída

MaxOutputTokens

Os LLMs operam em unidades chamadas tokens. Um token costuma ser associado a uma sequência específica de caracteres, embora isso não seja uma regra. Quando você transmite uma solicitação a um modelo, uma das primeiras etapas é tokenizar a string de solicitação em uma sequência de tokens. Em seguida, o LLM gera uma sequência de tokens da entrada tokenizada. Por fim, a sequência de tokens é convertida de volta em texto, que é a saída.

O parâmetro de tokens máximos de saída define um limite de quantos tokens gerar usando o LLM. Cada modelo pode usar um tokenizador diferente, mas é recomendável considerar que uma única palavra em inglês é composta por dois a quatro tokens.

Como mencionado anteriormente, alguns tokens podem não ser mapeados para sequências de caracteres. Um exemplo é que geralmente há um token que indica o fim da sequência: quando um LLM gera esse token, ele para de gerar mais. Portanto, é possível e, muitas vezes, um LLM gera menos tokens do que o máximo porque gerou o token "stop".

StopSequences

É possível usar esse parâmetro para definir os tokens ou as sequências de tokens que, quando gerados, indicam o fim da saída do LLM. Os valores corretos a serem usados aqui dependem de como o modelo foi treinado e geralmente são definidos pelo plug-in do modelo. No entanto, se você solicitou que o modelo gere outra sequência de parada, poderá especificar aqui.

Você está especificando sequências de caracteres, não tokens. Na maioria dos casos, você vai especificar uma sequência de caracteres que o tokenizer do modelo mapeia para um único token.

Parâmetros que controlam a "criatividade"

Os parâmetros temperatura, top-p e top-k controlam juntos o nível de "criatividade" que você quer que o modelo tenha. Esta seção fornece explicações muito breves sobre o significado desses parâmetros, mas o ponto mais importante é este: esses parâmetros são usados para ajustar o caractere da saída de um LLM. Os valores ideais para eles dependem das suas metas e preferências e provavelmente serão encontrados apenas por meio de experimentos.

Temperatura

Os LLMs são máquinas de previsão de tokens. Para uma determinada sequência de tokens (como o comando), um LLM prevê, para cada token no vocabulário, a probabilidade de que o token venha a seguir na sequência. A temperatura é um fator de dimensionamento pelo qual essas previsões são divididas antes de serem normalizadas para uma probabilidade entre 0 e 1.

Valores de temperatura baixos, entre 0,0 e 1,0, ampliam a diferença nas probabilidades entre os tokens, o que faz com que o modelo tenha ainda menos probabilidade de produzir um token que já foi avaliado como improvável. Isso geralmente é percebido como uma saída menos criativa. Embora 0,0 não seja tecnicamente um valor válido, muitos modelos o tratam como um indicador de que o modelo deve se comportar de forma determinística e considerar apenas o token mais provável.

Valores de temperatura alta (maiores que 1,0) comprimem as diferenças de probabilidade entre os tokens, com o resultado de que o modelo tem mais probabilidade de produzir tokens que ele havia avaliado anteriormente como improváveis. Isso é muitas vezes percebido como uma saída mais criativa. Algumas APIs de modelo impõem uma temperatura máxima, geralmente 2,0.

TopP

Top-p é um valor entre 0,0 e 1,0 que controla o número de tokens possíveis que você quer que o modelo considere, especificando a probabilidade cumulativa dos tokens. Por exemplo, um valor de 1,0 significa considerar todos os tokens possíveis, mas ainda considerar a probabilidade de cada token. Um valor de 0,4 significa considerar apenas os tokens mais prováveis, cujas probabilidades somam 0,4, e excluir os tokens restantes da consideração.

TopK

Top-k é um valor inteiro que também controla o número de tokens possíveis que você quer que o modelo considere, mas dessa vez especificando explicitamente o número máximo de tokens. Especificar um valor de 1 significa que o modelo deve se comportar de forma determinística.

Testar parâmetros do modelo

É possível testar o efeito desses parâmetros na saída gerada por diferentes combinações de modelo e comando usando a interface do desenvolvedor. Inicie a interface para desenvolvedores com o comando genkit start, que vai carregar automaticamente todos os modelos definidos pelos plug-ins configurados no projeto. É possível testar com rapidez diferentes comandos e valores de configuração sem precisar fazer essas mudanças repetidamente no código.

Parear o modelo com a configuração

Como cada provedor ou até mesmo um modelo específico pode ter o próprio esquema de configuração ou garantir determinadas configurações, pode haver erros ao definir opções separadas usando WithModelName() e WithConfig(), já que o segundo parâmetro não é fortemente tipado em relação ao primeiro.

Para parear um modelo com a configuração, crie uma referência de modelo que possa ser transmitida para a chamada de geração:

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)
}

O construtor da referência do modelo vai exigir que o tipo de configuração correto seja fornecido, o que pode reduzir as incompatibilidades.

Saída estruturada

Ao usar a IA generativa como um componente no seu app, você vai receber uma saída em um formato diferente do texto simples. Mesmo que você esteja apenas gerando conteúdo para mostrar ao usuário, é possível aproveitar a saída estruturada para apresentá-la de forma mais atraente ao usuário. No entanto, para usos mais avançados de IA generativa, como o uso programático da saída do modelo ou a alimentação da saída de um modelo em outro, a saída estruturada é essencial.

No Genkit, é possível solicitar uma saída estruturada de um modelo especificando um tipo de saída ao chamar 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.
}

Os tipos de saída do modelo são especificados como esquema JSON usando o pacote invopop/jsonschema. Isso oferece a verificação de tipo de execução, que conecta os tipos estáticos do Go e a saída imprevisível dos modelos de IA generativa. Esse sistema permite que você escreva código que pode depender do fato de que uma chamada de geração bem-sucedida sempre retornará uma saída que está em conformidade com seus tipos Go.

Quando você especifica um tipo de saída em genkit.Generate(), o Genkit faz várias ações nos bastidores:

  • Aumenta a solicitação com outras orientações sobre o formato de saída selecionado. Como consequência, isso especifica ao modelo exatamente o conteúdo que você quer gerar. Por exemplo, não apenas sugerir um item de menu, mas também gerar uma descrição, uma lista de alérgenos e assim por diante.
  • Verifica se a saída está em conformidade com o esquema.
  • Armazena a saída do modelo em um tipo Go.

Para receber uma saída estruturada de uma chamada de geração bem-sucedida, chame Output() na resposta do modelo com um valor vazio do tipo:

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)

Como alternativa, use genkit.GenerateData() para uma chamada mais sucinta:

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)

Essa função exige o parâmetro de tipo de saída, mas define automaticamente a opção WithOutputType() e chama resp.Output() antes de retornar o valor.

Tratamento de erros

No exemplo anterior, a chamada genkit.Generate() pode resultar em um erro. Um possível erro pode acontecer quando o modelo não consegue gerar uma saída que esteja em conformidade com o esquema. A melhor estratégia para lidar com esses erros vai depender do seu caso de uso exato, mas aqui estão algumas dicas gerais:

  • Tente um modelo diferente. Para que a saída estruturada funcione, o modelo precisa ser capaz de gerar saídas em JSON. Os LLMs mais avançados, como o Gemini, são versáteis o suficiente para fazer isso. No entanto, modelos menores, como alguns dos modelos locais que você usaria com o Ollama, podem não ser capazes de gerar uma saída estruturada de forma confiável, a menos que tenham sido treinados especificamente para fazer isso.

  • Simplifique o esquema. Os LLMs podem ter problemas para gerar tipos complexos ou profundamente aninhados. Tente usar nomes claros, menos campos ou uma estrutura simplificada se não for possível gerar dados estruturados de forma confiável.

  • Tente fazer a genkit.Generate() chamada. Se o modelo escolhido raramente falhar na geração de uma saída em conformidade, trate o erro como um erro de rede e tente novamente a solicitação usando algum tipo de estratégia de espera incremental.

Streaming

Ao gerar grandes quantidades de texto, é possível melhorar a experiência dos usuários apresentando a saída conforme ela é gerada, ou seja, fazendo o streaming dela. Existe um exemplo conhecido de streaming em ação na maioria dos apps de chat de LLM: os usuários podem ler a resposta do modelo à mensagem enquanto ela é gerada, o que melhora a capacidade de resposta percebida do aplicativo e aumenta a sensação de conversar com uma interlocutor inteligente.

No Genkit, é possível transmitir a saída usando a opção 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())

Entrada multimodal

Os exemplos que você analisou até agora usaram strings de texto como comandos de modelo. Embora essa seja a maneira mais comum de solicitar modelos de IA generativa, muitos modelos também aceitam outras mídias como comandos. Os comandos de mídia são usados com mais frequência em conjunto com comandos de texto que instruem o modelo a realizar alguma operação na mídia, como adicionar legenda a uma imagem ou transcrever uma gravação de áudio.

A capacidade de aceitar entrada de mídia e os tipos de mídia que você pode usar dependem completamente do modelo e da API dele. Por exemplo, a série de modelos Gemini 2.0 pode aceitar imagens, vídeos e áudio como comandos.

Para fornecer uma instrução de mídia a um modelo compatível, em vez de transmitir uma instrução de texto simples para genkit.Generate(), transmita uma matriz que seja parte mídia, parte texto. Este exemplo especifica uma imagem usando um URL HTTPS acessível publicamente.

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."),
        ),
    ),
)

Também é possível transmitir dados de mídia diretamente, codificando-os como um URL de dados. Exemplo:

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."),
        ),
    ),
)

Todos os modelos que oferecem suporte à entrada de mídia são compatíveis com URLs de dados e HTTPS. Alguns plug-ins de modelo oferecem suporte a outras fontes de mídia. Por exemplo, o plug-in da Vertex AI também permite usar URLs do Cloud Storage (gs://).

Próximas etapas

Saiba mais sobre o Genkit

  • Como desenvolvedor de apps, a principal maneira de influenciar a saída de modelos de IA generativa é com comandos. Leia Como gerenciar comandos com o Dotprompt para saber como o Genkit ajuda a desenvolver comandos eficazes e gerenciá-los na sua base de código.
  • Embora genkit.Generate() seja o núcleo de todos os aplicativos com tecnologia de IA generativa, os aplicativos reais geralmente exigem mais trabalho antes e depois de invocar um modelo de IA generativa. Para refletir isso, o Genkit introduz o conceito de fluxos, que são definidos como funções, mas adicionam outros recursos, como observabilidade e implantação simplificada. Para saber mais, consulte Como definir fluxos de trabalho de IA.

Uso avançado do LLM

Há técnicas que o app pode usar para aproveitar ainda mais os LLMs.

  • Uma maneira de aprimorar os recursos dos LLMs é mostrar uma lista de maneiras de solicitar mais informações ou pedir que você realize alguma ação. Isso é conhecido como chamada de ferramenta ou chamada de função. Os modelos treinados para oferecer suporte a esse recurso podem responder a um comando com uma resposta personalizada, que indica ao aplicativo de chamada que ele precisa realizar alguma ação e enviar o resultado de volta ao LLM junto com o comando original. O Genkit tem funções de biblioteca que automatizam a geração de comandos e os elementos de repetição de chamada e resposta de uma implementação de chamada de ferramenta. Consulte Chamada de ferramentas para saber mais.
  • A geração aumentada de recuperação (RAG) é uma técnica usada para introduzir informações específicas do domínio na saída de um modelo. Isso é feito inserindo informações relevantes em um comando antes de transmiti-las ao modelo de linguagem. Uma implementação completa da RAG exige que você reúna várias tecnologias: modelos de geração de embedding de texto, bancos de dados vetoriais e modelos de linguagem grandes. Consulte Geração aumentada de recuperação (RAG) para aprender como o Genkit simplifica o processo de coordenação desses vários elementos.