ساخت برنامه‌های کاربردی هوش مصنوعی عامل‌دار در جاوا با LangChain4j و Google GenAI

۱. ۱. قبل از شروع

خلاصه یادداشت‌های طراحی از Codelab

خوش آمدید! در این آزمایشگاه کد، شما یاد خواهید گرفت که چگونه با استفاده از چارچوب محبوب LangChain4j و ماژول جدید Google GenAI آن، برنامه‌های هوش مصنوعی عامل‌گرا را در جاوا بسازید.

هوش مصنوعی عامل‌محور به سیستم‌هایی اشاره دارد که در آن‌ها LLMها نه تنها به دستورات پاسخ می‌دهند، بلکه به ابزارها، حافظه و قابلیت‌های برنامه‌ریزی مجهز شده‌اند تا به طور خودکار اهداف پیچیده و چند مرحله‌ای را محقق کنند.

شما با پیکربندی‌های ساده شروع خواهید کرد، به سمت ساخت عامل‌ها با ابزارهای محلی و خروجی‌های ساختاریافته پیش خواهید رفت و در نهایت الگوهای پیشرفته هماهنگی چندعاملی را بررسی خواهید کرد که در نهایت به یک سیستم عامل‌محور برنامه‌ریزی اقدام هدفمند (GOAP) ختم می‌شود.

کاری که انجام خواهید داد

  • مدل جدید GoogleGenAiChatModel را برای اتصال به Gemini پیکربندی کنید.
  • برای اشکال‌زدایی آسان، ثبت درخواست/پاسخ را فعال کنید.
  • با استفاده از Tools به Gemini دسترسی به کد جاوای محلی بدهید.
  • قالب خروجی ساختاریافته (POJO) را از Gemini اعمال کنید.
  • تعریف و ساخت عامل‌های تک‌منظوره با حاشیه‌نویسی @Agent .
  • هماهنگ‌سازی گردش‌های کاری چندعاملی متوالی و موازی .
  • یک سیستم برنامه‌ریزی عملیاتی هدفمند (GOAP) بسازید که به صورت پویا اجرای عامل‌ها را برنامه‌ریزی کند.

آنچه نیاز دارید

۲. ۲. راه‌اندازی: پروژه و کلید API

برای شروع، باید یک پروژه Maven جدید ایجاد کنیم و کلید API مربوط به Gemini خود را پیکربندی کنیم.

ایجاد پروژه Maven

یک دایرکتوری جدید برای پروژه خود ایجاد کنید و آن را با یک فایل pom.xml مقداردهی اولیه کنید.

وابستگی‌های زیر را به pom.xml خود اضافه کنید. توجه داشته باشید که ما از آخرین نسخه 1.16.1-beta26 ماژول‌های LangChain4j Google GenAI و 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>

دریافت کلید API جمینی

  1. به استودیوی هوش مصنوعی گوگل بروید.
  2. روی دریافت کلید API کلیک کنید.
  3. یک کلید جدید ایجاد کنید (یا یک کلید موجود را انتخاب کنید).
  4. آن را به عنوان یک متغیر محیطی در ترمینال خود تنظیم کنید:
export GEMINI_API_KEY="your-api-key-here"

۳. ۳. پیکربندی مدل چت جمینی

حالا، بیایید یک برنامه ساده "Hello World" ایجاد کنیم که GoogleGenAiChatModel را نمونه‌سازی کرده و یک اعلان تست ارسال کند.

مدل جدید GoogleGenAiChatModel از کیت توسعه نرم‌افزار یکپارچه Google GenAI استفاده می‌کند که دسترسی یکپارچه به مدل‌های Gemini را فراهم می‌کند.

یک کلاس با نام HelloWorld.java در 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);
    }
}

این کلاس را اجرا کنید. از آنجایی که logRequestsAndResponses(true) فعال است، گزارش‌های مفصل SLF4J را مشاهده خواهید کرد که جزئیات دقیق درخواست ارسالی به API گوگل و پاسخ خام JSON دریافتی را شرح می‌دهند و به دنبال آن خروجی چاپ شده نمایش داده می‌شود:

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

۴. ۴. تعریف ابزارهای محلی جاوا

LLM ها قدرتمند هستند، اما به دلیل داده‌های آموزشی‌شان محدود شده‌اند. ما می‌توانیم با ارائه ابزارها (که به عنوان فراخوانی تابع نیز شناخته می‌شوند) قابلیت‌های آنها را گسترش دهیم.

در LangChain4j، ابزارها کلاس‌های ساده جاوا هستند که در آن‌ها متدها با @Tool حاشیه‌نویسی شده‌اند.

بیایید یک ابزار ساده بنویسیم که تعداد روزهای بین دو تاریخ را محاسبه کند. DateTools.java را در مسیر 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);
    }
}

