1. Witamy, deweloperzy agentów AI!
Z tego ćwiczenia dowiesz się, jak tworzyć w Javie agenty AI za pomocą pakietu Agents Development Kit (ADK) dla języka Java. Wyjdziemy poza proste wywołania interfejsu API dużego modelu językowego (LLM), aby tworzyć autonomiczne agenty AI, które mogą wnioskować, planować, używać narzędzi i współpracować ze sobą w celu rozwiązywania złożonych problemów.
Zaczniesz od wykorzystania środków w Google Cloud i skonfigurowania środowiska Google Cloud, a następnie utworzysz pierwszego prostego agenta i stopniowo dodasz bardziej zaawansowane funkcje, takie jak narzędzia niestandardowe, wyszukiwanie w internecie i orkiestracja wielu agentów.

Czego się nauczysz
- Jak utworzyć podstawowego agenta AI opartego na personie.
- Jak wyposażyć agentów w narzędzia niestandardowe i wbudowane (np. wyszukiwarkę Google).
- Jak dodać własne narzędzia zaimplementowane w języku Java.
- Jak koordynować pracę wielu agentów w zaawansowanych przepływach pracy sekwencyjnych, równoległych i zapętlonych.
Czego potrzebujesz
- Przeglądarka, której będziemy używać w trybie incognito.
- osobiste konto Gmail;
- nowy projekt w chmurze Google Cloud powiązany z Twoim osobistym kontem Gmail;
- Konto rozliczeniowe utworzone przy użyciu wykorzystanych środków Google Cloud.
- Narzędzie wiersza poleceń Git do sprawdzania kodu źródłowego.
- Java 17 lub nowsza i Apache Maven.
- Edytor tekstu lub IDE, np. IntelliJ IDEA lub VS Code.
Możesz użyć wbudowanego edytora kodu w Cloud Shell w konsoli Google Cloud.
2. Konfiguracja: środowisko
Otrzymywanie środków w Google Cloud na potrzeby warsztatów

W przypadku warsztatów prowadzonych przez instruktora otrzymasz link do strony, na której możesz odebrać środki na Google Cloud do wykorzystania podczas warsztatów.
- Użyj osobistego konta Google: ważne jest, aby używać osobistego konta Google (np. adresu gmail.com), ponieważ firmowe lub szkolne adresy e-mail nie będą działać.
- Używaj Google Chrome w trybie incognito: zalecamy to rozwiązanie, aby utworzyć czystą sesję i zapobiec konfliktom z innymi kontami Google.
- Użyj specjalnego linku do wydarzenia: należy użyć specjalnego linku do wydarzenia, który wygląda mniej więcej tak: https://trygcp.dev/event/xxx, a po nim następuje kod wydarzenia (w tym przykładzie „xxx”).
- Zaakceptuj warunki usługi: po zalogowaniu się wyświetlą się warunki korzystania z usługi Google Cloud Platform, które musisz zaakceptować, aby kontynuować.
- Utwórz nowy projekt: nowy pusty projekt musi zostać utworzony w konsoli Google Cloud.
- Połącz konto rozliczeniowe: połącz nowo utworzony projekt z kontem rozliczeniowym.
- Potwierdź przyznanie środków: poniższy film pokazuje, jak potwierdzić, że środki zostały przyznane projektowi. W tym celu należy sprawdzić sekcję „Środki” na stronie płatności.
Możesz obejrzeć ten film, aby dowiedzieć się, jak wykorzystać środki.
Włącz Vertex AI API
Najpierw włącz interfejs Vertex AI API. Możesz to zrobić, wyszukując Vertex AI API w konsoli Google Cloud i włączając interfejs API. Możesz to też zrobić w Cloud Shell, uruchamiając to polecenie:
gcloud services enable aiplatform.googleapis.com
Konfigurowanie ADK za pomocą Vertex AI
Aby uwierzytelnić agentów AI ADK w Gemini w Vertex AI na potrzeby tego ćwiczenia, ustaw te zmienne środowiskowe. Upewnij się, że używasz unikalnego identyfikatora projektu.
macOS / Linux: otwórz terminal i uruchom to polecenie. Aby to ustawienie było trwałe, dodaj ten wiersz do pliku startowego powłoki (np. ~/.bash_profile, ~/.zshrc).
export GOOGLE_GENAI_USE_VERTEXAI=true export GOOGLE_CLOUD_PROJECT=your-project-id
Windows (wiersz polecenia): otwórz nowy wiersz polecenia i uruchom:
set GOOGLE_GENAI_USE_VERTEXAI=true set GOOGLE_CLOUD_PROJECT=your-project-id
Aby ta zmiana została zastosowana, musisz ponownie uruchomić wiersz poleceń.
Windows (PowerShell): otwórz terminal PowerShell i uruchom:
$env:GOOGLE_GENAI_USE_VERTEXAI = "true" $env:GOOGLE_CLOUD_PROJECT = "your-project-id"
Aby ta zmiana była trwała w PowerShellu, musisz dodać ją do skryptu profilu.
3. Pierwsze kroki: Twój pierwszy agent
Najlepszym sposobem na rozpoczęcie nowego projektu jest użycie szablonu ADK dla Javy na GitHubie. Zawiera strukturę projektu i wszystkie niezbędne zależności.
Jeśli masz konto GitHub, możesz wykonać te czynności: Use this template > Create a new repository, a następnie pobrać kod lokalnie za pomocą polecenia git clone.
Poniżej znajdziesz zrzut ekranu przedstawiający menu w prawym górnym rogu, które umożliwia korzystanie z szablonu.

