Créer des applications multimodales et des agents gérés personnalisés avec le SDK Java Gemini Interactions

1. Bienvenue, développeur Gemini !

Sketchnote sur les apprentissages des développeurs

Dans cet atelier de programmation, vous allez apprendre à créer des applications d'IA de nouvelle génération en Java à l'aide du SDK Gemini Interactions personnalisé.

Qu'est-ce que l'API Gemini Interactions ?

Les API LLM traditionnelles sont sans état et axées sur les requêtes-réponses. Pour créer un assistant de chat multitour ou une boucle agentique complexe, les développeurs ont toujours dû gérer l'état de la conversation, la troncature de l'historique, l'orchestration des appels d'outils et les boucles d'exécution entièrement dans le code de l'application côté client.

L'API Gemini Interactions transfère cette complexité au serveur. Il s'agit d'une API avec état basée sur une session dans laquelle l'infrastructure de Google héberge et gère le graphique de conversation. Une seule interaction représente une session avec état. Lorsque vous interagissez avec elle, l'API renvoie une chronologie riche et structurée composée d'étapes polymorphes, telles que :

  • ThoughtStep : processus de raisonnement interne du modèle.
  • ModelOutputStep : contenu texte, audio ou image généré par le modèle.
  • ToolCallStep et ToolResultStep : appels d'outils initiés par le système ou le modèle.
  • UserInteractionStep : points où le système s'interrompt pour demander une entrée ou une approbation humaine.

Que sont les agents gérés ?

