Geração de texto de IA generativa em Java com PaLM e LangChain4J

1. Introdução

Última atualização:27/11/2023

O que é a IA generativa

IA generativa ou inteligência artificial generativa se refere ao uso de IA para criar novos conteúdos, como texto, imagens, música, áudio e vídeos.

Ela usa modelos de fundação (modelos de IA grandes) capazes de realizar várias tarefas ao mesmo tempo, além de resumos, perguntas e respostas, classificações e muito mais. Além disso, com o mínimo de treinamento necessário, os modelos de fundação podem ser adaptados para casos de uso específicos com poucos dados de exemplo.

Como a IA generativa funciona?

A IA generativa usa um modelo de ML (aprendizado de máquina) para aprender os padrões e as relações em um conjunto de dados de conteúdo criado por humanos. Os padrões aprendidos são então usados para gerar novo conteúdo.

A maneira mais comum de treinar um modelo de IA generativa é usar o aprendizado supervisionado: o modelo recebe um conjunto de conteúdo criado por humanos e rótulos correspondentes. Em seguida, ele aprende a gerar conteúdo semelhante ao criado por humanos e com os mesmos rótulos.

Quais são os aplicativos comuns de IA generativa?

A IA generativa processa um vasto conteúdo, criando insights e respostas por meio de texto, imagens e formatos amigáveis. A IA generativa pode ser usada para:

  • Melhorar as interações com os clientes por meio de experiências de pesquisa e chat aprimoradas
  • Explorar grandes quantidades de dados não estruturados por meio de interfaces de conversação e resumos
  • Ajudar com tarefas repetitivas, como responder a solicitações de propostas (RFPs), localizar o conteúdo de marketing em cinco idiomas, verificar a conformidade dos contratos do cliente e muito mais

Quais são as opções de IA generativa com o Google Cloud?

Com a Vertex AI, é possível interagir, personalizar e incorporar modelos de base nos seus aplicativos sem precisar de experiência em ML. Acesse modelos de fundação no Model Garden, ajuste modelos por meio de uma interface simples no Generative AI Studio ou use modelos em um notebook de ciência de dados.

A ferramenta de Vertex AI para Pesquisa e Conversação oferece aos desenvolvedores a maneira mais rápida de criar mecanismos de pesquisa e chatbots com tecnologia de IA generativa.

Além disso, a Duet AI é uma ferramenta com tecnologia de IA disponível no Google Cloud e em ambientes de desenvolvimento integrado para ajudar você a produzir mais e com mais rapidez.

Qual é o foco deste codelab?

Este codelab se concentra no modelo de linguagem grande (LLM) PaLM 2, hospedado na Vertex AI do Google Cloud, que abrange todos os produtos e serviços de machine learning.

Você vai usar Java para interagir com a API PaLM, em conjunto com o orquestrador de framework de LLM LangChain4J. Você vai conferir diferentes exemplos concretos para aproveitar o LLM em respostas a perguntas, geração de ideias, extração de entidades e conteúdo estruturado e resumo.

Quero saber mais sobre o framework LangChain4J!

O framework LangChain4J é uma biblioteca de código aberto para integrar modelos de linguagem grandes aos seus aplicativos Java, orquestrando vários componentes, como o próprio LLM, mas também outras ferramentas, como bancos de dados vetoriais (para pesquisas semânticas), carregadores e divisores de documentos (para analisar documentos e aprender com eles), analisadores de saída e muito mais.

c6d7f7c3fd0d2951.png

O que você vai aprender

  • Como configurar um projeto Java para usar o PaLM e o LangChain4J
  • Como fazer sua primeira chamada ao modelo de texto PaLM para gerar conteúdo e responder a perguntas
  • Como extrair informações úteis de conteúdo não estruturado (extração de entidade ou palavra-chave, saída em JSON)
  • Como fazer classificação de conteúdo ou análise de sentimentos com comandos de poucos disparos

O que é necessário

  • Conhecimento da linguagem de programação Java
  • um projeto do Google Cloud;
  • Um navegador, como o Chrome ou o Firefox

2. Configuração e requisitos

Configuração de ambiente autoguiada

  1. Faça login no Console do Google Cloud e crie um novo projeto ou reutilize um existente. Crie uma conta do Gmail ou do Google Workspace, se ainda não tiver uma.

295004821bab6a87.png

37d264871000675d.png

