Aller au contenu principal

Préserver les mises à jour de la configuration du chat

Lors de l'utilisation de la fonctionnalité de chat de l'API Gemini, il est courant d'initialiser une session de chat avec des paramètres spécifiques tels que la temperature, max_output_tokens, system_instruction et un history initial. Un défi se pose lorsque vous souhaitez ensuite mettre à jour dynamiquement uniquement la temperature et max_output_tokens sans perdre l'system_instruction précédemment défini ou l'history de conversation accumulé.

Le principe fondamental à comprendre de la structure d'API fournie est que la configuration (_config) et l'historique (_comprehensive_history) d'un objet Chat sont définis lors de son initialisation (__init__) et ne sont pas directement modifiables via des méthodes publiques par la suite. Par conséquent, pour réaliser des mises à jour dynamiques tout en préservant tous les paramètres existants, vous devez :

  1. Récupérer l'état actuel de la session Chat existante (sa configuration et son historique).
  2. Fusionner les nouvelles valeurs de temperature et max_output_tokens avec la configuration récupérée.
  3. Recréer une nouvelle instance Chat en utilisant la configuration combinée et mise à jour, et l'historique préservé.

Composants clés

  • google.genai.Client : Le client principal pour interagir avec l'API Gemini.
  • google.genai.chats.Chat : Représente une session de chat en cours.
  • google.genai.types.GenerateContentConfig : Un modèle Pydantic (ou GenerateContentConfigDict pour une entrée de dictionnaire) qui encapsule divers paramètres de génération de modèle, y compris temperature, max_output_tokens, et system_instruction.
  • google.genai.types.Content : Représente un élément de contenu dans la conversation, utilisé à la fois pour system_instruction et history.

Guide étape par étape pour la préservation de la configuration

Supposons que vous ayez un objet chat existant qui a été créé avec une system_instruction initiale et qui a accumulé de l'history.

  1. Accéder à la configuration et à l'historique actuels :

    • La GenerateContentConfig actuelle est stockée dans l'attribut _config de l'objet Chat.
    • L'historique actuel du chat est accessible via la méthode get_history() de l'objet Chat. Il est recommandé de récupérer l'historique comprehensive (par défaut curated=False) pour s'assurer que toutes les interactions, y compris celles avec des sorties invalides, sont préservées pour le contexte.
    # À partir d'un objet chat_session existant
    current_config = chat_session._config
    current_history = chat_session.get_history(curated=False)
  2. Préparer les nouvelles valeurs de paramètres :

    • Obtenez les nouvelles temperature et max_output_tokens souhaitées de l'utilisateur ou d'une autre source.
    • Implémentez une logique pour gérer les cas où l'utilisateur ne souhaiterait pas modifier un paramètre spécifique (par exemple, autoriser une entrée vide pour conserver la valeur actuelle).
  3. Fusionner les configurations :

    • Convertissez la current_config (qui est un modèle Pydantic) en un dictionnaire mutable en utilisant .model_dump().
    • Mettez à jour ce dictionnaire avec les nouvelles valeurs de temperature et max_output_tokens. L'system_instruction existante (et tout autre champ GenerateContentConfig) sera automatiquement reportée de current_config.
    • Reconstruisez un nouvel objet types.GenerateContentConfig à partir de ce dictionnaire fusionné.
    # new_temperature et new_max_output_tokens sont obtenus de l'entrée utilisateur
    # (par exemple, None si l'utilisateur n'a pas spécifié de changement)

    # Convertir la configuration actuelle en dictionnaire pour la fusion
    new_config_dict = current_config.model_dump() if current_config else {}

    if new_temperature is not None:
    new_config_dict['temperature'] = new_temperature
    if new_max_output_tokens is not None:
    new_config_dict['max_output_tokens'] = new_max_output_tokens

    # Créer l'objet GenerateContentConfig final
    final_config = types.GenerateContentConfig(**new_config_dict)
  4. Recréer la session de chat :

    • Appelez client.chats.create() à nouveau.
    • Passez le nom du model original (chat_session._model).
    • Passez la final_config qui contient maintenant tous les paramètres préservés et mis à jour.
    • Passez l'current_history pour vous assurer que le contexte conversationnel est maintenu.
    updated_chat_session = client.chats.create(
    model=chat_session._model,
    config=final_config,
    history=current_history # Passer l'historique préservé
    )
  5. Remplacer l'ancienne instance de chat :

    • Il est crucial de remplacer votre référence à l'ancien objet chat_session par l'objet updated_chat_session. Toutes les interactions ultérieures utiliseront alors la nouvelle instance Chat avec les paramètres persistants souhaités.