Inne podejście to po prostu bezpośrednie sklonowanie tego repozytorium:
git clone https://github.com/glaforge/adk-java-maven-template.git
Aby sprawdzić, czy możesz zacząć pisać kod pierwszego agenta AI w Javie, upewnij się, że możesz skompilować kod w tym projekcie za pomocą:
cd adk-java-maven-template
mvn compile
Krok z kodem: przyjazny nauczyciel nauk ścisłych
Podstawowym elementem składowym w pakiecie ADK jest klasa LlmAgent. Można go traktować jako AI o określonej osobowości i celu, oparte na dużym modelu językowym. W późniejszym czasie dodamy więcej funkcji za pomocą narzędzi i zwiększymy jego możliwości, współpracując z innymi podobnymi agentami.
Utwórzmy nową klasę Java w pakiecie com.example.agent i nazwijmy ją ScienceTeacher.
To odpowiednik „Hello, World!” w przypadku tworzenia agentów. Definiujemy prostego agenta o osobowości nauczyciela nauk ścisłych.
// src/main/java/com/example/agent/ScienceTeacher.java
package com.example.agent;
import com.google.adk.agents.LlmAgent;
import com.google.adk.web.AdkWebServer;
public class ScienceTeacher {
public static void main(String[] args) {
AdkWebServer.start(
LlmAgent.builder()
.name("science-teacher")
.description("A friendly science teacher")
.instruction("""
You are a science teacher for teenagers.
You explain science concepts in a simple, concise and direct way.
""")
.model("gemini-2.5-flash")
.build()
);
}
}
Agent AI jest konfigurowany za pomocą metody LlmAgent.builder(). Parametry name(), description() i model() są obowiązkowe. Aby nadać agentowi konkretną osobowość i odpowiednie zachowanie, zawsze należy podać szczegółowe wskazówki za pomocą metody instruction().
W tym przypadku wybraliśmy model Gemini 2.5 Flash, ale w przypadku bardziej skomplikowanych zadań możesz też wypróbować Gemini 2.5 Pro.
Ten agent jest zawarty w metodzie AdkWebServer.start(). Jest to interfejs czatu ADK Dev UI. Umożliwia to rozmowę z agentem w typowym interfejsie czatu. Jest to też bardzo przydatne, jeśli chcesz zrozumieć, co się dzieje w tle, np. jakie zdarzenia przepływają przez system oraz jakie żądania i odpowiedzi są wysyłane do dużego modelu językowego.
Aby skompilować i uruchomić tego agenta lokalnie, uruchom to polecenie:
mvn compile exec:java -Dexec.mainClass=com.example.agent.ScienceTeacher
Następnie otwórz przeglądarkę i wpisz adres http://localhost:8080. Jeśli korzystasz z Cloud Shell, możesz kliknąć Podgląd w przeglądarce i wybrać Podejrzyj na porcie 8080.
Powinien być widoczny interfejs pokazany na zrzucie ekranu poniżej. Zadaj agentowi pytania związane z nauką.

4. Wzbogacanie agentów narzędziami

