Créer des agents d'IA avec l'Agent Development Kit (ADK) pour Java

1. Bienvenue aux développeurs d'agents d'IA !

Dans cet atelier de programmation, vous allez apprendre à créer des agents d'IA en Java à l'aide de l'ADK (Agents Development Kit) pour Java. Nous allons au-delà des simples appels d'API de grands modèles de langage (LLM) pour créer des agents d'IA autonomes capables de raisonner, de planifier, d'utiliser des outils et de travailler ensemble pour résoudre des problèmes complexes.

Vous commencerez par utiliser les crédits Google Cloud, configurer votre environnement Google Cloud, puis créer votre premier agent simple et ajouter progressivement des fonctionnalités plus avancées telles que des outils personnalisés, la recherche sur le Web et l'orchestration multi-agents.

d666c455bb267688.png

Points abordés

  • Découvrez comment créer un agent d'IA de base axé sur les personas.
  • Découvrez comment donner aux agents les moyens d'agir grâce à des outils personnalisés et intégrés (comme la recherche Google).
  • Ajouter vos propres outils implémentés en Java
  • Orchestrer plusieurs agents dans des workflows séquentiels, parallèles et en boucle efficaces.

Prérequis

  • Un navigateur Web que nous utiliserons en mode navigation privée.
  • Un compte Gmail personnel.
  • Un nouveau projet Google Cloud associé à votre compte Gmail personnel.
  • Un compte de facturation créé avec les crédits Google Cloud utilisés.
  • L'outil de ligne de commande Git pour extraire le code source.
  • Java 17 ou version ultérieure et Apache Maven.
  • Un éditeur de texte ou un IDE, tel qu'IntelliJ IDEA ou VS Code.

Vous pouvez utiliser l'éditeur VS Code intégré à Cloud Shell dans la console Google Cloud.

2. Configuration : votre environnement

Demander des crédits Google Cloud pour l'atelier

e3e67ae61e86ec9f.png

Pour un atelier avec instructeur, vous avez reçu un lien vers le site Web où vous pouvez demander des crédits Google Cloud à utiliser pour l'atelier.

  • Utilisez un compte Google personnel : il est important d'utiliser un compte Google personnel (comme une adresse gmail.com), car les adresses e-mail professionnelles ou scolaires ne fonctionneront pas.
  • Utilisez Google Chrome en mode navigation privée : nous vous recommandons cette méthode pour créer une session propre et éviter les conflits avec d'autres comptes Google.
  • Utilisez le lien spécial de l'événement : vous devez utiliser un lien spécial pour l'événement, qui ressemble à https://trygcp.dev/event/xxx, suivi d'un code d'événement (ici "xxx" dans cet exemple).
  • Acceptez les conditions d'utilisation : après vous être connecté, vous serez invité à accepter les conditions d'utilisation de Google Cloud Platform pour continuer.
  • Créez un projet : un projet vide doit être créé à partir de la console Google Cloud.
  • Associer un compte de facturation : associez le projet nouvellement créé à un compte de facturation.
  • Confirmer le crédit : la vidéo suivante montre comment vérifier que le crédit est appliqué au projet en consultant la section "Crédits" sur la page de facturation.

N'hésitez pas à regarder cette vidéo pour savoir comment utiliser les avoirs.

Créer et configurer votre clé API

Pour authentifier vos agents d'IA ADK avec l'API Gemini pour cet atelier de programmation, vous utiliserez une clé API associée à votre projet Google Cloud.

  1. Générez une clé API :
  • Accédez à Google AI Studio, puis cliquez sur le lien "Obtenir une clé API" en bas du panneau latéral de gauche.
  • Sélectionnez Projets, puis cliquez sur le bouton Importer des projets.
  • Recherchez et sélectionnez le projet Google Cloud que vous souhaitez importer, puis cliquez sur le bouton Importer.
  • Une fois le projet importé, accédez à la page Clés API depuis le menu "Tableau de bord", puis créez une clé API dans le projet que vous venez d'importer.
  • Notez la clé API.
  1. Définissez la variable d'environnement : votre agent doit accéder à cette clé. La méthode standard consiste à définir une variable d'environnement nommée GOOGLE_API_KEY.
  • macOS / Linux : ouvrez votre terminal et exécutez la commande suivante, en remplaçant "your-api-key" par la clé que vous venez de copier. Pour que ce paramètre soit permanent, ajoutez cette ligne au fichier de démarrage de votre shell (par exemple, ~/.bash_profile, ~/.zshrc).
