Réponse courte
Installez le paquet Python openai-agents, décrivez chaque agent par un nom, des instructions et les fonctions Python qu’il peut appeler comme outils, puis exécutez-le avec Runner, qui gère pour vous la boucle des appels au modèle et des appels d’outils. Pour un service d’aide, un agent de triage confie chaque demande au bon agent spécialiste, et un garde-fou, une vérification rapide qui s’exécute sur le message entrant, arrête les demandes hors sujet avant que les agents principaux ne dépensent le moindre jeton.
Question de suivi Comment fonctionnent les transferts entre agents?
L’Agents SDK est la nouvelle bibliothèque Python à code source ouvert d’OpenAI pour créer des agents. Un agent, dans son vocabulaire, est un modèle de langage configuré avec des instructions, des outils qu’il peut appeler, des garde-fous et d’autres agents à qui il peut confier du travail. La bibliothèque exécute pour vous la boucle de l’agent : appeler le modèle, exécuter les outils qu’il demande, lui renvoyer les résultats, et recommencer jusqu’à obtenir une réponse finale. Si vous avez déjà écrit cette boucle à la main avec l’appel de fonctions (function calling), vous reconnaîtrez chaque étape; le SDK ne fait que l’emballer.
Ce guide crée un petit service d’aide pour une bibliothèque publique : un agent de triage qui lit chaque question, deux spécialistes qui répondent, et un garde-fou qui refuse les demandes qui n’ont rien à voir avec la bibliothèque.
Installation
Il vous faut Python et une clé d’API OpenAI. Dans un terminal :
python -m venv env
source env/bin/activate
pip install openai-agents
export OPENAI_API_KEY="your-key-here"
Le plus petit agent possible, selon le modèle du README du projet, tient en trois lignes : créer Agent(name=..., instructions=...), appeler Runner.run_sync(agent, "your question") et afficher result.final_output.
L’exemple complet : le service d’aide d’une bibliothèque
Chaque spécialiste reçoit un outil, une fonction Python ordinaire marquée du décorateur @function_tool, qui la transforme en outil que le modèle peut demander d’appeler. Les données sont inventées pour l’exemple.
import asyncio
from pydantic import BaseModel
from agents import (Agent, Runner, function_tool, input_guardrail,
GuardrailFunctionOutput, InputGuardrailTripwireTriggered,
RunContextWrapper, TResponseInputItem)
# --- Outils (données fictives) ---
@function_tool
def check_availability(title: str) -> str:
"""Indique si un livre est sur les rayons."""
shelf = {"the hobbit": "2 exemplaires disponibles", "dune": "tous les exemplaires sont prêtés"}
return shelf.get(title.lower(), "Absent du catalogue.")
@function_tool
def account_fines(card_number: str) -> str:
"""Indique les frais de retard dus sur une carte de bibliothèque."""
return "1,50 $ dus pour 1 document en retard." if card_number == "12345" else "Aucuns frais."
# --- Spécialistes ---
catalog_agent = Agent(
name="Catalog agent",
instructions="Réponds aux questions sur les livres et leur disponibilité. Utilise check_availability.",
tools=[check_availability],
)
accounts_agent = Agent(
name="Accounts agent",
instructions="Réponds aux questions sur les cartes de bibliothèque, les renouvellements et les frais. "
"Utilise account_fines. N'invente jamais de montants.",
tools=[account_fines],
)
# --- Garde-fou : est-ce que ça concerne la bibliothèque? ---
class TopicCheck(BaseModel):
is_library_question: bool
reasoning: str
topic_checker = Agent(
name="Topic checker",
instructions="Décide si le message est une question destinée au service d'aide d'une bibliothèque publique.",
output_type=TopicCheck,
)
@input_guardrail
async def library_only(ctx: RunContextWrapper[None], agent: Agent,
input: str | list[TResponseInputItem]) -> GuardrailFunctionOutput:
result = await Runner.run(topic_checker, input, context=ctx.context)
return GuardrailFunctionOutput(
output_info=result.final_output,
tripwire_triggered=not result.final_output.is_library_question,
)
# --- Triage ---
triage_agent = Agent(
name="Triage agent",
instructions="Transfère les questions sur les livres au Catalog agent et les questions "
"sur les cartes, les renouvellements ou les frais à l'Accounts agent.",
handoffs=[catalog_agent, accounts_agent],
input_guardrails=[library_only],
)
async def main():
for question in ["Dune est-il disponible?",
"Est-ce que je dois quelque chose sur la carte 12345?",
"Peux-tu faire mes devoirs de calcul différentiel?"]:
try:
result = await Runner.run(triage_agent, question)
print(question, "->", result.final_output)
except InputGuardrailTripwireTriggered:
print(question, "-> Désolé, je ne peux répondre qu'aux questions sur la bibliothèque.")
asyncio.run(main())
Voici ce qui se passe avec « Dune est-il disponible? » : le petit agent vérificateur du garde-fou confirme qu’il s’agit d’une question pour la bibliothèque; l’agent de triage transfère la demande à l’agent du catalogue (Catalog agent); cet agent appelle check_availability("Dune"); l’outil répond que tous les exemplaires sont prêtés; et l’agent du catalogue rédige la réponse finale. La question sur les devoirs déclenche le garde-fou, qui lève une exception que votre code intercepte pour répondre poliment.
À essayer : ajoutez un troisième spécialiste, un « Events agent » avec un outil qui renvoie les heures du conte de la semaine, inscrivez-le dans les handoffs de l’agent de triage et demandez « Quand a lieu la prochaine heure du conte pour les tout-petits? » Regardez ensuite la trace de l’exécution pour voir quel agent a traité chaque étape.
Trois choses à savoir
Les garde-fous s’exécutent en parallèle de l’agent. La documentation du SDK explique le principe : une vérification rapide et peu coûteuse peut empêcher un modèle coûteux de travailler sur une demande qu’il devrait refuser. Les garde-fous d’entrée ne s’exécutent que lorsque leur agent est le premier de l’exécution, et c’est pourquoi library_only est placé sur l’agent de triage. Les garde-fous de sortie, définis avec output_guardrails, vérifient la réponse finale du dernier agent.
Le traçage est activé par défaut. Chaque exécution est enregistrée sous forme de trace, un journal étape par étape des appels au modèle, des appels d’outils et des transferts, et c’est le premier endroit où regarder quand un agent fait quelque chose d’inattendu.
Les limites, c’est votre travail. Runner.run accepte max_turns pour plafonner le nombre de passages dans la boucle. Gardez des outils étroits et en lecture seule tant que vous ne faites pas confiance au système, et exigez qu’une personne confirme tout outil qui modifie des données, dépense de l’argent ou envoie des messages.
Comment fonctionnent les transferts entre agents?
Pour le modèle, un transfert (handoff) ressemble à n’importe quel autre outil. Quand vous inscrivez catalog_agent dans handoffs, le SDK offre au modèle de triage un outil qui porte son nom, transfer_to_catalog_agent. Si le modèle appelle cet outil, la boucle d’exécution fait de l’agent du catalogue l’agent actif et continue à partir de là. Le nouvel agent prend la responsabilité de la conversation et, par défaut, voit tout l’historique jusqu’à ce moment.
Vous pouvez modifier ce comportement avec la fonction handoff() au lieu d’inscrire un agent directement. Elle permet de renommer l’outil ou de réécrire sa description, d’exécuter un rappel on_handoff au moment même du transfert (utile pour la journalisation ou pour commencer à récupérer des données plus tôt), d’exiger que le modèle transmette des données structurées, comme le motif d’une escalade, au moyen de input_type, et de filtrer l’historique que reçoit l’agent suivant avec input_filter. Un filtre prêt à l’emploi, handoff_filters.remove_all_tools, retire les appels d’outils précédents pour que le spécialiste parte d’une conversation plus propre.
La documentation recommande aussi de parler des transferts aux agents dans leurs instructions, et fournit à cette fin un préfixe standard, RECOMMENDED_PROMPT_PREFIX. En pratique, plus le nom de chaque spécialiste et les instructions de triage sont clairs, plus le modèle oriente chaque question au bon endroit de façon fiable.
Sources
- OpenAI Agents SDK (README) — OpenAI (GitHub), 21 mars 2025
- Handoffs (Agents SDK documentation) — OpenAI (GitHub), 21 mars 2025
- Guardrails (Agents SDK documentation) — OpenAI (GitHub), 21 mars 2025