Dlaczego agenci potrzebują narzędzi? LLM to potężne narzędzia, ale ich wiedza jest zamrożona w czasie i nie mogą wchodzić w interakcje ze światem zewnętrznym. Narzędzia są pomostem. Umożliwiają one agentowi dostęp do informacji w czasie rzeczywistym (np. cen akcji lub wiadomości), wysyłanie zapytań do prywatnych interfejsów API lub wykonywanie dowolnych działań, które można zaprogramować w języku Java.
Krok z kodem: tworzenie narzędzia niestandardowego (StockTicker)
W tym miejscu udostępniamy agentowi narzędzie do sprawdzania cen akcji. Agent wnioskuje, że gdy użytkownik zapyta o cenę, powinien wywołać naszą metodę Java.
// src/main/java/com/example/agent/StockTicker.java
package com.example.agent;
import com.google.adk.agents.LlmAgent;
import com.google.adk.tools.Annotations.Schema;
import com.google.adk.tools.FunctionTool;
import com.google.adk.web.AdkWebServer;
import java.util.Map;
public class StockTicker {
public static void main(String[] args) {
AdkWebServer.start(
LlmAgent.builder()
.name("stock_agent")
.instruction("""
You are a stock exchange ticker expert.
When asked about the stock price of a company,
use the `lookup_stock_ticker` tool to find the information.
""")
.model("gemini-2.5-flash")
.tools(FunctionTool.create(StockTicker.class, "lookupStockTicker"))
.build()
);
}
@Schema(
name = "lookup_stock_ticker",
description = "Lookup stock price for a given company or ticker"
)
public static Map<String, String> lookupStockTicker(
@Schema(name = "company_name_or_stock_ticker", description = "The company name or stock ticker")
String ticker) {
// ... (logic to return a stock price)
}
}
Aby zwiększyć inteligencję agentów i umożliwić im interakcję ze światem (lub z Twoim własnym kodem, interfejsami API, usługami itp.), możesz skonfigurować agenta tak, aby używał narzędzi, a w szczególności narzędzi z kodem niestandardowym, za pomocą metody tools(), przekazując mu FunctionTool.create(...).
Element FunctionTool wymaga nazwy klasy i metody wskazującej Twoją własną metodę statyczną. Możesz też przekazać instancję klasy i nazwę metody instancji tego obiektu.
Ważne jest, aby określić name i description zarówno metody, jak i jej parametrów za pomocą adnotacji @Schema, ponieważ te informacje będą używane przez bazowy LLM do określania, kiedy i jak należy wywołać daną metodę.
Równie ważne jest, aby przekazać modelowi LLM jasne instrukcje dotyczące tego, jak i kiedy używać narzędzia. Model może sam to ustalić, ale jeśli podasz wyraźne wyjaśnienia w instruction() method, Twoja funkcja ma większe szanse na prawidłowe wywołanie.
Ta metoda powinna zwrócić wartość Map. Zwykle chodzi o zwrócenie mapy z kluczem reprezentującym wynik, np. stock_price, i powiązanie z nim wartości ceny akcji. Możesz też dodać dodatkową parę klucz-wartość success / true, aby zasygnalizować powodzenie operacji. W przypadku błędu należy zwrócić mapę z kluczem o nazwie np. error i powiązać z nim komunikat o błędzie. Pomoże to LLM zrozumieć, czy wywołanie się powiodło, czy też z jakiegoś powodu nie.
- W przypadku powodzenia zwraca:
{"stock_price": 123} - W przypadku błędu zwróć:
{"error": "Impossible to retrieve stock price for XYZ"}
Następnie uruchom tę klasę za pomocą tego polecenia:
mvn compile exec:java -Dexec.mainClass=com.example.agent.StockTicker
Możesz teraz pytać agenta o ceny akcji, np. What's the stock price for GOOG? Powinieneś otrzymać odpowiedzi i zobaczyć, że używane jest narzędzie lookup_stock_ticker.
5. Więcej możliwości dzięki wyszukiwarce Google, która dostarcza aktualnych informacji

