Crea app multimodali e agenti gestiti personalizzati con Gemini Interactions Java SDK

1. Benvenuto, sviluppatore Gemini!

Sketchnote sugli approfondimenti per gli sviluppatori

In questo codelab imparerai a creare applicazioni AI di nuova generazione in Java utilizzando l'SDK Gemini Interactions personalizzato.

Che cos'è l'API Gemini Interactions?

Le API LLM tradizionali sono senza stato e basate su richiesta-risposta. Per creare un assistente di chat a più turni o un ciclo agentico complesso, gli sviluppatori hanno dovuto storicamente gestire lo stato della conversazione, il troncamento della cronologia, l'orchestrazione delle chiamate agli strumenti e i cicli di esecuzione interamente nel codice dell'applicazione lato client.

L'API Gemini Interactions sposta questa complessità sul server. È un'API con stato, basata su sessioni, in cui l'infrastruttura di Google ospita e gestisce il grafico della conversazione. Una singola interazione rappresenta una sessione con stato. Quando interagisci con l'API, questa restituisce una sequenza temporale ricca e strutturata composta da passaggi polimorfici, ad esempio:

  • ThoughtStep: il processo di ragionamento interno del modello.
  • ModelOutputStep: contenuti di testo, audio o immagine generati dal modello.
  • ToolCallStep e ToolResultStep: chiamate agli strumenti avviate dal sistema o dal modello.
  • UserInteractionStep: punti in cui il sistema si mette in pausa per richiedere l'input o l'approvazione dell'utente.

Che cosa sono gli agenti gestiti?

L'orchestrazione degli agenti autonomi, la gestione dei loop, la logica di ripetizione, gli ambienti di esecuzione degli strumenti e la gestione dello stato sono notoriamente difficili.

