Outils et Agents
Outils pour LLM
Dans ce chapitre, nous abordons les divers outils que l'on peut intégrer à un modèle de langage à grande échelle (LLM) tel que GPT, afin d'élargir ses capacités de réponse et d'interaction. Notre objectif est de clarifier comment ces outils peuvent être utilisés par le LLM pour fournir des réponses plus précises et contextuelles aux requêtes des utilisateurs.
Principe de fonctionnement
Fonctionnement général
Les LLM, malgré leur capacité remarquable à générer du texte basé sur d'énormes volumes de données, ne possèdent pas une connaissance universelle. Pour compenser certaines de leurs lacunes, notamment en termes d'informations à jour ou spécifiques, il est possible de les équiper d'outils externes. Ces outils peuvent être sollicités par le LLM lorsqu'il identifie le besoin d'informations complémentaires pour répondre à une question.
Interaction avec les outils
Lorsqu'une question posée nécessite des informations externes, le LLM détermine quel outil est nécessaire pour obtenir ces informations. Il produit alors une requête structurée avec les paramètres nécessaires à l'outil. Les développeurs reçoivent cette requête, extraient les données requises et les rendent disponibles au LLM, qui les intègre dans sa réponse.

Exemple Pratique : Outil Météo
Considérons l'exemple de l'outil météo. Si un utilisateur interroge sur la météo à Wavre, en Belgique, le LLM reconnaît qu'il a besoin de données météorologiques externes pour formuler une réponse. Il initie une requête spécifiant l'outil "météo" et la localisation "Wavre, Belgique". Les développeurs récupèrent ces informations et les transmettent au LLM, qui les utilise pour élaborer une réponse informative et adaptée.
Types d'outils disponibles
Recherche sur Internet
Cet outil permet au LLM de réaliser des recherches sur Internet pour répondre à des questions demandant des informations récentes ou spécifiques, non incluses dans sa base de données d'entraînement.

Recherche dans des Documents
Pour des questions nécessitant l'analyse de documents spécifiques, cet outil autorise le LLM à fouiller dans un ensemble défini de documents ou de bases de données.

Génération d'Images
Cet outil habilite le LLM à créer des images à partir de descriptions textuelles, enrichissant ses réponses avec du contenu visuel pertinent.

Environnement d'Exécution de Code
Pour les questions exigeant l'exécution de code, cet outil met à disposition un environnement sécurisé où le code peut être exécuté et les résultats intégrés dans la réponse du LLM.




L'architecture de base : Comment organiser ce bordel 🏗️
Bon, fini de faire mumuse avec des concepts abstraits. On va coder pour de vrai maintenant ! (ಠ_ಠ)