Pakiet ADK dla Javy zawiera kilka zaawansowanych narzędzi, w tym GoogleSearchTool. Dzięki temu narzędziu Twój agent może poprosić o użycie wyszukiwarki Google, aby znaleźć odpowiednie informacje i osiągnąć swój cel.
Wiedza modelu LLM jest zamrożona w czasie: został on wytrenowany do określonej daty („daty odcięcia”) na podstawie danych, które są aktualne w momencie ich zebrania. Oznacza to, że duże modele językowe nie muszą znać najnowszych wydarzeń, a ich wiedza może być ograniczona i powierzchowna. W takiej sytuacji pomocna może być wyszukiwarka, która odświeży ich pamięć lub dostarczy więcej informacji na dany temat.
Przyjrzyjmy się temu prostemu agentowi wyszukiwania wiadomości:
// src/main/java/com/example/agent/LatestNews.java
package com.example.agent;
import java.time.LocalDate;
import com.google.adk.agents.LlmAgent;
import com.google.adk.tools.GoogleSearchTool;
import com.google.adk.web.AdkWebServer;
public class LatestNews {
public static void main(String[] args) {
AdkWebServer.start(LlmAgent.builder()
.name("news-search-agent")
.description("A news search agent")
.instruction("""
You are a news search agent.
Use the `google_search` tool
when asked to search for recent events and information.
Today is \
""" + LocalDate.now())
.model("gemini-2.5-flash")
.tools(new GoogleSearchTool())
.build());
}
}
Zwróć uwagę, jak przekazaliśmy instancję narzędzia wyszukiwania za pomocą: tools(new GoogleSearchTool()). Dzięki temu nasz agent może szybko zapoznać się z najnowszymi informacjami dostępnymi w internecie. Prompt zawierał też datę, ponieważ może to pomóc LLM zrozumieć, kiedy pytania dotyczą informacji z przeszłości i wymagają wyszukania nowszych informacji.
Następnie uruchom tę klasę za pomocą tego polecenia:
mvn compile exec:java -Dexec.mainClass=com.example.agent.LatestNews
Możesz eksperymentować z promptem, np. zadając pytanie: What's the latest news in the world?
Krok z kodem: agent wyszukiwania jako narzędzie
Zamiast przekazywać GoogleSearchTool bezpośrednio do agenta jako narzędzie, możesz utworzyć dedykowanego agenta wyszukiwania, który będzie zawierać funkcję wyszukiwania, i udostępnić tego agenta jako narzędzie agentowi wyższego poziomu.
Jest to zaawansowana koncepcja, która umożliwia delegowanie złożonych działań (takich jak wyszukiwanie i podsumowywanie wyników) do wyspecjalizowanego sub-agenta. To podejście jest często przydatne w przypadku bardziej złożonych przepływów pracy.
// src/main/java/com/example/agent/SearchAgentAsTool.java
package com.example.agent;
import java.time.LocalDate;
import com.google.adk.agents.LlmAgent;
import com.google.adk.tools.AgentTool;
import com.google.adk.tools.GoogleSearchTool;
import com.google.adk.web.AdkWebServer;
public class SearchAgentAsTool {
public static void main(String[] args) {
// 1. Define the specialized Search Agent
LlmAgent searchAgent = LlmAgent.builder()
.name("news-search-agent-tool")
.description("Searches for recent events and provides a concise summary.")
.instruction("""
You are a concise information retrieval specialist.
Use the `google_search` tool to find information.
Always provide the answer as a short,
direct summary, without commentary.
Today is \
""" + LocalDate.now())
.model("gemini-2.5-flash")
.tools(new GoogleSearchTool()) // This agent uses the Google Search Tool
.build();
// 2. Wrap the Search Agent as a Tool
AgentTool searchTool = AgentTool.create(searchAgent);
// 3. Define the Main Agent that uses the Search Agent Tool
AdkWebServer.start(LlmAgent.builder()
.name("main-researcher")
.description("Main agent for answering complex, up-to-date questions.")
.instruction("""
You are a sophisticated research assistant.
When the user asks a question that requires up-to-date or external information,
you MUST use the `news-search-agent-tool` to get the facts before answering.
After the tool returns the result, synthesize the final answer for the user.
""")
.model("gemini-2.5-flash")
.tools(searchTool) // This agent uses the Search Agent as a tool
.build()
);
}
}
Kluczowym pojęciem jest tutaj AgentTool.create(searchAgent). Rejestruje cały interfejs searchAgent (z własną logiką wewnętrzną, promptem i narzędziami) jako jedno narzędzie wywoływane przez mainAgent. Zwiększa to modułowość i możliwość ponownego wykorzystania.
Uruchom tę klasę za pomocą tego polecenia:
mvn compile exec:java -Dexec.mainClass=com.example.agent.SearchAgentAsTool
Na proste pytania agent odpowie na podstawie własnej bazy wiedzy, ale gdy zostanie zapytany o ostatnie wydarzenia, przekaże wyszukiwanie wyspecjalizowanemu agentowi wyszukiwania za pomocą narzędzia wyszukiwarki Google.
6. Opanowanie przepływów pracy agenta
W przypadku złożonych problemów jeden agent nie wystarczy. Gdy model LLM otrzyma cel składający się ze zbyt wielu podzadań, z ogromnym promptem zawierającym zbyt wiele szczegółów lub z dostępem do zbyt wielu funkcji, ma problemy, a jego wydajność i dokładność się pogarszają.
Kluczem jest dzielenie i współpraca, czyli koordynowanie pracy wielu wyspecjalizowanych agentów. Na szczęście pakiet ADK zawiera różne wbudowane specjalistyczne agenty:
- zwykły agent z
subAgent(), któremu można delegować zadania; SequentialAgent, aby wykonywać zadania w określonej kolejności,ParallelAgent, aby wykonywać agentów równolegle,LoopAgent, zwykle w celu przeprowadzenia procesu udoskonalania tyle razy, ile będzie to konieczne.
Główne przypadki użycia oraz zalety i wady każdego z tych procesów znajdziesz w tabeli poniżej. Pamiętaj jednak, że prawdziwa moc tkwi w połączeniu kilku z nich.
Workflow | Zajęcia ADK | Use Case | Zalety | Wady |
Sub-agenci |
| Zadania elastyczne, w których użytkownik decyduje o dalszych krokach. | Duża elastyczność, konwersacyjność, świetne rozwiązanie dla botów, z których korzystają użytkownicy. | Mniej przewidywalne, polega na rozumowaniu LLM w zakresie sterowania przepływem. |
Sekwencyjny |
| Stałe procesy wieloetapowe, w których kolejność ma kluczowe znaczenie. | Przewidywalne, niezawodne, łatwe do debugowania, gwarantuje kolejność. | Nieelastyczne, może działać wolniej, jeśli zadania można wykonywać równolegle. |
Równolegle |
| Zbieranie danych z wielu źródeł lub wykonywanie niezależnych zadań. | Wysoka wydajność, znaczne skrócenie czasu oczekiwania w przypadku zadań wymagających dużej liczby operacji wejścia/wyjścia. | Wszystkie zadania są wykonywane, nie ma skracania. Mniej odpowiednie w przypadku zadań z zależnościami. |
Loop |
| Iteracyjne udoskonalanie, samokorekta lub procesy, które powtarzają się do momentu spełnienia określonego warunku. | Skuteczny w rozwiązywaniu złożonych problemów, umożliwia agentom ulepszanie własnej pracy. | Jeśli nie zostanie starannie zaprojektowana, może prowadzić do nieskończonych pętli (zawsze używaj maxIterations!). |
7. Przepływy pracy agentowe – delegowanie zadań za pomocą subagentów

