Generazione di testi con l'IA generativa in Java con PaLM e LangChain4J

1. Introduzione

Ultimo aggiornamento: 27/11/2023

Che cos'è l'AI generativa

Per AI generativa o intelligenza artificiale generativa si intende l'utilizzo dell'AI per la creazione di nuovi contenuti, come testo, immagini, musica, audio e video.

L'IA generativa sfrutta modelli di base (modelli IA di grandi dimensioni) in grado di eseguire più operazioni contemporaneamente e di eseguire operazioni pronte all'uso, tra cui riepilogo, domande e risposte, classificazione e altro ancora. Inoltre, con un addestramento minimo richiesto, i modelli di base possono essere adattati per casi d'uso mirati con pochissimi dati di esempio.

Come funziona l'AI generativa?

L'AI generativa utilizza un modello di machine learning per apprendere i pattern e le relazioni in un set di dati di contenuti creati dall'uomo. Quindi utilizza i pattern appresi per generare nuovi contenuti.

Il modo più comune per addestrare un modello di AI generativa consiste nell'utilizzare l'apprendimento supervisionato. Al modello viene assegnato un set di contenuti creati dall'uomo ed etichette corrispondenti. Poi, impara a generare contenuti simili a quelli creati dall'uomo ed etichettati con le stesse etichette.

Quali sono le applicazioni comuni dell'AI generativa?

L'IA generativa elabora ampi contenuti, creando insight e risposte tramite testo, immagini e formati facili da usare. L'IA generativa può essere utilizzata per:

  • Migliorare le interazioni con i clienti grazie a esperienze avanzate di chat e ricerca
  • Esplorare enormi quantità di dati non strutturati attraverso interfacce di conversazione e riassunti
  • Assistere nelle attività ripetitive come rispondere alle richieste di proposta (RFP), localizzare i contenuti di marketing in cinque lingue, verificare la conformità dei contratti con i clienti e altro ancora

Quali sono le offerte di AI generativa di Google Cloud?

Con Vertex AI, interagisci con i modelli di base, personalizzali e incorporali nelle tue applicazioni, senza bisogno di competenze di machine learning. Accedi ai modelli di base su Model Garden, ottimizza i modelli tramite una semplice UI su Generative AI Studio oppure utilizza i modelli in un blocco note di data science.

Vertex AI Search and Conversation offre agli sviluppatori il modo più rapido per creare motori di ricerca e chatbot basati sull'AI generativa.

Inoltre, Duet AI è il tuo collaboratore basato sull'AI, disponibile su Google Cloud e negli IDE per aiutarti a fare di più in tempi più rapidi.

Su cosa si concentra questo codelab?

Questo codelab si concentra sul modello linguistico di grandi dimensioni (LLM) PaLM 2, ospitato su Google Cloud Vertex AI, che comprende tutti i prodotti e servizi di machine learning.

Utilizzerai Java per interagire con l'API PaLM, insieme all'orchestratore del framework LLM LangChain4J. Esaminerai diversi esempi concreti per sfruttare l'LLM per rispondere a domande, generare idee, estrarre entità e contenuti strutturati e riassumere.

Scopri di più sul framework LangChain4J.

Il framework LangChain4J è una libreria open source per l'integrazione di modelli linguistici di grandi dimensioni nelle tue applicazioni Java, orchestrando vari componenti, come l'LLM stesso, ma anche altri strumenti come database vettoriali (per ricerche semantiche), caricatori e splitter di documenti (per analizzare i documenti e imparare da loro), analizzatori di output e altro ancora.

c6d7f7c3fd0d2951.png

Cosa imparerai a fare

  • Come configurare un progetto Java per utilizzare PaLM e LangChain4J
  • Come effettuare la prima chiamata al modello di testo PaLM per generare contenuti e rispondere a domande
  • Come estrarre informazioni utili da contenuti non strutturati (estrazione di entità o parole chiave, output in formato JSON)
  • Come eseguire la classificazione dei contenuti o l'analisi del sentiment con il prompting few-shot

Che cosa ti serve

  • Conoscenza del linguaggio di programmazione Java
  • Un progetto Google Cloud
  • Un browser, ad esempio Chrome o Firefox

2. Configurazione e requisiti

Configurazione dell'ambiente autonomo

  1. Accedi alla console Google Cloud e crea un nuovo progetto o riutilizzane uno esistente. Se non hai ancora un account Gmail o Google Workspace, devi crearne uno.

295004821bab6a87.png

37d264871000675d.png