export GOOGLE_API_KEY="your-api-key"
  • Windows (invite de commande) : ouvrez une nouvelle invite de commande et exécutez la commande suivante :
setx GOOGLE_API_KEY "your-api-key"
  • Vous devrez redémarrer l'invite de commande pour que cette modification prenne effet.
  • Windows (PowerShell) : ouvrez un terminal PowerShell et exécutez la commande suivante :
$env:GOOGLE_API_KEY="your-api-key"
  • Pour que cette modification soit permanente dans PowerShell, vous devez l'ajouter à votre script de profil.

3. Premiers pas : votre premier agent

f814ab5b7614e071.png

Le meilleur moyen de démarrer un nouveau projet est d'utiliser le modèle GitHub de l'ADK pour Java. Il fournit la structure du projet et toutes les dépendances nécessaires.

Si vous disposez d'un compte GitHub, vous pouvez procéder comme suit : Use this template > Create a new repository, puis extraire le code en local avec la commande git clone.

Voici une capture d'écran du menu en haut à droite permettant d'utiliser le modèle.

1613a3d0ddc66dc5.png

L'autre approche consiste à cloner simplement ce dépôt directement, avec :

git clone https://github.com/glaforge/adk-java-maven-template.git

Ensuite, cd dans adk-java-maven-template.

Pour vérifier que vous êtes prêt à commencer à coder votre premier agent d'IA en Java, assurez-vous de pouvoir compiler le code de ce projet avec :

mvn compile

Étape de code : un agent de professeur de sciences sympathique

Le bloc de construction fondamental de l'ADK est la classe LlmAgent. Il s'agit d'une IA dotée d'une personnalité et d'un objectif spécifiques, optimisée par un grand modèle de langage. Nous ajouterons d'autres fonctionnalités par le biais d'outils et nous le rendrons plus puissant en collaborant étroitement avec d'autres agents similaires.

Nous allons créer une classe Java dans le package com.example.agent et l'appeler ScienceTeacher.

C'est le "Hello, World!" de la création d'agents. Nous définissons un agent simple avec le persona d'un professeur de sciences.

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

L'agent d'IA est configuré via la méthode LlmAgent.builder(). Les paramètres name(), description() et model() sont obligatoires. Pour donner une personnalité spécifique et un comportement approprié à votre agent, vous devez toujours fournir des instructions détaillées via la méthode instruction().

Ici, nous avons choisi d'utiliser le modèle Gemini 2.5 Flash, mais n'hésitez pas à essayer Gemini 2.5 Pro pour les tâches plus complexes.

Cet agent est encapsulé dans la méthode AdkWebServer.start(). Il s'agit de l'interface de chat ADK Dev UI. Il vous permet de discuter avec l'agent via une interface de chat classique. De plus, il est très utile si vous souhaitez comprendre ce qui se passe en arrière-plan, comme tous les événements qui transitent par le système, les requêtes et les réponses envoyées au LLM.

Pour compiler et exécuter cet agent en local, exécutez la commande suivante :

mvn compile exec:java -Dexec.mainClass=com.example.agent.ScienceTeacher

Accédez ensuite à votre navigateur à l'adresse http://localhost:8080. L'UI devrait s'afficher comme dans la capture d'écran ci-dessous. Posez des questions scientifiques à votre agent.

da094da276ba15d6.png

4. Équiper les agents d'outils

cd5c5798a0861a1c.png

Pourquoi les agents ont-ils besoin d'outils ? Les LLM sont puissants, mais leurs connaissances sont figées dans le temps et ils ne peuvent pas interagir avec le monde extérieur. Les outils sont le pont. Ils permettent à un agent d'accéder à des informations en temps réel (comme les cours boursiers ou les actualités), d'interroger des API privées ou d'effectuer toute action que vous pouvez coder en Java.

Étape de code : Créer un outil personnalisé (StockTicker)

Ici, nous fournissons à notre agent un outil pour rechercher les cours des actions. L'agent estime que lorsqu'un utilisateur demande un prix, il doit appeler notre méthode 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)
    }
}

Pour rendre les agents plus intelligents et leur permettre d'interagir avec le monde (ou avec votre propre code, vos API, vos services, etc.), vous pouvez configurer l'agent pour qu'il utilise des outils, et en particulier des outils de code personnalisé, via la méthode tools(), en lui transmettant un FunctionTool.create(...).