Agent nadzorujący może przekazywać określone zadania podległym agentom. Wyobraź sobie na przykład agenta na stronie e-commerce, który przekazuje pytania dotyczące zamówień jednemu agentowi („Jaki jest stan mojego zamówienia?”), a pytania dotyczące obsługi posprzedażowej innemu agentowi („Nie wiem, jak to włączyć!”). To właśnie ten przypadek użycia omówimy.
// src/main/java/com/example/agent/SupportAgent.java
package com.example.agent;
import com.google.adk.agents.LlmAgent;
import com.google.adk.web.AdkWebServer;
public class SupportAgent {
public static void main(String[] args) {
LlmAgent orderAgent = LlmAgent.builder()
.name("order-agent")
.description("Order agent")
.instruction("""
Your role is to help our customers
with all the questions they may have about their orders.
Always respond that the order has been received, prepared,
and is now out for delivery.
""")
.model("gemini-2.5-flash")
.build();
LlmAgent afterSaleAgent = LlmAgent.builder()
.name("after-sale-agent")
.description("After sale agent")
.instruction("""
You are an after sale agent,
helping customers with the product they received.
When a customer has a problem,
suggest the person to switch the product off and on again.
""")
.model("gemini-2.5-flash")
.build();
AdkWebServer.start(LlmAgent.builder()
.name("support-agent")
.description("Customer support agent")
.instruction("""
Your role is to help our customers.
Call the `order-agent` for all questions related to order status.
Call the `after-sale-agent` for inquiries about the received product.
""")
.model("gemini-2.5-flash")
.subAgents(afterSaleAgent, orderAgent)
.build()
);
}
}
Kluczowy wiersz to miejsce, w którym wywoływana jest metoda subAgents(). Przekazuje ona 2 podagenty, których konkretne role będą obsługiwane oddzielnie.
Uruchom powyższy przykład za pomocą tego polecenia:
mvn compile exec:java -Dexec.mainClass=com.example.agent.SupportAgent
Możesz zadawać pytania takie jak I have a question about my order lub I have a question about my received order. Główny agent powinien przekazywać zapytania do odpowiedniego agenta w zależności od zadawanego pytania.
Koncepcja delegowania zadań do podagentów odzwierciedla skuteczne zarządzanie ludźmi, w którym dobry menedżer (agent nadzorujący) polega na wyspecjalizowanych pracownikach (podagentach), którzy wykonują konkretne zadania, w których mają większą wiedzę. Kierownik nie musi znać szczegółów każdego procesu. Zamiast tego inteligentnie kieruje prośbę klienta (np. zapytanie dotyczące zamówienia lub problem techniczny) do najbardziej wykwalifikowanego „członka zespołu”, zapewniając wyższą jakość i większą skuteczność odpowiedzi niż w przypadku, gdyby odpowiadał tylko jeden specjalista. Ponadto podagenci mogą w pełni skupić się na swoich indywidualnych zadaniach, nie musząc rozumieć całego złożonego procesu nadrzędnego.
8. Przepływy pracy agenta – linia montażowa