L'orchestration d'agents autonomes (gestion des boucles, logique de nouvelle tentative, environnements d'exécution d'outils et gestion de l'état) est notoirement difficile.

Les agents gérés sont une solution au niveau de la plate-forme fournie par l'API Gemini Interactions. Au lieu d'exécuter des boucles d'agent localement, vous pouvez provisionner des agents spécialisés directement sur l'infrastructure de Google :

  • Agents intégrés : agents spécialisés prêts à l'emploi, tels que l'agent Deep Research , qui effectue des recherches Web en plusieurs étapes, agrège les résultats et génère des rapports complets.
  • Agents gérés personnalisés : entités autonomes que vous définissez. Vous fournissez des instructions système, associez des outils (tels que la recherche Google ou un environnement d'exécution Bash) et configurez un bac à sable cloud , un environnement d'exécution sécurisé, isolé et conteneurisé avec des règles de sortie réseau personnalisables (par exemple, autoriser l'accès uniquement à des domaines spécifiques tels que GitHub).

En utilisant le SDK Java Gemini Interactions, vous pouvez facilement amorcer, coordonner et collaborer avec ces agents gérés dans des applications Java standards.

Points abordés

  • Navigation dans la nouvelle architecture polymorphe basée sur Step.
  • Streaming audio TTS expressif directement vers les haut-parleurs.
  • Génération de musique (MP3 + paroles) avec Lyria.
  • Génération de notes visuelles avec Gemini 3 Pro Image.
  • Pilotage de l'agent Deep Research à l'aide de la planification collaborative.
  • Provisionnement d'un agent personnalisé avec des règles et des outils de sortie réseau.

Ce dont vous avez besoin

  • Java 21 ou version ultérieure
  • Apache Maven
  • Un éditeur de texte ou un IDE (IntelliJ IDEA, VS Code, etc.)
  • Une clé API Gemini (depuis Google AI Studio)

2. Configuration : projet et clé API

Créer un projet Maven

Amorcez un nouveau projet Maven à partir de votre terminal à l'aide de la commande suivante :

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

Accédez au répertoire du projet que vous venez de créer :

cd gemini-interactions-demo

Ouvrez votre fichier pom.xml et configurez-le :

  1. Mettez à jour les propriétés de la version Java pour cibler Java 21 :
    <properties>
        <maven.compiler.source>21</maven.compiler.source>
        <maven.compiler.target>21</maven.compiler.target>
    </properties>
    
  2. Ajoutez la dépendance du SDK dans le bloc :
    <dependency>
        <groupId>io.github.glaforge</groupId>
        <artifactId>gemini-interactions-api-sdk</artifactId>
        <version>0.10.1</version>
    </dependency>
    

Configurer la clé API

Obtenez une clé API Gemini depuis Google AI Studio.

Définissez la clé en tant que variable d'environnement dans votre terminal :

macOS / Linux :

export GEMINI_API_KEY="your_actual_api_key"

Windows (invite de commande) :

set GEMINI_API_KEY="your_actual_api_key"

3. Hello World : navigation dans l'architecture Step

L'API Interactions a introduit une architecture de chronologie polymorphe basée sur des étapes. Au lieu de renvoyer une liste plate de sorties, l'API renvoie une séquence d'objets Step typés (par exemple, ModelOutputStep, ThoughtStep, FunctionCallStep).

Dans cette étape, vous allez écrire une interaction simple pour comprendre comment extraire la sortie finale du modèle de cette structure.

Créer HelloInteractions.java

Créez le fichier src/main/java/com/example/HelloInteractions.java avec le contenu suivant :

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

Exécuter le Code

Compilez et exécutez la classe :

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

4. Audio pilotable : streaming TTS expressif

Gemini 3.1 Flash introduit la synthèse vocale (TTS) pilotable. Vous pouvez contrôler le rythme, le ton et l'environnement de la voix à l'aide de prompts, et utiliser des balises émotionnelles (comme [excitedly] ou [whispers]) au milieu d'une phrase.

Dans cette étape, vous allez générer un audio expressif et le diffuser directement sur vos haut-parleurs.

Créer StreamingDJ.java

Créez le fichier src/main/java/com/example/StreamingDJ.java avec le contenu suivant :

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

Exécuter le Code

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

Écouter la sortie

Voici un exemple audio de ce que vous entendrez lors de l'exécution du code (en utilisant la voix Algenib avec des balises émotionnelles) :

Écouter la sortie TTS générée (tts_output.wav)

5. Génération de musique avec Lyria 3

À l'aide du modèle DeepMind Lyria 3, vous pouvez générer de la musique et des jingles. En demandant deux modalités de réponse (AUDIO et TEXT), vous pouvez récupérer à la fois l'audio généré (MP3) et les paroles de la chanson.

Créer MusicGenerator.java

Créez le fichier src/main/java/com/example/MusicGenerator.java avec le contenu suivant :

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

Exécuter le Code

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

Écouter la chanson générée

Voici le fichier MP3 généré (coding_song.mp3) contenant la musique et les paroles :

Écouter la chanson générée (coding_song.mp3)

6. Visualisation avec des notes visuelles (Nano Banana Pro)

Gemini 3 Pro Image (également appelé Nano Banana Pro) peut générer des images. En demandant la modalité IMAGE, vous pouvez générer des infographies, des diagrammes ou des notes visuelles à partir d'une entrée de texte.

Dans cette étape, vous allez générer un résumé visuel d'un article sur les agents gérés et l'enregistrer en tant que fichier PNG.

Créer ImageGenerator.java

Créez le fichier src/main/java/com/example/ImageGenerator.java avec le contenu suivant :

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

Exécuter le Code

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

Notes visuelles générées

Voici les notes visuelles générées (sketchnote.png) créées par le modèle :

Sketchnote générée

7. Pilotage des agents : recherche approfondie collaborative

Deep Research est un agent puissant qui peut exécuter des tâches de recherche en plusieurs étapes. Toutefois, au lieu de s'exécuter immédiatement, vous pouvez utiliser la planification collaborative pour examiner, modifier et piloter le plan de recherche avant que l'agent ne commence à collecter des données.

Vous allez implémenter une conversation en plusieurs étapes qui utilise le même état côté serveur (previousInteractionId) pour affiner un plan.

Créer CollaborativeResearch.java

Créez le fichier src/main/java/com/example/CollaborativeResearch.java avec le contenu suivant :

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

Exécuter le Code

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

Sortie du rapport généré

L'agent Deep Research génère un rapport complet et structuré. Vous pouvez consulter le rapport complet généré par l'exemple d'exécution ici :

Afficher le rapport Deep Research généré (tpu_history_report.md)

8. Agents personnalisés et bacs à sable cloud

Pour les tâches de développement complexes, vous pouvez provisionner des agents personnalisés. Vous définissez leurs instructions système, les équipez d'outils (tels que l'exécution de code/Bash) et configurez leur environnement distant (par exemple, les règles de sortie réseau).

Dans cette étape, vous allez provisionner un agent qui dispose d'un accès Internet sécurisé à github.com et lui demander de cloner un dépôt et d'analyser ses fichiers de configuration dans son bac à sable cloud.

Créer GitHubAnalyzer.java

Créez le fichier src/main/java/com/example/GitHubAnalyzer.java avec le contenu suivant :

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.");
        }
    }
}

Exécuter le Code

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

Sortie de l'analyse générée

Vous pouvez consulter le rapport d'analyse architecturale complet généré par l'agent personnalisé après le clonage du dépôt ici :

Afficher la sortie de l'analyseur GitHub (github_analysis_report.md)

9. Félicitations !

Vous avez terminé cet atelier de programmation et appris à créer des workflows complexes, multimodaux et agentiques en Java à l'aide du SDK Gemini Interactions.

Ce que vous avez accompli :

  1. Navigation dans l'architecture Step : utilisation de la nouvelle architecture d'étape polymorphe pour interroger des modèles standards.
  2. Streaming TTS expressif : utilisation des notes du réalisateur et des balises émotionnelles intégrées pour diffuser de l'audio en temps réel.
  3. Génération de musique : génération de pistes MP3 et de paroles avec Lyria 3.
  4. Génération de notes visuelles : création de résumés visuels à l'aide de Gemini 3 Pro Image (Nano Banana Pro).
  5. Pilotage de Deep Research : utilisation de la planification collaborative pour affiner les plans de recherche.
  6. Provisionnement d'agents personnalisés : création d'environnements en bac à sable avec un contrôle personnalisé de la sortie réseau pour exécuter du code en toute sécurité.

En savoir plus :