Membangun Aplikasi AI Agentik di Java dengan LangChain4j dan GenAI Google

1. 1. Sebelum memulai

Ringkasan Sketchnote Codelab

Selamat datang! Dalam codelab ini, Anda akan mempelajari cara membangun aplikasi AI agentik di Java menggunakan framework LangChain4j yang populer dan modul Google GenAI yang baru.

AI agentik mengacu pada sistem di mana LLM tidak hanya menanggapi perintah, tetapi juga dilengkapi dengan alat, memori, dan kemampuan perencanaan untuk mencapai tujuan yang kompleks dan terdiri dari banyak langkah secara mandiri.

Anda akan memulai dengan konfigurasi sederhana, melanjutkan ke pembangunan agen dengan alat lokal dan output terstruktur, dan akhirnya mempelajari pola orkestrasi multi-agen tingkat lanjut, yang berpuncak pada sistem agentik Perencanaan Tindakan Berorientasi Sasaran (GOAP).

Yang akan Anda lakukan

  • Konfigurasi GoogleGenAiChatModel baru untuk terhubung ke Gemini.
  • Aktifkan logging permintaan/respons untuk memudahkan proses debug.
  • Memberi Gemini akses ke kode Java lokal menggunakan Tools.
  • Menerapkan format Output Terstruktur (POJO) dari Gemini.
  • Tentukan dan bangun Agen dengan tujuan tunggal menggunakan anotasi @Agent.
  • Mengorkestrasi alur kerja multi-agen Berurutan dan Paralel.
  • Membangun sistem Perencanaan Tindakan Berorientasi Sasaran (GOAP) yang secara dinamis merencanakan eksekusi agen.

Yang Anda butuhkan

  • Java Development Kit (JDK) 17 atau yang lebih baru.
  • Maven 3.5+ terinstal.
  • Kunci Gemini API dari Google AI Studio.

2. 2. Penyiapan: Project & Kunci API

Untuk memulai, kita perlu membuat project Maven baru dan mengonfigurasi kunci API Gemini.

Buat Project Maven

Buat direktori baru untuk project Anda dan lakukan inisialisasi dengan file pom.xml.

Tambahkan dependensi berikut ke pom.xml Anda. Perhatikan bahwa kita menggunakan versi 1.16.1-beta26 terbaru dari modul LangChain4j Google GenAI dan 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>

Mendapatkan Kunci Gemini API

  1. Buka Google AI Studio.
  2. Klik Get API Key.
  3. Buat kunci baru (atau pilih yang sudah ada).
  4. Tetapkan sebagai variabel lingkungan di terminal Anda:
export GEMINI_API_KEY="your-api-key-here"

3. 3. Mengonfigurasi Model Gemini Chat

Sekarang, mari kita buat aplikasi "Halo Dunia" sederhana yang membuat instance GoogleGenAiChatModel dan mengirimkan perintah pengujian.

GoogleGenAiChatModel baru menggunakan Google GenAI SDK terpadu, yang menawarkan akses terpadu ke model Gemini.

Buat class bernama HelloWorld.java di 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);
    }
}

Jalankan class ini. Karena logRequestsAndResponses(true) diaktifkan, Anda akan melihat log SLF4J verbose yang menjelaskan payload permintaan persis yang dikirim ke API Google, dan respons JSON mentah yang diterima, diikuti dengan output yang dicetak:

--- 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. Menentukan Alat Java Lokal

LLM sangat canggih, tetapi dibatasi oleh data pelatihannya. Kita dapat memperluas kemampuannya dengan memberinya Alat (juga dikenal sebagai panggilan fungsi).

Di LangChain4j, alat adalah class Java sederhana yang metodenya dianotasi dengan @Tool.

Mari kita tulis alat sederhana yang menghitung jumlah hari antara dua tanggal. Buat DateTools.java di 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);
    }
}

Untuk menggunakan alat ini, kita akan menentukan Layanan AI. Dalam framework Agentic LangChain4j, kita dapat membangunnya menggunakan AgenticServices.agentBuilder().

Buat ToolDemo.java di 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);
    }
}

Saat Anda menjalankan kode ini, Gemini akan menganalisis perintah, menyadari bahwa perintah tersebut perlu memanggil daysBetween, membuat permintaan panggilan alat, LangChain4j akan menjalankan metode Java lokal Anda, mengirimkan hasilnya kembali ke Gemini, dan Gemini akan memformat respons bahasa alami akhir.

Anda akan melihat output yang mirip dengan:

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

5. 5. Menentukan Output Terstruktur

Sering kali, Anda ingin LLM menampilkan data dalam format terstruktur tertentu (misalnya, JSON yang cocok dengan skema) daripada teks biasa.

LangChain4j menangani hal ini secara otomatis saat Anda menentukan POJO atau record Java sebagai jenis nilai yang ditampilkan dari metode agen atau layanan Anda.

Mari kita tentukan record Java yang merepresentasikan ekstraksi buku:

Buat Book.java di src/main/java/com/example/Book.java:

package com.example;

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

Sekarang buat antarmuka agen yang menampilkan Book. Buat StructuredOutputDemo.java di 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 mendukung output Skema JSON yang ketat. LangChain4j membuat skema JSON dari rekaman Book Anda, menginstruksikan Gemini untuk mengisinya, dan mendeserialisasi respons JSON kembali menjadi rekaman Book.

Anda akan melihat output yang mirip dengan:

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

6. 6. Membuat Agen Pertama Anda

Dalam framework langchain4j-agentic, Agent ditentukan menggunakan anotasi @Agent pada metode antarmuka. Anotasi ini memberikan nama/deskripsi yang dapat digunakan oleh sistem orkestrasi (seperti perencana).

Mari kita buat agen sederhana yang mengambil topik dan menyusun draf cerita yang sangat singkat tentang topik tersebut.

Buat CreativeWriter.java di 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);
}

Mari kita uji agen ini satu per satu. Buat AgentDemo.java di 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);
    }
}

Anda akan melihat output yang mirip dengan:

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.

Dengan menambahkan anotasi @Agent, class ini kini siap berpartisipasi dalam alur kerja yang lebih kompleks, seperti rangkaian berurutan.

7. 7. Mengorkestrasi Alur Kerja Multi-Agen: Berurutan

Pola agentic umum adalah Alur Kerja Berurutan, di mana agen dieksekusi dalam urutan yang telah ditentukan. Output satu agen diteruskan sebagai input agen berikutnya.

Mari kita tentukan agen kedua, StyleEditor, yang akan mengedit cerita yang ditulis oleh CreativeWriter agar sesuai dengan gaya tertentu (misalnya, komedi, drama).

Buat StyleEditor.java di 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);
}

Sekarang, mari kita hubungkan CreativeWriter dan StyleEditor secara berurutan menggunakan AgenticServices.sequenceBuilder().

Kita akan menggunakan UntypedAgent yang merepresentasikan urutan, yang memungkinkan kita meneruskan input dan mengumpulkan output melalui peta bersama.

Buat SequentialWorkflowDemo.java di 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);
    }
}

Anda akan melihat output yang mirip dengan:

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.

Memperkenalkan AgenticScope

Selama eksekusi, LangChain4j mengelola AgenticScope.

  1. Peta input {"topic": "...", "style": "..."} ditulis ke cakupan.
  2. CreativeWriter dieksekusi. Hal ini memerlukan topic, yang dibaca dari cakupan. Tindakan ini menghasilkan story, yang disimpan kembali ke cakupan.
  3. StyleEditor dieksekusi. Node ini memerlukan story (dihasilkan oleh penulis) dan style (dari input awal). Outputnya adalah edited_story ke cakupan.
  4. Alur kerja selesai dan menampilkan nilai edited_story.

8. 8. Mengorkestrasi Alur Kerja Multi-Agen: Paralel

Dalam beberapa skenario, sub-agen dapat bekerja secara independen pada input yang sama, dan tugasnya dapat dieksekusi secara paralel.

Misalnya, mari kita buat penasihat perjalanan yang meminta rekomendasi dari pakar film dan pakar kuliner untuk suatu kota, lalu menggabungkannya.

Buat MovieExpert.java di 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);
}

Buat DiningExpert.java di 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);
}

Sekarang, mari kita bangun sistem agentik paralel. Kita akan menentukan antarmuka untuk koordinator tingkat teratas: TravelAdvisorAgent.

Buat TravelAdvisorAgent.java di 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);
}

Buat ParallelWorkflowDemo.java di src/main/java/com/example/ParallelWorkflowDemo.java untuk menyatukannya:

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

Anda akan melihat output yang mirip dengan:

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

Buat Sign.java di src/main/java/com/example/Sign.java:

package com.example;

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

2. Menentukan Sub-Agen

Buat HoroscopeGenerator.java di 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);
}

Buat PersonExtractor.java di 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);
}

Buat SignExtractor.java di 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);
}

Buat AmusingWriter.java di 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. Menentukan Alat untuk Menemukan Cerita

Kita akan membuat class alat penelusuran sederhana yang menampilkan cerita tiruan. Buat MockSearchTool.java di 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!";
    }
}

Buat agen StoryFinder.java di agen src/main/java/com/example/StoryFinder.java yang menggunakan alat ini:

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. Membangun dan Menjalankan Sistem Agentik GOAP

Buat GoapDemo.java di 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);
    }
}

Cara GOAP Mengatasinya:

Saat dipanggil:

  1. Sistem mendeteksi bahwa status awal hanya berisi prompt.
  2. Sasaran yang diinginkan adalah writeup.
  3. Tindakan ini akan membuat grafik dependensi dan menghitung jalur:
    • prompt -> PersonExtractor -> person
    • prompt -> SignExtractor -> sign
    • person + sign -> HoroscopeGenerator -> horoscope
    • sign -> StoryFinder -> story
    • person + horoscope + story -> AmusingWriter -> writeup
  4. Urutan eksekusi yang dihitung adalah: [PersonExtractor, SignExtractor, HoroscopeGenerator, StoryFinder, AmusingWriter].
  5. Fungsi ini menjalankan setiap sub-agen secara berurutan dan menampilkan hasil akhir.

Anda akan melihat output yang menunjukkan jalur eksekusi dan ringkasan akhir, mirip dengan:

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

Untuk membersihkan resource:

  • Pastikan untuk menghapus kunci API dari Google AI Studio jika Anda tidak lagi menggunakannya.
  • Batalkan setelan variabel lingkungan di terminal Anda:
unset GEMINI_API_KEY

10. 11. Selamat

Selamat! Anda telah berhasil membangun serangkaian aplikasi AI Agentik menggunakan LangChain4j dan modul GenAI Google yang baru.

Untuk meningkatkan keterampilan Anda, sebaiknya lihat dokumentasi modul GenAI Google LangChain4j resmi dan pelajari lebih lanjut cara membuat agen dengan LangChain4j.

Yang telah Anda pelajari

  • Cara mengonfigurasi GoogleGenAiChatModel.
  • Cara menggunakan alat Java lokal dan logging permintaan/respons.
  • Cara menampilkan data POJO terstruktur.
  • Cara membangun agen dengan tujuan tunggal menggunakan @Agent.
  • Cara mengorkestrasi alur kerja agentic berurutan, paralel, dan Perencanaan Tindakan Berorientasi Tujuan (GOAP).

Pelajari Lebih Lanjut