Crea agenti di AI con Agent Development Kit (ADK) per Java

1. Benvenuti, sviluppatori di agenti di AI.

In questo codelab imparerai a creare agenti di AI in Java utilizzando l'Agent Development Kit (ADK) per Java. Andremo oltre le semplici chiamate API del modello linguistico di grandi dimensioni (LLM) per creare agenti AI autonomi in grado di ragionare, pianificare, utilizzare strumenti e collaborare per risolvere problemi complessi.

Inizierai riscattando i crediti Google Cloud, configurando l'ambiente Google Cloud, creando il tuo primo agente semplice e aggiungendo progressivamente funzionalità più avanzate come strumenti personalizzati, ricerca web e orchestrazione multi-agente.

d666c455bb267688.png

Obiettivi didattici

  • Come creare un agente AI di base basato su una persona.
  • Come potenziare gli agenti con strumenti personalizzati e integrati (come la Ricerca Google).
  • Come aggiungere i tuoi strumenti implementati in Java.
  • Come orchestrare più agenti in workflow sequenziali, paralleli e di loop efficaci.

Che cosa ti serve

  • Un browser web che utilizzeremo in modalità di navigazione in incognito.
  • Un account Gmail personale.
  • Un nuovo progetto Google Cloud associato al tuo account Gmail personale.
  • Un account di fatturazione creato con i crediti Google Cloud riscattati.
  • Lo strumento a riga di comando Git per estrarre il codice sorgente.
  • Java 17+ e Apache Maven.
  • Un editor di testo o un IDE, come IntelliJ IDEA o VS Code.

È possibile utilizzare l'editor VS Code integrato in Cloud Shell, nella console Google Cloud.

2. Configurazione: il tuo ambiente

Richiesta dei crediti Google Cloud per il workshop

e3e67ae61e86ec9f.png

Per un workshop guidato da un istruttore, avrai ricevuto un link al sito web in cui puoi richiedere i crediti Google Cloud da utilizzare per il workshop.

  • Utilizza un Account Google personale: è importante utilizzare un Account Google personale (ad esempio un indirizzo gmail.com) in quanto gli indirizzi email aziendali o scolastici non funzionano.
  • Utilizza Google Chrome in modalità di navigazione in incognito: questa operazione è consigliata per creare una sessione pulita ed evitare conflitti con altri Account Google.
  • Utilizza il link all'evento speciale: deve essere utilizzato un link speciale per l'evento, simile a https://trygcp.dev/event/xxx seguito da un codice evento (in questo esempio "xxx").
  • Accetta i termini di servizio: dopo aver eseguito l'accesso, ti verranno presentati i Termini di servizio di Google Cloud Platform, che devi accettare per continuare.
  • Crea un nuovo progetto: un nuovo progetto vuoto deve essere creato dalla console Google Cloud.
  • Collega un account di fatturazione: collega il progetto appena creato a un account di fatturazione.
  • Conferma del credito: il seguente video mostra come verificare che il credito sia stato applicato al progetto controllando la sezione "Crediti" nella pagina di fatturazione.

Guarda questo video per scoprire come riscattare e applicare i crediti.

Creare e configurare la chiave API

Per autenticare gli agenti AI dell'ADK con l'API Gemini per questo codelab, utilizzerai una chiave API associata al tuo progetto Google Cloud.

  1. Genera una chiave API:
  • Vai a Google AI Studio e fai clic sul link "Ottieni chiave API" in fondo al riquadro laterale sinistro.
  • Seleziona Progetti e poi fai clic sul pulsante Importa progetti.
  • Cerca e seleziona il progetto Google Cloud che vuoi importare, poi seleziona il pulsante Importa.
  • Una volta importato il progetto, vai alla pagina Chiavi API dal menu della dashboard e crea una chiave API nel progetto che hai appena importato.
  • Prendi nota della chiave API.
  1. Imposta la variabile di ambiente:il tuo agente deve accedere a questa chiave. Il modo standard è impostare una variabile di ambiente denominata GOOGLE_API_KEY.
  • macOS / Linux: apri il terminale ed esegui questo comando, sostituendo "your-api-key" con la chiave che hai appena copiato. Per rendere questa modifica permanente, aggiungi questa riga al file di avvio della shell (ad es. ~/.bash_profile, ~/.zshrc).