Gli agenti gestiti sono una soluzione a livello di piattaforma fornita dall'API Gemini Interactions. Anziché eseguire i loop degli agenti localmente, puoi eseguire il provisioning di agenti specializzati direttamente sull'infrastruttura di Google:

  • Agenti integrati: agenti specializzati pronti all'uso, come l'agente Deep Research, che esegue ricerche web multi-step, aggrega i risultati e genera report completi.
  • Agenti gestiti personalizzati: entità autonome che definisci tu. Fornisci istruzioni di sistema, allega strumenti (come Ricerca Google o un ambiente di esecuzione Bash) e configura una sandbox cloud , un ambiente di runtime sicuro, isolato e containerizzato con regole di uscita di rete personalizzabili (ad es. consentendo l'accesso solo a domini specifici come GitHub).

Utilizzando l'SDK Gemini Interactions Java, puoi facilmente eseguire il bootstrap, coordinare e collaborare con questi agenti gestiti nelle applicazioni Java standard.

Obiettivi didattici

  • Come navigare nella nuova architettura polimorfica basata su Step.
  • Come riprodurre in streaming audio TTS espressivo direttamente sugli speaker.
  • Come generare musica (MP3 + testi) con Lyria.
  • Come generare sketchnote visive con Gemini 3 Pro Image.
  • Come guidare l'agente Deep Research utilizzando la pianificazione collaborativa.
  • Come eseguire il provisioning di un agente personalizzato con regole di uscita di rete e strumenti.

Che cosa ti serve

  • Java 21 o versioni successive.
  • Apache Maven.
  • Un editor di testo o un IDE (IntelliJ IDEA, VS Code e così via).
  • Una chiave API Gemini (da Google AI Studio).

2. Configurazione: progetto e chiave API

Crea progetto Maven

Esegui il bootstrap di un nuovo progetto Maven dal terminale utilizzando il seguente comando:

mvn archetype:generate \
    -DgroupId=com.example \
    -DartifactId=gemini-interactions-demo \
    -DarchetypeGroupId=org.apache.maven.archetypes \
    -DarchetypeArtifactId=maven-archetype-quickstart \
    -DarchetypeVersion=1.5 \
    -DinteractiveMode=false

Vai alla directory del progetto appena creato:

cd gemini-interactions-demo

Apri il file pom.xml e configurarlo:

  1. Aggiorna le proprietà della versione Java in modo che siano destinate a Java 21:
    <properties>
        <maven.compiler.source>21</maven.compiler.source>
        <maven.compiler.target>21</maven.compiler.target>
    </properties>
    
  2. Aggiungi la dipendenza dell'SDK all'interno del blocco :
    <dependency>
        <groupId>io.github.glaforge</groupId>
        <artifactId>gemini-interactions-api-sdk</artifactId>
        <version>0.10.1</version>
    </dependency>
    

Configura chiave API

Ottieni una chiave API Gemini da Google AI Studio.

Imposta la chiave come variabile di ambiente nel terminale:

macOS / Linux:

export GEMINI_API_KEY="your_actual_api_key"

Windows (prompt dei comandi):

set GEMINI_API_KEY="your_actual_api_key"

3. Hello World: navigare nell'architettura dei passaggi

L'API Interactions ha introdotto un'architettura di sequenza temporale polimorfica basata su passaggi. Anziché restituire un elenco semplice di output, l'API restituisce una sequenza di oggetti Step tipizzati (ad es. ModelOutputStep, ThoughtStep, FunctionCallStep).

In questo passaggio scriverai una semplice interazione per capire come estrarre l'output finale del modello da questa struttura.

Crea HelloInteractions.java

Crea il file src/main/java/com/example/HelloInteractions.java con il seguente contenuto:

package com.example;

import io.github.glaforge.gemini.interactions.GeminiInteractionsClient;
import io.github.glaforge.gemini.interactions.model.*;
import io.github.glaforge.gemini.interactions.model.InteractionParams.ModelInteractionParams;

public class HelloInteractions {
    public static void main(String[] args) {
        // 1. Initialize the client
        GeminiInteractionsClient client = GeminiInteractionsClient.builder()
            .apiKey(System.getenv("GEMINI_API_KEY"))
            .build();

        // 2. Build the request
        ModelInteractionParams request = ModelInteractionParams.builder()
            .model("gemini-3.5-flash")
            .input("Explain the difference between a library and a framework in one sentence.")
            .build();

        // 3. Send request
        Interaction response = client.create(request);
        
        // 4. Navigate the step-based architecture to get the output
        response.steps().stream()
            .filter(step -> step instanceof Step.ModelOutputStep)
            .map(step -> (Step.ModelOutputStep) step)
            .findFirst()
            .ifPresent(step -> System.out.println(step.content().get(0)));
    }
}

Esegui il codice

Compila ed esegui la classe:

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

4. Audio guidabile: streaming TTS espressivo

Gemini 3.1 Flash introduce la sintesi vocale (TTS) guidabile. Puoi controllare il ritmo, il tono e l'ambiente della voce utilizzando i prompt e utilizzare tag emotivi (come [excitedly] o [whispers]) a metà frase.

In questo passaggio genererai audio espressivo e lo riprodurrai in streaming direttamente sugli speaker.

Crea StreamingDJ.java

Crea il file src/main/java/com/example/StreamingDJ.java con il seguente contenuto:

package com.example;

import io.github.glaforge.gemini.interactions.GeminiInteractionsClient;
import io.github.glaforge.gemini.interactions.model.*;
import io.github.glaforge.gemini.interactions.model.Config.SpeechConfig;
import io.github.glaforge.gemini.interactions.model.InteractionParams.ModelInteractionParams;
import javax.sound.sampled.*;
import java.util.Base64;
import java.util.stream.Stream;

public class StreamingDJ {
    public static void main(String[] args) throws Exception {
        GeminiInteractionsClient client = GeminiInteractionsClient.builder()
            .apiKey(System.getenv("GEMINI_API_KEY"))
            .build();

        // Prompt defining the voice profile and emotional tags
        String prompt = """
            # AUDIO PROFILE: Jaz R.
            ## THE SCENE: London Studio
            ### DIRECTOR'S NOTES
            Accent: Jaz is a DJ from Brixton, London.
            Style: Bouncy, energetic, high-speed delivery.
            
            #### TRANSCRIPT
            [excitedly] Yes, massive vibes in the studio! 
            [whispers] But keep it down, the boss is coming... 
            [shouting] Turn this up! Let's go!
            """;

        ModelInteractionParams request = ModelInteractionParams.builder()
            .model("gemini-3.1-flash-tts-preview")
            .input(prompt)
            .responseModalities(Interaction.Modality.AUDIO)
            .speechConfig(new SpeechConfig("Algenib", "en-GB"))
            .stream(true) // Enable streaming
            .build();

        System.out.println("Streaming audio from Gemini...");

        try (Stream<Events> eventStream = client.stream(request)) {
            // Configure the Java Audio System for 24kHz Mono 16-bit PCM
            AudioFormat format = new AudioFormat(24000, 16, 1, true, false);
            DataLine.Info info = new DataLine.Info(SourceDataLine.class, format);

            try (SourceDataLine line = (SourceDataLine) AudioSystem.getLine(info)) {
                line.open(format);
                line.start();

                // Process the stream and play audio chunks as they arrive
                eventStream.forEach(event -> {
                    if (event instanceof Events.StepDelta cd && cd.delta() instanceof Events.AudioDelta audioDelta) {
                        byte[] audioData = Base64.getDecoder().decode(audioDelta.data());
                        line.write(audioData, 0, audioData.length);
                    }
                });
                line.drain();
            }
        }
    }
}

Esegui il codice

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

Ascolta l'output

Ecco un esempio audio di ciò che sentirai quando esegui il codice (utilizzando la voce Algenib con tag emotivi):

Ascolta l'output TTS generato (tts_output.wav)

5. Generazione di musica con Lyria 3

Utilizzando il modello DeepMind Lyria 3, puoi generare musica e jingle. Se richiedi modalità di risposta duali (AUDIO e TEXT), puoi recuperare sia l'audio generato (MP3) sia i testi dei brani.

Crea MusicGenerator.java

Crea il file src/main/java/com/example/MusicGenerator.java con il seguente contenuto:

package com.example;

import io.github.glaforge.gemini.interactions.GeminiInteractionsClient;
import io.github.glaforge.gemini.interactions.model.*;
import io.github.glaforge.gemini.interactions.model.InteractionParams.ModelInteractionParams;
import io.github.glaforge.gemini.interactions.model.Content.AudioContent;
import java.nio.file.Files;
import java.nio.file.Paths;

public class MusicGenerator {
    public static void main(String[] args) throws Exception {
        GeminiInteractionsClient client = GeminiInteractionsClient.builder()
            .apiKey(System.getenv("GEMINI_API_KEY"))
            .build();

        ModelInteractionParams request = ModelInteractionParams.builder()
            .model("models/lyria-3-clip-preview") // 30-second clip
            .input("An uplifting rock song with acoustic guitars about coding in Java.")
            .responseModalities(
                Interaction.Modality.AUDIO,
                Interaction.Modality.TEXT) // Request both MP3 and Lyrics
            .build();

        System.out.println("Generating music (this might take a moment)...");
        Interaction response = client.create(request);

        // 1. Print the lyrics (TEXT output)
        System.out.println("\n--- Generated Lyrics ---");
        response.steps().stream()
            .filter(step -> step instanceof Step.ModelOutputStep)
            .flatMap(step -> ((Step.ModelOutputStep) step).content().stream())
            .filter(content -> content instanceof Content.TextContent)
            .forEach(content -> System.out.println(((Content.TextContent) content).text()));

        // 2. Save the MP3 (AUDIO output)
        response.steps().stream()
            .filter(step -> step instanceof Step.ModelOutputStep)
            .flatMap(step -> ((Step.ModelOutputStep) step).content().stream())
            .filter(content -> content instanceof AudioContent)
            .map(content -> (AudioContent) content)
            .findFirst()
            .ifPresent(audio -> {
                try {
                    Files.write(Paths.get("coding_song.mp3"), audio.data());
                    System.out.println("\nSuccess: Song saved to coding_song.mp3");
                } catch (Exception e) {
                    e.printStackTrace();
                }
            });
    }
}

Esegui il codice

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

Ascolta il brano generato

Ecco il file MP3 generato (coding_song.mp3) contenente la musica e i testi:

Ascolta il brano musicale generato (coding_song.mp3)

6. Visualizzazione con sketchnote (Nano Banana Pro)

Gemini 3 Pro Image (noto anche come Nano Banana Pro) può generare immagini. Se richiedi la modalità IMAGE, puoi generare infografiche, diagrammi o sketchnote in base all'input di testo.

In questo passaggio genererai un riepilogo di sketchnote di un articolo sugli agenti gestiti e lo salverai come file PNG.

Crea ImageGenerator.java

Crea il file src/main/java/com/example/ImageGenerator.java con il seguente contenuto:

package com.example;

import io.github.glaforge.gemini.interactions.GeminiInteractionsClient;
import io.github.glaforge.gemini.interactions.model.*;
import io.github.glaforge.gemini.interactions.model.InteractionParams.ModelInteractionParams;
import io.github.glaforge.gemini.interactions.model.Content.ImageContent;
import java.nio.file.Files;
import java.nio.file.Paths;

public class ImageGenerator {
    public static void main(String[] args) throws Exception {
        GeminiInteractionsClient client = GeminiInteractionsClient.builder()
            .apiKey(System.getenv("GEMINI_API_KEY"))
            .build();

        String articleSummary = """
            Managed Agents in the Gemini API allow developers to run autonomous agents
            that reason, plan, use tools, and execute code inside isolated cloud sandboxes.
            The Gemini API handles the infrastructure (containers, network, runtime).
            It is powered by the Antigravity agent running on Gemini 3.5 Flash.
            The Java Interactions SDK supports these capabilities, utilizing a Step-based
            architecture to model the execution timeline.
            """;

        ModelInteractionParams request = ModelInteractionParams.builder()
            .model("gemini-3-pro-image-preview")
            .input(String.format("""
                Create a hand-drawn and hand-written sketchnote
                style summary infographic, with a pure white background,
                about the following information:
                
                %s
                """, articleSummary))
            .responseModalities(Interaction.Modality.IMAGE) // Request IMAGE modality
            .build();

        System.out.println("Generating sketchnote (this might take a moment)...");
        Interaction response = client.create(request);

        // Save the generated image
        response.steps().stream()
            .filter(step -> step instanceof Step.ModelOutputStep)
            .flatMap(step -> ((Step.ModelOutputStep) step).content().stream())
            .filter(content -> content instanceof ImageContent)
            .map(content -> (ImageContent) content)
            .findFirst()
            .ifPresent(image -> {
                try {
                    Files.write(Paths.get("sketchnote.png"), image.data());
                    System.out.println("Success: Sketchnote saved to sketchnote.png");
                } catch (Exception e) {
                    e.printStackTrace();
                }
            });
    }
}

Esegui il codice

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

Sketchnote generata

Ecco la sketchnote generata (sketchnote.png) creata dal modello:

Sketchnote generato

7. Guida degli agenti: Deep Research collaborativa

Deep Research è un agente potente in grado di eseguire attività di ricerca multi-step. Tuttavia, anziché eseguire immediatamente, puoi utilizzare la pianificazione collaborativa per rivedere, modificare e guidare il piano di ricerca prima che l'agente inizi a raccogliere i dati.

Implementerai una conversazione multi-turno che utilizza lo stesso stato lato server (previousInteractionId) per perfezionare un piano.

Crea CollaborativeResearch.java

Crea il file src/main/java/com/example/CollaborativeResearch.java con il seguente contenuto:

package com.example;

import io.github.glaforge.gemini.interactions.GeminiInteractionsClient;
import io.github.glaforge.gemini.interactions.model.*;
import io.github.glaforge.gemini.interactions.model.InteractionParams.AgentInteractionParams;
import io.github.glaforge.gemini.interactions.model.Config.DeepResearchAgentConfig;
import io.github.glaforge.gemini.interactions.model.Config.ThinkingSummaries;
import io.github.glaforge.gemini.interactions.model.Config.Visualization;

public class CollaborativeResearch {
    public static void main(String[] args) throws Exception {
        GeminiInteractionsClient client = GeminiInteractionsClient.builder()
            .apiKey(System.getenv("GEMINI_API_KEY"))
            .build();

        String agentModel = "deep-research-preview-04-2026";

        // --- Phase 1: Request a Plan ---
        System.out.println("Phase 1: Requesting research plan...");
        AgentInteractionParams planParams = AgentInteractionParams.builder()
            .agent(agentModel)
            .input("Research the latest generations of Google Cloud TPUs (TPU7x and the 8th generation TPU 8t and TPU 8i).")
            .agentConfig(new DeepResearchAgentConfig(
                "deep-research", 
                ThinkingSummaries.AUTO, 
                Visualization.AUTO, 
                true // TRUE enables collaborative planning
            ))
            .background(true)
            .store(true)
            .build();

        Interaction planInteraction = client.create(planParams);
        planInteraction = waitForCompletion(client, planInteraction.id());
        
        System.out.println("\n--- Proposed Plan ---");
        printOutputText(planInteraction);

        // --- Phase 2: Refine the Plan ---
        System.out.println("\nPhase 2: Refining research plan...");
        AgentInteractionParams refineParams = AgentInteractionParams.builder()
            .agent(agentModel)
            .input("Focus on comparing the architectural, performance, and scaling differences between the TPU7x generation and the two flavors of the eighth generation: TPU 8t (optimized for training at scale) and TPU 8i (optimized for low-latency reasoning and inference).")
            .agentConfig(new DeepResearchAgentConfig(
                "deep-research", 
                ThinkingSummaries.AUTO, 
                Visualization.AUTO, 
                true // Keep collaborative planning TRUE to iterate
            ))
            .previousInteractionId(planInteraction.id()) // Resume session
            .background(true)
            .store(true)
            .build();

        Interaction refinedInteraction = client.create(refineParams);
        refinedInteraction = waitForCompletion(client, refinedInteraction.id());

        System.out.println("\n--- Refined Plan ---");
        printOutputText(refinedInteraction);

        // --- Phase 3: Approve and Execute ---
        System.out.println("\nPhase 3: Approving plan and starting deep research (this will take a few minutes)...");
        AgentInteractionParams executeParams = AgentInteractionParams.builder()
            .agent(agentModel)
            .input("Plan looks good, execute!")
            .agentConfig(new DeepResearchAgentConfig(
                "deep-research", 
                ThinkingSummaries.AUTO, 
                Visualization.AUTO, 
                false // FALSE approves the plan and executes the research
            ))
            .previousInteractionId(refinedInteraction.id()) // Resume session
            .background(true)
            .store(true)
            .build();

        Interaction finalReport = client.create(executeParams);
        finalReport = waitForCompletion(client, finalReport.id());

        System.out.println("\n--- Final Research Report ---");
        printOutputText(finalReport);
    }

    private static Interaction waitForCompletion(GeminiInteractionsClient client, String id) throws Exception {
        Interaction interaction = client.get(id);
        while (interaction.status() != Interaction.Status.COMPLETED && interaction.status() != Interaction.Status.FAILED) {
            Thread.sleep(5000);
            interaction = client.get(id);
        }
        if (interaction.status() == Interaction.Status.FAILED) {
            throw new RuntimeException("Interaction failed. Status: " + interaction.status());
        }
        return interaction;
    }

    private static void printOutputText(Interaction interaction) {
        interaction.steps().stream()
            .filter(step -> step instanceof Step.ModelOutputStep)
            .flatMap(step -> ((Step.ModelOutputStep) step).content().stream())
            .filter(content -> content instanceof Content.TextContent)
            .forEach(content -> System.out.println(((Content.TextContent) content).text()));
    }
}

Esegui il codice

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

Output del report generato

L'agente Deep Research produrrà un report completo e strutturato. Puoi visualizzare il report completo generato dall'esecuzione dell'esempio qui:

Visualizza il report Deep Research generato (tpu_history_report.md)

8. Agenti personalizzati e sandbox cloud

Per attività di sviluppo complesse, puoi eseguire il provisioning di agenti personalizzati. Definisci le istruzioni di sistema, fornisci loro strumenti (come l'esecuzione di codice/Bash) e configura il loro ambiente remoto (ad es. regole di uscita di rete).

In questo passaggio, eseguirai il provisioning di un agente che ha accesso sicuro a internet a github.com e gli chiederai di clonare un repository e analizzare i file di configurazione all'interno della sua sandbox cloud.

Crea GitHubAnalyzer.java

Crea il file src/main/java/com/example/GitHubAnalyzer.java con il seguente contenuto:

package com.example;

import io.github.glaforge.gemini.interactions.GeminiInteractionsClient;
import io.github.glaforge.gemini.interactions.model.*;
import io.github.glaforge.gemini.interactions.model.InteractionParams.AgentInteractionParams;
import java.util.List;

public class GitHubAnalyzer {
    public static void main(String[] args) throws Exception {
        GeminiInteractionsClient client = GeminiInteractionsClient.builder()
            .apiKey(System.getenv("GEMINI_API_KEY"))
            .build();

        String agentId = "github-analyzer-codelab";

        // 1. Define the Custom Agent with Network Egress and Tools
        Agent customAgent = Agent.builder()
            .id(agentId)
            .description("Clones and analyzes GitHub repos.")
            .baseAgent("antigravity-preview-05-2026")
            .baseEnvironment(new EnvironmentConfig(
                new EnvironmentNetworkEgressAllowlist(List.of(
                    new AllowlistEntry("github.com") // Allow git clone over HTTPS
                )),
                List.of()
            ))
            .systemInstruction("You are an architect. Clone the repo, inspect files, and write a summary.")
            .tools(List.of(
                new AgentTool.CodeExecution(), // Enables terminal bash execution in sandbox
                new AgentTool.GoogleSearch()
            ))
            .build();

        // 2. Provision the Agent
        System.out.println("Provisioning custom agent in the cloud...");
        client.createAgent(customAgent);

        try {
            // 3. Start the Interaction
            AgentInteractionParams params = AgentInteractionParams.builder()
                .agent(agentId)
                .input("Clone https://github.com/glaforge/gemini-interactions-api-sdk and explain its pom.xml structure.")
                .environment("remote") // Crucial: Run in cloud sandbox
                .build();

            System.out.println("Starting clone and analysis (polling status)...");
            Interaction interaction = client.create(params);

            // 4. Poll for completion
            while (interaction.status() != Interaction.Status.COMPLETED) {
                System.out.println("Agent working... Status: " + interaction.status());
                Thread.sleep(5000);
                interaction = client.get(interaction.id());
            }

            // 5. Output the results
            System.out.println("\n--- Architectural Analysis ---");
            interaction.steps().stream()
                .filter(step -> step instanceof Step.ModelOutputStep)
                .flatMap(step -> ((Step.ModelOutputStep) step).content().stream())
                .filter(content -> content instanceof Content.TextContent)
                .forEach(content -> System.out.println(((Content.TextContent) content).text()));

        } finally {
            // 6. Clean up resources
            client.deleteAgent(agentId);
            System.out.println("\nCustom agent resource deleted from cloud.");
        }
    }
}

Esegui il codice

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

Output dell'analisi generata

Puoi visualizzare il report completo di analisi dell'architettura prodotto dall'agente personalizzato dopo la clonazione del repository qui:

Visualizza l'output di GitHub Analyzer (github_analysis_report.md)

9. Complimenti!

Hai completato il codelab e hai imparato a creare workflow complessi, multimodali e agentici in Java utilizzando l'SDK Gemini Interactions.

Risultati ottenuti:

  1. Navigazione nell'architettura dei passaggi: hai utilizzato la nuova architettura dei passaggi polimorfici per eseguire query sui modelli standard.
  2. Streaming TTS espressivo: hai utilizzato le note del regista e i tag emotivi in linea per riprodurre l'audio in streaming in tempo reale.
  3. Generazione di musica: hai generato tracce MP3 e testi con Lyria 3.
  4. Generazione di sketchnote: hai creato riepiloghi visivi utilizzando Gemini 3 Pro Image (Nano Banana Pro).
  5. Guida di Deep Research: hai utilizzato la pianificazione collaborativa per perfezionare i piani di ricerca.
  6. Provisioning di agenti personalizzati: hai creato ambienti in sandbox con controllo dell'uscita di rete personalizzato per eseguire il codice in modo sicuro.

Ulteriori informazioni: