Criar aplicativos de IA com agentes em Java usando o LangChain4j e a IA generativa do Google

1. 1. Antes de começar

Resumo em sketchnote do codelab

Olá! Neste codelab, você vai aprender a criar aplicativos de IA agêntica em Java usando o framework popular LangChain4j e o novo módulo Google GenAI.

A IA agêntica se refere a sistemas em que os LLMs não apenas respondem a comandos, mas também são equipados com ferramentas, memória e recursos de planejamento para realizar metas complexas e de várias etapas de forma autônoma.

Você vai começar com configurações simples, progredir para a criação de agentes com ferramentas locais e saídas estruturadas e, por fim, explorar padrões avançados de orquestração multiagente, culminando em um sistema agêntico de planejamento de ações orientado a metas (GOAP).

Atividades deste laboratório

  • Configure o novo GoogleGenAiChatModel para se conectar ao Gemini.
  • Ative a geração de registros de solicitação/resposta para facilitar a depuração.
  • Conceda ao Gemini acesso ao código Java local usando ferramentas.
  • Aplique o formato de saída estruturada (POJOs) do Gemini.
  • Defina e crie agentes de propósito único com a anotação @Agent.
  • Orquestre fluxos de trabalho multiagentes sequenciais e paralelos.
  • Crie um sistema de planejamento de ações orientado a metas (GOAP) que planeja dinamicamente a execução do agente.

O que é necessário

  • Kit de desenvolvimento Java (JDK) 17 ou mais recente.
  • Maven 3.5 ou mais recente instalado.
  • Uma chave da API Gemini do Google AI Studio.

2. 2. Configuração: projeto e chave de API

Para começar, precisamos criar um novo projeto Maven e configurar nossa chave da API Gemini.

Criar o projeto Maven

Crie um novo diretório para o projeto e inicialize-o com um arquivo pom.xml.

Adicione as dependências a seguir ao pom.xml. Estamos usando a versão mais recente 1.16.1-beta26 dos módulos LangChain4j Google GenAI e 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>

Gerar uma chave da API Gemini

  1. Acessar o Google AI Studio.
  2. Clique em Gerar chave de API.
  3. Crie uma nova chave ou selecione uma já existente.
  4. Defina-a como uma variável de ambiente no terminal:
export GEMINI_API_KEY="your-api-key-here"

3. 3. Configurar o modelo de chat do Gemini

Agora, vamos criar um aplicativo "Hello World" simples que instancia o GoogleGenAiChatModel e envia um comando de teste.

O novo GoogleGenAiChatModel usa o SDK unificado do Google GenAI, que oferece acesso unificado aos modelos do Gemini.

Crie uma classe chamada HelloWorld.java em 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);
    }
}

Execute essa classe. Como logRequestsAndResponses(true) está ativado, você verá registros detalhados do SLF4J que detalham o payload de solicitação exato enviado à API do Google e a resposta JSON bruta recebida, seguida da saída impressa:

--- 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. Definir ferramentas Java locais

Os LLMs são poderosos, mas limitados pelos dados de treinamento. Podemos estender as capacidades deles fornecendo ferramentas (também conhecidas como chamada de função).

No LangChain4j, as ferramentas são classes Java simples em que os métodos são anotados com @Tool.

Vamos escrever uma ferramenta simples que calcula o número de dias entre duas datas. Crie DateTools.java em 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 essa ferramenta, vamos definir um serviço de IA. No framework Agentic do LangChain4j, podemos criá-lo usando AgenticServices.agentBuilder().

Crie ToolDemo.java em 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);
    }
}

Ao executar esse código, o Gemini vai analisar o comando, perceber que precisa chamar daysBetween, gerar uma solicitação de chamada de ferramenta, o LangChain4j vai executar seu método Java local, enviar o resultado de volta ao Gemini e o Gemini vai formatar a resposta final em linguagem natural.

A saída será semelhante a:

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

5. 5. Definir saída estruturada

Muitas vezes, você quer que o LLM retorne dados em um formato estruturado específico (por exemplo, JSON correspondente a um esquema) em vez de texto simples.

O LangChain4j processa isso automaticamente quando você especifica um POJO ou um record Java como o tipo de retorno do método do agente ou serviço.

Vamos definir um record Java que representa uma extração de livro:

Crie Book.java em src/main/java/com/example/Book.java:

package com.example;

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

Agora, crie uma interface de agente que retorne Book. Crie StructuredOutputDemo.java em 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);
    }
}

O Gemini 3.5 Flash oferece suporte à saída estrita do esquema JSON. O LangChain4j gera o esquema JSON do seu registro Book, instrui o Gemini a preenchê-lo e desserializa a resposta JSON de volta em um registro Book.

A saída será semelhante a:

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

6. 6. Criar seu primeiro agente

No framework langchain4j-agentic, um agente é definido usando a anotação @Agent no método da interface. Essa anotação fornece um nome/descrição que pode ser usado por sistemas de orquestração (como planejadores).

Vamos criar um agente simples que recebe um tópico e cria uma história muito curta sobre ele.