96d86d3d5655cdbe.png

  • O Nome do projeto é o nome de exibição para os participantes do projeto. É uma string de caracteres não usada pelas APIs do Google e pode ser atualizada quando você quiser.
  • O ID do projeto precisa ser exclusivo em todos os projetos do Google Cloud e não pode ser mudado após a definição. O console do Cloud gera automaticamente uma string exclusiva. Em geral, não importa o que seja. Na maioria dos codelabs, é necessário fazer referência ao ID do projeto, normalmente identificado como PROJECT_ID. Se você não gostar do ID gerado, crie outro aleatório. Se preferir, teste o seu e confira se ele está disponível. Ele não pode ser mudado após essa etapa e permanece durante o projeto.
  • Para sua informação, há um terceiro valor, um Número do projeto, que algumas APIs usam. Saiba mais sobre esses três valores na documentação.
  1. Em seguida, ative o faturamento no console do Cloud para usar os recursos/APIs do Cloud. A execução deste codelab não vai ser muito cara, se tiver algum custo. Para encerrar os recursos e evitar cobranças além deste tutorial, exclua os recursos criados ou exclua o projeto. Novos usuários do Google Cloud estão qualificados para o programa de US$ 300 de avaliação sem custos.

Inicie o Cloud Shell

Embora o Google Cloud possa ser operado remotamente do seu laptop, neste codelab usaremos o Cloud Shell, um ambiente de linha de comando executado no Cloud.

Ativar o Cloud Shell

  1. No Console do Cloud, clique em Ativar o Cloud Shelld1264ca30785e435.png.

cb81e7c8e34bc8d.png

Se esta for a primeira vez que você inicia o Cloud Shell, uma tela intermediária vai aparecer com a descrição dele. Se isso acontecer, clique em Continuar.

d95252b003979716.png

Leva apenas alguns instantes para provisionar e se conectar ao Cloud Shell.

7833d5e1c5d18f54.png

Essa máquina virtual contém todas as ferramentas de desenvolvimento necessárias. Ela oferece um diretório principal persistente de 5 GB, além de ser executada no Google Cloud. Isso aprimora o desempenho e a autenticação da rede. Neste codelab, quase todo o trabalho pode ser feito com um navegador.

Depois de se conectar ao Cloud Shell, você vai ver que sua conta já está autenticada e que o projeto está configurado com o ID do seu projeto.

  1. Execute o seguinte comando no Cloud Shell para confirmar se a conta está autenticada:
gcloud auth list

Resposta ao comando

 Credentialed Accounts
ACTIVE  ACCOUNT
*       <my_account>@<my_domain.com>

To set the active account, run:
    $ gcloud config set account `ACCOUNT`
  1. Execute o comando a seguir no Cloud Shell para confirmar se o comando gcloud sabe sobre seu projeto:
gcloud config list project

Resposta ao comando

[core]
project = <PROJECT_ID>

Se o projeto não estiver configurado, configure-o usando este comando:

gcloud config set project <PROJECT_ID>

Resposta ao comando

Updated property [core/project].

3. Como preparar seu ambiente para desenvolvedores

Neste codelab, você vai usar o terminal e o editor de código do Cloud Shell para desenvolver seus programas em Java.

Ativar APIs da Vertex AI

  1. No console do Google Cloud, verifique se o nome do seu projeto é exibido na parte de cima do console do Google Cloud. Se não estiver, clique em Selecionar um projeto para abrir o Seletor de projetos e escolha o projeto pretendido.
  2. Se você não estiver na parte da Vertex AI do console do Google Cloud, faça o seguinte:
  3. Em Pesquisar, insira "Vertex AI" e retorne
  4. Nos resultados da pesquisa, clique em "Vertex AI". O painel da Vertex AI vai aparecer.
  5. Clique em Ativar todas as APIs recomendadas no painel da Vertex AI.

Isso vai ativar várias APIs, mas a mais importante para o codelab é a aiplatform.googleapis.com, que também pode ser ativada na linha de comando, no terminal do Cloud Shell, executando o seguinte comando:

$ gcloud services enable aiplatform.googleapis.com

Como criar a estrutura do projeto com o Gradle

Para criar seus exemplos de código Java, você vai usar a ferramenta de build Gradle e a versão 17 do Java. Para configurar seu projeto com o Gradle, no terminal do Cloud Shell, crie um diretório (aqui, palm-workshop) e execute o comando gradle init nele:

$ mkdir palm-workshop
$ cd palm-workshop

$ gradle init

Select type of project to generate:
  1: basic
  2: application
  3: library
  4: Gradle plugin
Enter selection (default: basic) [1..4] 2

Select implementation language:
  1: C++
  2: Groovy
  3: Java
  4: Kotlin
  5: Scala
  6: Swift
Enter selection (default: Java) [1..6] 3

Split functionality across multiple subprojects?:
  1: no - only one application project
  2: yes - application and library projects
Enter selection (default: no - only one application project) [1..2] 1

Select build script DSL:
  1: Groovy
  2: Kotlin
Enter selection (default: Groovy) [1..2] 1

Generate build using new APIs and behavior (some features may change in the next minor release)? (default: no) [yes, no] 

Select test framework:
  1: JUnit 4
  2: TestNG
  3: Spock
  4: JUnit Jupiter
Enter selection (default: JUnit Jupiter) [1..4] 4

Project name (default: palm-workshop): 
Source package (default: palm.workshop): 

> Task :init
Get more help with your project: https://docs.gradle.org/7.4/samples/sample_building_java_applications.html

BUILD SUCCESSFUL in 51s
2 actionable tasks: 2 executed

Você vai criar um aplicativo (opção 2) usando a linguagem Java (opção 3), sem usar subprojetos (opção 1), usando a sintaxe Groovy para o arquivo de build (opção 1), sem usar novos recursos de build (opção não), gerando testes com JUnit Jupiter (opção 4). Para o nome do projeto, use palm-workshop e, para o pacote de origem, use palm.workshop.

A estrutura do projeto vai ficar assim:

├── gradle 
│   └── ...
├── gradlew 
├── gradlew.bat 
├── settings.gradle 
└── app
    ├── build.gradle 
    └── src
        ├── main
        │   └── java 
        │       └── palm
        │           └── workshop
        │               └── App.java
        └── test
            └── ...

Vamos atualizar o arquivo app/build.gradle para adicionar algumas dependências necessárias. Você pode remover a dependência guava, se ela estiver presente, e substituí-la pelas dependências do projeto LangChain4J e da biblioteca de geração de registros para evitar mensagens irritantes de logger ausente:

dependencies {
    // Use JUnit Jupiter for testing.
    testImplementation 'org.junit.jupiter:junit-jupiter:5.8.1'

    // Logging library
    implementation 'org.slf4j:slf4j-jdk14:2.0.9'

    // This dependency is used by the application.
    implementation 'dev.langchain4j:langchain4j-vertex-ai:0.24.0'
    implementation 'dev.langchain4j:langchain4j:0.24.0'
}

Há duas dependências para o LangChain4J:

  • um no projeto principal,
  • e um para o módulo dedicado da Vertex AI.

Para usar o Java 17 na compilação e execução dos nossos programas, adicione o bloco a seguir abaixo do bloco plugins {}:

java {
    toolchain {
        languageVersion = JavaLanguageVersion.of(17)
    }
}

Mais uma mudança: atualize o bloco application de app/build.gradle para permitir que os usuários substituam a classe principal para execução na linha de comando ao invocar a ferramenta de build:

application {
    mainClass = providers.systemProperty('javaMainClass')
                         .orElse('palm.workshop.App')
}

Para verificar se o arquivo de build está pronto para executar o aplicativo, execute a classe principal padrão, que imprime uma mensagem Hello World! simples:

$ ./gradlew run -DjavaMainClass=palm.workshop.App

> Task :app:run
Hello World!

BUILD SUCCESSFUL in 3s
2 actionable tasks: 2 executed

Agora você já pode programar com o modelo de texto de linguagem grande PaLM usando o projeto LangChain4J.

Para referência, confira como o arquivo de build app/build.gradle completo deve ficar agora:

plugins {
    // Apply the application plugin to add support for building a CLI application in Java.
    id 'application'
}

java {
    toolchain {
        // Ensure we compile and run on Java 17
        languageVersion = JavaLanguageVersion.of(17)
    }
}

repositories {
    // Use Maven Central for resolving dependencies.
    mavenCentral()
}

dependencies {
    // Use JUnit Jupiter for testing.
    testImplementation 'org.junit.jupiter:junit-jupiter:5.8.1'

    // This dependency is used by the application.
    implementation 'dev.langchain4j:langchain4j-vertex-ai:0.24.0'
    implementation 'dev.langchain4j:langchain4j:0.24.0'
    implementation 'org.slf4j:slf4j-jdk14:2.0.9'
}