export GOOGLE_API_KEY="your-api-key"
  • Windows (prompt dei comandi): apri un nuovo prompt dei comandi ed esegui:
setx GOOGLE_API_KEY "your-api-key"
  • Per applicare questa modifica, dovrai riavviare il prompt dei comandi.
  • Windows (PowerShell): apri un terminale PowerShell ed esegui:
$env:GOOGLE_API_KEY="your-api-key"
  • Per rendere permanente questa modifica in PowerShell, devi aggiungerla allo script del profilo.

3. Guida introduttiva: il tuo primo agente

f814ab5b7614e071.png

Il modo migliore per iniziare un nuovo progetto è utilizzare il modello GitHub dell'ADK per Java. Fornisce la struttura del progetto e tutte le dipendenze necessarie.

Se hai un account GitHub, puoi procedere nel seguente modo: Use this template > Create a new repository, quindi estrai il codice in locale con il comando git clone.

Ecco uno screenshot che mostra il menu in alto a destra per l'utilizzo del modello.

1613a3d0ddc66dc5.png

L'altro approccio consiste semplicemente nel clonare direttamente il repository con:

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

Poi cd in adk-java-maven-template.

Per verificare di essere pronto per iniziare a programmare il tuo primo agente AI in Java, assicurati di poter compilare il codice in questo progetto con:

mvn compile

Passaggio di codice: un agente insegnante di scienze amichevole

Il componente di base fondamentale in ADK è la classe LlmAgent. Consideralo un'AI con una personalità e un obiettivo specifici, basata su un modello linguistico di grandi dimensioni. In seguito aggiungeremo altre funzionalità tramite gli strumenti e lo renderemo più potente collaborando a stretto contatto con altri agenti simili.

Creiamo una nuova classe Java nel pacchetto com.example.agent e chiamiamola ScienceTeacher.

Si tratta della "Hello, World!" della creazione di agenti. Stiamo definendo un agente semplice con la personalità di un insegnante di scienze.

// 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'agente AI viene configurato tramite il metodo LlmAgent.builder(). I parametri name(), description() e model() sono obbligatori e, per dare una personalità specifica e un comportamento adeguato al tuo agente, devi sempre fornire indicazioni dettagliate tramite il metodo instruction().

Qui abbiamo scelto di utilizzare il modello Gemini 2.5 Flash, ma puoi provare anche Gemini 2.5 Pro per attività più complicate.

Questo agente è incluso nel metodo AdkWebServer.start(). Si tratta della cosiddetta interfaccia di chat ADK Dev UI. Ti consente di conversare con l'agente tramite una tipica interfaccia di chat. Inoltre, è molto utile se vuoi capire cosa succede sotto il cofano, ad esempio tutti gli eventi che scorrono nel sistema, le richieste e le risposte inviate al modello LLM.

Per compilare ed eseguire questo agente localmente, esegui questo comando:

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

Poi vai al browser all'indirizzo http://localhost:8080. Dovresti visualizzare l'interfaccia utente come mostrato nello screenshot di seguito. Fai pure domande di carattere scientifico al tuo agente.

da094da276ba15d6.png

4. Potenziare gli agenti con gli strumenti

cd5c5798a0861a1c.png

Perché gli agenti hanno bisogno di strumenti? Gli LLM sono potenti, ma le loro conoscenze sono congelate nel tempo e non possono interagire con il mondo esterno. Gli strumenti sono il ponte. Consentono a un agente di accedere a informazioni in tempo reale (come prezzi delle azioni o notizie), eseguire query su API private o eseguire qualsiasi azione che puoi codificare in Java.

Passaggio di codice: creazione di uno strumento personalizzato (StockTicker)

Qui forniamo al nostro agente uno strumento per cercare i prezzi delle azioni. L'agente ritiene che quando un utente chiede un prezzo, debba chiamare il nostro metodo 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)
    }
}

Per rendere gli agenti più intelligenti e dare loro la possibilità di interagire con il mondo (o con il tuo codice, le tue API, i tuoi servizi e così via), puoi configurare l'agente in modo che utilizzi strumenti, in particolare strumenti di codice personalizzato, tramite il metodo tools(), passandogli un FunctionTool.create(...).