برای استفاده از این ابزار، یک سرویس هوش مصنوعی تعریف خواهیم کرد. در چارچوب LangChain4j Agentic، می‌توانیم آن را با استفاده از AgenticServices.agentBuilder() بسازیم.

ToolDemo.java در مسیر 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);
    }
}

وقتی این کد را اجرا می‌کنید، Gemini اعلان را تجزیه و تحلیل می‌کند، متوجه می‌شود که باید daysBetween را فراخوانی کند، یک درخواست فراخوانی ابزار ایجاد می‌کند، LangChain4j متد جاوای محلی شما را اجرا می‌کند، نتیجه را به Gemini ارسال می‌کند و Gemini پاسخ نهایی زبان طبیعی را قالب‌بندی می‌کند.

شما باید خروجی مشابه زیر را ببینید:

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

۵. ۵. تعریف خروجی ساختاریافته

اغلب، شما می‌خواهید LLM داده‌ها را در یک قالب ساختاریافته خاص (مثلاً JSON منطبق با یک طرحواره) به جای متن ساده برگرداند.

LangChain4j این کار را به طور خودکار انجام می‌دهد، زمانی که یک POJO یا یک record جاوا را به عنوان نوع بازگشتی عامل یا متد سرویس خود مشخص می‌کنید.

بیایید یک record جاوا تعریف کنیم که نشان‌دهنده‌ی استخراج کتاب است:

Book.java در مسیر src/main/java/com/example/Book.java ایجاد کنید:

package com.example;

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

حالا یک رابط عامل ایجاد کنید که Book برگرداند. StructuredOutputDemo.java را در 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 از خروجی JSON Schema به طور دقیق پشتیبانی می‌کند. LangChain4j طرح JSON را از رکورد Book شما تولید می‌کند، به Gemini دستور می‌دهد تا آن را پر کند و پاسخ JSON را به صورت deserialize به یک رکورد Book برمی‌گرداند.

شما باید خروجی مشابه زیر را ببینید:

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

۶. ۶. اولین نماینده خود را ایجاد کنید

در چارچوب langchain4j-agentic ، یک عامل (Agent) با استفاده از حاشیه‌نویسی @Agent روی متد رابط تعریف می‌شود. این حاشیه‌نویسی یک نام/توضیح ارائه می‌دهد که می‌تواند توسط سیستم‌های هماهنگ‌سازی (مانند برنامه‌ریزان) مورد استفاده قرار گیرد.

بیایید یک عامل ساده بسازیم که یک موضوع را می‌گیرد و یک داستان بسیار کوتاه در مورد آن می‌نویسد.

CreativeWriter.java را در 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);
}

بیایید این عامل را به صورت جداگانه آزمایش کنیم. AgentDemo.java را در 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);
    }
}

شما باید خروجی مشابه زیر را ببینید:

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.

با اضافه کردن حاشیه‌نویسی @Agent ، این کلاس اکنون آماده است تا در گردش‌های کاری پیچیده‌تر، مانند زنجیره‌سازی متوالی، شرکت کند.

۷. ۷. هماهنگ‌سازی گردش‌های کاری چندعاملی: ترتیبی

یک الگوی عامل‌محور رایج، گردش کار ترتیبی (Sequential Workflow ) است که در آن عامل‌ها به ترتیب از پیش تعریف‌شده‌ای اجرا می‌شوند. خروجی یک عامل به عنوان ورودی عامل بعدی ارسال می‌شود.

بیایید یک عامل دوم به StyleEditor تعریف کنیم که داستان نوشته شده توسط CreativeWriter را ویرایش می‌کند تا با یک سبک خاص (مثلاً کمدی، دراماتیک) مطابقت داشته باشد.

StyleEditor.java در 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);
}

حالا، بیایید CreativeWriter و StyleEditor به صورت متوالی با استفاده از AgenticServices.sequenceBuilder() به هم متصل کنیم.

ما از یک UntypedAgent که نمایانگر توالی است استفاده خواهیم کرد که به ما امکان می‌دهد ورودی‌ها را ارسال و خروجی‌ها را از طریق یک نقشه مشترک جمع‌آوری کنیم.

SequentialWorkflowDemo.java را در مسیر 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);
    }
}

شما باید خروجی مشابه زیر را ببینید:

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.

معرفی AgenticScope

در حین اجرا، LangChain4j یک AgenticScope مدیریت می‌کند.

  1. نقشه ورودی {"topic": "...", "style": "..."} در محدوده نوشته می‌شود.
  2. CreativeWriter اجرا می‌شود. به topic نیاز دارد که آن را از scope می‌خواند. story را خروجی می‌دهد که دوباره در scope ذخیره می‌شود.
  3. StyleEditor اجرا می‌شود. به story (تولید شده توسط نویسنده) و style (از ورودی‌های اولیه) نیاز دارد. edited_story را در محدوده خروجی می‌دهد.
  4. گردش کار تکمیل شده و مقدار edited_story را برمی‌گرداند.