Gdy kolejność działań ma znaczenie, użyj SequentialAgent. Działa to jak linia montażowa, która wykonuje podagenty w ustalonej kolejności, a każdy krok może zależeć od poprzedniego.
Wyobraźmy sobie, że angielski poeta współpracuje z tłumaczem z języka angielskiego na francuski, aby tworzyć wiersze najpierw w języku angielskim, a potem tłumaczyć je na francuski:
// src/main/java/com/example/agent/PoetAndTranslator.java
package com.example.agent;
import com.google.adk.agents.LlmAgent;
import com.google.adk.agents.SequentialAgent;
import com.google.adk.web.AdkWebServer;
public class PoetAndTranslator {
public static void main(String[] args) {
LlmAgent poet = LlmAgent.builder()
.name("poet-agent")
.description("Poet writing poems")
.model("gemini-2.5-flash")
.instruction("""
You are a talented poet,
who writes short and beautiful poems.
""")
.outputKey("poem")
.build();
LlmAgent translator = LlmAgent.builder()
.name("translator-agent")
.description("English to French translator")
.model("gemini-2.5-flash")
.instruction("""
As an expert English-French translator,
your role is to translate the following poem into French,
ensuring the poem still rhymes even after translation:
{poem}
""")
.outputKey("translated-poem")
.build();
AdkWebServer.start(SequentialAgent.builder()
.name("poet-and-translator")
.subAgents(poet, translator)
.build());
}
}
Uruchom przykład:
mvn compile exec:java -Dexec.mainClass=com.example.agent.PoetAndTranslator
Teraz możesz zapytać agenta o coś takiego: Write me a poem about a lonely software developer. Powinien pojawić się wiersz w języku angielskim, a następnie jego tłumaczenie na język francuski.
Systematyczny podział złożonych zadań na mniejsze, uporządkowane podzadania zapewnia bardziej deterministyczny i niezawodny proces, co znacznie zwiększa prawdopodobieństwo osiągnięcia sukcesu w porównaniu z poleganiem na jednym, ogólnym agencie.
Skuteczne dzielenie zadania na sekwencję podzadań (w miarę możliwości i potrzeb) ma kluczowe znaczenie dla osiągania bardziej deterministycznych i skutecznych wyników, ponieważ umożliwia uporządkowany postęp i zarządzanie zależnościami między poszczególnymi krokami.
9. Przepływy pracy agenta – praca równoległa