FunctionTool ha bisogno di un nome di classe e di un nome di metodo che rimandino al tuo metodo statico. È anche possibile passare un'istanza di una classe e il nome di un metodo di istanza di quell'oggetto.

È importante specificare name e description sia del metodo sia dei relativi parametri tramite l'annotazione @Schema, poiché queste informazioni verranno utilizzate dall'LLM sottostante per capire quando e come chiamare un determinato metodo.

Altrettanto importante, è meglio aiutare il modello LLM con istruzioni chiare su come e quando utilizzare lo strumento. Il modello potrebbe essere in grado di capirlo da solo, ma se fornisci spiegazioni esplicite nel metodo instruction(), la tua funzione ha maggiori probabilità di essere chiamata in modo appropriato.

Questo metodo dovrebbe restituire un Map. In genere, l'idea è di restituire una mappa con una chiave che rappresenta il risultato, ad esempio stock_price, e associarvi il valore del prezzo delle azioni. Infine, puoi aggiungere una coppia chiave-valore di esito positivo / true per segnalare l'esito positivo dell'operazione. In caso di errore, devi restituire una mappa con una chiave chiamata, ad esempio, error e associare il messaggio di errore nel valore associato. In questo modo, il LLM può capire se la chiamata è andata a buon fine o se non è riuscita per qualche motivo.

  • In caso di esito positivo, restituisci: {"stock_price": 123}
  • In caso di errore, restituisci: {"error": "Impossible to retrieve stock price for XYZ"}

Quindi esegui questa classe con il comando seguente:

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

5. La potenza della Ricerca Google per informazioni aggiornate

ae215e7b7cde02ab.png

L'ADK per Java include una serie di strumenti potenti, tra cui GoogleSearchTool. Con questo strumento, l'agente può richiedere l'utilizzo della Ricerca Google per trovare informazioni pertinenti per raggiungere il suo obiettivo.

Infatti, le conoscenze di un LLM sono congelate nel tempo: è stato addestrato fino a una certa data (la "data limite") con dati aggiornati al momento della raccolta. Ciò significa che gli LLM potrebbero non essere a conoscenza di eventi recenti o le loro conoscenze potrebbero essere limitate e superficiali. L'aiuto di un motore di ricerca potrebbe rinfrescare la loro memoria o insegnare loro di più sull'argomento.

Diamo un'occhiata a questo semplice agente di ricerca di notizie:

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

Nota come abbiamo passato un'istanza dello strumento di ricerca con: tools(new GoogleSearchTool()). È questo che consente al nostro agente di aggiornarsi con le ultime informazioni disponibili sul web. Inoltre, il prompt specificava la data del giorno, in quanto potrebbe aiutare l'LLM a capire quando le domande riguardano informazioni passate e quando è necessaria la ricerca di informazioni più recenti.

Quindi esegui questa classe con il comando seguente:

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

Puoi sperimentare con il prompt per chiedere risultati diversi in termini di stile, concisione o focus e così via.

Passaggio di codice: l'agente di ricerca come strumento

Anziché passare GoogleSearchTool a un agente direttamente come strumento, puoi creare un agente di ricerca dedicato che incapsula la funzionalità di ricerca ed espone questo agente come strumento a un agente di livello superiore.

Si tratta di un concetto avanzato che consente di delegare comportamenti complessi (come la ricerca e il riepilogo dei risultati) a un sub-agente specializzato. Questo approccio è spesso utile per i flussi di lavoro più complessi, poiché gli strumenti integrati non possono essere utilizzati con strumenti personalizzati basati su codice.

// 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 riga AgentTool.create(searchAgent) è il concetto chiave. Registra l'intero searchAgent (con la propria logica interna, il prompt e gli strumenti) come singolo strumento richiamabile per mainAgent. Ciò promuove la modularità e la riusabilità.

Esegui questa classe con il seguente comando:

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

Per le domande banali, l'agente risponderà dalla propria knowledge base, ma quando gli vengono chiesti eventi recenti, delegherà la ricerca all'agente di ricerca specializzato utilizzando lo strumento Ricerca Google.

6. Padroneggiare i workflow agentici

