Aller au contenu principal
Leçon 2 sur 6 · API Anthropic — Fondamentaux

Travailler avec les messages

Leçon 2 sur 6 Mis à jour le 5 novembre 2026 Développeur
Sur cette page
  1. Le format des messages
  2. L’objet réponse
  3. Les règles d’enchaînement
  4. Le préremplissage, et ce qui le remplace
  5. Des exemples par l’historique
  6. À vous de jouer
  7. Points clés à retenir

Le paramètre messages est le cœur de l’API : c’est la conversation que vous envoyez, et la réponse de Claude en est le tour suivant. Cette leçon détaille son format, l’objet que renvoie l’API, les règles d’enchaînement des tours, ce qui a changé depuis 2024 pour le « préremplissage », et la technique des exemples par l’historique. Vous construisez à la fin un petit chatbot en ligne de commande.

Le format des messages

messages est une liste de dictionnaires, un par tour de parole. Chacun a deux clés : role, qui vaut "user" (vous) ou "assistant" (Claude), et content, le contenu du tour. content est soit une chaîne, soit une liste de blocs typés ({"type": "text", "text": "…"}, une image, un document…) ; une chaîne équivaut à un unique bloc text. La leçon 6 utilise la forme en liste pour joindre des images.

messages = [
    {"role": "user", "content": "Bonjour Claude ! Comment vas-tu ?"},
    {"role": "assistant", "content": "Très bien, merci. Que puis-je faire pour vous ?"},
    {"role": "user", "content": "Un fait amusant sur les furets ?"},
]

Beaucoup d’usages n’ont pas besoin d’historique : une liste d’un seul message user est parfaitement normale. Quand il y a un historique, Claude le voit en entier à chaque requête : l’API ne garde aucune mémoire entre deux appels, c’est votre code qui renvoie la conversation.

Ce que vous envoyez, ce que vous recevez Deux colonnes : la requête (model, max_tokens, messages avec role et content, system facultatif) et la réponse (content en liste de blocs, stop_reason, usage, id et model). MESSAGES API Ce que vous envoyez, ce que vous recevez Requête model Le modèle qui traite la demande. max_tokens Le plafond de jetons produits, réflexion comprise. messages La conversation : tours role user ou assistant, content en chaîne ou en blocs. system Facultatif : rôle, ton, contexte de toute la conversation. → Réponse content Liste de blocs : thinking, text, tool_use… lue par type. stop_reason end_turn, max_tokens, stop_sequence, tool_use, pause_turn, refusal… usage Jetons d'entrée et de sortie facturés. id, model Identifiant du message, modèle qui a répondu. L'API ne garde aucune mémoire : à chaque appel, votre code renvoie tout l'historique. Une liste qui finit par un tour assistant (préremplissage) renvoie 400 depuis Claude 4.6.
D'après le carnet « Working with messages » (anthropics/courses, carnet archivé) et la référence Create a Message (documentation Claude).

L’objet réponse

response = client.messages.create(
    model="claude-opus-5-5",
    max_tokens=2048,
    messages=[{"role": "user", "content": "Traduis « hello » en français. Réponds par un seul mot."}],
)
print(response)

L’API renvoie un objet Message dont voici les champs utiles :

  • content : la liste des blocs produits. Pour une réponse simple, un bloc text, éventuellement précédé d’un bloc thinking ; avec des outils, des blocs tool_use. C’est le champ qu’on lit, par type.
  • stop_reason : pourquoi la génération s’est arrêtée. "end_turn" (fin naturelle), "max_tokens" (plafond atteint), "stop_sequence" (séquence d’arrêt rencontrée, leçon 4), "tool_use" (demande d’outil), "pause_turn" (tour long mis en pause), "refusal" (intervention des classificateurs de sécurité), "model_context_window_exceeded" (fenêtre de contexte dépassée).
  • stop_sequence : la séquence d’arrêt rencontrée, le cas échéant.
  • usage : les jetons facturés, input_tokens et output_tokens (plus les jetons de cache quand vous en utilisez).
  • id, type (toujours "message"), role (toujours "assistant"), model.

Le carnet le résumait d’une phrase qui reste vraie : si vous ne retenez qu’une chose, c’est que content contient ce que le modèle a produit. Ajoutez-y aujourd’hui : on le lit par type de bloc.

def text_of(response):
    """Concatène les blocs de texte d'une réponse."""
    return "".join(block.text for block in response.content if block.type == "text")

print(text_of(response))  # Bonjour

Les règles d’enchaînement

Les modèles sont entraînés sur des tours alternés user / assistant, et une conversation commence par un message user. Deux erreurs du carnet de 2024 ont changé de nature. Deux messages consécutifs du même rôle ne provoquent plus d’erreur : l’API les fusionne en un seul tour. Et une liste qui se termine par un message assistant n’est plus une astuce mais une erreur sur les modèles actuels, comme l’explique la section suivante.

Le préremplissage, et ce qui le remplace