FunctionTool a besoin d'un nom de classe et de méthode pointant vers votre propre méthode statique. Il est également possible de transmettre une instance d'une classe et le nom d'une méthode d'instance de cet objet.

Il est important de spécifier les name et description de la méthode et de ses paramètres via l'annotation @Schema, car ces informations seront utilisées par le LLM sous-jacent pour déterminer quand et comment appeler une méthode donnée.

Il est tout aussi important d'aider le LLM en lui fournissant des instructions claires sur la façon et le moment d'utiliser l'outil. Le modèle peut être en mesure de le comprendre par lui-même, mais si vous fournissez des explications explicites dans la méthode instruction(), votre fonction a plus de chances d'être appelée de manière appropriée.

Cette méthode doit renvoyer un Map. L'idée est généralement de renvoyer une carte avec une clé représentant le résultat, comme stock_price, et d'y associer la valeur du cours de l'action. Vous pouvez ensuite ajouter une paire clé/valeur "success"/"true" pour indiquer que l'opération a réussi. En cas d'erreur, vous devez renvoyer une carte avec une clé appelée, par exemple, error, et associer le message d'erreur à la valeur associée. Cela aide le LLM à comprendre si l'appel a réussi ou échoué pour une raison quelconque.

  • En cas de réussite, renvoie : {"stock_price": 123}
  • En cas d'erreur, renvoie : {"error": "Impossible to retrieve stock price for XYZ"}

Exécutez ensuite cette classe avec la commande suivante :

mvn compile exec:java -Dexec.mainClass=com.example.agent.StockTicker

5. Toute la puissance de la recherche Google pour obtenir des informations à jour

ae215e7b7cde02ab.png

Le SDK ADK pour Java est fourni avec un certain nombre d'outils puissants, dont GoogleSearchTool. Grâce à cet outil, votre agent peut demander à utiliser la recherche Google pour trouver les informations pertinentes qui lui permettront d'atteindre son objectif.

En effet, les connaissances d'un LLM sont figées dans le temps : il a été entraîné jusqu'à une certaine date (la "date limite") avec des données qui sont également à jour au moment où les informations ont été collectées. Cela signifie que les LLM ne connaissent pas forcément les événements récents, ou que leurs connaissances peuvent être limitées et superficielles. L'aide d'un moteur de recherche peut leur rafraîchir la mémoire ou leur en apprendre davantage sur le sujet.

Prenons l'exemple de cet agent de recherche d'actualités simple :

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

Notez que nous avons transmis une instance de l'outil de recherche avec : tools(new GoogleSearchTool()). C'est ce qui permet à notre agent de se tenir au courant des dernières informations disponibles sur le Web. Le prompt spécifiait également la date du jour, car cela peut aider le LLM à comprendre quand les questions portent sur des informations passées et quand il est nécessaire de rechercher des informations plus récentes.

Exécutez ensuite cette classe avec la commande suivante :

mvn compile exec:java -Dexec.mainClass=com.example.agent.LatestNews

N'hésitez pas à jouer avec la requête pour demander des résultats différents en termes de style, de concision, de focus, etc.

Étape de code : l'agent de recherche en tant qu'outil

Au lieu de transmettre GoogleSearchTool directement à un agent en tant qu'outil, vous pouvez créer un agent de recherche dédié qui encapsule la fonctionnalité de recherche et expose cet agent en tant qu'outil à un agent de niveau supérieur.

Il s'agit d'un concept avancé qui vous permet de déléguer des comportements complexes (comme la recherche et la synthèse des résultats) à un sous-agent spécialisé. Cette approche est souvent utile pour les workflows plus complexes, car les outils intégrés ne peuvent pas être utilisés avec des outils personnalisés basés sur du code.

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

La ligne AgentTool.create(searchAgent) est le concept clé ici. Il enregistre l'intégralité de searchAgent (avec sa propre logique interne, son propre prompt et ses propres outils) en tant qu'outil appelable unique pour mainAgent. Cela favorise la modularité et la réutilisabilité.

Exécutez cette classe avec la commande suivante :

mvn compile exec:java -Dexec.mainClass=com.example.agent.SearchAgentAsTool

Pour les questions banales, l'agent répondra à partir de sa propre base de connaissances. En revanche, lorsqu'il sera interrogé sur des événements récents, il délèguera la recherche à l'agent de recherche spécialisé à l'aide de l'outil de recherche Google.

6. Maîtriser les workflows agentifs