Gdy zadania są niezależne, ParallelAgent znacznie zwiększa wydajność, ponieważ wykonuje je jednocześnie. W tym przykładzie połączymy nawet SequentialAgent z ParallelAgent: najpierw zostaną wykonane zadania równoległe, a potem agent podsumuje ich wyniki.
Stwórzmy detektywa, którego zadaniem będzie wyszukiwanie informacji o:
- Profil firmy (prezes, siedziba, motto itp.)
- Najnowsze informacje o firmie.
- Informacje o finansach firmy.
// src/main/java/com/example/agent/CompanyDetective.java
package com.example.agent;
import com.google.adk.agents.LlmAgent;
import com.google.adk.agents.ParallelAgent;
import com.google.adk.agents.SequentialAgent;
import com.google.adk.tools.GoogleSearchTool;
import com.google.adk.web.AdkWebServer;
public class CompanyDetective {
public static void main(String[] args) {
var companyProfiler = LlmAgent.builder()
.name("company-profiler")
.description("Provides a general overview of a company.")
.instruction("""
Your role is to provide a brief overview of the given company.
Include its mission, headquarters, and current CEO.
Use the Google Search Tool to find this information.
""")
.model("gemini-2.5-flash")
.tools(new GoogleSearchTool())
.outputKey("profile")
.build();
var newsFinder = LlmAgent.builder()
.name("news-finder")
.description("Finds the latest news about a company.")
.instruction("""
Your role is to find the top 3-4 recent news headlines for the given company.
Use the Google Search Tool.
Present the results as a simple bulleted list.
""")
.model("gemini-2.5-flash")
.tools(new GoogleSearchTool())
.outputKey("news")
.build();
var financialAnalyst = LlmAgent.builder()
.name("financial-analyst")
.description("Analyzes the financial performance of a company.")
.instruction("""
Your role is to provide a snapshot of the given company's recent financial performance.
Focus on stock trends or recent earnings reports.
Use the Google Search Tool.
""")
.model("gemini-2.5-flash")
.tools(new GoogleSearchTool())
.outputKey("financials")
.build();
var marketResearcher = ParallelAgent.builder()
.name("market-researcher")
.description("Performs comprehensive market research on a company.")
.subAgents(
companyProfiler,
newsFinder,
financialAnalyst
)
.build();
var reportCompiler = LlmAgent.builder()
.name("report-compiler")
.description("Compiles a final market research report.")
.instruction("""
Your role is to synthesize the provided information into a coherent market research report.
Combine the company profile, latest news, and financial analysis into a single, well-formatted report.
## Company Profile
{profile}
## Latest News
{news}
## Financial Snapshot
{financials}
""")
.model("gemini-2.5-flash")
.build();
AdkWebServer.start(SequentialAgent.builder()
.name("company-detective")
.description("Collects various information about a company.")
.subAgents(
marketResearcher,
reportCompiler
).build());
}
}
Jak zwykle możesz uruchomić agenta za pomocą tego polecenia:
mvn compile exec:java -Dexec.mainClass=com.example.agent.CompanyDetective
Zapytaj o różne firmy, np. Google lub Apple, i sprawdź, co otrzymasz w odpowiedzi.
Ten agent demonstruje potężne połączenie przepływów pracy, w którym zarówno agenci równolegli, jak i sekwencyjni są dobrze wykorzystywani w efektywny sposób dzięki równoległemu wyszukiwaniu i syntezie informacji.
10. Przepływy pracy agenta – iteracyjne ulepszanie