Le carnet montrait une technique appelée « mettre des mots dans la bouche de Claude » : terminer la liste par un message assistant partiel, que Claude continue. Avec {"role": "assistant", "content": "calming mountain air"} après la demande d’un haïku, Claude 3 Haiku écrivait la suite du premier vers. Cette technique, le préremplissage, renvoie aujourd’hui une erreur 400 (invalid_request_error) sur Claude 4.6 et tous les modèles plus récents, donc sur toute la gamme actuelle. Ce qu’elle permettait se fait autrement :

  • Imposer un début : le demander dans la consigne. « Écris un haïku dont le premier vers est exactement “l’air frais de montagne”. »
  • Imposer un format : l’exiger dans la consigne, ou, pour du JSON, utiliser les sorties structurées (un schéma que la réponse doit respecter).
  • Couper un préambule : « Réponds directement, sans phrase d’introduction », dans le prompt système.
response = client.messages.create(
    model="claude-opus-5-5",
    max_tokens=2048,
    messages=[{"role": "user",
               "content": "Écris un haïku dont le premier vers est exactement « l'air frais de montagne ». N'écris que le haïku."}],
)
print(text_of(response))

Des exemples par l’historique

L’historique sert aussi à montrer à Claude ce que vous attendez : c’est le prompting par exemples (few-shot). Le carnet voulait classer le sentiment de messages sur des cornichons. Demandé tel quel, Claude rendait une analyse détaillée en plusieurs paragraphes ; pour traiter des milliers de messages, on veut un seul mot. On fournit donc quelques échanges d’exemple, des vrais tours complets, avant le message à classer :

response = client.messages.create(
    model="claude-opus-5-5",
    max_tokens=2048,
    messages=[
        {"role": "user", "content": "Avis impopulaire : les cornichons, c'est dégoûtant."},
        {"role": "assistant", "content": "NEGATIF"},
        {"role": "user", "content": "Mon amour des cornichons va trop loin : j'ai acheté une bouée en forme de cornichon."},
        {"role": "assistant", "content": "POSITIF"},
        {"role": "user", "content": "Sérieusement, qui peut manger un cornichon ? Immonde !"},
        {"role": "assistant", "content": "NEGATIF"},
        {"role": "user", "content": "Je viens de goûter les nouveaux cornichons épicés de @PickleCo, mes papilles dansent ! 🌶️🥒"},
    ],
)
print(text_of(response))  # POSITIF

Ce n’est pas du préremplissage : chaque exemple est un tour terminé, et la liste finit par un message user. Pour un format strictement contrôlé à grande échelle, la consigne explicite et les sorties structurées restent plus sûres que les seuls exemples.

À vous de jouer

Traduire. Écrivez une fonction translate(word, language) qui renvoie la traduction d’un mot, et uniquement le mot : translate("chicken", "italien") doit renvoyer pollo, sans phrase autour.

Voir une solution
def translate(word, language):
    response = client.messages.create(
        model="claude-opus-5-5",
        max_tokens=1024,
        messages=[{"role": "user",
                   "content": f"Traduis le mot « {word} » en {language}. Réponds uniquement par le mot traduit, sans rien d'autre."}],
    )
    return text_of(response).strip()

Un chatbot en ligne de commande. Gardez une liste conversation ; à chaque tour, lisez la saisie de l’utilisateur avec input(), ajoutez-la comme message user, envoyez toute la liste, affichez le texte de la réponse, puis ajoutez la réponse comme message assistant. Prévoyez un mot pour quitter.

Voir une solution
conversation = []

while True:
    user_input = input("Vous : ")
    if user_input.lower() in ("quit", "quitter"):
        print("Fin de la conversation.")
        break

    conversation.append({"role": "user", "content": user_input})
    response = client.messages.create(
        model="claude-opus-5-5",
        max_tokens=4096,
        messages=conversation,
    )
    print(f"Claude : {text_of(response)}")
    # on renvoie le tour de Claude tel quel, blocs de réflexion compris (recommandé par la documentation)
    conversation.append({"role": "assistant", "content": response.content})

Renvoyer response.content plutôt que le seul texte est ce que la documentation recommande : hors appel d’outil, retirer les blocs de réflexion des tours précédents est permis, mais renvoyer chaque tour tel quel et n’ajouter qu’à la fin de la liste garde la réflexion valide et le cache efficace.

Sources officielles : 02_messages_format.ipynb (anthropics/courses, archivé) · Create a Message (référence de l’API : messages, fusion des tours consécutifs, stop_reason) · Errors (préremplissage refusé depuis Claude 4.6) · Thinking (documentation Claude : blocs de réflexion d’un tour à l’autre)

Points clés à retenir

  • messages est une liste de tours {"role", "content"} ; content est une chaîne ou une liste de blocs typés.
  • L’API ne garde aucune mémoire : votre code renvoie l’historique à chaque appel.
  • La réponse se lit dans content, par type de bloc ; stop_reason dit pourquoi elle s’est arrêtée ; usage dit ce que vous payez.
  • Deux tours consécutifs du même rôle sont fusionnés ; une liste qui finit par un message assistant (préremplissage) renvoie 400 depuis Claude 4.6.
  • Les exemples par l’historique restent valables ; pour imposer un début ou un format, on le demande, ou on utilise les sorties structurées.