Compila aplicaciones de IA con agentes en Java con LangChain4j y la IA generativa de Google

1. 1. Antes de comenzar

Resumen del codelab en formato de boceto

¡Te damos la bienvenida! En este codelab, aprenderás a compilar aplicaciones de IA de agentes en Java con el popular framework LangChain4j y su nuevo módulo Google GenAI.

La IA de agentes se refiere a sistemas en los que los LLM no solo responden a instrucciones, sino que están equipados con herramientas, memoria y capacidades de planificación para lograr de forma autónoma objetivos complejos de varios pasos.

Comenzarás con configuraciones simples, avanzarás hasta crear agentes con herramientas locales y resultados estructurados, y, por último, explorarás patrones avanzados de organización multiagente, que culminarán en un sistema de agentes de planificación de acciones orientada a objetivos (GOAP).

Actividades

  • Configura el nuevo GoogleGenAiChatModel para conectarte a Gemini.
  • Habilita el registro de solicitudes y respuestas para facilitar la depuración.
  • Otorga acceso a Gemini al código Java local con Herramientas.
  • Aplicar el formato de salida estructurada (POJO) de Gemini
  • Define y crea agentes de un solo propósito con la anotación @Agent.
  • Organiza flujos de trabajo multiagente secuenciales y paralelos.
  • Crea un sistema de planificación de acciones orientada a objetivos (GOAP) que planifique de forma dinámica la ejecución del agente.

Requisitos

  • Java Development Kit (JDK) 17 o una versión posterior
  • Maven 3.5 o una versión posterior instalada
  • Una clave de la API de Gemini de Google AI Studio

2. 2. Configuración: Proyecto y clave de API

Para comenzar, debemos crear un proyecto nuevo de Maven y configurar nuestra clave de la API de Gemini.

Crea el proyecto de Maven

Crea un directorio nuevo para tu proyecto y, luego, inicialízalo con un archivo pom.xml.

Agrega las siguientes dependencias a tu pom.xml. Ten en cuenta que usamos la versión más reciente 1.16.1-beta26 de los módulos de LangChain4j Google GenAI y Agentic:

<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <groupId>com.example</groupId>
    <artifactId>gemini-agents-demo</artifactId>
    <version>1.0-SNAPSHOT</version>

    <properties>
        <maven.compiler.source>17</maven.compiler.source>
        <maven.compiler.target>17</maven.compiler.target>
        <langchain4j.version>1.16.1-beta26</langchain4j.version>
    </properties>

    <dependencies>
        <!-- LangChain4j Google GenAI Integration -->
        <dependency>
            <groupId>dev.langchain4j</groupId>
            <artifactId>langchain4j-google-genai</artifactId>
            <version>${langchain4j.version}</version>
        </dependency>

        <!-- LangChain4j Agentic Framework Core -->
        <dependency>
            <groupId>dev.langchain4j</groupId>
            <artifactId>langchain4j-agentic</artifactId>
            <version>${langchain4j.version}</version>
        </dependency>

        <!-- LangChain4j Agentic Patterns (needed for GOAP) -->
        <dependency>
            <groupId>dev.langchain4j</groupId>
            <artifactId>langchain4j-agentic-patterns</artifactId>
            <version>${langchain4j.version}</version>
        </dependency>

        <!-- SLF4J Logger for logging requests/responses -->
        <dependency>
            <groupId>org.slf4j</groupId>
            <artifactId>slf4j-simple</artifactId>
            <version>2.0.12</version>
        </dependency>
    </dependencies>
</project>

Obtén una clave de API de Gemini

  1. Ve a Google AI Studio.
  2. Haz clic en Obtener clave de API.
  3. Crea una clave nueva (o selecciona una existente).
  4. Establécela como una variable de entorno en tu terminal:
export GEMINI_API_KEY="your-api-key-here"

3. 3. Configura el modelo de Gemini Chat

Ahora, creemos una aplicación simple de "Hello World" que cree una instancia de GoogleGenAiChatModel y envíe una instrucción de prueba.

El nuevo GoogleGenAiChatModel usa el SDK unificado de Google GenAI, que ofrece acceso unificado a los modelos de Gemini.

Crea una clase llamada HelloWorld.java en src/main/java/com/example/HelloWorld.java:

package com.example;

import dev.langchain4j.model.chat.ChatModel;
import dev.langchain4j.model.google.genai.GoogleGenAiChatModel;

public class HelloWorld {
    public static void main(String[] args) {
        // 1. Configure the Gemini model
        ChatModel model = GoogleGenAiChatModel.builder()
                .apiKey(System.getenv("GEMINI_API_KEY"))
                .modelName("gemini-3.5-flash")
                // Enable logging for both requests and responses
                .logRequestsAndResponses(true)
                .build();

        // 2. Invoke the model
        String response = model.chat("Hello Gemini! Explain 'Agentic AI' in one sentence.");

        // 3. Print response
        System.out.println("\n--- Gemini Response ---");
        System.out.println(response);
    }
}

Ejecuta esta clase. Como logRequestsAndResponses(true) está habilitado, verás registros detallados de SLF4J que describen la carga útil de la solicitud exacta enviada a la API de Google y la respuesta JSON sin procesar recibida, seguida del resultado impreso:

--- Gemini Response ---
**Agentic AI** refers to autonomous artificial intelligence systems that can proactively plan, make decisions, use tools, and execute multi-step tasks to achieve specific goals with minimal human supervision.

4. 4. Define herramientas locales de Java

Los LLMs son poderosos, pero están limitados por sus datos de entrenamiento. Podemos extender sus capacidades proporcionándoles Herramientas (también conocidas como llamadas a funciones).

En LangChain4j, las herramientas son clases de Java simples en las que los métodos se anotan con @Tool.

Escribamos una herramienta simple que calcule la cantidad de días entre dos fechas. Crea DateTools.java en src/main/java/com/example/DateTools.java:

package com.example;

import dev.langchain4j.agent.tool.P;
import dev.langchain4j.agent.tool.Tool;
import java.time.LocalDate;
import java.time.temporal.ChronoUnit;

public class DateTools {

    @Tool("Calculates the number of days between two dates")
    public long daysBetween(
            @P("The start date in ISO format (YYYY-MM-DD)") String startDate,
            @P("The end date in ISO format (YYYY-MM-DD)") String endDate) {
        LocalDate start = LocalDate.parse(startDate);
        LocalDate end = LocalDate.parse(endDate);
        return ChronoUnit.DAYS.between(start, end);
    }
}

Para usar esta herramienta, definiremos un servicio de IA. En el framework Agentic de LangChain4j, podemos compilarlo con AgenticServices.agentBuilder().

Crea ToolDemo.java en src/main/java/com/example/ToolDemo.java:

package com.example;

import dev.langchain4j.agentic.Agent;
import dev.langchain4j.agentic.AgenticServices;
import dev.langchain4j.model.chat.ChatModel;
import dev.langchain4j.model.google.genai.GoogleGenAiChatModel;
import dev.langchain4j.service.V;

public class ToolDemo {

    public interface DateAssistant {
        @Agent
        String ask(@V("prompt") String prompt);
    }

    public static void main(String[] args) {
        ChatModel model = GoogleGenAiChatModel.builder()
                .apiKey(System.getenv("GEMINI_API_KEY"))
                .modelName("gemini-3.5-flash")
                .build();

        // Build the assistant and register our DateTools
        DateAssistant assistant = AiServices.builder(DateAssistant.class)
                .chatModel(model)
                .tools(new DateTools())
                .build();

        String response = assistant.ask("How many days are there between 2026-01-01 and 2026-06-30?");
        System.out.println("Response: " + response);
    }
}

Cuando ejecutes este código, Gemini analizará la instrucción, se dará cuenta de que debe llamar a daysBetween, generará una solicitud de llamada a la herramienta, LangChain4j ejecutará tu método Java local, enviará el resultado a Gemini y Gemini formateará la respuesta final en lenguaje natural.

Deberías ver un resultado similar al siguiente:

Response: There are 180 days between 2026-01-01 and 2026-06-30.

5. 5. Cómo definir el resultado estructurado

A menudo, deseas que el LLM devuelva datos en un formato estructurado específico (p.ej., JSON que coincida con un esquema) en lugar de texto sin formato.

LangChain4j controla esto automáticamente cuando especificas un POJO o un record de Java como el tipo de datos que se devuelve de tu agente o método de servicio.

Definamos un record de Java que represente una extracción de libro:

Crea Book.java en src/main/java/com/example/Book.java:

package com.example;

public record Book(String title, String author, int publicationYear) {}

Ahora, crea una interfaz de agente que devuelva Book. Crea StructuredOutputDemo.java en src/main/java/com/example/StructuredOutputDemo.java:

package com.example;

import dev.langchain4j.agentic.Agent;
import dev.langchain4j.agentic.AgenticServices;
import dev.langchain4j.model.chat.ChatModel;
import dev.langchain4j.model.google.genai.GoogleGenAiChatModel;
import dev.langchain4j.service.UserMessage;
import dev.langchain4j.service.V;

public class StructuredOutputDemo {

    public interface BookExtractor {
        @UserMessage("Extract book details from: {{text}}")
        Book extract(@V("text") String text);
    }

    public static void main(String[] args) {
        ChatModel model = GoogleGenAiChatModel.builder()
                .apiKey(System.getenv("GEMINI_API_KEY"))
                .modelName("gemini-3.5-flash")
                .build();

        BookExtractor extractor = AiServices.builder(BookExtractor.class)
                .chatModel(model)
                .build();

        String text = "I just finished reading 'Project Hail Mary' by Andy Weir, published in 2021. It was amazing!";
        Book book = extractor.extract(text);

        System.out.println("Extracted POJO: " + book);
    }
}

Gemini 3.5 Flash admite una salida estricta del esquema JSON. LangChain4j genera el esquema JSON a partir de tu registro Book, le indica a Gemini que lo complete y deserializa la respuesta JSON en un registro Book.

Deberías ver un resultado similar al siguiente:

Extracted POJO: Book[title=Project Hail Mary, author=Andy Weir, publicationYear=2021]

6. 6. Crea tu primer agente

En el framework de langchain4j-agentic, se define un agente con la anotación @Agent en el método de la interfaz. Esta anotación proporciona un nombre o una descripción que pueden usar los sistemas de organización (como los planificadores).

Creemos un agente simple que tome un tema y escriba un borrador de un cuento muy corto sobre él.

Crea CreativeWriter.java en src/main/java/com/example/CreativeWriter.java:

package com.example;

import dev.langchain4j.agentic.Agent;
import dev.langchain4j.service.SystemMessage;
import dev.langchain4j.service.UserMessage;
import dev.langchain4j.service.V;

public interface CreativeWriter {

    @SystemMessage("You are a creative writer. Generate a draft of a story no more than 3 sentences long.")
    @UserMessage("Write a story about {{topic}}.")
    @Agent(description = "Generates a story based on the given topic", outputKey = "story")
    String writeStory(@V("topic") String topic);
}

Probemos este agente de forma individual. Crea AgentDemo.java en src/main/java/com/example/AgentDemo.java:

package com.example;

import dev.langchain4j.agentic.AgenticServices;
import dev.langchain4j.model.chat.ChatModel;
import dev.langchain4j.model.google.genai.GoogleGenAiChatModel;

public class AgentDemo {
    public static void main(String[] args) {
        ChatModel model = GoogleGenAiChatModel.builder()
                .apiKey(System.getenv("GEMINI_API_KEY"))
                .modelName("gemini-3.5-flash")
                .build();

        CreativeWriter writer = AgenticServices.agentBuilder(CreativeWriter.class)
                .chatModel(model)
                .build();

        String story = writer.writeStory("a lonely robot on Mars");
        System.out.println("Generated Story:\n" + story);
    }
}

Deberías ver un resultado similar al siguiente:

Generated Story:
For eighty years, the rusty little rover trundled across the crimson dunes, diligently collecting soil samples for a home world that had long since gone dark. Each evening, it pointed its high-gain antenna toward the fading blue speck of Earth and beamed its lonely coordinates into the silent cosmos. Receiving only static in return, the robot tucked its camera arm close against the freezing Martian wind and sang a quiet lullaby to the empty stars.

Si agregas la anotación @Agent, esta clase ahora está preparada para participar en flujos de trabajo más complejos, como el encadenamiento secuencial.

7. 7. Organiza flujos de trabajo multiagente: secuenciales

Un patrón de agente común es el flujo de trabajo secuencial, en el que los agentes se ejecutan en un orden predefinido. El resultado de un agente se pasa como entrada del siguiente.

Definamos un segundo agente, StyleEditor, que editará el cuento escrito por CreativeWriter para que se ajuste a un estilo específico (p.ej., cómico o dramático).

Crea StyleEditor.java en src/main/java/com/example/StyleEditor.java:

package com.example;

import dev.langchain4j.agentic.Agent;
import dev.langchain4j.service.SystemMessage;
import dev.langchain4j.service.UserMessage;
import dev.langchain4j.service.V;

public interface StyleEditor {

    @SystemMessage("You are a professional editor. Analyze and rewrite the story to align with the style requested.")
    @UserMessage("Rewrite this story: '{{story}}' into a {{style}} style.")
    @Agent(description = "Edits a story to fit a specific style", outputKey = "edited_story")
    String editStory(@V("story") String story, @V("style") String style);
}

Ahora, conectemos CreativeWriter y StyleEditor de forma secuencial con AgenticServices.sequenceBuilder().

Usaremos un UntypedAgent que representa la secuencia, lo que nos permite pasar entradas y recopilar salidas a través de un mapa compartido.

Crea SequentialWorkflowDemo.java en src/main/java/com/example/SequentialWorkflowDemo.java:

package com.example;

import dev.langchain4j.agentic.AgenticServices;
import dev.langchain4j.agentic.UntypedAgent;
import dev.langchain4j.model.chat.ChatModel;
import dev.langchain4j.model.google.genai.GoogleGenAiChatModel;
import java.util.Map;

public class SequentialWorkflowDemo {
    public static void main(String[] args) {
        ChatModel model = GoogleGenAiChatModel.builder()
                .apiKey(System.getenv("GEMINI_API_KEY"))
                .modelName("gemini-3.5-flash")
                .build();

        // 1. Build the sub-agents
        CreativeWriter writer = AgenticServices.agentBuilder(CreativeWriter.class)
                .chatModel(model)
                .outputKey("story") // Output goes into AgenticScope as "story"
                .build();

        StyleEditor editor = AgenticServices.agentBuilder(StyleEditor.class)
                .chatModel(model)
                .outputKey("edited_story") // Output goes into AgenticScope as "edited_story"
                .build();

        // 2. Build the sequence
        UntypedAgent workflow = AgenticServices.sequenceBuilder()
                .subAgents(writer, editor)
                .outputKey("edited_story") // Final output of workflow
                .build();

        // 3. Run the workflow with inputs
        Map<String, Object> inputs = Map.of(
                "topic", "a cat learning to fly",
                "style", "Shakespearean"
        );

        String result = (String) workflow.invoke(inputs);
        System.out.println("Final Edited Story:\n" + result);
    }
}

Deberías ver un resultado similar al siguiente:

Final Edited Story:
For years had Barnaby with envy watched
The soaring sparrows with a green-eyed spite,
Convinced that heavy gravity was but
An idle law he deigned to tolerate.
But lo! Upon the rare and azure moon,
He scaled the summit of the ancient oak,
Closed fast his eyes, and leapt with blind belief.
While the dread squirrel shrieked in sheer dismay,
No downward plunge befell the daring beast;
For summer's zephyr bore his belly up,
And through the vault of night's celestial sphere,
He rowed his velvet paws among the stars.

Presentamos AgenticScope

Durante la ejecución, LangChain4j administra un AgenticScope.

  1. El mapa de entrada {"topic": "...", "style": "..."} se escribe en el alcance.
  2. CreativeWriter se ejecuta. Requiere topic, que lee del alcance. Genera story, que se guarda de nuevo en el alcance.
  3. Se ejecuta StyleEditor. Requiere story (producido por el escritor) y style (de las entradas iniciales). Genera edited_story en el alcance.
  4. El flujo de trabajo se completa y devuelve el valor de edited_story.

8. 8. Organiza flujos de trabajo multiagente: Paralelo

En algunas situaciones, los subagentes pueden trabajar de forma independiente en la misma entrada, y sus tareas se pueden ejecutar en paralelo.

Por ejemplo, creemos un asesor de viajes que les pida recomendaciones sobre una ciudad a un experto en películas y a un experto en gastronomía, y luego las combine.