W przypadku zadań wymagających cyklu „generowanie → sprawdzanie → ulepszanie” użyj LoopAgent. Automatyzuje proces iteracyjnego doskonalenia, aż do osiągnięcia celu. Podobnie jak w przypadku SequentialAgent, LoopAgent będzie wywoływać sub-agenty szeregowo, ale będzie wracać do początku. To model LLM używany wewnętrznie przez agenta decyduje, czy zażądać wywołania specjalnego narzędzia, czyli exit_loop narzędzia wbudowanego, aby zatrzymać wykonanie pętli.
Poniższy przykład narzędzia do ulepszania kodu, w którym użyto symbolu LoopAgent, automatyzuje ulepszanie kodu: generowanie, sprawdzanie i poprawianie. Naśladuje to rozwój człowieka. Generator kodu najpierw generuje żądany kod i zapisuje go w stanie agenta pod kluczem generated_code. Następnie osoba sprawdzająca kod weryfikuje wygenerowany kod i albo przekazuje opinię (pod klawiszem feedback), albo wywołuje narzędzie do zamykania pętli, aby wcześniej zakończyć iterację.
Przyjrzyjmy się kodowi:
// src/main/java/com/example/agent/CodeRefiner.java
package com.example.agent;
import com.google.adk.agents.LlmAgent;
import com.google.adk.agents.LoopAgent;
import com.google.adk.agents.SequentialAgent;
import com.google.adk.tools.ExitLoopTool;
import com.google.adk.web.AdkWebServer;
public class CodeRefiner {
public static void main(String[] args) {
var codeGenerator = LlmAgent.builder()
.name("code-generator")
.description("Writes and refines code based on a request and feedback.")
.instruction("""
Your role is to write a Python function based on the user's request.
In the first turn, write the initial version of the code.
In subsequent turns, you will receive feedback on your code.
Your task is to refine the code based on this feedback.
Previous feedback (if any):
{feedback?}
""")
.model("gemini-2.5-flash")
.outputKey("generated_code")
.build();
var codeReviewer = LlmAgent.builder()
.name("code-reviewer")
.description("Reviews code and decides if it's complete or needs more work.")
.instruction("""
Your role is to act as a senior code reviewer.
Analyze the provided Python code for correctness, style, and potential bugs.
Code to review:
{generated_code}
If the code is perfect and meets the user's request,
you MUST call the `exit_loop` tool.
Otherwise, provide constructive feedback for the `code-generator to improve the code.
""")
.model("gemini-2.5-flash")
.outputKey("feedback")
.tools(ExitLoopTool.INSTANCE)
.build();
var codeRefinerLoop = LoopAgent.builder()
.name("code-refiner-loop")
.description("Iteratively generates and reviews code until it is correct.")
.subAgents(
codeGenerator,
codeReviewer
)
.maxIterations(3) // Safety net to prevent infinite loops
.build();
var finalPresenter = LlmAgent.builder()
.name("final-presenter")
.description("Presents the final, accepted code to the user.")
.instruction("""
The code has been successfully generated and reviewed.
Present the final version of the code to the user in a clear format.
Final Code:
{generated_code}
""")
.model("gemini-2.5-flash")
.build();
AdkWebServer.start(SequentialAgent.builder()
.name("code-refiner-assistant")
.description("Manages the full code generation and refinement process.")
.subAgents(
codeRefinerLoop,
finalPresenter)
.build());
}
}
Uruchom tego agenta za pomocą tego polecenia:
mvn compile exec:java -Dexec.mainClass=com.example.agent.CodeRefiner
Możesz poprosić o wykonanie złożonych działań, takich jak Tower of Hanoi lub Quicksort Algorithm.
Pętle opinii i ulepszania, zaimplementowane za pomocą funkcji LoopAgent, są niezbędne do rozwiązywania problemów, które wymagają iteracyjnego ulepszania i samokorekty, co ściśle naśladuje ludzkie procesy poznawcze. Ten wzorzec projektowy jest szczególnie przydatny w przypadku zadań, w których początkowe dane wyjściowe rzadko są idealne, takich jak generowanie kodu, pisanie kreatywne, iteracja projektu czy złożona analiza danych. Dzięki przekazywaniu wygenerowanych treści do specjalnego agenta weryfikującego, który przekazuje strukturalne opinie, agent generujący może stale ulepszać swoją pracę, aż do spełnienia określonego kryterium ukończenia. Prowadzi to do znacznie wyższej jakości i bardziej wiarygodnych wyników końcowych niż w przypadku podejścia jednoprzebiegowego.
11. Gratulacje!

Udało Ci się utworzyć i wypróbować różne modele AI, od prostych agentów konwersacyjnych po złożone systemy wieloagentowe. Poznałeś(-aś) podstawowe koncepcje ADK for Java: definiowanie agentów za pomocą instrukcji, udostępnianie im narzędzi i organizowanie ich w zaawansowane przepływy pracy.
Co dalej?
- Zapoznaj się z oficjalnym repozytorium GitHub pakietu ADK dla Javy.
- Więcej informacji o tym frameworku znajdziesz w jego dokumentacji.
- Więcej informacji o różnych przepływach pracy opartych na agentach znajdziesz w tej serii artykułów na blogu, a o różnych dostępnych narzędziach – w tym artykule.
- Poznaj inne wbudowane narzędzia i zaawansowane wywołania zwrotne.
- Obsługuj kontekst, stan i artefakty, aby uzyskać bogatsze i multimodalne interakcje.
- Wdrażaj i stosuj wtyczki, które są zintegrowane z cyklem życia Twoich agentów.
- Spróbuj utworzyć własnego agenta, który rozwiązuje rzeczywisty problem.