Generación de texto de IA generativa en Java con PaLM y LangChain4J

1. Introducción

Última actualización: 27/11/2023

Qué es la IA generativa

La IA generativa o inteligencia artificial generativa hace referencia al uso de la IA para crear contenido nuevo, como texto, imágenes, música, audio y videos.

La IA generativa usa modelos de base (modelos de IA grandes) que pueden realizar varias tareas a la vez y de manera predeterminada, como resúmenes, preguntas y respuestas, clasificación y mucho más. Además, con el entrenamiento mínimo necesario, los modelos de base se pueden adaptar a casos de uso segmentados con muy pocos ejemplos de datos.

¿Cómo funciona la IA generativa?

La IA generativa usa un modelo de AA (aprendizaje automático) para aprender los patrones y relaciones en un conjunto de datos de contenido creado por humanos. Luego, usa los patrones aprendidos para generar contenido nuevo.

La forma más común de entrenar un modelo de IA generativa es a través del aprendizaje supervisado; al modelo se le asigna un conjunto de contenido creado por humanos y las etiquetas correspondientes. Luego, aprende a generar contenido similar al creado por humanos y etiquetado con las mismas etiquetas.

¿Cuáles son las aplicaciones comunes de IA generativa?

La IA generativa procesa mucho contenido, lo que crea estadísticas y respuestas a través de texto, imágenes y formatos fáciles de usar. Estos son algunos usos de la IA generativa:

  • Optimiza las interacciones con los clientes por medio de las experiencias de búsqueda y de chat mejoradas
  • Explora grandes cantidades de datos no estructurados a través de interfaces conversacionales y resúmenes
  • Brinda asistencia con tareas repetitivas, como responder solicitudes de propuestas (RFP), localizar contenido de marketing en cinco idiomas, revisar el cumplimiento de los contratos de los clientes y mucho más.

¿Qué ofertas de IA generativa tiene Google Cloud?

Con Vertex AI, puedes interactuar con los modelos de base, incorporarlos y personalizarlos en tus aplicaciones. Se necesita poca o ninguna experiencia en AA. Accede a los modelos de base en Model Garden, ajústalos con una IU simple en Generative AI Studio o usa modelos en un notebook de ciencia de datos.

Vertex AI Search and Conversation ofrece a los desarrolladores la forma más rápida de compilar motores de búsqueda y chatbots potenciados por IA generativa.

Además, Duet AI es tu colaborador potenciado por IA, disponible en Google Cloud y en los IDE para ayudarte a hacer más tareas con mayor rapidez.

¿En qué se enfoca este codelab?

Este codelab se enfoca en el modelo grande de lenguaje (LLM) PaLM 2, alojado en Vertex AI de Google Cloud, que abarca todos los productos y servicios del aprendizaje automático.

Usarás Java para interactuar con la API de PaLM y el organizador del framework de LLM LangChain4J. Verás diferentes ejemplos concretos para aprovechar el LLM para responder preguntas, generar ideas, extraer entidades y contenidos estructurados, y resumirlos.

¡Dame más información sobre el framework de LangChain4J!

El framework LangChain4J es una biblioteca de código abierto para integrar modelos grandes de lenguaje en tus aplicaciones de Java mediante la organización de varios componentes, como el LLM mismo, pero también otras herramientas, como bases de datos de vectores (para búsquedas semánticas), cargadores y divisores de documentos (para analizar documentos y aprender de ellos), analizadores de salida y mucho más.

c6d7f7c3fd0d2951.png

Qué aprenderás

  • Cómo configurar un proyecto de Java para usar PaLM y LangChain4J
  • Cómo hacer tu primera llamada al modelo de texto PaLM para generar contenido y responder preguntas
  • Cómo extraer información útil de contenido no estructurado (extracción de entidades o palabras clave, resultado en JSON)
  • Cómo realizar una clasificación de contenido o un análisis de opiniones con instrucciones de pocas tomas

Requisitos

  • Conocimientos del lenguaje de programación Java
  • Un proyecto de Google Cloud
  • Un navegador, como Chrome o Firefox

2. Configuración y requisitos

Configuración del entorno de autoaprendizaje

  1. Accede a Google Cloud Console y crea un proyecto nuevo o reutiliza uno existente. Si aún no tienes una cuenta de Gmail o de Google Workspace, debes crear una.

295004821bab6a87.png

37d264871000675d.png