96d86d3d5655cdbe.png

  • Il nome del progetto è il nome visualizzato per i partecipanti a questo progetto. È una stringa di caratteri non utilizzata dalle API di Google. Puoi sempre aggiornarlo.
  • L'ID progetto è univoco in tutti i progetti Google Cloud ed è immutabile (non può essere modificato dopo l'impostazione). La console Cloud genera automaticamente una stringa univoca, di solito non ti interessa di cosa si tratta. Nella maggior parte dei codelab, dovrai fare riferimento all'ID progetto (in genere identificato come PROJECT_ID). Se non ti piace l'ID generato, puoi generarne un altro casuale. In alternativa, puoi provare a crearne uno e vedere se è disponibile. Non può essere modificato dopo questo passaggio e rimane per tutta la durata del progetto.
  • Per tua informazione, esiste un terzo valore, un numero di progetto, utilizzato da alcune API. Scopri di più su tutti e tre questi valori nella documentazione.
  1. Successivamente, devi abilitare la fatturazione in Cloud Console per utilizzare le risorse/API Cloud. Completare questo codelab non costa molto, se non nulla. Per arrestare le risorse ed evitare addebiti oltre a quelli previsti in questo tutorial, puoi eliminare le risorse che hai creato o il progetto. I nuovi utenti di Google Cloud possono usufruire del programma prova senza costi di 300$.

Avvia Cloud Shell

Sebbene Google Cloud possa essere gestito da remoto dal tuo laptop, in questo codelab utilizzerai Cloud Shell, un ambiente a riga di comando in esecuzione nel cloud.

Attiva Cloud Shell

  1. Nella console Cloud, fai clic su Attiva Cloud Shell d1264ca30785e435.png.

cb81e7c8e34bc8d.png

Se è la prima volta che avvii Cloud Shell, viene visualizzata una schermata intermedia che ne descrive le funzionalità. Se è stata visualizzata una schermata intermedia, fai clic su Continua.

d95252b003979716.png

Bastano pochi istanti per eseguire il provisioning e connettersi a Cloud Shell.

7833d5e1c5d18f54.png

Questa macchina virtuale è caricata con tutti gli strumenti di sviluppo necessari. Offre una home directory permanente da 5 GB e viene eseguita in Google Cloud, migliorando notevolmente le prestazioni e l'autenticazione della rete. Gran parte del lavoro per questo codelab, se non tutto, può essere svolto con un browser.

Una volta eseguita la connessione a Cloud Shell, dovresti vedere che il tuo account è autenticato e il progetto è impostato sul tuo ID progetto.

  1. Esegui questo comando in Cloud Shell per verificare che l'account sia autenticato:
gcloud auth list

Output comando

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

To set the active account, run:
    $ gcloud config set account `ACCOUNT`
  1. Esegui questo comando in Cloud Shell per verificare che il comando gcloud conosca il tuo progetto:
gcloud config list project

Output comando

[core]
project = <PROJECT_ID>

In caso contrario, puoi impostarlo con questo comando:

gcloud config set project <PROJECT_ID>

Output comando

Updated property [core/project].

3. Preparazione dell'ambiente di sviluppo

In questo codelab utilizzerai il terminale e l'editor di codice di Cloud Shell per sviluppare i tuoi programmi Java.

Abilita le API Vertex AI

  1. Nella console Google Cloud, assicurati che il nome del progetto sia visualizzato nella parte superiore della console Google Cloud. In caso contrario, fai clic su Seleziona un progetto per aprire il selettore di progetti e seleziona il progetto che ti interessa.
  2. Se non ti trovi nella sezione Vertex AI della console Google Cloud, segui questi passaggi:
  3. In Cerca, inserisci Vertex AI, quindi premi Invio
  4. Nei risultati di ricerca, fai clic su Vertex AI. Viene visualizzata la dashboard di Vertex AI.
  5. Fai clic su Abilita tutte le API consigliate nella dashboard di Vertex AI.

Verranno abilitate diverse API, ma la più importante per il codelab è aiplatform.googleapis.com, che puoi abilitare anche dalla riga di comando, nel terminale Cloud Shell, eseguendo questo comando:

$ gcloud services enable aiplatform.googleapis.com

Creazione della struttura del progetto con Gradle

Per creare gli esempi di codice Java, utilizzerai lo strumento di compilazione Gradle e la versione 17 di Java. Per configurare il progetto con Gradle, nel terminale Cloud Shell crea una directory (in questo caso, palm-workshop) ed esegui il comando gradle init in quella directory:

$ 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

Creerai un'applicazione (opzione 2), utilizzando il linguaggio Java (opzione 3), senza utilizzare i sottoprogetti (opzione 1), utilizzando la sintassi Groovy per il file di build (opzione 1), senza utilizzare nuove funzionalità di build (opzione No), generando test con JUnit Jupiter (opzione 4) e per il nome del progetto puoi utilizzare palm-workshop e, analogamente, per il pacchetto di origine puoi utilizzare palm.workshop.