Crea MovieExpert.java en src/main/java/com/example/MovieExpert.java:

package com.example;

import dev.langchain4j.agentic.Agent;
import dev.langchain4j.service.UserMessage;
import dev.langchain4j.service.V;
import java.util.List;

public interface MovieExpert {
    @UserMessage("Suggest 2 movies filmed in {{city}}.")
    @Agent(description = "Suggests movies filmed in a city")
    List<String> findMovies(@V("city") String city);
}

Crea DiningExpert.java en src/main/java/com/example/DiningExpert.java:

package com.example;

import dev.langchain4j.agentic.Agent;
import dev.langchain4j.service.UserMessage;
import dev.langchain4j.service.V;
import java.util.List;

public interface DiningExpert {
    @UserMessage("Suggest 2 local dishes to try in {{city}}.")
    @Agent(description = "Suggests local dishes to try in a city")
    List<String> findDishes(@V("city") String city);
}

Ahora, creemos el sistema paralelo basado en agentes. Definiremos una interfaz para nuestro coordinador de nivel superior: TravelAdvisorAgent.

Crea TravelAdvisorAgent.java en src/main/java/com/example/TravelAdvisorAgent.java:

package com.example;

import dev.langchain4j.agentic.Agent;
import dev.langchain4j.service.V;
import java.util.Map;

public interface TravelAdvisorAgent {
    @Agent
    Map<String, Object> planTrip(@V("city") String city);
}

Crea ParallelWorkflowDemo.java en src/main/java/com/example/ParallelWorkflowDemo.java para unirlo todo:

package com.example;

import dev.langchain4j.agentic.AgenticServices;
import dev.langchain4j.model.chat.ChatModel;
import dev.langchain4j.model.google.genai.GoogleGenAiChatModel;
import java.util.List;
import java.util.Map;

public class ParallelWorkflowDemo {
    public static void main(String[] args) {
        ChatModel model = GoogleGenAiChatModel.builder()
                .apiKey(System.getenv("GEMINI_API_KEY"))
                .modelName("gemini-3.5-flash")
                .build();

        // 1. Build independent agents
        MovieExpert movieExpert = AgenticServices.agentBuilder(MovieExpert.class)
                .chatModel(model)
                .outputKey("movies")
                .build();

        DiningExpert diningExpert = AgenticServices.agentBuilder(DiningExpert.class)
                .chatModel(model)
                .outputKey("dishes")
                .build();

        // 2. Build the Parallel agent
        TravelAdvisorAgent travelAdvisor = AgenticServices.parallelBuilder(TravelAdvisorAgent.class)
                .subAgents(movieExpert, diningExpert)
                .output(scope -> {
                    // Combine the independent outputs in the AgenticScope
                    List<String> movies = scope.readState("movies", List.of());
                    List<String> dishes = scope.readState("dishes", List.of());
                    return Map.of("movies", movies, "dishes", dishes);
                })
                .build();

        // 3. Invoke
        Map<String, Object> plan = travelAdvisor.planTrip("Tokyo");
        System.out.println("Tokyo Trip Plan:\n" + plan);
    }
}

Deberías ver un resultado similar al siguiente:

Tokyo Trip Plan:
{movies=[Lost in Translation, Tokyo Story], dishes=[Monjayaki, Edomae-zushi]}
In this parallel workflow, `movieExpert` and `diningExpert` execute concurrently. The `output(...)` configuration defines how to gather their respective results from the `AgenticScope` and merge them into the final result.

## 9. Build Goal-Oriented Agents (GOAP)
Duration: 07:00

Sequential and Parallel workflows are structured and predictable, but rigid. What if we want the system to figure out the path to the goal autonomously, but in a **deterministic, algorithmic way** rather than trusting an LLM to loop (like ReAct)?

This is where **Goal-Oriented Action Planning (GOAP)** shines. 

By looking at the declared inputs and outputs of each agent, the `GoalOrientedPlanner` builds a dependency graph. When you invoke the system with a goal, it calculates the shortest path from the current state (available variables) to that goal.

Let's build a Horoscope & News combined writer. It requires 4 agents:
1. `PersonExtractor`: extracts person details from prompt.
2. `SignExtractor`: extracts zodiac sign from prompt.
3. `HoroscopeGenerator`: generates horoscope given person and sign.
4. `AmusingWriter`: writes a funny story combining a horoscope and a news story.