application {
    mainClass = providers.systemProperty('javaMainClass').orElse('palm.workshop.App')
}

tasks.named('test') {
    // Use JUnit Platform for unit tests.
    useJUnitPlatform()
}

4. Fazer sua primeira chamada para o modelo de texto do PaLM

Agora que o projeto está configurado corretamente, é hora de chamar a API PaLM.

Crie uma classe chamada TextPrompts.java no diretório app/src/main/java/palm/workshop (ao lado da classe App.java padrão) e digite o seguinte conteúdo:

package palm.workshop;

import dev.langchain4j.model.output.Response;
import dev.langchain4j.model.vertexai.VertexAiLanguageModel;

public class TextPrompts {
    public static void main(String[] args) {
        VertexAiLanguageModel model = VertexAiLanguageModel.builder()
            .endpoint("us-central1-aiplatform.googleapis.com:443")
            .project("YOUR_PROJECT_ID")
            .location("us-central1")
            .publisher("google")
            .modelName("text-bison@001")
            .maxOutputTokens(500)
            .build();

        Response<String> response = model.generate("What are large language models?");

        System.out.println(response.content());
    }
}

Neste primeiro exemplo, você precisa importar a classe Response e o modelo de linguagem da Vertex AI para o PaLM.

Em seguida, no método main, você vai configurar o modelo de linguagem usando o builder para o VertexAiLanguageModel e especificar:

  • o endpoint,
  • o projeto,
  • a região,
  • o publisher,
  • e o nome do modelo (text-bison@001).

Agora que o modelo de linguagem está pronto, você pode chamar o método generate() e transmitir seu "comando" (ou seja, sua pergunta ou instruções para enviar ao LLM). Aqui, você faz uma pergunta simples sobre o que são LLMs. Mas você pode mudar esse comando para testar outras perguntas ou tarefas.

Para executar essa classe, execute o comando a seguir no terminal do Cloud Shell:

./gradlew run -DjavaMainClass=palm.workshop.TextPrompts

A resposta será parecida com esta:

Large language models (LLMs) are artificial intelligence systems that can understand and generate human language. They are trained on massive datasets of text and code, and can learn to perform a wide variety of tasks, such as translating languages, writing different kinds of creative content, and answering your questions in an informative way.

LLMs are still under development, but they have the potential to revolutionize many industries. For example, they could be used to create more accurate and personalized customer service experiences, to help doctors diagnose and treat diseases, and to develop new forms of creative expression.

However, LLMs also raise a number of ethical concerns. For example, they could be used to create fake news and propaganda, to manipulate people's behavior, and to invade people's privacy. It is important to carefully consider the potential risks and benefits of LLMs before they are widely used.

Here are some of the key features of LLMs:

* They are trained on massive datasets of text and code.
* They can learn to perform a wide variety of tasks, such as translating languages, writing different kinds of creative content, and answering your questions in an informative way.
* They are still under development, but they have the potential to revolutionize many industries.
* They raise a number of ethical concerns, such as the potential for fake news, propaganda, and invasion of privacy.

O builder VertexAILanguageModel permite definir parâmetros opcionais que já têm alguns valores padrão que podem ser substituídos. Veja alguns exemplos:

  • .temperature(0.2): para definir o nível de criatividade da resposta. 0 é para respostas menos criativas e mais factuais, enquanto 1 é para respostas mais criativas.
  • .maxOutputTokens(50): no exemplo, foram solicitados 500 tokens (3 tokens equivalem a cerca de 4 palavras), dependendo do tamanho da resposta gerada.
  • .topK(20): para selecionar aleatoriamente uma palavra entre um número máximo de palavras prováveis para a conclusão de texto (de 1 a 40)
  • .topP(0.95): para selecionar as palavras possíveis cuja probabilidade total seja igual a esse número de ponto flutuante (entre 0 e 1).
  • .maxRetries(3): se você estiver excedendo a cota de solicitações por período, o modelo poderá tentar fazer a chamada três vezes, por exemplo.

Os modelos de linguagem grandes são muito poderosos e podem responder a perguntas complexas, além de lidar com uma grande variedade de tarefas interessantes. Na próxima seção, vamos analisar uma tarefa útil: extrair dados estruturados de texto.