La struttura del progetto sarà la seguente:

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

Aggiorniamo il file app/build.gradle per aggiungere alcune dipendenze necessarie. Puoi rimuovere la dipendenza guava, se presente, e sostituirla con le dipendenze del progetto LangChain4J e della libreria di logging per evitare messaggi di avviso relativi alla mancanza del logger:

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

Esistono due dipendenze per LangChain4J:

  • uno sul progetto principale,
  • e uno per il modulo Vertex AI dedicato.

Per utilizzare Java 17 per compilare ed eseguire i nostri programmi, aggiungi il seguente blocco sotto il blocco plugins {}:

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

Un'altra modifica da apportare: aggiorna il blocco application di app/build.gradle per consentire agli utenti di eseguire l'override della classe principale da eseguire dalla riga di comando quando viene richiamato lo strumento di compilazione:

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

Per verificare che il file di build sia pronto per eseguire l'applicazione, puoi eseguire la classe principale predefinita che stampa un semplice messaggio Hello World!:

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

> Task :app:run
Hello World!

BUILD SUCCESSFUL in 3s
2 actionable tasks: 2 executed

Ora puoi programmare con il modello linguistico di grandi dimensioni PaLM utilizzando il progetto LangChain4J.

Per riferimento, ecco come dovrebbe apparire ora il file di build app/build.gradle completo:

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. Eseguire la prima chiamata al modello di testo di PaLM

Ora che il progetto è configurato correttamente, è il momento di chiamare l'API PaLM.

Crea una nuova classe denominata TextPrompts.java nella directory app/src/main/java/palm/workshop (accanto alla classe App.java predefinita) e digita i seguenti contenuti:

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

In questo primo esempio, devi importare la classe Response e il modello linguistico Vertex AI per PaLM.

Successivamente, nel metodo main, configurerai il modello linguistico utilizzando lo strumento di creazione per VertexAiLanguageModel per specificare:

  • l'endpoint
  • il progetto,
  • la regione,
  • l'editore,
  • e il nome del modello (text-bison@001).