Pour les problèmes complexes, un seul agent ne suffit pas. Les LLM ont du mal à gérer les objectifs qui comportent trop de sous-tâches, les requêtes trop longues et détaillées, ou l'accès à un trop grand nombre de fonctions. Leurs performances et leur précision s'en trouvent dégradées.

La clé est de diviser pour mieux régner en orchestrant plusieurs agents spécialisés. Heureusement, ADK est fourni avec différents agents spécialisés intégrés :

  • Agent normal avec subAgent() pour déléguer des tâches,
  • SequentialAgent, pour effectuer des tâches dans un ordre précis ;
  • ParallelAgent pour exécuter les agents en parallèle.
  • LoopAgent, généralement pour effectuer le processus d'affinage autant de fois que nécessaire.

Pour connaître les principaux cas d'utilisation, ainsi que les avantages et les inconvénients de chaque workflow, consultez le tableau ci-dessous. Mais sachez que la véritable puissance proviendra en fait de la combinaison de plusieurs d'entre eux.

Workflow

Classe ADK

Cas d'utilisation

Avantages

Inconvénients

Sous-agents

LlmAgent

Tâches flexibles et axées sur l'utilisateur, dont l'étape suivante n'est pas toujours connue.

Très flexible, conversationnel, idéal pour les robots destinés aux utilisateurs.

Moins prévisible, repose sur le raisonnement du LLM pour le contrôle du flux.

Séquentielle

SequentialAgent

Processus fixes en plusieurs étapes où l'ordre est essentiel.

Prévisibles, fiables, faciles à déboguer, garantissent l'ordre.

Peut être plus lent si les tâches pouvaient être parallélisées.

Parallèle

ParallelAgent

Recueillir des données provenant de plusieurs sources ou exécuter des tâches indépendantes.

Très efficace, il réduit considérablement la latence pour les tâches liées aux E/S.

Toutes les tâches sont exécutées, sans court-circuit. Moins adapté aux tâches avec dépendances.

Boucle

LoopAgent

Affinement itératif, auto-correction ou processus qui se répètent jusqu'à ce qu'une condition soit remplie.

Puissant pour résoudre des problèmes complexes, il permet aux agents d'améliorer leur propre travail.

Peut entraîner des boucles infinies si elle n'est pas conçue avec soin (utilisez toujours maxIterations !).

7. Workflows agentifs : délégation avec des sous-agents

3b3074b840f57c1c.png

Un agent superviseur peut déléguer des tâches spécifiques à des sous-agents. Par exemple, imaginez l'agent d'un site Web d'e-commerce qui déléguerait les questions liées aux commandes à un agent ("Quel est l'état de ma commande ?") et les questions liées au service après-vente à un autre agent ("Je ne sais pas comment l'allumer !"). C'est le cas d'utilisation que nous allons aborder.

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

La ligne clé ici est celle où la méthode subAgents() est appelée, en transmettant les deux sous-agents dont le rôle spécifique sera géré séparément par chacun d'eux.

Exécutez l'exemple ci-dessus avec la commande suivante :

mvn compile exec:java -Dexec.mainClass=com.example.agent.SupportAgent

Ce concept de délégation de tâches à des sous-agents reflète une gestion humaine efficace, où un bon responsable (l'agent superviseur) s'appuie sur des employés spécialisés (les sous-agents) pour gérer des tâches spécifiques pour lesquelles ils ont une plus grande expertise. Le superviseur n'a pas besoin de connaître les détails de chaque processus. Il a plutôt pour rôle de rediriger intelligemment la demande d'un client (par exemple, une demande concernant une commande ou un problème technique) vers le "membre de l'équipe" le plus qualifié. Il garantit ainsi une réponse plus efficace et de meilleure qualité qu'un généraliste pourrait fournir seul. De plus, ces sous-agents peuvent se concentrer pleinement sur leurs tâches individuelles sans avoir besoin de comprendre l'ensemble du processus complexe.

8. Workflows agentifs : la chaîne de montage

108f8601cd36b559.png

Lorsque l'ordre des opérations est important, utilisez un SequentialAgent. Il s'agit d'une chaîne d'assemblage qui exécute les sous-agents dans un ordre fixe, où chaque étape peut dépendre de la précédente.

Imaginons qu'un poète anglophone collabore avec un traducteur anglais-français pour créer des poèmes d'abord en anglais, puis les traduire en français :

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

Exécutez l'exemple pour obtenir un poème en anglais, puis traduit en français, avec la commande suivante :

mvn compile exec:java -Dexec.mainClass=com.example.agent.PoetAndTranslator

Cette décomposition systématique des tâches complexes en sous-tâches plus petites et ordonnées garantit un processus plus déterministe et fiable, ce qui augmente considérablement la probabilité de réussite par rapport à l'utilisation d'un seul agent à usage général.

Décomposer efficacement une tâche en une séquence de sous-tâches (lorsque cela est possible et pertinent) est essentiel pour obtenir des résultats plus déterministes et plus efficaces, car cela permet une progression structurée et une gestion des dépendances entre les étapes.

9. Workflows agentifs : travailler en parallèle

4ba95f71e0189ae7.png

Lorsque les tâches sont indépendantes, un ParallelAgent permet d'améliorer considérablement l'efficacité en les exécutant simultanément. Dans l'exemple suivant, nous allons même combiner un SequentialAgent avec un ParallelAgent : les tâches parallèles s'exécutent en premier, puis un agent final résume le résultat des tâches parallèles.

Nous allons créer un détective d'entreprise dont le rôle sera de rechercher des informations sur :

  • Profil de l'entreprise (PDG, siège social, devise, etc.)
  • Les dernières actualités de l'entreprise.
  • Informations sur les finances de l'entreprise.
// 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());
    }
}