۸. ۸. هماهنگ‌سازی گردش‌های کاری چندعاملی: موازی

در برخی سناریوها، زیرعامل‌ها می‌توانند به‌طور مستقل روی ورودی یکسان کار کنند و وظایف آنها می‌تواند به‌صورت موازی اجرا شود.

برای مثال، بیایید یک مشاور سفر ایجاد کنیم که از یک متخصص سینما و یک متخصص رستوران، پیشنهادهایی برای یک شهر ارائه می‌دهد و سپس آنها را با هم ترکیب می‌کند.

MovieExpert.java در مسیر 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);
}

DiningExpert.java در 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);
}

حالا، بیایید سیستم عامل موازی را بسازیم. ما یک رابط برای هماهنگ‌کننده سطح بالای خود تعریف خواهیم کرد: TravelAdvisorAgent .

TravelAdvisorAgent.java را در 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);
}

برای اتصال موارد زیر به یکدیگر، ParallelWorkflowDemo.java در src/main/java/com/example/ParallelWorkflowDemo.java ایجاد کنید:

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

شما باید خروجی مشابه زیر را ببینید:

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

Sign.java در مسیر src/main/java/com/example/Sign.java ایجاد کنید:

package com.example;

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

۲. زیر-عامل‌ها را تعریف کنید

HoroscopeGenerator.java را در 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);
}

PersonExtractor.java در 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);
}

SignExtractor.java در مسیر 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);
}

AmusingWriter.java را در 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);
}

۳. ابزار یافتن داستان را تعریف کنید

ما یک کلاس ابزار جستجوی ساده ایجاد خواهیم کرد که یک داستان ساختگی (mock story) برمی‌گرداند. MockSearchTool.java را در مسیر 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!";
    }
}

فایل StoryFinder.java در src/main/java/com/example/StoryFinder.java که از این ابزار استفاده می‌کند، ایجاد کنید:

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

۴. ساخت و اجرای سیستم عامل GOAP

GoapDemo.java در مسیر 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);
    }
}

چگونه GOAP این مشکل را حل کرد:

هنگام فراخوانی:

  1. سیستم تشخیص می‌دهد که حالت اولیه فقط شامل prompt است.
  2. هدف مورد نظر، writeup است.
  3. این یک نمودار وابستگی می‌سازد و مسیر را محاسبه می‌کند:
    • prompt -> PersonExtractor -> person
    • prompt -> SignExtractor -> sign
    • person + sign -> HoroscopeGenerator -> horoscope
    • sign -> StoryFinder -> story
    • person + horoscope + story -> AmusingWriter -> writeup
  4. ترتیب اجرای محاسبه‌شده عبارت است از: [PersonExtractor, SignExtractor, HoroscopeGenerator, StoryFinder, AmusingWriter] .
  5. هر زیرعامل را به ترتیب اجرا می‌کند و نتیجه نهایی را برمی‌گرداند.

شما باید خروجی‌ای را مشاهده کنید که مسیر اجرا و نوشتن نهایی را نشان می‌دهد، مشابه:

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

۹. ۱۰. تمیز کردن

برای پاکسازی منابع:

  • اگر دیگر از کلیدهای API استفاده نمی‌کنید، حتماً آنها را از Google AI Studio حذف کنید.
  • متغیر محیطی را در ترمینال خود غیرفعال کنید:
unset GEMINI_API_KEY

۱۰. ۱۱. تبریک می‌گویم

تبریک! شما با موفقیت مجموعه‌ای از برنامه‌های هوش مصنوعی Agentic را با استفاده از LangChain4j و ماژول جدید Google GenAI ساختید.

برای ارتقای مهارت‌هایتان، توصیه می‌کنیم به مستندات رسمی ماژول LangChain4j Google GenAI نگاهی بیندازید و درباره ایجاد عامل‌ها با LangChain4j بیشتر بیاموزید.

آنچه آموختید

  • نحوه پیکربندی GoogleGenAiChatModel .
  • نحوه استفاده از ابزارهای محلی جاوا و ثبت درخواست/پاسخ.
  • نحوه خروجی گرفتن از داده‌های POJO ساختاریافته.
  • نحوه ساخت عامل‌های تک منظوره با @Agent .
  • چگونه گردش‌های کاری عاملی برنامه‌ریزی عملیاتی متوالی، موازی و هدف‌گرا (GOAP) را هماهنگ کنیم؟

اطلاعات بیشتر