Le tool spécial : DirectResponse 🎯
Avant de parler des vrais tools, il faut comprendre un truc important : on donne toujours au LLM l'option de répondre directement SANS utiliser de tools. Pour ça, on a créé un tool spécial :
class DirectResponseTool implements ToolInterface
{
public function getName(): string
{
return 'direct_response';
}
public function getDescription(): string
{
return 'Utilise ce tool quand tu peux répondre directement sans avoir besoin d\'informations externes';
}
}
Comme ça, le LLM a le choix : soit il utilise des tools externes (météo, calcul...), soit il répond directement avec ses connaissances. C'est lui qui décide ! 🤓
L'interface ToolInterface : Le contrat sacré 📜
Première règle du fight club des tools : tous les tools doivent respecter le même contrat. En PHP, on définit une interface :
interface ToolInterface
{
public function getName(): string; // "get_weather", "calculator", etc.
public function getDescription(): string; // Pour que le LLM comprenne à quoi ça sert
public function getParametersSchema(): array; // JSON Schema des paramètres
public function execute(array $parameters): array; // La magie opère ici
public function isEnabledByDefault(): bool; // Actif ou pas ? That is the question
}
Voilà, c'est tout ! Si ton tool ne respecte pas ça, il peut aller se faire voir ailleurs 🚮
Le ToolManager : Le chef d'orchestre qui fait tout le boulot 🎭
Le ToolManager, c'est comme un manager de boîte de nuit : il connaît tous les videurs (tools), sait lesquels sont disponibles, et les fait bosser quand il faut.
class ToolManager
{
private Collection $tools; // Notre collection de tools
public function registerTool(ToolInterface $tool): void
{
$this->tools->put($tool->getName(), $tool);
}
public function getToolsForAPI(array $enabledToolNames = []): array
{
// Convertit les tools au format OpenAI/OpenRouter
// Parce que oui, il faut leur mâcher le travail...
}
}
Exemple concret : Le WeatherTool 🌦️
Parce qu'apparemment, les LLMs ne peuvent pas regarder par la fenêtre :
class WeatherTool implements ToolInterface
{
public function getName(): string
{
return 'get_weather';
}
public function getParametersSchema(): array
{
return [
'type' => 'object',
'properties' => [
'location' => [
'type' => 'string',
'description' => 'La ville (ex: "Wavre")'
],
],
'required' => ['location'],
];
}
}
Le flow magique : Comment le LLM devient moins bête 🪄
Étape 1 : "Choisis ton arme !" ⚔️
Quand un utilisateur pose une question, on envoie TOUT au LLM :
- Les messages de la conversation
- La liste des tools disponibles
- Un petit "tool_choice": "auto" (traduit : "débrouille-toi")
$toolChoiceResponse = $this->client->chat()->create([
'model' => $model,
'messages' => $allMessages,
'tools' => $this->toolManager->getToolsForAPI($enabledTools),
'tool_choice' => 'auto', // Le LLM fait son malin tout seul
]);
Le LLM répond soit :
- "J'ai pas besoin de tools, je suis trop intelligent" →
direct_response - "Donne-moi la météo stp" →
toolCallsavec les détails
Étape 2 : Exécution des tools et compilation des résultats 🔨
Si le LLM demande des tools, on les exécute :
foreach ($choice->message->toolCalls as $toolCall) {
$result = $this->toolManager->executeTool(
$toolCall->function->name,
json_decode($toolCall->function->arguments, true)
);
// On stocke le résultat pour le renvoyer au LLM après
$toolResults[] = [
'role' => 'tool',
'tool_call_id' => $toolCall->id,
'content' => json_encode($result),
];
}
Puis on renvoie TOUT au LLM : "Tiens, voilà tes données, maintenant fais une belle phrase !" 🎯
Le streaming : Parce que personne n'aime attendre 🚀
Les générateurs PHP : yield > return
Un générateur en PHP, c'est comme un distributeur de bonbons : il donne un bonbon à la fois au lieu de vider tout le paquet dans ta bouche ! 🍬
function sendMessageWithToolsStream(...): \Generator
{
// Au lieu de return, on yield progressivement
yield json_encode(['type' => 'tool_call_start', 'data' => [...]]) . "\n";
yield json_encode(['type' => 'tool_call_result', 'data' => [...]]) . "\n";
yield json_encode(['type' => 'message_chunk', 'data' => $chunk]) . "\n";
}
Les events JSON : Le front-end adore ça 📡
On envoie différents types d'events au navigateur :
{"type": "tool_call_start", "data": {"tool_name": "get_weather", "parameters": {...}}}
{"type": "tool_call_result", "data": {"result": "Il pleut à Wavre"}}
{"type": "message_chunk", "data": "Il fait "}
{"type": "message_chunk", "data": "15°C à Wavre"}
{"type": "message_end"}
Le front peut ainsi afficher en temps réel : "Le LLM appelle la météo... ⏳" puis la réponse qui arrive mot par mot. Magique ! ✨
Dans le controller : Le chef d'orchestre du streaming 🎼
return response()->stream(function () use (...) {
$eventStream = $this->chatService->sendMessageWithToolsStream(...);
foreach ($eventStream as $eventJson) {
echo $eventJson;
ob_flush(); // PHP, sors ça de ton buffer !
flush(); // Envoie au navigateur, MAINTENANT !
}
}, 200, [
'Content-Type' => 'text/plain; charset=utf-8',
'X-Accel-Buffering' => 'no', // Nginx, touche pas à mon stream !
]);
Exemple concret : "Quel temps fait-il à Wavre ?" 🌧️
-
User : "Quel temps fait-il à Wavre ?"
-
LLM : "Hmm, j'ai besoin du tool météo"
{"tool_calls": [{"function": {"name": "get_weather", "arguments": "{\"location\": \"Wavre\"}"}}]} -
Notre code : Appelle l'API météo → "15°C, pluie"
-
LLM avec les résultats : "Il fait actuellement 15°C à Wavre avec de la pluie. Typique de la Belgique ! 🌧️"