We will also define a `StoryFinder` that uses a mock search tool.

### 1. Define Model Classes
Create `Person.java` in `src/main/java/com/example/Person.java`:
```java
package com.example;

public record Person(String name) {
    @Override public String toString() { return name; }
}

Crea Sign.java en src/main/java/com/example/Sign.java:

package com.example;

public record Sign(String signName) {
    @Override public String toString() { return signName; }
}

2. Define los subagentes

Crea HoroscopeGenerator.java en src/main/java/com/example/HoroscopeGenerator.java:

package com.example;

import dev.langchain4j.agentic.Agent;
import dev.langchain4j.service.UserMessage;
import dev.langchain4j.service.V;

public interface HoroscopeGenerator {
    @UserMessage("Generate a funny horoscope for {{person}} who is a {{sign}}.")
    @Agent(description = "Generates horoscopes based on name and zodiac sign")
    String horoscope(@V("person") Person person, @V("sign") Sign sign);
}

Crea PersonExtractor.java en src/main/java/com/example/PersonExtractor.java:

package com.example;

import dev.langchain4j.agentic.Agent;
import dev.langchain4j.service.UserMessage;
import dev.langchain4j.service.V;

public interface PersonExtractor {
    @UserMessage("Extract the person name from: {{prompt}}")
    @Agent(description = "Extracts a person from user's prompt")
    Person extractPerson(@V("prompt") String prompt);
}

Crea SignExtractor.java en src/main/java/com/example/SignExtractor.java:

package com.example;

import dev.langchain4j.agentic.Agent;
import dev.langchain4j.service.UserMessage;
import dev.langchain4j.service.V;

public interface SignExtractor {
    @UserMessage("Extract the zodiac sign from: {{prompt}}")
    @Agent(description = "Extracts a zodiac sign from user's prompt")
    Sign extractSign(@V("prompt") String prompt);
}

Crea AmusingWriter.java en src/main/java/com/example/AmusingWriter.java:

package com.example;

import dev.langchain4j.agentic.Agent;
import dev.langchain4j.service.UserMessage;
import dev.langchain4j.service.V;

public interface AmusingWriter {
    @UserMessage("Create an amusing writeup for {{person}} based on their horoscope: {{horoscope}} and current news story: {{story}}.")
    @Agent(description = "Create an amusing writeup combining horoscope and news")
    String write(@V("person") Person person, @V("horoscope") String horoscope, @V("story") String story);
}

3. Define la herramienta para encontrar historias

Crearemos una clase simple de herramienta de búsqueda que devolverá un simulacro de historia. Crea MockSearchTool.java en src/main/java/com/example/MockSearchTool.java:

package com.example;

import dev.langchain4j.agent.tool.P;
import dev.langchain4j.agent.tool.Tool;

public class MockSearchTool {
    @Tool("Searches the web for news stories related to a zodiac sign")
    public String searchNews(@P("The zodiac sign") String sign) {
        return "Breaking news: A massive cheese festival was announced for " + sign + " natives today!";
    }
}

Crea StoryFinder.java en el agente src/main/java/com/example/StoryFinder.java que usa esta herramienta:

package com.example;

import dev.langchain4j.agentic.Agent;
import dev.langchain4j.service.UserMessage;
import dev.langchain4j.service.V;

public interface StoryFinder {
    @UserMessage("Find a funny story for zodiac sign {{sign}} using search tool.")
    @Agent(description = "Finds a news story on the internet about a zodiac sign")
    String findStory(@V("sign") Sign sign);
}

4. Compila y ejecuta el sistema agentic de GOAP

Crea GoapDemo.java en src/main/java/com/example/GoapDemo.java:

package com.example;

import dev.langchain4j.agentic.AgenticServices;
import dev.langchain4j.agentic.UntypedAgent;
import dev.langchain4j.agentic.patterns.goap.GoalOrientedPlanner;
import dev.langchain4j.model.chat.ChatModel;
import dev.langchain4j.model.google.genai.GoogleGenAiChatModel;
import java.util.Map;

public class GoapDemo {
    public static void main(String[] args) {
        ChatModel model = GoogleGenAiChatModel.builder()
                .apiKey(System.getenv("GEMINI_API_KEY"))
                .modelName("gemini-3.5-flash")
                .build();

        // Instantiate sub-agents with output keys matching the inputs of other agents
        HoroscopeGenerator horoscopeGen = AgenticServices.agentBuilder(HoroscopeGenerator.class)
                .chatModel(model).outputKey("horoscope").build();

        PersonExtractor personExt = AgenticServices.agentBuilder(PersonExtractor.class)
                .chatModel(model).outputKey("person").build();

        SignExtractor signExt = AgenticServices.agentBuilder(SignExtractor.class)
                .chatModel(model).outputKey("sign").build();

        StoryFinder storyFinder = AgenticServices.agentBuilder(StoryFinder.class)
                .chatModel(model).tools(new MockSearchTool()).outputKey("story").build();

        AmusingWriter writer = AgenticServices.agentBuilder(AmusingWriter.class)
                .chatModel(model).outputKey("writeup").build();

        // Build the GOAP Planner agentic system
        UntypedAgent horoscopeNewsAgent = AgenticServices.plannerBuilder()
                .subAgents(horoscopeGen, personExt, signExt, storyFinder, writer)
                .outputKey("writeup") // The Goal we want to achieve
                .planner(GoalOrientedPlanner::new) // Register the GOAP Planner
                .build();

        // Input provides only "prompt"
        Map<String, Object> inputs = Map.of(
                "prompt", "My name is Alice and my zodiac sign is Leo"
        );

        System.out.println("Invoking GOAP Agentic System...");
        String result = (String) horoscopeNewsAgent.invoke(inputs);

        System.out.println("\n--- Final Writeup ---");
        System.out.println(result);
    }
}

Cómo lo resolvió GOAP:

Cuando se invoca:

  1. El sistema detecta que el estado inicial solo contiene prompt.
  2. El objetivo deseado es writeup.
  3. Crea un gráfico de dependencias y calcula la ruta de acceso:
    • prompt -> PersonExtractor -> person
    • prompt -> SignExtractor -> sign
    • person + sign -> HoroscopeGenerator -> horoscope
    • sign -> StoryFinder -> story
    • person + horoscope + story -> AmusingWriter -> writeup
  4. El orden de ejecución calculado es: [PersonExtractor, SignExtractor, HoroscopeGenerator, StoryFinder, AmusingWriter].
  5. Ejecuta cada agente secundario en orden y devuelve el resultado final.

Deberías ver un resultado que muestre la ruta de ejecución y el texto final, similar al siguiente:

Invoking GOAP Agentic System...
[com.example.GoapDemo.main()] INFO dev.langchain4j.agentic.patterns.goap.GoalOrientedSearchGraph - Agents path sequence: [extractPerson, extractSign, findStory, horoscope, write]

--- Final Writeup ---
**The Cosmic Registry's Weekly Forecast & Special Event Guide for: Alice, the Leo Lioness**

Alice, the universe looked at your astrological chart this week and frankly, it's asking for your autograph. Your main-character energy is currently so potent that secondary characters are practically fading into the background.

But the biggest cosmic news of the week? The universe has finally recognized your royal status with the announcement of a **Massive Cheese Festival**...

9. 10. Limpia

Para limpiar los recursos, haz lo siguiente:

  • Asegúrate de borrar las claves de API de Google AI Studio si ya no las usas.
  • Anula la configuración de la variable de entorno en tu terminal:
unset GEMINI_API_KEY

10. 11. Felicitaciones

¡Felicitaciones! Creaste correctamente una serie de aplicaciones de IA de agentes con LangChain4j y el nuevo módulo de IA generativa de Google.

Para mejorar tus habilidades, te recomendamos que consultes la documentación oficial del módulo de GenAI de Google de LangChain4j y obtengas más información para crear agentes con LangChain4j.

Qué aprendiste

  • Cómo configurar GoogleGenAiChatModel
  • Cómo usar herramientas locales de Java y el registro de solicitudes y respuestas
  • Cómo generar datos POJO estructurados
  • Cómo crear agentes de un solo propósito con @Agent
  • Cómo organizar flujos de trabajo de agentes secuenciales, paralelos y de planificación de acciones orientada a objetivos (GOAP)

Más información