← Retour au blog
Analyse

Gemini 3.8 Live : comment un Agent vocal temps réel transforme-t-il une phrase en appel d'outil JSON ?

Publié le 22/09/2026 Dernière mise à jour le 22/09/2026 Environ 14 min JSON Toolbox

Comment lire cet article

La fiche modèle officielle marque gemini-3.8-live comme option par défaut pour un Agent vocal à faible latence ; la dernière mise à jour date de septembre 2026. La page outils Live a été mise à jour le 15/09/2026. Article daté du 22/09/2026 : on suit le cercle audio vers session → toolCall → exécution locale → FunctionResponse → audio à nouveau. Le tutoriel pas à pas pour extraire args reste dans la file suivante. Ce n'est pas l'API de transcription : Gemini 3.5 Transcribe ; pourquoi la couche contrat reste un objet : Pourquoi l'IA aime JSON.

L'utilisateur dit « allume la lumière du salon ». Le modèle entend un flux audio ; quand il tend la main, il donne encore name, id et un objet args. L'API Live n'exécute pas à votre place, et ne renvoie rien automatiquement. Si le client oublie id, ou envoie un nom de pièce mal reconnu à l'exécuteur, l'audio continue de dire « d'accord » — l'effet de bord a déjà eu lieu. Comme pour un Agent texte hébergé : la boucle peut être rapide, le contrat doit pouvoir refuser. Comment refermer côté texte : Pourquoi l'Agents API a encore plus besoin de JSON.

Ce que 3.8 Live publie vraiment

Au 22/09/2026, la chaîne modèle stable est gemini-3.8-live. En migrant depuis gemini-3.1-flash-live-preview, la documentation demande de changer le nom de modèle et de retirer thinking_level / thinking_config. L'entrée peut être texte, image, audio, vidéo ; la sortie est texte et audio. Contexte 131 072 / 65 536 tokens.

Les frontières utiles pour cet article, à figer :

  • Function calling : pris en charge. Par défaut behavior: NON_BLOCKING. BLOCKING reste disponible pour les anciens clients.
  • Structured outputs : non pris en charge. Ne configurez pas une session Live comme le mode réponse JSON de generateContent.
  • Search grounding : pris en charge. Peut cohabiter avec les déclarations function dans le même tableau tools.
  • Exécution de code / File search / Maps / URL context : non pris en charge.
  • Forme de réponse : audio. Pour du texte visible, ouvrez à part la transcription de sortie. L'audio proactif (proactive audio) est activé en permanence ; le couper lève une erreur. L'interrupteur de dialogue émotionnel a été retiré de l'API.

Il existe aussi une variante gemini-3.8-live-extended-thinking : raisonnement de fond plus lourd, Function Calling uniquement asynchrone ; poser BLOCKING lève une erreur dure. Le chemin faible latence par défaut est 3.8 Live : ne mélangez pas les deux comportements.

En une phrase. 3.8 Live accélère la boucle vocale. Le contrat d'outil n'est pas hébergé avec. L'exécution automatique n'existe pas.

De la voix à l'outil : cinq sauts

La page outils Live officielle dit net la responsabilité client : déclarer les fonctions dans la config de session ; à la réception d'un toolCall, renvoyer un ensemble de FunctionResponse via session.send_tool_response. Contrairement à generateContent, pas de tool response automatique.

