Aller au contenu principal

Module 5 — Outils partagés entre agents

Un agent qui ne dispose que de son modèle de langage ne fait que du texte à partir de texte. Il ne peut pas lire un fichier de spécifications, chercher dans un référentiel, ni interroger une API interne. Les outils sont ce qui transforme une équipe éloquente en une équipe qui livre. Ce module montre comment les définir, les attribuer et les autoriser.

Deux familles d'outils

CrewAI reconnaît deux familles d'outils. La première contient les outils intégrés — recherche web, lecture de fichier, requête SQL, appel HTTP, exécution de code Python — que la bibliothèque fournit prêts à l'emploi via crewai_tools. Ils couvrent 80 % des cas courants.

from crewai_tools import FileReadTool, DirectoryReadTool, SerperDevTool

lire_specifications = FileReadTool(file_path="specifications/factureexpress.md")
lister_livrables = DirectoryReadTool(directory="livrables/")
chercher_web = SerperDevTool() # nécessite une clé Serper

La seconde famille contient les outils personnalisés, écrits par vous à partir de BaseTool. Ils encapsulent un appel à votre système d'information : votre catalogue produit, votre base d'anciennes documentations, votre gestionnaire de tickets. C'est cette famille qui rend l'équipe utile dans votre contexte.

from crewai.tools import BaseTool
from pydantic import BaseModel, Field

class RechercheDocParams(BaseModel):
requete: str = Field(..., description="Termes à chercher dans le corpus de documentation.")
limite: int = Field(5, description="Nombre maximal d'extraits renvoyés.")

class RechercheDoc(BaseTool):
name: str = "recherche_documentation_interne"
description: str = (
"Recherche dans le corpus de documentation interne. Renvoie les "
"extraits les plus pertinents avec le titre du document et l'URL."
)
args_schema: type[BaseModel] = RechercheDocParams

def _run(self, requete: str, limite: int = 5) -> str:
# Appel à votre moteur d'indexation
extraits = mon_moteur.chercher(requete, k=limite)
return "\n\n".join(f"[{e.titre}]({e.url})\n{e.extrait}" for e in extraits)

Deux règles pour un outil personnalisé. La description est lue par le modèle au moment de décider s'il faut l'appeler : elle doit être précise, en une ou deux phrases. Le args_schema typé par Pydantic évite qu'un agent passe une chaîne à un paramètre entier — cette validation économise des cycles perdus.

Attribution : par agent ou par tâche ?

CrewAI accepte les outils à deux endroits, et la différence est structurante.

Attribués à un agent (Agent(tools=[…])), les outils sont disponibles à toutes ses tâches. C'est le bon choix pour un outil qui définit la compétence de l'agent : le rédacteur lit toujours le glossaire, le relecteur consulte toujours le guide de style.

Attribués à une tâche (Task(tools=[…])), ils ne sont disponibles que pour cette tâche précise. C'est le bon choix pour un outil dont l'usage est ponctuel : la recherche web n'est utile qu'à la tâche d'analyse initiale ; l'ouvrir à tout le monde invite le rédacteur à s'égarer sur des articles hors sujet.

La règle pratique se résume ainsi : les outils décrivent-ils l'agent, ou l'étape ? La réponse dicte l'attribution.

Le principe du moindre privilège

Un agent qui a accès à trop d'outils prend de mauvaises décisions. Pas parce qu'il est malintentionné, mais parce qu'à chaque appel, le modèle voit la liste complète des outils dans sa consigne système et doit choisir. Une liste de dix outils allonge cette consigne, augmente la probabilité de choisir un outil inapproprié, et fait exploser les jetons d'entrée.

La règle du moindre privilège s'applique donc pour deux raisons — la sécurité et la qualité :

  • Un outil qui modifie un système externe (envoi de courriel, écriture en base, appel API tarifé) doit être attribué explicitement, jamais par défaut.
  • Un outil qui lit un fichier de spécifications sensibles n'est donné qu'aux agents qui doivent le lire.
  • Un outil rarement pertinent est mis à la tâche, pas à l'agent.

L'outil clé du fil rouge

Pour notre équipe de rédaction, l'outil pivot est un FileReadTool sur le fichier specifications/factureexpress.md, attribué à la tâche d'analyse. L'analyste s'en sert au démarrage, personne d'autre. Le rédacteur reçoit ensuite la sortie de l'analyste, plus l'accès à un glossaire de style via un second FileReadTool. Le relecteur reçoit son propre outil — un fichier de conventions éditoriales.

tache_analyse = Task(
description="Lis les spécifications et produis la liste des fonctionnalités.",
expected_output="…",
agent=analyste,
tools=[lire_specifications], # scoped à cette tâche
)

redacteur = Agent(
role="Rédacteur documentation",
goal="…",
tools=[lire_glossaire], # compétence permanente
llm=ChatOpenAI(model="gpt-4o-mini"),
)

Cette répartition donne trois traces d'exécution qui se distinguent au coup d'œil : chaque agent n'a que ce qu'il lui faut, on voit vite qui appelle quoi, et personne ne « fouille » là où ce n'est pas son travail.

Nommer les outils explicitement

Un outil qui s'appelle search_v2 ne dit rien au modèle. Un outil qui s'appelle recherche_documentation_interne guide le choix d'appel. Investir dans les noms et les descriptions d'outils est ce qui fait la différence entre une équipe qui appelle le bon outil au bon moment et une équipe qui hésite à chaque étape.

En résumé

  • CrewAI fournit des outils intégrés via crewai_tools et permet d'écrire des outils personnalisés à partir de BaseTool.
  • La description d'un outil est lue par le modèle : elle doit être précise ; le args_schema typé Pydantic évite les appels malformés.
  • Attribuer à l'agent un outil qui décrit sa compétence permanente, à la tâche un outil ponctuel — cette règle réduit le bruit.
  • Le moindre privilège vaut par sécurité et par qualité : moins d'outils par agent, moins d'appels ratés, moins de jetons dans la consigne.

Module suivant : la délégation entre agents et la supervision qui empêche les boucles.