Exemple de code

L'exemple suivant démontre un chat interactif où les utilisateurs peuvent taper update_params pour modifier la temperature et max_output_tokens tout en conservant l'system_instruction et l'history intacts.

import google.genai as genai
from google.genai import types
import os

# Assurez-vous que votre clé API est définie comme variable d'environnement ou transmise directement
# os.environ["GOOGLE_API_KEY"] = "VOTRE_CLE_API"

# --- Initialisation du client ---
try:
client = genai.Client()
except Exception:
print("Le client Google GenAI n'a pas pu être initialisé.")
print("Veuillez vous assurer que la variable d'environnement GOOGLE_API_KEY est définie ou la transmettre directement.")
print("Utilisation d'un client factice à des fins de démonstration uniquement si un client réel n'est pas configuré.")

# --- Client factice pour les tests locaux sans clé API ---
class MockResponse:
def __init__(self, text):
self.text = text
def __str__(self):
return self.text

class MockChat:
def __init__(self, model: str, config: types.GenerateContentConfig, history: list[types.Content]):
self._model = model
self._config = config
self._comprehensive_history = history if history is not None else []
print(f"MockChat créé : Modèle='{model}', Temp={config.temperature}, MaxTokens={config.max_output_tokens}, Longueur de l'historique={len(self._comprehensive_history)}")
if config.system_instruction:
print(f" Instruction système : '{config.system_instruction.parts[0].text}'")

def send_message(self, message: str):
# Ajouter le message utilisateur à l'historique factice
self._comprehensive_history.append(types.Content(role='user', parts=[types.Part.from_text(message)]))

# Simuler la réponse du modèle
response_text = (
f"Réponse factice (T={self._config.temperature}, MaxTok={self._config.max_output_tokens})"
f" à : '{message}'. Instruction système actuelle : '{self._config.system_instruction.parts[0].text}'"
)
model_content = types.Content(role='model', parts=[types.Part.from_text(response_text)])
self._comprehensive_history.append(model_content)

# Retourner une réponse factice GenerateContentResponse
mock_gen_response = types.GenerateContentResponse(
candidates=[types.Candidate(content=model_content)]
)
return mock_gen_response

def get_history(self, curated: bool = False) -> list[types.Content]:
# Pour le factice, toujours retourner l'historique complet
return self._comprehensive_history

class MockChats:
def create(self, model: str, config: types.GenerateContentConfig, history: list[types.Content] = None):
return MockChat(model=model, config=config, history=history)

class MockClient:
def __init__(self):
self.chats = MockChats()
client = MockClient()
# --- Fin du client factice ---

def get_user_param_overrides():
"""Demande à l'utilisateur la température et le nombre maximal de tokens de sortie, en autorisant une entrée vide."""
print("\n--- Entrez les nouveaux paramètres du modèle (Laissez vide pour conserver les valeurs actuelles) ---")
temp_input = input("Nouvelle température (flottant, ex. 0.7) : ")
max_tokens_input = input("Nouveau nombre maximal de tokens de sortie (entier, ex. 200) : ")

new_temperature = None
if temp_input:
try:
new_temperature = float(temp_input)
if not (0.0 <= new_temperature <= 1.0):
print("Remarque : La température est généralement comprise entre 0.0 et 1.0 pour les cas d'utilisation typiques.")
except ValueError:
print("Entrée invalide pour la température. Conservation de la valeur actuelle.")
new_temperature = None # Réinitialiser à None si invalide

new_max_output_tokens = None
if max_tokens_input:
try:
new_max_output_tokens = int(max_tokens_input)
if new_max_output_tokens <= 0:
print("Remarque : Le nombre maximal de tokens de sortie doit être un entier positif.")
new_max_output_tokens = None # Réinitialiser à None si invalide
except ValueError:
print("Entrée invalide pour le nombre maximal de tokens de sortie. Conservation de la valeur actuelle.")
new_max_output_tokens = None # Réinitialiser à None si invalide

