Le mois dernier, j’ai vu un agent effectuer 47 appels API pour répondre à une question qu’il aurait pu résoudre en deux. La configuration semblait raisonnable — appel d’outils activé, tampon mémoire en place, gestion des erreurs sur le papier. L’agent n’avait tout simplement aucune idée de l’outil à utiliser en premier, continuait d’appeler le même, et n’avait aucun moyen de savoir qu’il bouclait.
C’est ce qui arrive lorsque vous construisez un agent sans comprendre ses véritables modes d’échec. L’architecture compte. Voici ce que j’ai appris en déployant des agents en production.
Les Trois Modèles Fondamentaux
Un agent IA a besoin de trois choses pour fonctionner : un moyen de décider quoi faire, l’accès à des outils, et la mémoire de ce qui s’est passé. La manière dont vous connectez ces trois éléments détermine si votre agent fonctionne proprement ou s’il brûle des tokens en courant après sa queue.
Modèle 1 : Routage Simple (Décision → Outil → Réponse)
C’est la base. L’agent voit une requête utilisateur, choisit un outil, l’exécute et renvoie un résultat. Pas de boucles. Pas de récursion. Un seul point de décision.
from anthropic import Anthropic
client = Anthropic()
def route_and_execute(user_message: str) -> str:
tools = [
{
"name": "lookup_price",
"description": "Obtenir le prix actuel d'un produit",
"input_schema": {
"type": "object",
"properties": {
"product_id": {"type": "string"}
},
"required": ["product_id"]
}
},
{
"name": "check_stock",
"description": "Vérifier le stock d'un produit",
"input_schema": {
"type": "object",
"properties": {
"product_id": {"type": "string"}
},
"required": ["product_id"]
}
}
]
response = client.messages.create(
model="claude-3-5-sonnet-20241022",
max_tokens=1024,
tools=tools,
messages=[{
"role": "user",
"content": user_message
}]
)
# Vérifier le type de réponse
for block in response.content:
if block.type == "tool_use":
tool_name = block.name
tool_input = block.input
# Exécution de l'outil (implémentation mock)
if tool_name == "lookup_price":
result = f"Prix pour {tool_input['product_id']}: $29.99"
elif tool_name == "check_stock":
result = f"Stock pour {tool_input['product_id']}: 15 unités"
else:
result = "Outil non trouvé"
return result
# S'il aucun outil n'a été appelé, retourner la réponse texte
return response.content[0].text if response.content else ""
# Utilisation
response = route_and_execute("Quel est le prix du produit ABC-123 ?")
print(response)
Cela fonctionne bien pour les tâches simples — requêtes de service client, recherches de données, décisions uniques. Cela échoue lorsque la réponse nécessite plusieurs étapes.
Modèle 2 : Boucle Agentique (Décider → Outil → Évaluer → Décider à Nouveau)
Lorsqu’une tâche nécessite plusieurs étapes — rechercher quelque chose, puis calculer, puis formater — vous avez besoin d’une boucle. L’agent prend une décision, l’exécute, obtient un retour, et décide quoi faire ensuite. Le piège : sans conditions de sortie, cela devient infini.
def agentic_loop(user_message: str, max_iterations: int = 5) -> str:
tools = [
{
"name": "search_knowledge_base",
"description": "Rechercher des informations dans la base de connaissances interne",
"input_schema": {
"type": "object",
"properties": {
"query": {"type": "string"}
},
"required": ["query"]
}
},
{
"name": "calculate_metric",
"description": "Effectuer un calcul sur des données",
"input_schema": {
"type": "object",
"properties": {
"values": {"type": "array", "items": {"type": "number"}},
"operation": {"type": "string", "enum": ["sum", "average", "max"]}
},
"required": ["values", "operation"]
}
}
]
messages = [{
"role": "user",
"content": user_message
}]
for iteration in range(max_iterations):
response = client.messages.create(
model="claude-3-5-sonnet-20241022",
max_tokens=1024,
tools=tools,
messages=messages
)
# Vérifier si nous avons une réponse finale
if response.stop_reason == "end_turn":
return response.content[0].text if response.content else ""
# Traiter les appels d'outils
if response.stop_reason == "tool_use":
# Ajouter la réponse de l'assistant à l'historique des messages
messages.append({
"role": "assistant",
"content": response.content
})
# Exécuter les outils et collecter les résultats
tool_results = []
for block in response.content:
if block.type == "tool_use":
# Exécution mock
if block.name == "search_knowledge_base":
result = f"Documents trouvés sur : {block.input['query']}"
elif block.name == "calculate_metric":
values = block.input['values']
op = block.input['operation']
if op == "sum":
result = f"Résultat : {sum(values)}"
elif op == "average":
result = f"Résultat : {sum(values)/len(values)}"
else:
result = f"Résultat : {max(values)}"
else:
result = "Outil inconnu"
tool_results.append({
"type": "tool_result",
"tool_use_id": block.id,
"content": result
})
# Ajouter les résultats des outils aux messages
messages.append({
"role": "user",
"content": tool_results
})
return "Nombre maximum d'itérations atteint"
# Utilisation
result = agentic_loop("Trouvez nos données de revenus du T3 et calculez la valeur mensuelle moyenne")
print(result)
Point clé : La limite max_iterations n’est pas facultative. J’ai vu des agents faire plus de 100 appels car personne n’avait défini de plafond. Définissez-la à 5 par défaut et n’augmentez que lorsque les tests prouvent que vous en avez besoin de plus.
Modèle 3 : Planification Hiérarchique (Planifier → Exécuter les Sous-tâches → Synthétiser)
Pour les flux de travail complexes — analyser un rapport, planifier une campagne, déboguer un système — décomposez d’abord le problème en sous-tâches. Laissez l’agent planifier, puis exécuter le plan, puis synthétiser. Cela vous donne une visibilité sur ce que l’agent pense devoir faire avant qu’il ne gaspille des tokens à le faire.
Appel d’Outils : Configuration et Modes d’Échec
L’appel d’outils dans Claude (depuis mars 2025) est fiable, mais la configuration est importante. Vous définissez les outils sous forme de schémas JSON. Le modèle décide quel outil appeler et avec quels paramètres. Vous exécutez l’outil et renvoyez les résultats.
La plupart des échecs proviennent de deux sources :
1. Descriptions d’Outils Vagues
Mauvais : "search" - rechercher des informations
Bon : "search_customer_database" - rechercher par email, nom ou ID. Renvoie l'enregistrement client avec l'historique des achats. Utilisez cet outil lorsque vous devez vérifier les détails du client avant de traiter les commandes.
Le modèle choisit les outils en fonction de leurs descriptions. Des descriptions vagues entraînent une mauvaise sélection d’outils.
2. Manque de Retour d’Erreur
Lorsqu’un outil échoue, indiquez spécifiquement à l’agent pourquoi. Ne renvoyez pas simplement une erreur générique. Dans le code de boucle agentique ci-dessus, chaque résultat d’outil est renvoyé comme un message. Si une recherche échoue, dites "Aucun résultat trouvé pour la requête 'xyz'. Essayez un terme de recherche différent." au lieu de "Erreur."
Mémoire : Sans État vs Persistante
Les agents doivent se souvenir du contexte. Vous avez deux options :
Historique de conversation (sans état) : Transmettez l’intégralité du fil de discussion au modèle à chaque fois. Fonctionne pour les interactions courtes. Devient rapidement coûteux. Coût en tokens = O(longueur_conversation) par appel.
Mémoire persistante : Stockez le résumé de la conversation, les faits clés et les journaux d’exécution des outils dans une base de données. Transmettez uniquement le contexte pertinent. Le coût en tokens reste constant.
Pour les agents en production, utilisez la mémoire persistante. Stockez les 10 à 15 derniers messages dans l’historique du fil, plus un résumé roulant. Si la conversation dépasse environ 20 messages, demandez au modèle de résumer et de stocker séparément.
Un Modèle à Tester Aujourd’hui
Choisissez le Modèle 1 (Routage Simple) et implémentez-le pour une tâche réelle dans votre système — recherche client, récupération de données, tout ce qui est à étape unique. Définissez 2 à 3 outils avec des descriptions précises. Exécutez 10 requêtes de test et vérifiez :
- A-t-il choisi le bon outil ? (Sinon, réécrivez la description.)
- A-t-il utilisé les bons paramètres ? (Sinon, votre schéma d’entrée n’est pas clair.)
- La sortie répond-elle réellement à la question de l’utilisateur ?
Une fois que cela fonctionne, passez au Modèle 2. Les agents multi-étapes ne sont pas plus difficiles — ce sont juste le Modèle 1 en boucle. Mais n’ajoutez la boucle que lorsque l’étape unique n’est pas suffisante.