Comme d'habitude, vous pouvez exécuter l'agent avec la commande suivante :

mvn compile exec:java -Dexec.mainClass=com.example.agent.CompanyDetective

Cet agent démontre une combinaison puissante de workflows, avec des agents parallèles et séquentiels mis à profit de manière efficace grâce à la parallélisation de la recherche et de la synthèse d'informations.

10. Workflows agentifs : affinement itératif

ea37b0ab05aa5b28.png

Pour les tâches nécessitant un cycle "générer → examiner → affiner", utilisez un LoopAgent. Elle automatise l'amélioration itérative jusqu'à ce qu'un objectif soit atteint. Comme pour SequentialAgent, LoopAgent appellera les sous-agents de manière séquentielle, mais il reviendra au début. C'est le LLM utilisé en interne par l'agent qui décidera de demander ou non l'appel à un outil spécial, l'outil intégré exit_loop, pour arrêter l'exécution de la boucle.

L'exemple de raffineur de code ci-dessous, utilisant un LoopAgent, automatise le raffinement du code : générer, examiner, corriger. Cela imite le développement humain. Un générateur de code génère d'abord le code demandé et l'enregistre dans l'état de l'agent sous la clé generated_code. Un réviseur de code examine ensuite le code généré et fournit des commentaires (sous la clé feedback) ou appelle un outil de boucle de sortie pour mettre fin à l'itération plus tôt.

Examinons le code :

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

Exécutez cet agent à l'aide de la commande suivante :

mvn compile exec:java -Dexec.mainClass=com.example.agent.CodeRefiner

Les boucles de feedback/d'affinage, implémentées à l'aide de LoopAgent, sont indispensables pour résoudre les problèmes qui nécessitent une amélioration itérative et une auto-correction, imitant de près les processus cognitifs humains. Ce modèle de conception est particulièrement utile pour les tâches où le résultat initial est rarement parfait, comme la génération de code, l'écriture créative, l'itération de conception ou l'analyse de données complexes. En faisant passer la sortie par un agent d'examen spécialisé qui fournit des commentaires structurés, l'agent de génération peut affiner continuellement son travail jusqu'à ce qu'un critère d'achèvement prédéfini soit rempli. Cela permet d'obtenir des résultats finaux de qualité nettement supérieure et plus fiables qu'une approche en une seule passe.

11. Félicitations !

337a2e319008d004.png

Vous avez créé et exploré différents agents d'IA, allant de simples agents conversationnels à des systèmes multi-agents complexes. Vous avez découvert les concepts de base de l'ADK pour Java : définir des agents avec des instructions, leur donner des outils et les orchestrer dans des workflows puissants.

Étape suivante

  • Explorez le dépôt GitHub officiel de l'ADK pour Java.
  • Pour en savoir plus sur le framework, consultez sa documentation.
  • Découvrez les différents workflows agentiques dans cette série de blogs et les différents outils disponibles.
  • Découvrez plus en détail les autres outils intégrés et les rappels avancés.
  • Gérez le contexte, l'état et les artefacts pour des interactions plus riches et multimodales.
  • Implémentez et appliquez des plug-ins qui se connectent au cycle de vie de vos agents.
  • Essayez de créer votre propre agent qui résout un problème concret.