Vers un agent autonome : Le boss final 🤖
Un agent, c'est un LLM sous stéroïdes qui peut :
La boucle de l'agent 🔄
while (objectif_non_atteint) {
1. Réfléchir : "Qu'est-ce que je dois faire ?"
2. Agir : Utiliser un ou plusieurs tools
3. Observer : Analyser les résultats
4. Décider : Continuer ou s'arrêter ?
}
La mémoire comme tool 🧠
Dans un agent sophistiqué, même la mémoire devient un tool ! L'agent peut :
- Sauvegarder des informations :
memory_save("hotel_paris", "Hôtel Le Marais - 120€/nuit") - Récupérer des informations :
memory_retrieve("hotel_paris") - Chercher dans sa mémoire :
memory_search("tous les hôtels")
class MemoryTool implements ToolInterface
{
private $storage = [];
public function execute(array $parameters): array
{
switch ($parameters['action']) {
case 'save':
$this->storage[$parameters['key']] = $parameters['value'];
return ['status' => 'saved'];
case 'retrieve':
return ['value' => $this->storage[$parameters['key']] ?? null];
case 'search':
// Recherche intelligente dans la mémoire
return ['results' => $this->searchMemory($parameters['query'])];
}
}
}
Exemples d'agents spécialisés 🦾
1. Agent Web Browser 🌐
Cet agent peut naviguer sur le web comme un humain :
$webAgent = new Agent([
new NavigateTool(), // Aller à une URL
new ClickTool(), // Cliquer sur un élément
new TypeTool(), // Taper du texte
new ExtractTool(), // Extraire des données
new ScreenshotTool(), // Prendre une capture
new MemoryTool() // Se souvenir de ce qu'il trouve
]);
// Exemple de tâche
$webAgent->run("Trouve le prix du dernier iPhone sur le site d'Apple");
// L'agent va : naviguer → chercher → cliquer → extraire → mémoriser
2. Agent Développeur 👨💻
Cet agent peut écrire et débugger du code :
$devAgent = new Agent([
new WriteCodeTool(), // Écrire du code
new RunCodeTool(), // Exécuter et tester
new DebugTool(), // Analyser les erreurs
new RefactorTool(), // Améliorer le code
new GitTool(), // Commit et push
new MemoryTool() // Se souvenir des bugs rencontrés
]);
// Exemple de tâche
$devAgent->run("Crée une API REST pour gérer des todos en Laravel");
// L'agent va : planifier → coder → tester → corriger → optimiser → versionner
Architecture complète d'un agent 🏛️
class Agent {
private array $tools;
private LLMInterface $llm;
private int $maxIterations = 10;
public function run(string $objective): array
{
$iteration = 0;
$completed = false;
$results = [];
while (!$completed && $iteration < $this->maxIterations) {
// 1. Planification
$plan = $this->llm->plan($objective, $results);
// 2. Sélection du tool
$toolChoice = $this->llm->selectTool($plan, $this->tools);
// 3. Exécution
$toolResult = $this->executeTool($toolChoice);
$results[] = $toolResult;
// 4. Évaluation
$completed = $this->llm->isObjectiveCompleted($objective, $results);
$iteration++;
}
return $results;
}
}
Les patterns d'agents avancés 🎭
- Multi-agents : Plusieurs agents qui collaborent
- Hierarchical agents : Un agent manager qui délègue à des agents spécialisés
- Self-improving agents : Qui apprennent de leurs erreurs (via la mémoire)
Conclusion : T'as compris ou pas ? 🎓
Voilà, maintenant tu sais :
- ✅ Comment créer des tools pour ton LLM
- ✅ Comment les faire communiquer ensemble
- ✅ Comment streamer tout ça proprement
- ✅ Comment transformer ton LLM en agent autonome
Les tools transforment complètement les capacités des LLMs. Ils passent de simples générateurs de texte à de véritables assistants capables d'interagir avec le monde réel. Et avec les agents, on entre dans une nouvelle dimension où l'IA peut vraiment automatiser des tâches complexes ! 🚀