Per problemi complessi, un singolo agente non è sufficiente. Quando viene assegnato un obiettivo composto da troppe attività secondarie, con un prompt enorme che spiega con troppi dettagli o con accesso a un numero elevato di funzioni, gli LLM hanno difficoltà e le loro prestazioni e la loro precisione peggiorano.

La chiave è dividere e conquistare orchestrando più agenti specializzati. Fortunatamente, ADK include diversi agenti specializzati integrati:

  • Agente normale con subAgent() a cui delegare le attività,
  • SequentialAgent, per svolgere le attività in sequenza,
  • ParallelAgent, per eseguire gli agenti in parallelo,
  • LoopAgent, in genere per eseguire una procedura di perfezionamento tutte le volte che è necessario.

Per conoscere i principali casi d'uso e i pro e i contro di ogni flusso di lavoro, consulta la tabella riportata di seguito. Tuttavia, tieni presente che la vera potenza deriverà dalla combinazione di più di uno.

Workflow

ADK Class

Caso d'uso

Vantaggi

Svantaggi

Sub-agenti

LlmAgent

Attività flessibili e guidate dall'utente in cui il passaggio successivo non è sempre noto.

Elevata flessibilità, conversazionale, ideale per i bot rivolti agli utenti.

Meno prevedibile, si basa sul ragionamento del LLM per il controllo del flusso.

Sequenziale

SequentialAgent

Processi fissi e in più passaggi in cui l'ordine è fondamentale.

Prevedibile, affidabile, facile da eseguire il debug, garantisce l'ordine.

In flessibile, può essere più lento se le attività possono essere parallelizzate.

Parallel

ParallelAgent

Raccolta di dati da più origini o esecuzione di attività indipendenti.

Altamente efficiente, riduce significativamente la latenza per le attività con I/O elevato.

Tutte le attività vengono eseguite, senza cortocircuiti. Meno adatta per attività con dipendenze.

Loop

LoopAgent

Raffinatezza iterativa, autocorrezione o processi che si ripetono finché non viene soddisfatta una condizione.

Potente per la risoluzione di problemi complessi, consente agli agenti di migliorare il proprio lavoro.

Se non progettato con attenzione, può portare a loop infiniti (utilizza sempre maxIterations).

7. Workflow agentici: delega con subagenti

3b3074b840f57c1c.png

Un agente supervisore può delegare attività specifiche ai subagenti. Ad esempio, immagina l'agente di un sito web di e-commerce che delega le domande relative agli ordini a un agente ("Qual è lo stato del mio ordine?") e le domande sul servizio post-vendita a un altro agente ("Non so come accenderlo!"). Questo è il caso d'uso che esamineremo.

// 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 riga chiave qui è quella in cui viene chiamato il metodo subAgents(), passando i due subagenti il cui ruolo specifico verrà gestito separatamente l'uno dall'altro.

Esegui l'esempio precedente con questo comando:

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

Questo concetto di delega delle attività ai subagenti rispecchia la gestione efficace delle risorse umane, in cui un buon manager (l'agente supervisore) si affida a dipendenti specializzati (i subagenti) per gestire attività specifiche per le quali hanno maggiore competenza. Il supervisore non ha bisogno di conoscere i dettagli di ogni processo. Al contrario, indirizza in modo intelligente la richiesta di un cliente (ad esempio una richiesta di ordine o un problema tecnico) al "membro del team" più qualificato, garantendo una risposta di qualità superiore e più efficiente rispetto a quella che un generalista potrebbe fornire da solo. Inoltre, questi subagenti possono concentrarsi completamente sui loro incarichi individuali senza dover comprendere l'intero processo complesso e generale.

8. Workflow agentici: la linea di assemblaggio

108f8601cd36b559.png

Quando l'ordine delle operazioni è importante, utilizza un SequentialAgent. È come una catena di montaggio, in cui i subagenti vengono eseguiti in un ordine fisso e ogni passaggio può dipendere da quello precedente.

Immagina che un poeta inglese collabori con un traduttore inglese-francese per creare poesie prima in inglese e poi tradurle in francese:

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

Esegui l'esempio per ottenere una poesia in inglese, poi tradotta in francese, con questo comando:

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

Questa scomposizione sistematica di attività complesse in sottoattività più piccole e ordinate garantisce un processo più deterministico e affidabile, aumentando significativamente la probabilità di un risultato positivo rispetto all'utilizzo di un singolo agente con uno scopo generico.

Decomporre in modo efficace un'attività in una sequenza di sottoattività (quando possibile e quando ha senso) è fondamentale per ottenere risultati più deterministici e di successo, in quanto consente una progressione strutturata e la gestione delle dipendenze tra i passaggi.

9. Workflow agentici: lavorare in parallelo

4ba95f71e0189ae7.png

Quando le attività sono indipendenti, un ParallelAgent offre un enorme aumento dell'efficienza eseguendole contemporaneamente. Nell'esempio seguente, combineremo persino un SequentialAgent con un ParallelAgent: le attività parallele vengono eseguite per prime, poi un agente finale riassume il risultato delle attività parallele.

Creiamo un detective aziendale il cui compito sarà quello di cercare informazioni su:

  • Il profilo dell'azienda (CEO, sede centrale, motto e così via)
  • Le ultime notizie sull'azienda.
  • Dettagli sui dati finanziari dell'azienda.
// 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());
    }
}