5. Extrair informações de texto não estruturado

Na seção anterior, você gerou uma saída de texto. Isso é bom se você quiser mostrar diretamente essa saída aos usuários finais. Mas, se você quiser recuperar os dados mencionados nessa saída, como extrair essas informações do texto não estruturado?

Vamos supor que você queira extrair o nome e a idade de uma pessoa com base em uma biografia ou descrição dela. É possível instruir o modelo de linguagem grande a gerar estruturas de dados JSON ajustando o comando da seguinte maneira (isso é comumente chamado de engenharia de comandos):

Extract the name and age of the person described below.

Return a JSON document with a "name" and an "age" property, 
following this structure: {"name": "John Doe", "age": 34}
Return only JSON, without any markdown markup surrounding it.

Here is the document describing the person:
---
Anna is a 23 year old artist based in Brooklyn, New York. She was 
born and raised in the suburbs of Chicago, where she developed a 
love for art at a young age. She attended the School of the Art 
Institute of Chicago, where she studied painting and drawing. 
After graduating, she moved to New York City to pursue her art career. 
Anna's work is inspired by her personal experiences and observations 
of the world around her. She often uses bright colors and bold lines 
to create vibrant and energetic paintings. Her work has been 
exhibited in galleries and museums in New York City and Chicago.
---

JSON: 

Modifique a chamada model.generate() na classe TextPrompts para transmitir toda a solicitação de texto acima:

Response<String> response = model.generate("""
    Extract the name and age of the person described below.
    Return a JSON document with a "name" and an "age" property, \
    following this structure: {"name": "John Doe", "age": 34}
    Return only JSON, without any markdown markup surrounding it.
    Here is the document describing the person:
    ---
    Anna is a 23 year old artist based in Brooklyn, New York. She was born and 
    raised in the suburbs of Chicago, where she developed a love for art at a 
    young age. She attended the School of the Art Institute of Chicago, where 
    she studied painting and drawing. After graduating, she moved to New York 
    City to pursue her art career. Anna's work is inspired by her personal 
    experiences and observations of the world around her. She often uses bright 
    colors and bold lines to create vibrant and energetic paintings. Her work 
    has been exhibited in galleries and museums in New York City and Chicago.    
    ---
    JSON: 
    """
);

Se você executar esse comando na nossa classe TextPrompts, ele vai retornar a seguinte string JSON, que pode ser analisada com um analisador JSON, como a biblioteca GSON:

$ ./gradlew run -DjavaMainClass=palm.workshop.TextPrompts

> Task :app:run
{"name": "Anna", "age": 23}

BUILD SUCCESSFUL in 24s
2 actionable tasks: 1 executed, 1 up-to-date

Sim. A Anna tem 23 anos!

6. Modelos e comandos estruturados

Além de respostas a perguntas

Modelos de linguagem grandes, como o PaLM, são poderosos para responder a perguntas, mas podem ser usados em muitas outras tarefas. Por exemplo, tente os comandos a seguir no Generative AI Studio (ou modificando a classe TextPrompts). Mude as palavras em maiúsculas pelas suas próprias ideias e examine a saída:

  • Tradução: "Traduza a seguinte frase em francês: YOUR_SENTENCE_HERE"
  • Resumo: "Forneça um resumo do seguinte documento: PASTE_YOUR_DOC"
  • Geração de conteúdo criativo: "Escreva um poema sobre TOPIC_OF_THE_POEM"
  • Programação: "Como escrever uma função de Fibonacci em PROGRAMMING_LANGUAGE?"

Modelos de comandos

Se você testou os comandos acima para tradução, resumo, geração de conteúdo criativo ou tarefas de programação, substituiu os valores de marcador de posição pelas suas próprias ideias. Em vez de fazer alguma manipulação de strings, você também pode aproveitar os modelos de comandos, que permitem definir esses valores de marcador de posição e preencher o espaço em branco depois com seus dados.

Vamos analisar um comando delicioso e criativo. Para isso, substitua todo o conteúdo do método main() pelo código a seguir:

VertexAiLanguageModel model = VertexAiLanguageModel.builder()
            .endpoint("us-central1-aiplatform.googleapis.com:443")
            .project("YOUR_PROJECT_ID")
            .location("us-central1")
            .publisher("google")
            .modelName("text-bison@001")
            .maxOutputTokens(300)
            .build();