Gemini 3.8 Live : de la voix à l'exécution d'outil L'audio entre en session Live ; le modèle émet toolCall ; le client valide args contre le Schema, exécute, puis send_tool_response ; la session continue en audio. Audio L'utilisateur parle Session Live gemini-3.8-live toolCall name / id / args Schema avant exécution Retour + audio
La voix ne fait que déclencher. Ce qui entre vraiment dans l'exécuteur, c'est l'objet déjà parsé dans toolCall.
  1. Ouvrir la session. client.aio.live.connect(model="gemini-3.8-live", config=...). Dans la config : response_modalities: ["AUDIO"] et tools.
  2. Envoyer le contenu. Audio temps réel, ou send_client_content. 3.8 permet de mettre à jour le contenu client tout au long de la session ; turn_complete=true interrompt la réponse en cours de génération.
  3. Recevoir response.tool_call. Parcourir function_calls, lire name, id, args. Un prompt peut émettre plusieurs appels, en parallèle ou en chaîne.
  4. Vous exécutez en local. D'abord valider args contre le Schema déclaré, puis lancer la fonction. En échec, renvoyer un objet d'erreur — ne « faites pas au mieux ».
  5. send_tool_response. Chaque entrée porte le même id / name ; response est un objet JSON. La session continue à produire de l'audio 24 kHz.

C'est la même forme que required_actions → tool_result d'un Agent texte, l'enveloppe en moins : des événements Live. En regard : Agents API vs MCP.

Sans Structured Output, pourquoi le Schema compte encore plus

La fiche modèle dit clairement que Live ne prend pas en charge Structured outputs. La phrase finale « la lumière est allumée » est de l'audio, pas un objet que vous pourriez figer avec text.format. On en conclut trop vite : « Live n'a pas de contrat JSON ». L'erreur est de couche :

  • Structured Output contraint la réponse finale.
  • Function Calling contraint les arguments d'outil.

La voix rend la seconde couche plus dangereuse. Un lapsus, un accent, un nom de pièce entendu comme une autre valeur d'enum : le modèle peut encore émettre un args d'apparence légale. Sans Schema de réponse pour rattraper, la validation des paramètres avant exécution est la seule porte dure. Définition : Qu'est-ce que la Structured Output — là-bas, c'est la réponse ; ici, c'est la main tendue.

L'API de transcription a un autre JSON WordInfo : ne le mélangez pas avec toolCall.args. Frontière : 3.5 Transcribe.

Asynchrone par défaut : NON_BLOCKING et scheduling

Le Function Calling de 3.1 Flash Live Preview n'était que synchrone : sans retour, le modèle ne continuait pas à parler. 3.8 Live pose l'asynchrone par défaut. Avec behavior: NON_BLOCKING, l'outil tourne et l'utilisateur peut encore parler. S'il faut « d'abord chercher, ensuite ouvrir la bouche », ajoutez BLOCKING à cette déclaration.

Au retour asynchrone, scheduling dit au modèle comment utiliser ce résultat :

  • INTERRUPT : couper la parole en cours, dire le résultat tout de suite.
  • WHEN_IDLE : attendre la fin du segment actuel.
  • SILENT : noter d'abord, utiliser plus tard.

L'exemple de la documentation place scheduling dans FunctionResponse.response, à côté de result. C'est un indice d'ordonnancement, pas un champ métier. L'objet métier doit encore se refermer tout seul : ne laissez pas scheduling fuiter dans votre exécuteur.

Comment déclarer les fonctions en session

La déclaration va dans config.tools de la session. L'exemple officiel minimal n'a que name. En production, ajoutez au moins description et parameters. Les types, à la manière Gemini, s'écrivent souvent en majuscules OBJECT / STRING :

{
  "functionDeclarations": [
    {
      "name": "set_light",
      "description": "Set one allowlisted room light. Use when the user asks to turn a light on or off.",
      "behavior": "NON_BLOCKING",
      "parameters": {
        "type": "OBJECT",
        "properties": {
          "room": {
            "type": "STRING",
            "enum": ["living_room", "kitchen", "bedroom"],
            "description": "Allowlisted room id. Do not invent rooms."
          },
          "on": { "type": "BOOLEAN" }
        },
        "required": ["room", "on"]
      }
    }
  ]
}

La même config peut encore porter {"google_search": {}}. La recherche passe par la plateforme ; set_light, c'est encore vous qui l'exécutez. N'écrivez pas un outil trop large « n'importe quelle pièce, n'importe quelle commande ». La forme des permissions est la même qu'un Agent texte : limiter les permissions d'outils avec un Schema.

Un toolCall recettable en local

