1. 1. Прежде чем начать

Добро пожаловать! В этом практическом занятии вы научитесь создавать приложения для искусственного интеллекта на Java, используя популярный фреймворк LangChain4j и его новый модуль Google GenAI .
Агентный ИИ относится к системам, в которых логические модели не просто реагируют на подсказки, но и оснащены инструментами, памятью и возможностями планирования для автономного выполнения сложных многоэтапных задач.
Вы начнете с простых конфигураций, перейдете к созданию агентов с использованием локальных инструментов и структурированных выходных данных, и, наконец, изучите сложные шаблоны оркестровки многоагентных систем, кульминацией которых станет агентная система планирования действий, ориентированных на цели (GOAP) .
Что вы будете делать
- Настройте новую модель
GoogleGenAiChatModelдля подключения к Gemini. - Включите логирование запросов/ответов для упрощения отладки.
- Предоставьте Gemini доступ к локальному Java-коду с помощью Tools .
- Внедрить в Gemini формат структурированного вывода (POJO).
- Определяйте и создавайте агенты узкого назначения с помощью аннотации
@Agent. - Организация последовательных и параллельных многоагентных рабочих процессов.
- Создайте систему планирования действий, ориентированную на достижение целей (GOAP) , которая динамически планирует выполнение действий агентами.
Что вам понадобится
- Комплект разработки Java (JDK) 17 или выше.
- Установлен Maven 3.5+.
- Ключ API Gemini от Google AI Studio .
2. 2. Настройка: Проект и ключ 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 Gemini
- Перейдите в Google AI Studio .
- Нажмите « Получить ключ API» .
- Создайте новый ключ (или выберите существующий).
- Установите её в качестве переменной окружения в терминале:
export GEMINI_API_KEY="your-api-key-here"
3. 3. Настройка модели чата Gemini
Теперь давайте создадим простое приложение "Hello World", которое создаст экземпляр GoogleGenAiChatModel и отправит тестовое сообщение.
Новая модель GoogleGenAiChatModel использует унифицированный SDK 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 Google, полученный необработанный 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.
4. 4. Определение локальных инструментов Java
LLM-ы обладают мощными возможностями, но их возможности ограничены объемом обучающих данных. Мы можем расширить их возможности, предоставив им инструменты (также известные как вызов функций).
В LangChain4j инструменты представляют собой простые Java-классы, методы которых аннотированы с помощью @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 выполнит ваш локальный метод Java, отправит результат обратно в Gemini, и Gemini отформатирует окончательный ответ на естественном языке.
В результате вы должны увидеть примерно следующее:
Response: There are 180 days between 2026-01-01 and 2026-06-30.
5. 5. Определение структурированного вывода
Часто требуется, чтобы LLM возвращал данные в определенном структурированном формате (например, JSON, соответствующий схеме), а не в виде простого текста.
LangChain4j обрабатывает это автоматически, если вы указываете POJO или record Java в качестве типа возвращаемого значения для вашего агента или метода сервиса.
Давайте определим record Java, представляющую собой извлечение данных из книги:
Создайте 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-ответ обратно в запись Book .
В результате вы должны увидеть примерно следующее:
Extracted POJO: Book[title=Project Hail Mary, author=Andy Weir, publicationYear=2021]
6. 6. Создайте своего первого агента.
В фреймворке langchain4j-agentic агент определяется с помощью аннотации @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 этот класс теперь готов участвовать в более сложных рабочих процессах, таких как последовательная цепочка.
7. 7. Организация многоагентных рабочих процессов: последовательная
Распространенным шаблоном работы агентов является последовательный рабочий процесс , в котором агенты выполняют действия в заранее определенном порядке. Результат работы одного агента передается в качестве входных данных для следующего.
Давайте определим второго агента, 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 .
- Входная карта
{"topic": "...", "style": "..."}записывается в область видимости. -
CreativeWriterвыполняется. Она запрашиваетtopic, которую считывает из области видимости. В результате она выводитstory, которая сохраняется обратно в область видимости. - Выполняется
StyleEditor. Она принимает наstory(составленный автором) иstyle(из исходных данных). В результате в область видимости выводитсяedited_story. - Процесс завершается и возвращает значение
edited_story.
8. 8. Организация многоагентных рабочих процессов: параллельный режим
В некоторых сценариях суб-агенты могут работать независимо над одними и теми же входными данными, и их задачи могут выполняться параллельно.
Например, давайте создадим сервис для поиска туристических услуг, который запрашивает рекомендации у киноэксперта и эксперта по ресторанам в определенном городе, а затем объединяет их.
Создайте 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; }
}
2. Определите субагентов.
Создайте 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);
}
3. Определите инструмент для поиска историй.
Мы создадим простой класс инструмента поиска, который возвращает фиктивную историю. Создайте 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);
}
4. Создайте и запустите агентную систему 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 решила эту проблему:
При вызове:
- Система определяет, что начальное состояние содержит только
prompt. - Желаемая цель —
writeup. - Она строит граф зависимостей и вычисляет путь:
-
prompt->PersonExtractor->person -
prompt->SignExtractor->sign -
person+sign->HoroscopeGenerator->horoscope -
sign->StoryFinder->story -
person+horoscope+story->AmusingWriter->writeup
-
- Рассчитанный порядок выполнения:
[PersonExtractor, SignExtractor, HoroscopeGenerator, StoryFinder, AmusingWriter]. - Он последовательно запускает каждого субагента и возвращает окончательный результат.
В результате вы должны увидеть вывод, отображающий путь выполнения и итоговый отчет, примерно следующего вида:
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. Уборка
Для очистки ресурсов:
- Обязательно удалите все ключи API из Google AI Studio, если вы ими больше не пользуетесь.
- Отмените установку переменной среды в терминале:
unset GEMINI_API_KEY
10. 11. Поздравляем!
Поздравляем! Вы успешно разработали серию приложений Agentic AI с использованием LangChain4j и нового модуля Google GenAI.
Для дальнейшего совершенствования ваших навыков мы рекомендуем ознакомиться с официальной документацией модуля LangChain4j Google GenAI и узнать больше о создании агентов с помощью LangChain4j .
Что вы узнали
- Как настроить
GoogleGenAiChatModel. - Как использовать локальные инструменты Java и вести логирование запросов/ответов.
- Как вывести структурированные данные POJO.
- Как создавать агенты с одной целью с помощью
@Agent. - Как организовать последовательные, параллельные и ориентированные на достижение целей рабочие процессы с использованием агентного подхода.