Ora che il modello linguistico è pronto, puoi chiamare il metodo generate() e passare il "prompt" (ovvero la domanda o le istruzioni da inviare all'LLM). Qui poni una semplice domanda su cosa sono gli LLM. Tuttavia, puoi modificare questo prompt per provare domande o attività diverse.

Per eseguire questa classe, esegui questo comando nel terminale Cloud Shell:

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

Dovresti visualizzare un output simile a questo:

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.

Il generatore VertexAILanguageModel ti consente di definire parametri facoltativi che hanno già alcuni valori predefiniti che puoi ignorare. Ecco alcuni esempi:

  • .temperature(0.2): per definire il livello di creatività della risposta (0 indica una creatività bassa e spesso più oggettiva, mentre 1 indica risultati più creativi)
  • .maxOutputTokens(50): nell'esempio, sono stati richiesti 500 token (3 token equivalgono a circa 4 parole), a seconda della lunghezza della risposta generata
  • .topK(20): per selezionare in modo casuale una parola tra un numero massimo di parole probabili per il completamento del testo (da 1 a 40)
  • .topP(0.95): per selezionare le parole possibili la cui probabilità totale è pari a quel numero in virgola mobile (compreso tra 0 e 1)
  • .maxRetries(3): se superi la quota di richieste per periodo di tempo, puoi fare in modo che il modello riprovi la chiamata 3 volte, ad esempio

I modelli linguistici di grandi dimensioni (LLM) sono molto potenti, possono fornire risposte a domande complesse e sono in grado di gestire un'ampia gamma di attività interessanti. Nella prossima sezione, esamineremo un'attività utile: l'estrazione di dati strutturati dal testo.

5. Estrazione di informazioni da testo non strutturato

Nella sezione precedente hai generato un output di testo. Va bene se vuoi mostrare direttamente questo output agli utenti finali. Ma se vuoi recuperare i dati menzionati in questo output, come fai a estrarre queste informazioni dal testo non strutturato?

Supponiamo che tu voglia estrarre il nome e l'età di una persona, data una biografia o una descrizione della persona. Puoi indicare al modello linguistico di grandi dimensioni di generare strutture di dati JSON modificando il prompt come segue (questa operazione è comunemente chiamata "prompt engineering"):

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: 

Modifica la chiamata model.generate() nella classe TextPrompts per passare l'intero prompt di testo riportato sopra:

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 esegui questo prompt nella nostra classe TextPrompts, dovrebbe restituire la seguente stringa JSON, che puoi analizzare con un parser JSON come la libreria 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

Sì. Anna ha 23 anni.

6. Modelli di prompt e prompt strutturati

Oltre alla risposta alle domande

I modelli linguistici di grandi dimensioni come PaLM sono potenti per rispondere alle domande, ma puoi utilizzarli per molte altre attività. Ad esempio, prova i seguenti prompt in Generative AI Studio (o modificando la classe TextPrompts). Modifica le parole in maiuscolo con le tue idee ed esamina l'output:

  • Traduzione: "Traduci la seguente frase in francese: YOUR_SENTENCE_HERE"
  • Riepilogo: "Fornisci un riepilogo del seguente documento: INCOLLA_IL_DOCUMENTO"
  • Generazione di creatività: "Scrivi una poesia su TOPIC_OF_THE_POEM"
  • Programmazione: "Come scrivere una funzione di Fibonacci in PROGRAMMING_LANGUAGE?"

Modelli di prompt

Se hai provato i prompt precedenti per la traduzione, il riepilogo, la generazione di creatività o le attività di programmazione, hai sostituito i valori dei segnaposto con le tue idee. Tuttavia, anziché manipolare le stringhe, puoi anche sfruttare i "modelli di prompt", che ti consentono di definire i valori dei segnaposto e riempire lo spazio vuoto in un secondo momento con i tuoi dati.

Diamo un'occhiata a un prompt gustoso e creativo sostituendo l'intero contenuto del metodo main() con il seguente codice:

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 aggiungendo le seguenti importazioni:

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

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

Quindi esegui di nuovo l'applicazione. L'output dovrebbe essere simile al seguente:

$ ./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.

Delizioso!

Con i modelli di prompt, puoi inserire i parametri richiesti prima di chiamare il metodo di generazione del testo. Questo è un ottimo modo per trasmettere dati e personalizzare i prompt per valori diversi forniti dagli utenti.

Come suggerisce il nome della classe, la classe PromptTemplate crea un prompt del modello e puoi assegnare valori agli elementi segnaposto applicando una mappa di nomi e valori dei segnaposto.

Prompt strutturati (FACOLTATIVO)

Un altro modo per strutturare i prompt è con l'annotazione @StructuredPrompt, se vuoi utilizzare un approccio più orientato agli oggetti. Annoti una classe con questa annotazione e i relativi campi corrispondono ai segnaposto definiti nel prompt. Vediamo come funziona.

Innanzitutto, avremo bisogno di alcuni nuovi import:

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

Poi possiamo creare una classe statica interna all'interno della classe TextPrompts che raccoglie i dati necessari per inserire i segnaposto nel prompt descritto nell'annotazione @StructuredPrompt:

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

Poi crea un'istanza della nuova classe e inserisci il piatto e gli ingredienti della nostra ricetta, crea e passa il prompt al metodo generate() come prima:

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

Invece di riempire i vuoti tramite una mappa, puoi utilizzare un oggetto Java con campi che possono essere completati automaticamente dal tuo IDE in modo più sicuro per i tipi.

Ecco il codice completo se vuoi incollare più facilmente le modifiche nella tua 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. Classificare il testo e analizzare il sentiment

Come hai imparato nella sezione precedente, scoprirai un'altra tecnica di "prompt engineering" per fare in modo che il modello PaLM classifichi il testo o analizzi i sentiment. Parliamo del "few-shot prompting". È un modo per migliorare i prompt con alcuni esempi che aiuteranno il modello linguistico a seguire la direzione che preferisci, in modo da comprendere meglio la tua intenzione.

Rielaboriamo la nostra classe TextPrompts per sfruttare i modelli di prompt:

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

Nota l'approccio che prevede di offrire alcuni esempi di input e output nel prompt. Questi sono i "pochi esempi" che aiutano l'LLM a seguire la stessa struttura. Quando il modello riceve un input, restituisce un output che corrisponde al pattern input/output.

L'esecuzione del programma dovrebbe restituire solo la parola POSITIVE, perché anche le fragole sono deliziose.

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

> Task :app:run
POSITIVE

L'analisi del sentiment è anche uno scenario di classificazione dei contenuti. Puoi applicare lo stesso approccio di "few-shot prompting" per classificare documenti diversi in bucket di categorie diverse.

8. Complimenti

Congratulazioni, hai creato la tua prima applicazione di IA generativa in Java utilizzando LangChain4J e l'API PaLM. Nel corso del tempo, hai scoperto che i modelli linguistici di grandi dimensioni sono piuttosto potenti e in grado di gestire varie attività come domande/risposte, estrazione di dati, riepilogo, classificazione del testo, analisi del sentiment e altro ancora.

Passaggi successivi

Dai un'occhiata ai seguenti codelab per approfondire l'utilizzo di PaLM in Java:

Further reading

Documenti di riferimento