Ci-dessous, le contrôle de lumière de la documentation, ramené à « appel en attente + retour ». D'abord comme objet cœur, sans envelopper le SDK.

{
  "toolCall": {
    "functionCalls": [
      {
        "id": "call_light_01",
        "name": "set_light",
        "args": {
          "room": "living_room",
          "on": true
        }
      }
    ]
  },
  "functionResponse": {
    "id": "call_light_01",
    "name": "set_light",
    "response": {
      "result": {
        "room": "living_room",
        "on": true,
        "applied": true
      },
      "scheduling": "INTERRUPT"
    }
  }
}

Le contrat d'entrée referme les pièces en enum. « Hall », « séjour-salle à manger » : ça ne correspond pas, on refuse, on renvoie une erreur dicible — on ne devine pas :

{
  "$schema": "https://json-schema.org/draft/2020-12/schema",
  "type": "object",
  "additionalProperties": false,
  "required": ["room", "on"],
  "properties": {
    "room": {
      "type": "string",
      "enum": ["living_room", "kitchen", "bedroom"]
    },
    "on": { "type": "boolean" }
  }
}

En regard, des formes qui doivent échouer : room écrit garage ; un extra_cmd en trop ; on écrit "开". Ces objets doivent échouer dès l'espace de travail. Dériver depuis un exemple : Comment générer un Schema. Comment extraire args d'un événement : le tutoriel pas à pas est dans la file suivante.

Recetter dans JSON Toolbox

  1. Coller args et response.result dans le formatage JSON, confirmer que ça parse.
  2. Avec JSON → Schema, générer le contrat cœur, compléter enum, required et additionalProperties.
  3. Les mêmes champs via Function Calling ; pour réutiliser sur d'autres Hosts, envelopper encore dans MCP Tool.
  4. Préparer des objets qui doivent échouer, confirmer le refus dans la validation Schema. Pour aligner une forme de réponse, Structured Output — souvenez-vous : la session Live elle-même n'avale pas ce contrat de réponse.

Tout est traité dans le navigateur, rien n'est envoyé. D'abord un objet capable de refuser un mauvais args, ensuite seulement accrocher la fonction à la session Live.

FAQ

Gemini 3.8 Live prend-il en charge Structured Output ?

La fiche modèle dit non. La réponse finale est de l'audio. Ce que vous pouvez figer, c'est le Schema des paramètres de fonction, et la validation de args avant exécution.

L'API Live exécute-t-elle les outils automatiquement ?

Non. Il faut traiter toolCall soi-même, puis send_tool_response. Chaque retour recopie id et name.

Comment choisir entre NON_BLOCKING et BLOCKING ?

Asynchrone par défaut : l'appel peut continuer. Il faut attendre le résultat avant de parler : BLOCKING. Au retour : INTERRUPT / WHEN_IDLE / SILENT. La variante extended-thinking n'autorise que l'asynchrone.

Une fois la voix en session, les arguments d'outil restent-ils du JSON ?

Oui. Le modèle entend de l'audio ; quand il tend la main, il donne encore un objet. La voix est plus instable : valider d'abord, exécuter ensuite.

Est-ce la même chose que Gemini 3.5 Transcribe ?

Non. Transcribe sort du WordInfo ; Live sort de l'audio bidirectionnel et un toolCall. Deux JSON, pas un seul contrat.

En résumé

Gemini 3.8 Live fait de la boucle vocale à faible latence le modèle par défaut : l'audio entre en session, l'audio sort en réponse, les outils sont asynchrones par défaut. Il n'a pas repris le droit d'exécuter, ni donné un Structured Output à la réponse finale. Ce que le développeur doit tenir, ce sont encore les functionDeclarations de la config de session, et le JSON Schema de toolCall.args avant l'exécuteur. La voix change le déclencheur, pas le contrat. La suite n'est pas d'abord d'ajouter plus d'outils de pièces, c'est d'abord un objet lumière capable de refuser garage et extra_cmd.