96d86d3d5655cdbe.png

  • El Nombre del proyecto es el nombre visible de los participantes de este proyecto. Es una cadena de caracteres que no se utiliza en las APIs de Google. Puedes actualizarla cuando quieras.
  • El ID del proyecto es único en todos los proyectos de Google Cloud y es inmutable (no se puede cambiar después de configurarlo). La consola de Cloud genera automáticamente una cadena única. Por lo general, no importa cuál sea. En la mayoría de los codelabs, deberás hacer referencia al ID de tu proyecto (suele identificarse como PROJECT_ID). Si no te gusta el ID que se generó, podrías generar otro aleatorio. También puedes probar uno propio y ver si está disponible. No se puede cambiar después de este paso y se usa el mismo durante todo el proyecto.
  • Recuerda que hay un tercer valor, un número de proyecto, que usan algunas APIs. Obtén más información sobre estos tres valores en la documentación.
  1. A continuación, deberás habilitar la facturación en la consola de Cloud para usar las APIs o los recursos de Cloud. Ejecutar este codelab no costará mucho, tal vez nada. Para cerrar recursos y evitar que se generen cobros más allá de este instructivo, puedes borrar los recursos que creaste o borrar el proyecto. Los usuarios nuevos de Google Cloud son aptos para participar en el programa Prueba gratuita de $300.

Inicia Cloud Shell

Si bien Google Cloud se puede operar de manera remota desde tu laptop, en este codelab usarás Cloud Shell, un entorno de línea de comandos que se ejecuta en la nube.

Activar Cloud Shell

  1. En la consola de Cloud, haz clic en Activar Cloud Shelld1264ca30785e435.png.

cb81e7c8e34bc8d.png

Si es la primera vez que inicias Cloud Shell, verás una pantalla intermedia que describe en qué consiste. Si apareció una pantalla intermedia, haz clic en Continuar.

d95252b003979716.png

El aprovisionamiento y la conexión a Cloud Shell solo tomará unos minutos.

7833d5e1c5d18f54.png

Esta máquina virtual está cargada con todas las herramientas de desarrollo necesarias. Ofrece un directorio principal persistente de 5 GB y se ejecuta en Google Cloud, lo que mejora considerablemente el rendimiento de la red y la autenticación. Gran parte de tu trabajo en este codelab, si no todo, se puede hacer con un navegador.

Una vez que te conectes a Cloud Shell, deberías ver que estás autenticado y que el proyecto está configurado con tu ID del proyecto.

  1. En Cloud Shell, ejecuta el siguiente comando para confirmar que tienes la autenticación:
gcloud auth list

Resultado del comando

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

To set the active account, run:
    $ gcloud config set account `ACCOUNT`
  1. Ejecuta el siguiente comando en Cloud Shell para confirmar que el comando de gcloud conoce tu proyecto:
gcloud config list project

Resultado del comando

[core]
project = <PROJECT_ID>

De lo contrario, puedes configurarlo con el siguiente comando:

gcloud config set project <PROJECT_ID>

Resultado del comando

Updated property [core/project].

3. Cómo preparar tu entorno de desarrollo

En este codelab, usarás la terminal y el editor de código de Cloud Shell para desarrollar tus programas de Java.

Habilita las APIs de Vertex AI

  1. En la consola de Google Cloud, asegúrate de que el nombre de tu proyecto aparezca en la parte superior de la consola de Google Cloud. Si no lo está, haz clic en Seleccionar un proyecto para abrir el Selector de proyectos y selecciona el proyecto deseado.
  2. Si no estás en la parte de Vertex AI de la consola de Google Cloud, haz lo siguiente:
  3. En Buscar, ingresa Vertex AI y, luego, regresa.
  4. En los resultados de la búsqueda, haz clic en Vertex AI. Aparecerá el panel de Vertex AI.
  5. Haz clic en Habilitar todas las APIs recomendadas en el panel de Vertex AI.

Esto habilitará varias APIs, pero la más importante para el codelab es aiplatform.googleapis.com, que también puedes habilitar en la línea de comandos, en la terminal de Cloud Shell, ejecutando el siguiente comando:

$ gcloud services enable aiplatform.googleapis.com

Cómo crear la estructura del proyecto con Gradle

Para compilar tus ejemplos de código Java, usarás la herramienta de compilación Gradle y la versión 17 de Java. Para configurar tu proyecto con Gradle, en la terminal de Cloud Shell, crea un directorio (aquí, palm-workshop) y ejecuta el comando gradle init en ese directorio:

$ 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

Compilarás una aplicación (opción 2) con el lenguaje Java (opción 3), sin usar subproyectos (opción 1), usarás la sintaxis de Groovy para el archivo de compilación (opción 1), no usarás nuevas funciones de compilación (opción no), generando pruebas con JUnit Jupiter (opción 4) y, para el nombre del proyecto, puedes usar palm-workshop.De manera similar, puedes usar palm-workshop.

La estructura del proyecto será la siguiente:

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

Actualicemos el archivo app/build.gradle para agregar algunas dependencias necesarias. Puedes quitar la dependencia guava si está presente y reemplazarla con las dependencias para el proyecto LangChain4J y la biblioteca de registro para evitar la molestia de los mensajes de registrador que faltan:

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

Hay 2 dependencias para LangChain4J:

  • una en el proyecto principal,
  • y otro para el módulo dedicado de Vertex AI.

Si deseas usar Java 17 para compilar y ejecutar nuestros programas, agrega el siguiente bloque debajo del bloque plugins {}:

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

Un cambio más para hacer: actualiza el bloque application de app/build.gradle para permitir que los usuarios puedan anular la clase principal que se ejecutará en la línea de comandos cuando invoquen la herramienta de compilación:

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

Para comprobar que tu archivo de compilación esté listo para ejecutar tu aplicación, puedes ejecutar la clase principal predeterminada que imprime un mensaje Hello World! simple:

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

> Task :app:run
Hello World!

BUILD SUCCESSFUL in 3s
2 actionable tasks: 2 executed

Ya tienes todo listo para programar con el modelo de texto de lenguaje grande de PaLM usando el proyecto LangChain4J.

A modo de referencia, así es como debería verse el archivo de compilación app/build.gradle completo ahora:

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. Cómo hacer tu primera llamada al modelo de texto de PaLM

Ahora que el proyecto está configurado correctamente, es momento de llamar a la API de PaLM.

Crea una clase nueva llamada TextPrompts.java en el directorio app/src/main/java/palm/workshop (junto con la clase App.java predeterminada) y escribe el siguiente contenido:

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

En este primer ejemplo, debes importar la clase Response y el modelo de lenguaje de Vertex AI para PaLM.

A continuación, en el método main, configurarás el modelo de lenguaje con el compilador del VertexAiLanguageModel para especificar:

  • el extremo,
  • el proyecto,
  • la región
  • el publicador,
  • y el nombre del modelo (text-bison@001).

Ahora que el modelo de lenguaje está listo, puedes llamar al método generate() y pasar la "instrucción" (es decir, tu pregunta o instrucciones para enviar al LLM). Aquí, harás una pregunta sencilla sobre qué son los LLM. Pero siéntete libre de cambiar esta instrucción para probar diferentes preguntas o tareas.

Para ejecutar esta clase, ejecuta el siguiente comando en la terminal de Cloud Shell:

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

Deberías ver un resultado similar al siguiente:

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.

El compilador de VertexAILanguageModel te permite definir parámetros opcionales que ya tienen algunos valores predeterminados que puedes anular. Estos son algunos ejemplos:

  • .temperature(0.2): Indica qué tan creativa quieres que sea la respuesta (0 es poco creativa y, a menudo, más fáctica, mientras que 1 es para más resultados de creatividades).
  • .maxOutputTokens(50): En el ejemplo, se solicitaron 500 tokens (3 tokens son equivalentes a 4 palabras), según el tiempo que desees que tenga la respuesta generada.
  • .topK(20): Permite seleccionar de forma aleatoria una palabra de la cantidad máxima de palabras probablemente para completar el texto (de 1 a 40).
  • .topP(0.95): Para seleccionar las palabras posibles cuya probabilidad total suma ese número de punto flotante (entre 0 y 1)
  • .maxRetries(3): En caso de que estés ejecutando más allá de la cuota de solicitudes por tiempo, puedes hacer que el modelo vuelva a intentar la llamada 3 veces, por ejemplo.

Los modelos grandes de lenguaje son muy potentes y pueden proporcionar respuestas a preguntas complejas y pueden manejar una gran variedad de tareas interesantes. En la siguiente sección, examinaremos una tarea útil: extraer datos estructurados de un texto.

5. Extrae información de texto no estructurado

En la sección anterior, generaste alguna salida de texto. Esto está bien si quieres mostrar directamente este resultado a tus usuarios finales. Pero si quieres recuperar los datos que se mencionan en este resultado, ¿cómo puedes extraer esa información del texto no estructurado?

Digamos que quieres extraer el nombre y la edad de una persona, según una biografía o descripción de esa persona. Puedes indicarle al modelo grande de lenguaje que genere estructuras de datos JSON ajustando la instrucción de la siguiente manera (esto se suele denominar "ingeniería de instrucciones"):

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 llamada model.generate() en la clase TextPrompts para pasar toda la instrucción de texto anterior:

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

Si ejecutas esta instrucción en nuestra clase TextPrompts, debería mostrar la siguiente cadena JSON, que puedes analizar con un analizador de JSON como la 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

Sí. ¡Anna tiene 23 años!

6. Plantillas de instrucciones e instrucciones estructuradas

Más allá de responder preguntas

Los modelos grandes de lenguaje como PaLM son potentes para responder preguntas, pero los puedes usar para muchas más tareas. Por ejemplo, prueba las siguientes instrucciones en Generative AI Studio (o modifica la clase TextPrompts). Cambia las palabras en mayúsculas con tus propias ideas y examina su resultado:

  • Traducción: "Traduce la siguiente oración al francés: YOUR_SENTENCE_HERE"
  • Resúmenes: "Proporciona un resumen del siguiente documento: PASTE_YOUR_DOC"
  • Generación de creatividades: "Escribe un poema sobre TOPIC_OF_THE_POEM"
  • Programación: "¿Cómo se escribe una función de Fibonacci en PROGRAMMING_LANGUAGE?"

Plantillas de instrucciones

Si probaste las instrucciones de traducción, resumen, generación de creatividades o tareas de programación, reemplazaste los valores de marcador de posición por tus propias ideas. Pero en lugar de modificar algunas cadenas, también puedes aprovechar las “plantillas de instrucciones”, que te permiten definir esos valores de marcador de posición y, luego, completar el espacio en blanco con tus datos.

Veamos una instrucción deliciosa y creativa reemplazando todo el contenido del método main() por el siguiente código:

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

Y agregando las siguientes importaciones:

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

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

A continuación, vuelve a ejecutar la aplicación. El resultado debería ser similar al siguiente:

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

Con las plantillas de instrucciones, puedes ingresar los parámetros necesarios antes de llamar al método de generación de texto. Esta es una excelente manera de pasar datos y personalizar mensajes para diferentes valores que proporcionan los usuarios.

Como sugiere el nombre de la clase, la clase PromptTemplate crea una instrucción de plantilla y puedes asignar valores a los elementos de marcador de posición aplicando un mapa de nombres y valores de marcador de posición.

Instrucciones estructuradas (OPCIONAL)

Otra forma de estructurar tus instrucciones es con la anotación @StructuredPrompt, si quieres usar un enfoque más enriquecido y orientado a objetos. Puedes anotar una clase con esta anotación, y sus campos corresponden a los marcadores de posición definidos en la instrucción. Veamos eso en acción.

Primero, necesitaremos algunas importaciones nuevas:

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

Luego, podemos crear una clase estática interna dentro de nuestra clase TextPrompts que recopile los datos necesarios para pasar los marcadores de posición en la instrucción descrita en la anotación @StructuredPrompt:

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

Luego, crea una instancia de esa clase nueva y agrégale el plato y los ingredientes de nuestra receta. Luego, crea y pasa la instrucción al método generate() como lo hiciste 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);

En lugar de llenar los vacíos en un mapa, puedes usar un objeto Java con campos que tu IDE pueda autocompletar, de manera más segura de tipos.

Este es el código completo si quieres pegar esos cambios con mayor facilidad en tu clase 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. Clasificar texto y analizar opiniones

De manera similar a lo que aprendiste en la sección anterior, descubrirás otra técnica de “ingeniería de instrucciones” para hacer que el modelo PaLM clasifique texto o analice opiniones. Hablemos sobre la "instrucción con ejemplos limitados". Es una forma de mejorar tus instrucciones con algunos ejemplos que te ayudarán a dirigir el modelo de lenguaje hacia la dirección que deseas, para comprender mejor tu intención.

Volvamos a crear nuestra clase TextPrompts para aprovechar las plantillas de instrucciones:

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

Observa el enfoque que se usa para ofrecer algunos ejemplos de entradas y salidas en las instrucciones. Estas son las "pocas tomas" que ayudan al LLM a seguir la misma estructura. Cuando el modelo reciba una entrada, querrá devolver una salida que coincida con el patrón de entrada/salida.

Cuando ejecutes el programa, se debería mostrar solo la palabra POSITIVE, ya que las fresas también son deliciosas.

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

> Task :app:run
POSITIVE

El análisis de opiniones también es un escenario de clasificación de contenido. Puedes aplicar el mismo enfoque de “instrucciones con ejemplos limitados” para categorizar diferentes documentos en diferentes segmentos de categorías.

8. Felicitaciones

¡Felicitaciones! Compilaste con éxito tu primera aplicación de IA generativa en Java usando LangChain4J y la API de PaLM. Con el tiempo, descubriste que los modelos grandes de lenguaje son bastante poderosos y capaces de manejar varias tareas, como preguntas y respuestas, extracción de datos, resúmenes, clasificación de textos, análisis de opiniones y mucho más.

¿Qué sigue?

Consulta algunos de los siguientes codelabs para avanzar con PaLM en Java:

Lecturas adicionales

Documentos de referencia