PromptTemplate promptTemplate = PromptTemplate.from("""
    Create a recipe for a {{dish}} with the following ingredients: \
    {{ingredients}}, and give it a name.
    """
);

Map<String, Object> variables = new HashMap<>();
variables.put("dish", "dessert");
variables.put("ingredients", "strawberries, chocolate, whipped cream");

Prompt prompt = promptTemplate.apply(variables);

Response<String> response = model.generate(prompt);

System.out.println(response.content());

e adicionando as seguintes importações:

import dev.langchain4j.model.input.Prompt;
import dev.langchain4j.model.input.PromptTemplate;

import java.util.HashMap;
import java.util.Map;

Em seguida, execute o aplicativo novamente. A saída será semelhante a esta:

$ ./gradlew run -DjavaMainClass=palm.workshop.TextPrompts

> Task :app:run
**Strawberry Shortcake**

Ingredients:

* 1 pint strawberries, hulled and sliced
* 1/2 cup sugar
* 1/4 cup cornstarch
* 1/4 cup water
* 1 tablespoon lemon juice
* 1/2 cup heavy cream, whipped
* 1/4 cup confectioners' sugar
* 1/4 teaspoon vanilla extract
* 6 graham cracker squares, crushed

Instructions:

1. In a medium saucepan, combine the strawberries, sugar, cornstarch, water, and lemon juice. Bring to a boil over medium heat, stirring constantly. Reduce heat and simmer for 5 minutes, or until the sauce has thickened.
2. Remove from heat and let cool slightly.
3. In a large bowl, combine the whipped cream, confectioners' sugar, and vanilla extract. Beat until soft peaks form.
4. To assemble the shortcakes, place a graham cracker square on each of 6 dessert plates. Top with a scoop of whipped cream, then a spoonful of strawberry sauce. Repeat layers, ending with a graham cracker square.
5. Serve immediately.

**Tips:**

* For a more elegant presentation, you can use fresh strawberries instead of sliced strawberries.
* If you don't have time to make your own whipped cream, you can use store-bought whipped cream.

Delicioso!

Com modelos de comandos, é possível transmitir os parâmetros obrigatórios antes de chamar o método de geração de texto. Essa é uma ótima maneira de transmitir dados e personalizar comandos para diferentes valores fornecidos pelos usuários.

Como o nome da classe sugere, a classe PromptTemplate cria um modelo de solicitação, e você pode atribuir valores aos elementos de marcador de posição aplicando um mapa de nomes e valores de marcador de posição.

Comandos estruturados (OPCIONAL)

Outra maneira de estruturar seus comandos é com a anotação @StructuredPrompt, se você quiser usar uma abordagem orientada a objetos mais completa. Você anota uma classe com essa anotação, e os campos dela correspondem aos marcadores definidos no comando. Vamos conferir como isso funciona.

Primeiro, vamos precisar de algumas novas importações:

import java.util.Arrays;
import java.util.List;
import dev.langchain4j.model.input.structured.StructuredPrompt;
import dev.langchain4j.model.input.structured.StructuredPromptProcessor;

Em seguida, podemos criar uma classe estática interna na classe TextPrompts que coleta os dados necessários para transmitir os marcadores de posição no comando descrito na anotação @StructuredPrompt:

@StructuredPrompt("Create a recipe of a {{dish}} that can be prepared using only {{ingredients}}")
static class RecipeCreationPrompt {
    String dish;
    List<String> ingredients;
}

Em seguida, crie uma instância dessa nova classe e transmita a ela o prato e os ingredientes da receita. Crie e transmita o comando ao método generate() como antes:

RecipeCreationPrompt createRecipePrompt = new RecipeCreationPrompt();
createRecipePrompt.dish = "salad";
createRecipePrompt.ingredients = Arrays.asList("cucumber", "tomato", "feta", "onion", "olives");
Prompt prompt = StructuredPromptProcessor.toPrompt(createRecipePrompt);

Response<String> response = model.generate(prompt);

Em vez de preencher as lacunas com um mapa, use um objeto Java com campos que podem ser preenchidos automaticamente pelo seu ambiente de desenvolvimento integrado (IDE, na sigla em inglês) de uma maneira mais segura para tipos.

Confira o código completo se quiser colar essas mudanças com mais facilidade na sua classe TextPrompts:

package palm.workshop;