return new_temperature, new_max_output_tokens

def recreate_chat_with_updates(current_chat: genai.chats.Chat) -> genai.chats.Chat:
"""
Récupère l'état actuel du chat, le fusionne avec de nouveaux paramètres et recrée le chat.
"""
print("\nTentative de mise à jour des paramètres du chat...")

# 1. Récupérer la configuration et l'historique actuels
# L'accès direct à _config est nécessaire car il n'y a pas de getter public
current_model_name = current_chat._model
current_gen_config: types.GenerateContentConfig = current_chat._config
current_history = current_chat.get_history(curated=False) # Obtenir l'historique complet

# 2. Obtenir les nouvelles valeurs de paramètres de l'utilisateur
new_temperature, new_max_output_tokens = get_user_param_overrides()

# 3. Fusionner les configurations
# Commencer par une représentation dictionnaire de la configuration actuelle
updated_config_dict = current_gen_config.model_dump()

# Appliquer les nouveaux paramètres s'ils sont fournis par l'utilisateur
if new_temperature is not None:
updated_config_dict['temperature'] = new_temperature
if new_max_output_tokens is not None:
updated_config_dict['max_output_tokens'] = new_max_output_tokens

# Créer un nouvel objet GenerateContentConfig à partir du dictionnaire fusionné
final_gen_config = types.GenerateContentConfig(**updated_config_dict)

print("\nRecréation de la session de chat avec :")
print(f" Modèle : {current_model_name}")
print(f" Température : {final_gen_config.temperature}")
print(f" Tokens de sortie max. : {final_gen_config.max_output_tokens}")
if final_gen_config.system_instruction:
# L'accès à parts[0].text est une simplification pour les instructions système textuelles typiques
print(f" Instruction système : '{final_gen_config.system_instruction.parts[0].text}'")
print(f" Longueur de l'historique : {len(current_history)} tours")

# 4. Recréer la session de chat
updated_chat = client.chats.create(
model=current_model_name,
config=final_gen_config,
history=current_history # Passer l'historique préservé
)
return updated_chat

def main_interactive_chat():
"""Initialise et exécute une session de chat interactive."""

# --- Configuration initiale du chat ---
# Définir une instruction système et un historique initiaux
initial_system_instruction = types.Content(parts=[types.Part.from_text("Vous êtes un assistant IA compétent et amical. Gardez les réponses concises sauf si on vous demande des détails.")])
initial_history = [
types.Content(role='user', parts=[types.Part.from_text("Salut, quel est ton but ?")]),
types.Content(role='model', parts=[types.Part.from_text("Je suis là pour vous aider avec des informations et des tâches, conçu par Google.")])
]

# Définir la configuration de génération initiale
initial_gen_config = types.GenerateContentConfig(
temperature=0.7,
max_output_tokens=150,
system_instruction=initial_system_instruction
)

print("--- Initialisation de la session de chat ---")
current_chat_session = client.chats.create(
model='gemini-pro', # Ou votre modèle préféré
config=initial_gen_config,
history=initial_history
)
print(f"Configuration initiale du chat : Température={current_chat_session._config.temperature}, Tokens max.={current_chat_session._config.max_output_tokens}")
print(f"Instruction système initiale : {current_chat_session._config.system_instruction.parts[0].text}")
print(f"Longueur de l'historique initial : {len(current_chat_session.get_history())} tours")


print("\n--- Début du chat ---")
print("Tapez 'update_params' pour modifier la température et le nombre maximal de tokens de sortie.")
print("Tapez 'quit' ou 'exit' pour terminer le chat.")

while True:
user_input = input("\nVous : ")
if user_input.lower() in ["quit", "exit"]:
print("Fin de la session de chat. Au revoir !")
break

if user_input.lower() == "update_params":
# Appeler la fonction pour recréer le chat avec les paramètres mis à jour
current_chat_session = recreate_chat_with_updates(current_chat_session)
print("\nParamètres de la session de chat mis à jour. Continuez à taper des messages.")
continue # Ignorer l'envoi du message "update_params" au modèle

try:
response = current_chat_session.send_message(user_input)
print(f"Modèle : {response.text}")
except Exception as e:
print(f"Une erreur est survenue pendant la génération : {e}")
break

if __name__ == "__main__":
main_interactive_chat()