Exercice : construire un chatbot
Sur cette page
Premier exercice du cours, et le plus formateur : assembler ce que vous savez déjà, requêtes, historique, fonctions utilitaires, en un chatbot interactif en ligne de commande. Cet exercice est un complément de notre adaptation ; il prolonge la leçon « Multi-turn conversations » du cours officiel.
Objectif
Écrire un programme Python qui :
- lit les messages de l’utilisateur en boucle ;
- garde l’historique de la conversation ;
- envoie l’historique complet à chaque requête ;
- affiche les réponses de Claude ;
- s’arrête quand l’utilisateur tape
quitouexit.
Le point 3 est le cœur de l’exercice : sans l’historique complet, votre chatbot répondra à chaque message comme au premier.
Consignes
- Réutilisez
add_user_message,add_assistant_messageetchatde la leçon précédente. - Affichez un message d’accueil, ignorez les saisies vides, gérez proprement la sortie.
- Encadrez l’appel à l’API d’un
try/except: une erreur réseau ne doit pas tuer la session. - Bonus : donnez une personnalité au chatbot avec un prompt système (leçon suivante), en ajoutant un paramètre
systemàchat.
À vous de jouer
Écrivez le programme avant de lire la solution : l’exercice ne vaut que par la friction de l’essai. Bloqué plus de vingt minutes, regardez la structure de main(), puis refermez et terminez seul.
Voir la solution
from dotenv import load_dotenv
from anthropic import Anthropic
load_dotenv()
client = Anthropic()
model = "claude-sonnet-5-5"
def add_user_message(messages, text):
messages.append({"role": "user", "content": text})
def add_assistant_message(messages, text):
messages.append({"role": "assistant", "content": text})
def chat(messages, system=None):
params = {"model": model, "max_tokens": 4096, "messages": messages}
if system:
params["system"] = system
message = client.messages.create(**params)
return "".join(block.text for block in message.content if block.type == "text")
def main():
print("=== Chatbot Claude ===")
print("Tapez 'quit' ou 'exit' pour quitter.\n")
messages = []
system = "Tu es un assistant sympathique et concis. Tu réponds en français, avec des exemples concrets quand c'est utile."
while True:
user_input = input("Vous : ").strip()
if not user_input:
continue
if user_input.lower() in ("quit", "exit"):
print("Au revoir !")
break
add_user_message(messages, user_input)
try:
answer = chat(messages, system=system)
except Exception as e:
messages.pop() # on retire la question restée sans réponse
print(f"\nErreur : {e}\n")
continue
add_assistant_message(messages, answer)
print(f"\nClaude : {answer}\n")
if __name__ == "__main__":
main()
Trois détails de la solution méritent l’attention. La réponse de Claude est ajoutée à l’historique après chaque tour : c’est l’étape que les premières versions oublient, et le fil se rompt sans erreur visible. En cas d’erreur, la question restée sans réponse est retirée, sinon l’historique contiendrait deux messages user d’affilée (l’API les fusionnerait, mais la conversation perdrait son sens). Et chat n’ajoute system à la requête que s’il est fourni : l’API n’accepte pas system=None, d’où la construction conditionnelle des paramètres, que le cours officiel utilise aussi.
Pour aller plus loin. Affichez les tokens consommés à chaque tour (message.usage, en faisant renvoyer le message par chat) pour voir le coût croître ; sauvegardez l’historique dans un fichier JSON pour reprendre une conversation ; ajoutez une commande /reset qui vide la liste.
Sources officielles : Multi-turn conversations et System prompts (Claude Academy) · Create a Message (documentation Claude)
Points clés à retenir
- Un chatbot, c’est une boucle : lire, ajouter à l’historique, appeler, afficher, ajouter la réponse.
- Le piège classique : oublier d’ajouter la réponse de Claude, et le contexte se perd sans erreur.
- Paramètres optionnels construits conditionnellement : l’API n’accepte pas
system=None. - Un
try/exceptautour de l’appel, et l’historique reste cohérent même en cas d’erreur.