import java.util.Arrays;
import java.util.List;
import dev.langchain4j.model.input.Prompt;
import dev.langchain4j.model.output.Response;
import dev.langchain4j.model.vertexai.VertexAiLanguageModel;
import dev.langchain4j.model.input.structured.StructuredPrompt;
import dev.langchain4j.model.input.structured.StructuredPromptProcessor;

public class TextPrompts {

    @StructuredPrompt("Create a recipe of a {{dish}} that can be prepared using only {{ingredients}}")
    static class RecipeCreationPrompt {
        String dish;
        List<String> ingredients;
    }
    public static void main(String[] args) {
        VertexAiLanguageModel model = VertexAiLanguageModel.builder()
            .endpoint("us-central1-aiplatform.googleapis.com:443")
            .project("YOUR_PROJECT_ID")
            .location("us-central1")
            .publisher("google")
            .modelName("text-bison@001")
            .maxOutputTokens(300)
            .build();

        RecipeCreationPrompt createRecipePrompt = new RecipeCreationPrompt();
        createRecipePrompt.dish = "salad";
        createRecipePrompt.ingredients = Arrays.asList("cucumber", "tomato", "feta", "onion", "olives");
        Prompt prompt = StructuredPromptProcessor.toPrompt(createRecipePrompt);

        Response<String> response = model.generate(prompt);
        
        System.out.println(response.content());
    }
}

7. Classificar texto e analisar sentimento

Assim como no que você aprendeu na seção anterior, você vai descobrir outra técnica de engenharia de comandos para fazer com que o modelo PaLM classifique textos ou analise sentimentos. Vamos falar sobre comando de poucos disparos". É uma maneira de melhorar seus comandos com alguns exemplos que ajudam a direcionar o modelo de linguagem para o que você quer, para entender melhor sua intenção.

Vamos reformular nossa classe TextPrompts para aproveitar os modelos de solicitação:

package palm.workshop;

import java.util.Map;

import dev.langchain4j.model.output.Response;
import dev.langchain4j.model.vertexai.VertexAiLanguageModel;
import dev.langchain4j.model.input.Prompt;
import dev.langchain4j.model.input.PromptTemplate;

public class TextPrompts {
    public static void main(String[] args) {
        VertexAiLanguageModel model = VertexAiLanguageModel.builder()
            .endpoint("us-central1-aiplatform.googleapis.com:443")
            .project("YOUR_PROJECT_ID")
            .location("us-central1")
            .publisher("google")
            .modelName("text-bison@001")
            .maxOutputTokens(10)
            .build();

        PromptTemplate promptTemplate = PromptTemplate.from("""
            Analyze the sentiment of the text below. Respond only with one word to describe the sentiment.

            INPUT: This is fantastic news!
            OUTPUT: POSITIVE

            INPUT: Pi is roughly equal to 3.14
            OUTPUT: NEUTRAL

            INPUT: I really disliked the pizza. Who would use pineapples as a pizza topping?
            OUTPUT: NEGATIVE

            INPUT: {{text}}
            OUTPUT: 
            """);

        Prompt prompt = promptTemplate.apply(
            Map.of("text", "I love strawberries!"));

        Response<String> response = model.generate(prompt);

        System.out.println(response.content());
    }
}

Observe a abordagem de oferecer alguns exemplos de entradas e saídas no comando. Esses são os "poucos disparos" que ajudam o LLM a seguir a mesma estrutura. Quando o modelo recebe uma entrada, ele quer retornar uma saída que corresponda ao padrão de entrada/saída.

A execução do programa vai retornar apenas a palavra POSITIVE, já que morangos também são deliciosos.

$ ./gradlew run -DjavaMainClass=palm.workshop.TextPrompts

> Task :app:run
POSITIVE

A análise de sentimento também é um cenário de classificação de conteúdo. Você pode aplicar a mesma abordagem de "comando de poucos exemplos" para categorizar diferentes documentos em diferentes grupos de categorias.

8. Parabéns

Parabéns! Você criou seu primeiro aplicativo de IA generativa em Java usando o LangChain4J e a API PaLM. Você descobriu ao longo do caminho que os modelos de linguagem grandes são bastante poderosos e capazes de lidar com várias tarefas, como perguntas/respostas, extração de dados, resumo, classificação de texto, análise de sentimentos e muito mais.

Qual é a próxima etapa?

Confira os seguintes codelabs para saber mais sobre o PaLM em Java:

Leia mais

Documentos de referência