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

1. Introduzione

Ultimo aggiornamento: 27-11-2023

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, i modelli di base possono essere adattati per casi d'uso mirati con pochissimi dati di esempio.

Come funziona l'IA generativa?

L'IA generativa funziona utilizzando un modello di ML (machine learning) per apprendere i pattern e le relazioni in un set di dati di contenuti creati da persone fisiche. Quindi utilizza i pattern appresi per generare nuovi contenuti.

Il modo più comune per addestrare un modello di IA generativa è utilizzare l'apprendimento supervisionato: al modello viene assegnato un insieme di contenuti creati dall'uomo e le relative etichette. Poi, impara a generare contenuti simili a quelli creati dall'uomo ed etichettati con le stesse etichette.

Cosa sono le applicazioni comuni di IA 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:

  • Migliora le interazioni con i clienti grazie a esperienze di chat e ricerca avanzate
  • Esplora grandi quantità di dati non strutturati attraverso interfacce conversazionali 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 offerte di IA generativa offre Google Cloud?

Con Vertex AI, puoi interagire con i modelli di base, personalizzarli e incorporarli nelle tue applicazioni, il che richiede poca o nessuna esperienza in termini di ML. Accedi ai modelli di base su Model Garden, ottimizza i modelli tramite una semplice UI su Generative AI Studio o 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'IA generativa.

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

Su cosa si concentra questo codelab?

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

Utilizzerai Java per interagire con l'API PaLM, insieme allo strumento di orchestrazione del framework LLM LangChain4J. Osserverai diversi esempi concreti per sfruttare l'LLM per la risposta alle domande, la generazione di idee, l'estrazione di entità e contenuti strutturati e il riassunto.

Vorrei maggiori informazioni sul framework LangChain4J.

Il framework LangChain4J è una libreria open source per integrare modelli linguistici di grandi dimensioni (LLM) nelle applicazioni Java, orchestrando vari componenti, come l'LLM stesso, ma anche altri strumenti come database vettoriali (per le ricerche semantiche), caricatori di documenti e splitter (per analizzare documenti e imparare da essi), parser 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 alle domande
  • Come estrarre informazioni utili da contenuti non strutturati (estrazione di entità o parole chiave, output in JSON)
  • Come eseguire la classificazione dei contenuti o l'analisi del sentiment con pochi prompt

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 da seguire in modo 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 progetto è il nome visualizzato dei partecipanti del progetto. Si tratta di una stringa di caratteri non utilizzata dalle API di Google. Puoi sempre aggiornarla.
  • L'ID progetto è univoco in tutti i progetti Google Cloud ed è immutabile (non può essere modificato dopo essere stato impostato). La console Cloud genera automaticamente una stringa univoca. di solito non ti importa cosa sia. Nella maggior parte dei codelab, dovrai fare riferimento al tuo ID progetto (in genere identificato come PROJECT_ID). Se l'ID generato non ti soddisfa, potresti generarne un altro casuale. In alternativa, puoi provarne una personalizzata per verificare se è disponibile. Non può essere modificato dopo questo passaggio e rimane per tutta la durata del progetto.
  • Per informazione, c'è un terzo valore, un numero di progetto, utilizzato da alcune API. Scopri di più su tutti e tre questi valori nella documentazione.
  1. Successivamente, dovrai abilitare la fatturazione nella console Cloud per utilizzare risorse/API Cloud. L'esecuzione di questo codelab non ha alcun costo. Per arrestare le risorse ed evitare di incorrere in fatturazione dopo questo tutorial, puoi eliminare le risorse che hai creato o eliminare il progetto. I nuovi utenti di Google Cloud sono idonei al programma prova senza costi di 300$.

Avvia Cloud Shell

Mentre Google Cloud può essere utilizzato 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. Dalla console Cloud, fai clic su Attiva Cloud Shell d1264ca30785e435.png.

cb81e7c8e34bc8d.png

Se è la prima volta che avvii Cloud Shell, ti verrà mostrata una schermata intermedia che descrive di cosa si tratta. Se ti è stata presentata una schermata intermedia, fai clic su Continua.

d95252b003979716.png

Il provisioning e la connessione a Cloud Shell dovrebbero richiedere solo qualche istante.

7833d5e1c5d18f54.png

Questa macchina virtuale viene 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 di rete e l'autenticazione. Gran parte, se non tutto, del lavoro in questo codelab può essere svolto con un browser.

Una volta stabilita la connessione a Cloud Shell, dovresti vedere che hai eseguito l'autenticazione e che 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 confermare che il comando gcloud è a conoscenza del 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 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 parte Vertex AI della console Google Cloud, segui questi passaggi:
  3. In Ricerca, inserisci Vertex AI e poi torna
  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.

Questa operazione abiliterà diverse API, ma la più importante per il codelab è aiplatform.googleapis.com, che puoi abilitare anche sulla 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 esempi di codice Java, utilizzerai lo strumento di creazione Gradle e la versione 17 di Java. Per configurare il tuo progetto con Gradle, crea una directory (qui, palm-workshop) nel terminale Cloud Shell 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 sottoprogetti (opzione 1), utilizzando la sintassi Groovy per il file di build (opzione 1), non utilizzare nuove caratteristiche di build (opzione no), generando test con JUnit Jupiter (opzione 4) e, per il nome del progetto, puoi utilizzare palm-workshop allo stesso modo.

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 con la libreria di log per evitare fastidiosi messaggi del logger mancanti:

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

Ci sono 2 dipendenze per LangChain4J:

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

Per usare 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 dalla riga di comando quando richiamano lo strumento di build:

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 è tutto pronto per programmare con il modello di testo linguistico di grandi dimensioni (LLM) PaLM, utilizzando il progetto LangChain4J.

Come 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. Effettuare 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 (oltre 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.

Poi, nel metodo main, configurerai il modello linguistico, utilizzando il generatore per VertexAiLanguageModel, per specificare:

  • l'endpoint,
  • del progetto.
  • 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" (ad es. la domanda o le istruzioni da inviare all'LLM). Qui devi fare una semplice domanda su cosa sono gli LLM. Puoi però modificare questo prompt per provare altre domande o attività.

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

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

Dovresti vedere 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.

Lo strumento per la creazione di VertexAILanguageModel consente di definire parametri facoltativi che hanno già alcuni valori predefiniti che puoi sostituire. Ecco alcuni esempi:

  • .temperature(0.2): per definire la creatività desiderata per la risposta (0 corrisponde a una creatività scarsa e spesso più fattuale, mentre 1 indica risultati più creativi)
  • .maxOutputTokens(50): nell'esempio, sono stati richiesti 500 token (3 token equivalgono circa a 4 parole), a seconda di quanto tempo vuoi che venga utilizzata la 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 possibili parole la cui probabilità totale somma la somma di quel numero in virgola mobile (compreso tra 0 e 1)
  • .maxRetries(3): se hai superato la richiesta per quota di tempo, puoi chiedere al modello di riprovare la chiamata 3 volte, ad esempio

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

5. Estrazione di informazioni da testo non strutturato

Nella sezione precedente, hai generato un output di testo. Questo va bene se vuoi mostrare direttamente questo output agli utenti finali. Ma se vuoi recuperare i dati menzionati in questo output, come puoi 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 di quella persona. Puoi indicare al modello LLM di generare strutture di dati JSON modificando il prompt come segue (comunemente, "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 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 potresti 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 il question answering

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). Cambia le parole maiuscole con le tue idee ed esaminane l'output:

  • Traduzione — "Traduci la seguente frase in francese: YOUR_SENTENCE_HERE"
  • Riassunto: "Fornisci un riepilogo del seguente documento: PASTE_YOUR_DOC"
  • 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 le attività di traduzione, riepilogo, generazione di creatività o programmazione, hai sostituito i valori segnaposto con le tue idee. Tuttavia, invece di eseguire un po' di gestione delle stringhe, puoi anche ricorrere ai "modelli di prompt", che ti consentono di definire questi valori segnaposto e di riempire in seguito gli spazi vuoti con i tuoi dati.

Diamo un'occhiata a un prompt delizioso 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());

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 fornire i parametri richiesti prima di chiamare il metodo di generazione del testo. Questo è un ottimo modo per trasmettere i dati e personalizzare le richieste per valori diversi, forniti dagli utenti.

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

Prompt strutturati (FACOLTATIVO)

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

Innanzitutto, avremo bisogno di alcune nuove importazioni:

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 da passare nei 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;
}

Quindi crea un'istanza per la nuova classe e fornisci 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 colmare le lacune attraverso una mappa, puoi usare un oggetto Java con campi che possono essere completati automaticamente dal tuo IDE, in modo più sicuro dal tipo.

Ecco il codice completo per incollare più facilmente queste modifiche nel tuo corso 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. Classificazione del testo e analisi del sentiment

Analogamente a quanto appreso nella sezione precedente, scoprirai un'altra tecnica di "prompt engineering" per far classificare il testo o analizzare il sentiment al modello PaLM. Parliamo di "prompt few-shot". È un modo per migliorare i tuoi prompt con alcuni esempi che ti aiuteranno a indirizzare il modello linguistico nella direzione desiderata, per comprendere meglio le tue intenzioni.

Rielabora la nostra lezione 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 alcuni esempi di input e output nel prompt. Ecco le "poche immagini" che aiutano l'LLM a seguire la stessa struttura. Quando il modello riceve un input, vuole restituire un output che corrisponda al pattern di input/output.

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

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

> Task :app:run
POSITIVE

Anche l'analisi del sentiment è uno scenario di classificazione dei contenuti. Puoi applicare lo stesso approccio di "prompt few-shot" per classificare documenti diversi in bucket di categorie differenti.

8. Complimenti

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

Passaggi successivi

Dai un'occhiata ad alcuni dei seguenti codelab per andare oltre con PaLM in Java:

Per approfondire

Documenti di riferimento