Aller au contenu principal

Architecture d'un agent : boucle outil-raisonnement

Mis à jour le 29 juillet 2026

Architecture d’un agent : la boucle outil-raisonnement

Pour construire des agents efficaces, vous devez comprendre leur architecture interne. Un agent OpenAI fonctionne selon une boucle de raisonnement : il reçoit une tâche, réfléchit, utilise un outil, observe le résultat, puis décide s’il a terminé ou s’il doit continuer. Tout ce que vous ferez ensuite — déclarer des tools, poser des guardrails, orchestrer plusieurs agents — vient se greffer sur cette boucle.

Le cycle de vie d’un agent

Chaque exécution suit six étapes :

  1. Réception : l’agent reçoit le message de l’utilisateur et ses instructions système
  2. Raisonnement : le modèle analyse la demande et décide de la prochaine action
  3. Appel d’outil : si nécessaire, l’agent appelle un ou plusieurs outils
  4. Observation : l’agent reçoit les résultats des outils
  5. Décision : l’agent décide s’il doit continuer (retour à l’étape 2) ou répondre
  6. Réponse : l’agent produit sa réponse finale

La subtilité tient à la boucle entre les étapes 2 et 5, qui peut s’exécuter plusieurs fois. Un agent peut enchaîner 5, 10, ou même 20 appels d’outils avant de produire sa réponse finale, sans que vous ayez écrit la moindre ligne d’orchestration. L’exemple ci-dessous le montre : deux outils indépendants sont déclarés, et c’est le modèle qui décide de les enchaîner.

from agents import Agent, Runner, function_tool

@function_tool
def rechercher_produit(nom: str) -> str:
    """Recherche un produit dans le catalogue."""
    # Simulation - en production, appel à votre base de données
    catalogue = {
        "laptop-pro": {"prix": 1299, "stock": 45},
        "tablet-air": {"prix": 599, "stock": 120},
    }
    produit = catalogue.get(nom)
    if produit:
        return f"Produit {nom}: {produit[prix]}€, stock: {produit[stock]}"
    return f"Produit {nom} non trouvé"

@function_tool
def calculer_remise(prix: float, pourcentage: float) -> str:
    """Calcule le prix après remise."""
    prix_final = prix * (1 - pourcentage / 100)
    return f"Prix après {pourcentage}% de remise : {prix_final:.2f}€"

agent = Agent(
    name="Agent commercial",
    instructions="Vous aidez les clients à trouver des produits et calculer des remises.",
    tools=[rechercher_produit, calculer_remise],
    model="gpt-5.6-terra",
)

# L'agent va : 1) chercher le produit, 2) calculer la remise, 3) répondre
result = Runner.run_sync(
    agent,
    "Quel est le prix du laptop-pro avec 15% de remise ?"
)
print(result.final_output)

La question posée exige deux opérations que rien ne relie explicitement dans le code. L’agent effectue automatiquement deux appels d’outils en séquence : d’abord rechercher_produit, puis calculer_remise avec le prix obtenu. Le chaînage est une décision du modèle, pas une instruction de votre part.

La structure interne : items et messages

La Responses API structure chaque interaction en items, et c’est en les lisant que vous comprendrez ce que votre agent a réellement fait. Trois types se succèdent dans la conversation :

  • message : un message texte (de l’utilisateur ou de l’agent)
  • function_call : un appel d’outil décidé par l’agent
  • function_call_output : le résultat retourné par l’outil
result = Runner.run_sync(agent, "Cherche le tablet-air")

# Inspecter les étapes de raisonnement
for item in result.raw_responses:
    print(f"Type: {type(item).__name__}")
    # Vous verrez : message input → function_call → function_call_output → message output

Prenez l’habitude de dérouler cette boucle quand un agent produit une réponse surprenante : neuf fois sur dix, l’anomalie se voit dans un function_call aux arguments inattendus.

Appels parallèles vs. séquentiels

Toutes les étapes ne dépendent pas les unes des autres. Quand deux appels sont indépendants, l’agent peut décider de les lancer en parallèle.

@function_tool
def obtenir_meteo(ville: str) -> str:
    """Obtient la météo actuelle pour une ville."""
    meteos = {"Paris": "18°C, ensoleillé", "Lyon": "16°C, nuageux"}
    return meteos.get(ville, "Données non disponibles")

agent = Agent(
    name="Agent voyage",
    instructions="Vous aidez à planifier des voyages.",
    tools=[obtenir_meteo, rechercher_produit],
    model="gpt-5.6-terra",
)

# L'agent appellera obtenir_meteo("Paris") et obtenir_meteo("Lyon") en parallèle
result = Runner.run_sync(
    agent,
    "Quelle est la météo à Paris et à Lyon ?"
)

La météo de Lyon ne dépend pas de celle de Paris : le SDK gère automatiquement le parallélisme et lance les deux appels simultanément, ce qui réduit la latence. Comparez avec l’exemple commercial précédent, où le calcul de remise exigeait d’attendre le prix : là, la séquence s’impose d’elle-même.

Le paramètre max_turns

Une boucle autonome peut, dans le pire des cas, ne jamais s’arrêter : l’agent appelle un outil, le résultat le pousse à en appeler un autre, et ainsi de suite. Le garde-fou tient en un paramètre.

result = Runner.run_sync(
    agent,
    "Analyse complète du catalogue",
    max_turns=10  # Maximum 10 itérations de la boucle
)

Si l’agent atteint la limite, il s’arrête avec les résultats obtenus jusque-là. En production, c’est une sécurité essentielle : elle borne à la fois le temps de réponse et la facture.

Points clés à retenir

  • Un agent fonctionne en boucle : raisonnement → outil → observation → décision
  • Cette boucle peut s’exécuter plusieurs fois avant de produire une réponse
  • Le modèle décide automatiquement quels outils appeler et dans quel ordre
  • Les appels d’outils indépendants sont exécutés en parallèle
  • max_turns permet de limiter le nombre d’itérations pour la sécurité