1. Willkommen, KI-Agent-Entwickler!
In diesem Codelab erfahren Sie, wie Sie mit dem Agents Development Kit (ADK) für Java KI-Agents in Java erstellen. Wir werden über einfache LLM-API-Aufrufe hinausgehen und autonome KI-Agents erstellen, die komplexe Probleme logisch durchdenken, planen, Tools verwenden und zusammenarbeiten können.
Sie beginnen mit dem Einlösen des Google Cloud-Guthabens, richten Ihre Google Cloud-Umgebung ein, erstellen dann Ihren ersten einfachen Agenten und fügen nach und nach erweiterte Funktionen wie benutzerdefinierte Tools, Websuche und Multi-Agent-Orchestration hinzu.
Lerninhalte
- So erstellen Sie einen einfachen, persona-basierten KI‑Agenten.
- Wie Sie Agenten mit benutzerdefinierten und integrierten Tools (z. B. der Google Suche) unterstützen können.
- So fügen Sie Ihre eigenen in Java implementierten Tools hinzu.
- So orchestrieren Sie mehrere Agents in leistungsstarken sequenziellen, parallelen und Schleifen-Workflows.
Voraussetzungen
- Ein Webbrowser, den wir im Inkognitomodus verwenden.
- Ein privates Gmail-Konto.
- Ein neues Google Cloud-Projekt, das mit Ihrem privaten Gmail-Konto verknüpft ist.
- Ein Rechnungskonto, das mit den eingelösten Google Cloud-Guthaben erstellt wurde.
- Das Git-Befehlszeilentool zum Auschecken des Quellcodes.
- Java 17+ und Apache Maven.
- Einen Texteditor oder eine IDE wie IntelliJ IDEA oder VS Code.
Sie können den integrierten VS Code-Editor in Cloud Shell in der Google Cloud Console verwenden.
2. Einrichtung: Ihre Umgebung
Google Cloud-Guthaben für den Workshop einlösen
Für einen von einem Kursleiter geleiteten Workshop haben Sie einen Link zur Website erhalten, auf der Sie Google Cloud-Guthaben für den Workshop einlösen können.
- Privates Google-Konto verwenden: Es ist wichtig, ein privates Google-Konto (z. B. eine @gmail.com-Adresse) zu verwenden, da geschäftliche oder schulische E‑Mail-Adressen nicht funktionieren.
- Google Chrome im Inkognitomodus verwenden: Dies wird empfohlen, um eine saubere Sitzung zu erstellen und Konflikte mit anderen Google-Konten zu vermeiden.
- Sonderveranstaltungslink verwenden: Es sollte ein spezieller Link für die Veranstaltung verwendet werden, der in etwa so aussieht: https://trygcp.dev/event/xxx, gefolgt von einem Veranstaltungscode (hier „xxx“ in diesem Beispiel).
- Nutzungsbedingungen akzeptieren: Nach der Anmeldung werden Ihnen die Nutzungsbedingungen der Google Cloud Platform angezeigt, die Sie akzeptieren müssen, um fortzufahren.
- Neues Projekt erstellen: Ein neues leeres Projekt muss über die Google Cloud Console erstellt werden.
- Rechnungskonto verknüpfen: Verknüpfen Sie das neu erstellte Projekt mit einem Rechnungskonto.
- Gutschrift bestätigen: Im folgenden Video wird gezeigt, wie Sie auf der Abrechnungsseite im Bereich „Gutschriften“ prüfen können, ob die Gutschrift auf das Projekt angewendet wurde.
In diesem Video wird erklärt, wie Sie die Gutschriften einlösen und anwenden können.
API-Schlüssel erstellen und konfigurieren
Zur Authentifizierung Ihrer ADK AI-Agents bei der Gemini API für dieses Codelab verwenden Sie einen API-Schlüssel, der Ihrem Google Cloud-Projekt zugeordnet ist.
- API-Schlüssel generieren:
- Rufen Sie Google AI Studio auf und klicken Sie unten in der linken Seitenleiste auf den Link „API-Schlüssel abrufen“.
- Wählen Sie Projekte aus und klicken Sie dann auf die Schaltfläche Projekte importieren.
- Suchen Sie nach dem Google Cloud-Projekt, das Sie importieren möchten, und wählen Sie es aus. Klicken Sie dann auf die Schaltfläche Importieren.
- Nachdem das Projekt importiert wurde, rufen Sie im Dashboard-Menü die Seite API-Schlüssel auf und erstellen Sie einen API-Schlüssel in dem Projekt, das Sie gerade importiert haben.
- Notieren Sie sich den API-Schlüssel.
- Umgebungsvariable festlegen:Ihr Agent muss auf diesen Schlüssel zugreifen können. Die Standardmethode ist das Festlegen einer Umgebungsvariable namens
GOOGLE_API_KEY
.
- macOS / Linux:Öffnen Sie das Terminal und führen Sie den folgenden Befehl aus. Ersetzen Sie dabei
"your-api-key"
durch den Schlüssel, den Sie gerade kopiert haben. Wenn Sie diese Einstellung dauerhaft festlegen möchten, fügen Sie diese Zeile der Startdatei Ihrer Shell hinzu (z.B.~/.bash_profile
,~/.zshrc
).
export GOOGLE_API_KEY="your-api-key"
- Windows (Eingabeaufforderung): Öffnen Sie eine neue Eingabeaufforderung und führen Sie Folgendes aus:
setx GOOGLE_API_KEY "your-api-key"
- Sie müssen die Eingabeaufforderung neu starten, damit diese Änderung wirksam wird.
- Windows (PowerShell): Öffnen Sie ein PowerShell-Terminal und führen Sie Folgendes aus:
$env:GOOGLE_API_KEY="your-api-key"
- Damit diese Änderung in PowerShell dauerhaft ist, müssen Sie sie Ihrem Profilskript hinzufügen.
3. Erste Schritte: Ihr erster Agent
Am besten starten Sie ein neues Projekt mit der ADK for Java GitHub-Vorlage. Es enthält die Projektstruktur und alle erforderlichen Abhängigkeiten.
Wenn Sie ein GitHub-Konto haben, können Sie Folgendes tun: Use this template
> Create a new repository
und dann den Code lokal mit dem Befehl git clone
auschecken.
Hier sehen Sie einen Screenshot des Menüs oben rechts, über das Sie die Vorlage verwenden können.
Alternativ können Sie das Repository auch direkt klonen:
git clone https://github.com/glaforge/adk-java-maven-template.git
Dann cd
in adk-java-maven-template
.
Prüfen Sie, ob Sie den Code in diesem Projekt mit Folgendem kompilieren können, um sicherzugehen, dass Sie mit dem Programmieren Ihres ersten KI-Agents in Java beginnen können:
mvn compile
Code-Schritt: Ein freundlicher KI-Assistent für Naturwissenschaften
Der grundlegende Baustein im ADK ist die Klasse LlmAgent
. Stellen Sie sich vor, es ist eine KI mit einer bestimmten Persönlichkeit und einem bestimmten Ziel, die auf einem Large Language Model basiert. Wir werden später weitere Funktionen über Tools hinzufügen und die Möglichkeiten durch die Zusammenarbeit mit anderen ähnlichen Agents erweitern.
Erstellen wir eine neue Java-Klasse im Paket com.example.agent
und nennen wir sie ScienceTeacher
.
Das ist die „Hello World“-Version der Agentenerstellung. Wir definieren einen einfachen Agenten mit der Persona eines Naturwissenschaftslehrers.
// 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()
);
}
}
Der KI-Agent wird über die Methode LlmAgent.builder()
konfiguriert. Die Parameter name()
, description()
und model()
sind obligatorisch. Damit Ihr Agent eine bestimmte Persönlichkeit und ein angemessenes Verhalten erhält, sollten Sie immer detaillierte Anweisungen über die Methode instruction()
geben.
Hier haben wir uns für das Modell Gemini 2.5 Flash entschieden. Sie können aber auch Gemini 2.5 Pro für komplexere Aufgaben ausprobieren.
Dieser Agent ist in der Methode AdkWebServer.start()
enthalten. Das ist die Chat-Oberfläche des sogenannten ADK Dev UI. Sie können über eine typische Chat-Oberfläche mit dem Agent interagieren. Außerdem ist es sehr hilfreich, wenn Sie verstehen möchten, was im Hintergrund passiert, z. B. alle Ereignisse, die durch das System fließen, die Anfragen und Antworten, die an das LLM gesendet werden.
Führen Sie den folgenden Befehl aus, um diesen Agenten lokal zu kompilieren und auszuführen:
mvn compile exec:java -Dexec.mainClass=com.example.agent.ScienceTeacher
Rufen Sie dann in Ihrem Browser http://localhost:8080 auf. Die Benutzeroberfläche sollte wie im Screenshot unten aussehen. Stellen Sie Ihrem Agenten wissenschaftliche Fragen.
4. Kundenservicemitarbeiter mit Tools unterstützen
Warum benötigen Kundenservicemitarbeiter Tools? LLMs sind leistungsstark, aber ihr Wissen ist auf den Zeitpunkt ihres Trainings beschränkt und sie können nicht mit der Außenwelt interagieren. Tools sind die Brücke. Damit kann ein KI-Agent auf Echtzeitinformationen (z. B. Aktienkurse oder Nachrichten) zugreifen, private APIs abfragen oder beliebige Aktionen ausführen, die Sie in Java codieren können.
Code-Schritt: Benutzerdefiniertes Tool erstellen (StockTicker
)
Hier geben wir unserem Agent ein Tool, mit dem er Aktienkurse nachschlagen kann. Der Agent geht davon aus, dass unsere Java-Methode aufgerufen werden sollte, wenn ein Nutzer nach einem Preis fragt.
// 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)
}
}
Damit Agents intelligenter werden und mit der Welt (oder mit Ihrem eigenen Code, APIs, Diensten usw.) interagieren können, können Sie den Agenten so konfigurieren, dass er Tools und insbesondere benutzerdefinierte Code-Tools über die Methode tools()
verwendet. Dazu übergeben Sie ihm ein FunctionTool.create(...)
.
Für FunctionTool
sind ein Klassen- und ein Methodenname erforderlich, die auf Ihre eigene statische Methode verweisen. Es ist auch möglich, eine Instanz einer Klasse und den Namen einer Instanzmethode dieses Objekts zu übergeben.
Es ist wichtig, die name
und description
sowohl der Methode als auch ihrer Parameter über die Annotation @Schema
anzugeben, da diese Informationen vom zugrunde liegenden LLM verwendet werden, um zu ermitteln, wann und wie eine bestimmte Methode aufgerufen werden soll.
Ebenso wichtig ist es, dem LLM klare Anweisungen dazu zu geben, wie und wann das Tool verwendet werden soll. Das Modell kann es möglicherweise selbst herausfinden, aber wenn Sie in der Methode instruction()
explizite Erklärungen angeben, wird Ihre Funktion mit höherer Wahrscheinlichkeit richtig aufgerufen.
Diese Methode sollte eine Map
zurückgeben. Normalerweise wird eine Map mit einem Schlüssel zurückgegeben, der das Ergebnis darstellt, z. B. stock_price
, und der Wert des Aktienkurses wird damit verknüpft. Schließlich können Sie ein zusätzliches Schlüssel/Wert-Paar für „success“ / „true“ hinzufügen, um den Erfolg des Vorgangs zu signalisieren. Im Fehlerfall sollten Sie eine Zuordnung mit einem Schlüssel zurückgeben, der beispielsweise error
heißt, und die Fehlermeldung im zugehörigen Wert angeben. So kann das LLM nachvollziehen, ob der Aufruf erfolgreich war oder aus irgendeinem Grund fehlgeschlagen ist.
- Bei Erfolg wird Folgendes zurückgegeben:
{"stock_price": 123}
- Bei Fehler zurückgeben:
{"error": "Impossible to retrieve stock price for XYZ"}
Führen Sie dann diese Klasse mit dem folgenden Befehl aus:
mvn compile exec:java -Dexec.mainClass=com.example.agent.StockTicker
5. Das Potenzial der Google Suche für aktuelle Informationen
Das ADK für Java enthält eine Reihe leistungsstarker Tools, darunter GoogleSearchTool
. Mit diesem Tool kann Ihr Agent die Google Suche nutzen, um relevante Informationen zu finden, die für das Erreichen des Ziels erforderlich sind.
Das Wissen eines LLM ist in der Tat auf einen bestimmten Zeitpunkt begrenzt: Es wurde bis zu einem bestimmten Datum (dem „Stichtag“) mit Daten trainiert, die auch so aktuell sind, wie zum Zeitpunkt der Erfassung der Informationen. Das bedeutet, dass LLMs möglicherweise nicht über aktuelle Ereignisse Bescheid wissen oder ihr Wissen begrenzt und oberflächlich ist. Eine Suchmaschine kann ihnen helfen, ihr Wissen aufzufrischen oder mehr über das Thema zu erfahren.
Sehen wir uns diesen einfachen Agent für die Nachrichtensuche an:
// 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());
}
}
Beachten Sie, dass wir eine Instanz des Suchtools mit tools(new GoogleSearchTool())
übergeben haben. So kann unser Agent auf die neuesten Informationen zugreifen, die im Web zu finden sind. Außerdem wurde im Prompt das aktuelle Datum angegeben, da dies dem LLM helfen kann, zu verstehen, wann es sich bei Fragen um vergangene Informationen handelt und wann neuere Informationen gesucht werden müssen.
Führen Sie dann diese Klasse mit dem folgenden Befehl aus:
mvn compile exec:java -Dexec.mainClass=com.example.agent.LatestNews
Sie können den Prompt anpassen, um unterschiedliche Ergebnisse in Bezug auf Stil, Prägnanz oder Fokus zu erhalten.
Code-Schritt: Der Search Agent als Tool
Anstatt die GoogleSearchTool
direkt als Tool an einen Agent zu übergeben, können Sie einen dedizierten Such-Agent erstellen, der die Suchfunktion kapselt, und diesen Agent als Tool für einen Agent auf höherer Ebene verfügbar machen.
Dies ist ein fortgeschrittenes Konzept, mit dem Sie komplexe Verhaltensweisen (z. B. Suchen und Zusammenfassen der Ergebnisse) an einen spezialisierten untergeordneten Agenten delegieren können. Dieser Ansatz ist oft für komplexere Workflows nützlich, da integrierte Tools nicht mit benutzerdefinierten codebasierten Tools verwendet werden können.
// 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()
);
}
}
Die Zeile AgentTool.create(searchAgent)
ist hier das Schlüsselkonzept. Es registriert das gesamte searchAgent
(mit eigener interner Logik, eigenem Prompt und eigenen Tools) als einzelnes aufrufbares Tool für das mainAgent
. Das fördert die Modularität und Wiederverwendbarkeit.
Führen Sie diese Klasse mit dem folgenden Befehl aus:
mvn compile exec:java -Dexec.mainClass=com.example.agent.SearchAgentAsTool
Bei alltäglichen Fragen antwortet der Agent aus seiner eigenen Wissensdatenbank. Wenn er jedoch nach aktuellen Ereignissen gefragt wird, delegiert er die Suche mithilfe des Google-Suchtools an den spezialisierten Such-Agenten.
6. Agentische Workflows meistern
Bei komplexen Problemen reicht ein einzelner Kundenservicemitarbeiter nicht aus. Wenn LLMs ein Ziel erhalten, das aus zu vielen untergeordneten Aufgaben besteht, mit einem riesigen Prompt, der zu viele Details enthält, oder mit Zugriff auf eine große Anzahl von Funktionen, haben sie Schwierigkeiten und ihre Leistung und Genauigkeit sinken.
Der Schlüssel liegt darin, zu teilen und zu erobern, indem mehrere spezialisierte KI-Agenten orchestriert werden. Glücklicherweise enthält das ADK verschiedene integrierte spezialisierte Agents:
- Normaler Agent mit
subAgent()
zum Delegieren von Aufgaben, SequentialAgent
, um Aufgaben in einer bestimmten Reihenfolge zu erledigen,ParallelAgent
, um Agents parallel auszuführen,LoopAgent
, in der Regel, um den Verfeinerungsprozess so oft wie nötig zu durchlaufen.
Die wichtigsten Anwendungsfälle sowie die Vor- und Nachteile der einzelnen Workflows finden Sie in der Tabelle unten. Die wahre Stärke liegt aber in der Kombination mehrerer dieser Tools.
Workflow | ADK-Klasse | Anwendungsfall | Vorteile | Nachteile |
Sub-Agents |
| Nutzergesteuerte, flexible Aufgaben, bei denen der nächste Schritt nicht immer bekannt ist. | Hohe Flexibilität, dialogorientiert, ideal für nutzerorientierte Bots. | Weniger vorhersagbar, da die Ablaufsteuerung auf der Logik des LLM basiert. |
Sequenziell |
| Feste, mehrstufige Prozesse, bei denen die Reihenfolge entscheidend ist. | Vorhersehbar, zuverlässig, einfach zu debuggen, garantiert die Reihenfolge. | Unflexibel, kann langsamer sein, wenn Aufgaben parallelisiert werden könnten. |
Parallel |
| Daten aus mehreren Quellen erheben oder unabhängige Aufgaben ausführen | Hocheffizient, reduziert die Latenz für E/A-gebundene Aufgaben erheblich. | Alle Aufgaben werden ausgeführt. Weniger geeignet für Aufgaben mit Abhängigkeiten. |
Schleife |
| Iterative Verfeinerung, Selbstkorrektur oder Prozesse, die sich wiederholen, bis eine Bedingung erfüllt ist. | Leistungsstark für die Lösung komplexer Probleme, ermöglicht es Kundenservicemitarbeitern, ihre eigene Arbeit zu verbessern. | Kann zu Endlosschleifen führen, wenn sie nicht sorgfältig konzipiert wird (immer maxIterations verwenden!). |
7. Agentische Workflows – Delegation mit untergeordneten Agenten
Ein Supervisor-Agent kann bestimmte Aufgaben an Sub-Agents delegieren. Stellen Sie sich beispielsweise den Kundenservice einer E-Commerce-Website vor, der Fragen zu Bestellungen an einen Kundenservicemitarbeiter („Was ist der Status meiner Bestellung?“) und Fragen zum Kundenservice nach dem Kauf an einen anderen Kundenservicemitarbeiter („Ich weiß nicht, wie ich das Gerät einschalte!“) weiterleitet. Diesen Anwendungsfall werden wir uns genauer ansehen.
// 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 topicSearchAgent = 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 socialMediaAgent = 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 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(socialMediaAgent, topicSearchAgent)
.build()
);
}
}
Die entscheidende Zeile ist hier der Aufruf der Methode subAgents()
, bei dem die beiden untergeordneten Agents übergeben werden, deren spezifische Rolle jeweils separat behandelt wird.
Führen Sie das obige Beispiel mit dem folgenden Befehl aus:
mvn compile exec:java -Dexec.mainClass=com.example.agent.SupportAgent
Dieses Konzept, Aufgaben an untergeordnete Agents zu delegieren, spiegelt eine effektive menschliche Führung wider. Ein guter Manager (der Supervisor-Agent) verlässt sich auf spezialisierte Mitarbeiter (die untergeordneten Agents), um bestimmte Aufgaben zu erledigen, für die sie mehr Fachwissen haben. Der Supervisor muss nicht die Details jedes Prozesses kennen. Stattdessen leitet er die Anfrage eines Kunden (z. B. eine Bestellanfrage oder ein technisches Problem) intelligent an das am besten geeignete „Teammitglied“ weiter. So wird eine qualitativ hochwertigere und effizientere Antwort ermöglicht, als ein Generalist allein geben könnte. Außerdem können sich diese untergeordneten Agents voll und ganz auf ihre individuellen Aufgaben konzentrieren, ohne den gesamten komplexen übergeordneten Prozess verstehen zu müssen.
8. Agentische Workflows – Die Fertigungsstraße
Wenn die Reihenfolge der Operationen wichtig ist, verwenden Sie ein SequentialAgent
. Es ist wie ein Fließband, auf dem untergeordnete Agents in einer festen Reihenfolge ausgeführt werden, wobei jeder Schritt vom vorherigen abhängen kann.
Stellen wir uns vor, ein englischer Dichter arbeitet mit einem Englisch-Französisch-Übersetzer zusammen, um Gedichte zuerst auf Englisch zu verfassen und dann ins Französische zu übersetzen:
// 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());
}
}
Führen Sie das Beispiel mit dem folgenden Befehl aus, um ein Gedicht auf Englisch zu erhalten, das dann ins Französische übersetzt wird:
mvn compile exec:java -Dexec.mainClass=com.example.agent.PoetAndTranslator
Durch diese systematische Zerlegung komplexer Aufgaben in kleinere, geordnete Teilaufgaben wird ein deterministischer und zuverlässigerer Prozess gewährleistet, wodurch die Wahrscheinlichkeit eines erfolgreichen Ergebnisses im Vergleich zu einem einzelnen, breit gefächerten Agenten deutlich erhöht wird.
Eine Aufgabe effektiv in eine Reihe von untergeordneten Aufgaben zu zerlegen (wenn möglich und sinnvoll), ist entscheidend für deterministischere und erfolgreichere Ergebnisse, da dies eine strukturierte Entwicklung und Abhängigkeitsverwaltung zwischen den Schritten ermöglicht.
9. Agentische Workflows – Parallel arbeiten
Wenn Aufgaben unabhängig voneinander sind, kann durch die gleichzeitige Ausführung ein ParallelAgent
erzielt werden. Im folgenden Beispiel kombinieren wir sogar eine SequentialAgent
mit einer ParallelAgent
: Die parallelen Aufgaben werden zuerst ausgeführt und dann fasst ein letzter Agent das Ergebnis der parallelen Aufgaben zusammen.
Wir erstellen einen Unternehmensdetektiv, der nach Informationen zu Folgendem suchen soll:
- Das Profil des Unternehmens (CEO, Hauptsitz, Motto usw.)
- Die neuesten Nachrichten zum Unternehmen.
- Details zu den Finanzdaten des Unternehmens.
// 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());
}
}
Wie gewohnt können Sie den Agent mit dem folgenden Befehl ausführen:
mvn compile exec:java -Dexec.mainClass=com.example.agent.CompanyDetective
Dieser Agent demonstriert eine leistungsstarke Kombination aus Workflows, bei der sowohl parallele als auch sequenzielle Agents effizient eingesetzt werden, da die Informationsrecherche und ‑synthese parallelisiert werden.
10. Agentische Workflows – Iterative Optimierung
Verwenden Sie für Aufgaben, die einen Zyklus aus „generieren → überprüfen → optimieren“ erfordern, ein LoopAgent
. Der Prozess wird automatisiert, bis ein Ziel erreicht ist. Ähnlich wie bei SequentialAgent
werden die untergeordneten Agents bei LoopAgent
seriell aufgerufen, aber es wird zum Anfang zurückgekehrt. Das LLM, das intern vom KI-Agenten verwendet wird, entscheidet, ob der Aufruf eines speziellen Tools, des integrierten Tools exit_loop
, angefordert werden soll, um die Ausführung der Schleife zu beenden.
Im folgenden Beispiel für die Code-Optimierung wird ein LoopAgent
verwendet, um die Code-Optimierung zu automatisieren: generieren, überprüfen, korrigieren. Das ähnelt der menschlichen Entwicklung. Ein Codegenerator generiert zuerst den angeforderten Code und speichert ihn im Agentenstatus unter dem Schlüssel generated_code
. Ein Code-Reviewer überprüft dann den generierten Code und gibt entweder Feedback (unter dem feedback
-Schlüssel) oder ruft ein Tool zum Beenden der Schleife auf, um die Iteration vorzeitig zu beenden.
Sehen wir uns den Code an:
// 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());
}
}
Führen Sie diesen Agent mit dem folgenden Befehl aus:
mvn compile exec:java -Dexec.mainClass=com.example.agent.CodeRefiner
Feedback-/Optimierungsschleifen, die mit LoopAgent
implementiert werden, sind unerlässlich, um Probleme zu lösen, die iterative Verbesserungen und Selbstkorrekturen erfordern. Sie ahmen kognitive Prozesse des Menschen nach. Dieses Designmuster ist besonders nützlich für Aufgaben, bei denen die ursprüngliche Ausgabe selten perfekt ist, z. B. bei der Codeerstellung, beim kreativen Schreiben, bei Designiterationen oder bei komplexen Datenanalysen. Indem die Ausgabe durch einen spezialisierten Prüfungs-Agenten geleitet wird, der strukturiertes Feedback gibt, kann der generierende Agent seine Arbeit kontinuierlich optimieren, bis ein vordefiniertes Abschlusskriterium erfüllt ist. Dies führt zu einer nachweislich höheren Qualität und zuverlässigeren Endergebnissen als bei einem Single-Pass-Ansatz.
11. Glückwunsch!
Sie haben erfolgreich eine Vielzahl von KI-Agenten erstellt und kennengelernt, von einfachen Gesprächspartnern bis hin zu komplexen Multi-Agent-Systemen. Sie haben die wichtigsten Konzepte des ADK für Java kennengelernt: Agents mit Anweisungen definieren, sie mit Tools ausstatten und in leistungsstarke Workflows einbinden.
Nächste Schritte
- Offizielles GitHub-Repository für das ADK für Java
- Weitere Informationen zum Framework finden Sie in der Dokumentation.
- In dieser Blogreihe finden Sie Informationen zu den verschiedenen agentenbasierten Workflows und zu den verschiedenen verfügbaren Tools.
- Weitere Informationen zu den anderen integrierten Tools und erweiterten Callbacks
- Kontext, Status und Artefakte verarbeiten, um umfassendere und multimodale Interaktionen zu ermöglichen.
- Implementieren und wenden Sie Plug-ins an, die in den Lebenszyklus Ihrer Agents eingebunden werden.
- Erstellen Sie einen eigenen Agenten, der ein reales Problem löst.