Crie CreativeWriter.java em 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);
}

Vamos testar esse agente individualmente. Crie AgentDemo.java em 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);
    }
}

A saída será semelhante a:

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.

Ao adicionar a anotação @Agent, essa classe agora está preparada para participar de fluxos de trabalho mais complexos, como o encadeamento sequencial.

7. 7. Orquestrar fluxos de trabalho multiagentes: sequencial

Um padrão agêntico comum é o fluxo de trabalho sequencial, em que os agentes são executados em uma ordem predefinida. A saída de um agente é transmitida como entrada do próximo.

Vamos definir um segundo agente, StyleEditor, que vai editar a história escrita por CreativeWriter para se adequar a um estilo específico (por exemplo, cômico, dramático).

Crie StyleEditor.java em 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);
}

Agora, vamos conectar CreativeWriter e StyleEditor sequencialmente usando AgenticServices.sequenceBuilder().

Vamos usar um UntypedAgent que representa a sequência, o que nos permite transmitir entradas e coletar saídas por um mapa compartilhado.

Crie SequentialWorkflowDemo.java em 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);
    }
}

A saída será semelhante a:

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.

Apresentamos o AgenticScope

Durante a execução, o LangChain4j gerencia um AgenticScope.

  1. O mapa de entrada {"topic": "...", "style": "..."} é gravado no escopo.
  2. CreativeWriter é executado. Ele exige topic, que lê do escopo. Ele gera story, que é salvo de volta no escopo.
  3. StyleEditor é executado. Ele exige story (produzido pelo escritor) e style (das entradas iniciais). Ele gera edited_story para o escopo.
  4. O fluxo de trabalho é concluído e retorna o valor de edited_story.

8. 8. Orquestrar fluxos de trabalho multiagentes: paralelo

Em alguns cenários, os subagentes podem trabalhar de forma independente na mesma entrada, e as tarefas deles podem ser executadas em paralelo.

Por exemplo, vamos criar um consultor de viagens que pede a um especialista em filmes e a um especialista em restaurantes recomendações para uma cidade e, em seguida, as combina.

Crie MovieExpert.java em 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);
}

Crie DiningExpert.java em 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);
}

Agora, vamos criar o sistema agêntico paralelo. Vamos definir uma interface para nosso coordenador de nível superior: TravelAdvisorAgent.

Crie TravelAdvisorAgent.java em 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);
}

Crie ParallelWorkflowDemo.java em src/main/java/com/example/ParallelWorkflowDemo.java para vinculá-lo:

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

A saída será semelhante a:

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

Crie Sign.java em src/main/java/com/example/Sign.java:

package com.example;

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

2. Definir os subagentes

Crie HoroscopeGenerator.java em 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);
}

Crie PersonExtractor.java em 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);
}

Crie SignExtractor.java em 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);
}

Crie AmusingWriter.java em 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. Definir a ferramenta para encontrar histórias

Vamos criar uma classe de ferramenta de pesquisa simples que retorna uma história simulada. Crie MockSearchTool.java em 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!";
    }
}

Crie StoryFinder.java em src/main/java/com/example/StoryFinder.java agente que usa essa ferramenta:

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. Criar e executar o sistema agêntico GOAP

Crie GoapDemo.java em 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);
    }
}

Como o GOAP resolveu o problema:

Quando invocado:

  1. O sistema detecta que o estado inicial contém apenas prompt.
  2. O objetivo desejado é writeup.
  3. Ele cria um gráfico de dependência e calcula o caminho:
    • prompt -> PersonExtractor -> person
    • prompt -> SignExtractor -> sign
    • person + sign -> HoroscopeGenerator -> horoscope
    • sign -> StoryFinder -> story
    • person + horoscope + story -> AmusingWriter -> writeup
  4. A ordem de execução calculada é: [PersonExtractor, SignExtractor, HoroscopeGenerator, StoryFinder, AmusingWriter].
  5. Ele executa cada subagente em ordem e retorna o resultado final.

Você verá uma saída mostrando o caminho de execução e o texto final, semelhante a:

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. Limpar

Para limpar recursos:

  • Exclua as chaves de API do Google AI Studio se não estiver mais usando-as.
  • Desative a variável de ambiente no terminal:
unset GEMINI_API_KEY

10. 11. Parabéns

Parabéns! Você criou uma série de aplicativos de IA agêntica usando o LangChain4j e o novo módulo Google GenAI.

Para aprimorar suas habilidades, recomendamos que você consulte a documentação oficial do módulo LangChain4j Google GenAI e saiba mais sobre como criar agentes com o LangChain4j.

O que você aprendeu

  • Como configurar GoogleGenAiChatModel.
  • Como usar ferramentas Java locais e geração de registros de solicitação/resposta.
  • Como gerar dados POJO estruturados.
  • Como criar agentes de propósito único com @Agent.
  • Como orquestrar fluxos de trabalho agênticos sequenciais, paralelos e de planejamento de ações orientado a metas (GOAP).

Saiba mais