Accueil / Articles

API Gemini en Python : la même boucle sans état avec des rôles de modèle et des objets de chat.

Appeler Gemini depuis Python à l’aide du SDK google-genai : contenus et parties, instruction système, utilisation des tokens ainsi qu’un objet de chat qui enregistre l’historique côté client.

Éditeur : REACTAPP.TOP4 min de lecture892 mots

Sources: Part 4 — Call the Gemini API in Python (user / model, same loop)

Après OpenAI et Claude, Gemini de Google est le troisième fournisseur à suivre ce même schéma : une extrémité sans état, une conversation marquée par un rôle et l’historique complet envoyé à chaque appel. Gemini ajoute une particularité agréable dans sa nomenclature.

Changement de nom, pas de redessin

La structure des conversations de Gemini correspond à celle d’OpenAI et de Claude, à l’exception de deux changements de nom. Le rôle de l’assistant s’appelle model. Ce terme est sans doute plus honnête, car « assistant » suggère une personnalité, tandis que model indique simplement que le texte provient d’un modèle. Il occupe la même place dans la liste. L’instruction système devient system_instruction, transmise via un objet de configuration et non dans la liste des messages. Il s’agit de l’idée de Claude concernant un « système en parallèle » poussée encore plus loin.

La liste des messages est accessible via contents. Chaque tour contient des parts, car Gemini gère nativement le texte, les images et l’audio. Dans une conversation de texte brut, rien de tout cela n’apparaît : les chaînes de caractères entrent et resp.text en sort.

Avertissement concernant les bibliothèques avant tout code : Google a publié plusieurs paquets Python au fil des années, et les tutoriels plus anciens sont remplis d’imports obsolètes tels que google-generativeai ainsi que des wrappers de l’époque Bard. Le SDK officiel actuel est google-genai, importé avec from google import genai, et c’est celui qui est utilisé ici.

Mise en place et un seul tour

Installez-le avec pip install google-genai, créez une clé dans Google AI Studio et exportez-la sous le nom GEMINI_API_KEY. Le client récupère cette clé depuis l’environnement, de sorte qu’aucune clé n’apparaît jamais dans le code.

# current official SDK: pip install google-genai
from google import genai
from google.genai import types

client = genai.Client()  # key from env

resp = client.models.generate_content(
    model="gemini-2.5-flash",
    contents="Why does Gemini name the reply "
             "role 'model', not 'assistant'?",
    config=types.GenerateContentConfig(
        system_instruction="Be concise.",
        temperature=0,
    ),
)
print(resp.text)

Par rapport aux deux fournisseurs précédents, messages est désormais remplacé par contents, et une seule étape peut correspondre à une simple chaîne de caractères. L’instruction système est stockée dans GenerateContentConfig. La température redevient un champ de configuration normal, ce que l’SDK Claude actuel avait supprimé. La réponse se trouve simplement dans resp.text, tandis que le comptage des tokens est indiqué dans resp.usage_metadata sous les noms prompt_token_count et candidates_token_count, ce sont les mêmes mesures mais avec des noms propres à Google. Il faut toujours les enregistrer.

Boucle d’historique gérée

Il est possible d’importer directement sa propre fonction ask() : stockez les valeurs de user et model dans une liste, ajoutez chaque échange à cette liste et passez à nouveau contents= à chaque fois. Cela fonctionne. Cependant, le SDK offre une commodité absente par défaut des clients OpenAI et Anthropic : un objet de chat qui s’occupe de l’ajout automatique des échanges.

chat = client.chats.create(
    model="gemini-2.5-flash",
    config=types.GenerateContentConfig(
        system_instruction="Be concise.",
    ),
)

r1 = chat.send_message(
    "Define a context window."
)
print(r1.text)

r2 = chat.send_message(
    "Now for a five-year-old."
)
print(r2.text)

for turn in chat.get_history():
    part = turn.parts[0].text[:40]
    print(turn.role, "->", part)

La réponse suit dans le contexte, car l’objet de chat a réexécuté silencieusement l’échange précédent, ce que ferait une fonction manuelle. En parcourant get_history() à la fin, on observe des tours alternés entre user et model, c’est-à-dire exactement la même liste qui a été envoyée lors de la dernière demande. Rien du côté serveur ne se souvient de quoi que ce soit. L’objet de chat enregistre les saisies côté client, donc les tokens d’entrée s’accumulent à chaque tour, ce qui fait que les conversations longues coûtent plus par appel.

Une chose n’a pas changé : le service derrière le SDK ne se souvient de rien entre les demandes.

Le confort a un prix, et cela devient important plus tard avec les frameworks. Une historique gérée signifie moins de code et moins d’erreurs, jusqu’au moment où vous devez supprimer des éléments anciens, les résumer ou insérer des documents récupérés au milieu d’une conversation. C’est alors que vous voudrez retrouver la simple liste. LangChain se situe au même niveau sur cette échelle, mais un cran au-dessus. Soyez à l’aise tant avec la liste gérée manuellement que avec l’objet géré, car aucun des deux ne peut vous limiter.

Exécuter l’exemple

pip install -r requirements.txt
export GEMINI_API_KEY="AIza..."
python examples/part04_gemini.py

Le script traite successivement trois éléments : une seule interaction, la boucle de liste manuelle pour vérifier l’équivalence, et la conversation gérée avec son historique affiché. Le comptage des tokens est enregistré après chaque appel. En l’absence de clé définie, il s’arrête immédiatement avec un message explicite. Comme les appels sont en temps réel et facturés, ne l’exécutez pas dans un environnement CI.

Trois fournisseurs, une même structure

Une comparaison rapide des trois. OpenAI traite system comme un message et laisse l’historique à votre charge. Claude fait de system un paramètre distinct, exige max_tokens et laisse également l’historique à votre charge. Gemini intègre system_instruction dans la configuration, nomme l’assistant model et conserve l’historique si vous le permettez. Tous trois fonctionnent selon la même boucle sans état : envoyer toute la conversation, recevoir une réponse, l’ajouter et recommencer.

C’est pourquoi les frameworks multi-fournisseurs peuvent rester légers, et pourquoi changer de fournisseur n’a pas besoin d’être effrayant. La migration consiste en un simple mappage de noms, et non en une réécriture complète.