Aller au contenu principal

Conversations Multi-Tour en Python

Le principe des conversations multi-tour

Contrairement à un moteur de recherche, un modèle de langage peut maintenir le fil d’une conversation. Il se souvient de ce que vous avez dit précédemment et construit ses réponses en tenant compte du contexte accumulé. C’est ce qu’on appelle une conversation multi-tour.

Techniquement, le modèle ne « se souvient » de rien. À chaque requête, vous lui envoyez l’intégralité de l’historique : il le relit à chaque fois pour produire une réponse cohérente.

Les trois rôles de messages

Chaque message dans l’historique porte un rôle qui indique au modèle qui parle :

Le rôle system

Le message système définit le comportement global du modèle. Il est placé en premier et influence toutes les réponses :

{"role": "system", "content": "Vous êtes un assistant expert en cuisine française. Répondez toujours en français avec des termes culinaires précis."}

Le rôle user

Les messages de l’utilisateur. C’est la question ou l’instruction envoyée :

{"role": "user", "content": "Comment réussir une pâte feuilletée ?"}

Le rôle assistant

Les réponses précédentes du modèle, renvoyées dans l’historique pour maintenir la cohérence :

{"role": "assistant", "content": "Pour réussir une pâte feuilletée, commencez par..."}

Construire une conversation

Voici un exemple complet de conversation multi-tour :

import os
from mistralai import Mistral

client = Mistral(api_key=os.environ["MISTRAL_API_KEY"])

historique = [
    {
        "role": "system",
        "content": "Vous êtes un assistant pédagogique spécialisé en programmation Python. Répondez de façon concise et avec des exemples de code."
    }
]

def poser_question(question: str) -> str:
    """Envoie une question et met à jour l'historique."""
    historique.append({"role": "user", "content": question})

    response = client.chat.complete(
        model="mistral-small-latest",
        messages=historique,
    )

    reponse_texte = response.choices[0].message.content
    historique.append({"role": "assistant", "content": reponse_texte})

    return reponse_texte

# Tour 1
print("Q: Qu'est-ce qu'un décorateur en Python ?")
r1 = poser_question("Qu'est-ce qu'un décorateur en Python ?")
print(f"R: {r1}\n")

# Tour 2 — le modèle connaît le contexte
print("Q: Pouvez-vous me montrer un exemple concret ?")
r2 = poser_question("Pouvez-vous me montrer un exemple concret ?")
print(f"R: {r2}\n")

# Tour 3 — référence implicite aux tours précédents
print("Q: Comment l'utiliser avec des arguments ?")
r3 = poser_question("Comment l'utiliser avec des arguments ?")
print(f"R: {r3}\n")

Au tour 3, le modèle comprend que « l’utiliser » fait référence au décorateur discuté précédemment, car il a accès à tout l’historique.

Gérer la taille du contexte

Chaque modèle a une fenêtre de contexte limitée (mesurée en tokens). Plus l’historique est long, plus vous consommez de tokens à chaque requête, et plus le coût augmente.

Stratégies de gestion

Troncation par nombre de messages :

MAX_MESSAGES = 20

def ajouter_message(historique, role, content):
    historique.append({"role": role, "content": content})

    # Garder le message system + les N derniers messages
    if len(historique) > MAX_MESSAGES + 1:  # +1 pour le system
        system_msg = historique[0]
        historique = [system_msg] + historique[-(MAX_MESSAGES):]

    return historique

Résumé du contexte :

Pour les conversations très longues, résumez périodiquement l’historique :

def resumer_historique(client, historique):
    """Résume les anciens messages pour libérer du contexte."""
    texte_complet = "\n".join(
        f"{m['role']}: {m['content']}"
        for m in historique[1:-4]  # Exclure system et les 4 derniers
    )

    resume = client.chat.complete(
        model="mistral-small-latest",
        messages=[
            {"role": "user", "content": f"Résumez cette conversation en 3-4 phrases :\n{texte_complet}"}
        ]
    )

    return [
        historique[0],  # System message
        {"role": "assistant", "content": f"[Résumé de la conversation] {resume.choices[0].message.content}"},
    ] + historique[-4:]  # Les 4 derniers messages

Le message système : bonnes pratiques

Le message système est puissant mais souvent sous-exploité. Voici comment l’optimiser :

system_prompt = """Vous êtes un assistant technique Corsen AI.

Règles :
- Répondez en français avec un ton professionnel
- Fournissez des exemples de code quand c'est pertinent
- Si vous n'êtes pas sûr, dites-le plutôt que d'inventer
- Limitez vos réponses à 200 mots sauf demande contraire

Contexte : l'utilisateur travaille sur un projet Python 3.12 avec FastAPI."""

Un bon message système est concis, précis, et définit les contraintes sans ambiguïté.

Points clés à retenir

  • L’historique complet est renvoyé à chaque requête — le modèle ne « mémorise » rien
  • Les trois rôles (system, user, assistant) structurent la conversation
  • Le message system définit le comportement global — placez-le toujours en premier
  • Gérez la taille du contexte en tronquant ou en résumant les anciens messages
  • Plus l’historique est long, plus chaque requête coûte cher en tokens