Come di consueto, puoi eseguire l'agente con il seguente comando:

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

Questo agente dimostra una potente combinazione di flussi di lavoro, con agenti paralleli e sequenziali utilizzati in modo efficiente grazie alla parallelizzazione della ricerca e della sintesi delle informazioni.

10. Workflow agentici: perfezionamento iterativo

ea37b0ab05aa5b28.png

Per le attività che richiedono un ciclo "genera → rivedi → perfeziona", utilizza un LoopAgent. Automatizza il miglioramento iterativo fino al raggiungimento di un obiettivo. Analogamente a SequentialAgent, LoopAgent chiamerà i subagenti in sequenza, ma tornerà all'inizio. È il modello LLM utilizzato internamente dall'agente a decidere se richiedere o meno la chiamata a uno strumento speciale, lo strumento integrato exit_loop, per interrompere l'esecuzione del ciclo.

L'esempio di perfezionamento del codice riportato di seguito, che utilizza un LoopAgent, automatizza il perfezionamento del codice: genera, rivedi, correggi. In questo modo si imita lo sviluppo umano. Un generatore di codice genera prima il codice richiesto, lo salva nello stato dell'agente nella chiave generated_code. Un revisore del codice esamina quindi il codice generato e fornisce un feedback (tasto feedback) o chiama uno strumento di ciclo di uscita per terminare l'iterazione in anticipo.

Diamo un'occhiata al codice:

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

Esegui questo agente con il seguente comando:

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

I cicli di feedback/affinamento, implementati utilizzando LoopAgent, sono indispensabili per risolvere problemi che richiedono miglioramenti iterativi e autocorreggersi, imitando da vicino i processi cognitivi umani. Questo pattern di progettazione è particolarmente utile per le attività in cui l'output iniziale è raramente perfetto, come la generazione di codice, la scrittura creativa, l'iterazione del design o l'analisi di dati complessi. Se l'output viene inviato a un agente di revisione specializzato che fornisce un feedback strutturato, l'agente di generazione può perfezionare continuamente il proprio lavoro fino a quando non viene soddisfatto un criterio di completamento predefinito, ottenendo risultati finali di qualità dimostrabilmente superiore e più affidabili rispetto a un approccio a passaggio singolo.

11. Complimenti!

337a2e319008d004.png

Hai creato ed esplorato con successo una serie di agenti AI, da semplici conversazioni a sistemi multi-agente complessi. Hai appreso i concetti di base dell'ADK per Java: definire gli agenti con le istruzioni, dotarli di strumenti e orchestrarli in flussi di lavoro efficaci.

Passaggi successivi

  • Esplora il repository GitHub dell'ADK per Java ufficiale.
  • Scopri di più sul framework nella relativa documentazione.
  • Leggi le informazioni sui vari flussi di lavoro agentici in questa serie di post del blog e sui vari strumenti disponibili.
  • Approfondisci gli altri strumenti integrati e i callback avanzati.
  • Gestisci contesto, stato e artefatti per interazioni più ricche e multimodali.
  • Implementa e applica plug-in che si integrano nel ciclo di vita dei tuoi agenti.
  • Prova a creare il tuo agente che risolva un problema reale.