Qu'est-ce qu'un AI Agent ? Explication détaillée avec exemples en Java
1. Aperçu général
« AI Agent » est un terme qui apparaît partout mais dont la définition est souvent floue : certains appellent tout chatbot un agent, d’autres ne considèrent que les systèmes multi-étapes complexes comme de véritables agents. Cet article explique clairement ce qu’est un AI Agent, les composants indispensables qu’il doit avoir, et le mécanisme de boucle qui se cache derrière. À la fin de la lecture, vous pourrez construire un agent minimal en Java pur pour comprendre comment il fonctionne « de l’intérieur », puis le faire évoluer vers une version utilisant un vrai LLM avec Spring AI.
2. Qu’est-ce qu’un AI Agent ?
Définition courte : Un AI Agent est un système utilisant un LLM comme cerveau pour prendre automatiquement des décisions et effectuer des actions afin d’atteindre un objectif, au lieu de simplement répondre à une question puis s’arrêter.
Différence avec un chatbot ordinaire :
| Caractéristique | Chatbot ordinaire | AI Agent |
|---|---|---|
| Nombre de traitements | 1 passage : demander → répondre | Plusieurs étapes : observer → raisonner → agir → répéter |
| Appelle des tools/API | Généralement non | Oui, décide automatiquement quel tool appeler |
| A-t-il un objectif à long terme | Non | Oui, l’agent se divise lui-même les tâches pour atteindre l’objectif |
| Exemple | « Quel est la météo de Hanoï ? » → retourner une description textuelle | « Réserver les billets les moins chers Hanoï - Ho Chi Minh-Ville demain » → trouver les billets, comparer les prix, réserver, confirmer |
Autrement dit, un LLM n’est qu’un « cerveau linguistique » capable de générer du texte. Un agent transforme ce cerveau en une entité capable d’agir dans le monde réel (appeler des API, lire des fichiers, interroger une base de données) et de s’auto-itérer le processus de raisonnement jusqu’à ce que la tâche soit terminée.
3. Composants essentiels d’un AI Agent
Un agent minimal a besoin de 4 composants. En manquer un, et le système n’est qu’un chatbot « déguisé » en agent.
3.1. LLM – le cerveau de raisonnement
Le LLM reçoit un prompt (contenant l’objectif, l’historique, la liste des outils disponibles) et génère la décision suivante : répondre directement ou appeler quel outil, avec quels paramètres.
3.2. Tool (function calling) – les mains de l’agent
Un tool est une fonction concrète que l’agent peut appeler : rechercher une commande, appeler une API météo, interroger une base de données. C’est la partie qui transforme l’agent de « sait parler » à « sait agir ».
public interface Tool {
String name();
boolean canHandle(String input);
String execute(String input);
}
canHandle vérifie si ce tool peut traiter l’input actuel ; execute effectue l’action et retourne le résultat (observation).
3.3. Memory – la mémoire
L’agent doit se souvenir de ce qu’il a fait à l’étape précédente (historique de conversation, résultats des outils appelés) pour éviter de répéter des actions inutiles. La mémoire peut être aussi simple qu’une List<String> stockant les logs des étapes, ou plus complexe, comme un magasin vectoriel pour retrouver des informations pertinentes.
3.4. Control loop – boucle de contrôle
C’est la partie « moteur » qui exécute tout le processus : itère sur les étapes Thought → Action → Observation jusqu’à atteindre l’objectif ou épuiser le nombre d’étapes autorisées. La section suivante approfondit ce mécanisme.
4. La boucle ReAct : comment l’agent « réfléchit puis agit »
ReAct (Reasoning + Acting) est le modèle de boucle le plus courant pour les agents :
- Thought : le LLM réfléchit « que dois-je faire ensuite ? »
- Action : choisir un outil et l’appeler avec les paramètres appropriés.
- Observation : recevoir le résultat du tool et le réintégrer dans le contexte.
- Répéter à partir de l’étape 1 jusqu’à ce que le LLM décide d’avoir assez d’informations pour répondre finalement, ou jusqu’à épuisement de
maxSteps.
Pour bien comprendre ce mécanisme sans appeler un vrai LLM (qui coûte de l’API), on construit un mini-agent en Java pur, utilisant des if-else à la place d’un vrai LLM.
public class SimpleAgent {
private final List<Tool> tools;
private final int maxSteps;
public SimpleAgent(List<Tool> tools, int maxSteps) {
this.tools = tools;
this.maxSteps = maxSteps;
}
public String run(String goal) {
String observation = goal;
for (int step = 1; step <= maxSteps; step++) {
Tool chosen = tools.stream()
.filter(t -> t.canHandle(observation))
.findFirst()
.orElse(null);
if (chosen == null) {
return "Aucun tool ne peut gérer : " + observation;
}
System.out.printf("Étape %d - Thought : doit utiliser tool '%s'%n", step, chosen.name());
String result = chosen.execute(observation);
System.out.printf("Étape %d - Observation : %s%n", step, result);
return result; // exemple simple : fini après 1 étape
}
return "Nombre d'étapes autorisées (" + maxSteps + ") épuisé mais la tâche n'est pas terminée.";
}
}
maxSteps est précisément le « budget » d’étapes — c’est obligatoire pour que l’agent ne tourne pas indéfiniment s’il n’atteint jamais l’objectif. La boucle for simule Thought (choisir l’outil), Action (execute), Observation (résultat affiché sur console).
Trois outils à titre d’illustration :
public class WeatherTool implements Tool {
@Override
public String name() {
return "WeatherTool";
}
@Override
public boolean canHandle(String input) {
return input.toLowerCase().contains("météo");
}
@Override
public String execute(String input) {
return "Aujourd'hui à Hanoï, 28°C, temps nuageux.";
}
}
public class OrderStatusTool implements Tool {
@Override
public String name() {
return "OrderStatusTool";
}
@Override
public boolean canHandle(String input) {
return input.toLowerCase().contains("commande");
}
@Override
public String execute(String input) {
return "Commande #1023 est en cours de livraison, livraison prévue dans 2 jours.";
}
}
public class CalculatorTool implements Tool {
@Override
public String name() {
return "CalculatorTool";
}
@Override
public boolean canHandle(String input) {
return input.matches(".*\\d+\\s*\\+\\s*\\d+.*");
}
@Override
public String execute(String input) {
String digits = input.replaceAll("[^0-9+]", "");
String[] parts = digits.split("\\+");
int sum = Integer.parseInt(parts[0]) + Integer.parseInt(parts[1]);
return "Résultat : " + sum;
}
}
Essayer :
SimpleAgent agent = new SimpleAgent(
List.of(new CalculatorTool(), new WeatherTool(), new OrderStatusTool()),
3
);
String result = agent.run("Dis-moi la météo de Hanoï aujourd'hui");
System.out.println(result);
Résultat :
Étape 1 - Thought : doit utiliser tool 'WeatherTool'
Étape 1 - Observation : Aujourd'hui à Hanoï, 28°C, temps nuageux.
Aujourd'hui à Hanoï, 28°C, temps nuageux.
Écrire un test pour valider le choix correct du tool et gérer le cas où aucun outil ne convient :
import org.junit.jupiter.api.Test;
import java.util.List;
import static org.assertj.core.api.Assertions.assertThat;
class SimpleAgentTest {
@Test
void shouldPickWeatherToolWhenGoalMentionsWeather() {
SimpleAgent agent = new SimpleAgent(
List.of(new CalculatorTool(), new WeatherTool(), new OrderStatusTool()),
3
);
String result = agent.run("Dis-moi la météo de Hanoï aujourd'hui");
assertThat(result).contains("Hanoï");
}
@Test
void shouldReturnErrorWhenNoToolMatches() {
SimpleAgent agent = new SimpleAgent(List.of(new CalculatorTool()), 3);
String result = agent.run("Chante-moi une chanson");
assertThat(result).startsWith("Aucun tool ne peut gérer");
}
}
Cet exemple utilise des if-else à la place d’un LLM, donc le « raisonnement » est très rigide. Un vrai agent diffère sur ce point : au lieu de canHandle rigide, c’est le LLM lui-même qui lit la description du tool et décide de l’appeler, les paramètres étant extraits par le LLM lui-même du langage naturel.
5. Construire un vrai agent avec Spring AI et tool calling
Pour voir le vrai LLM en action dans la prise de décision, on utilise Spring AI — un framework qui intègre les modèles d’IA dans Spring Boot et supporte nativement le tool calling.
<dependency>
<groupId>org.springframework.ai</groupId>
<artifactId>spring-ai-starter-model-openai</artifactId>
<version>1.0.0</version>
</dependency>
Configuration de la clé API et du modèle :
spring:
ai:
openai:
api-key: ${OPENAI_API_KEY}
chat:
options:
model: gpt-4o-mini
Déclarer le tool avec l’annotation @Tool, similaire à OrderStatusTool de l’exemple précédent mais cette fois le vrai LLM l’appellera :
import org.springframework.ai.tool.annotation.Tool;
import org.springframework.stereotype.Component;
@Component
public class OrderTools {
@Tool(description = "Rechercher le statut d'une commande par son ID de commande")
public String getOrderStatus(String orderId) {
// en pratique, on appellerait OrderService / la base de données ici
return "Commande " + orderId + " est en cours de livraison, livraison prévue dans 2 jours.";
}
}
description est extrêmement important : le LLM se base sur cette description pour décider s’il doit appeler ce tool et quels paramètres passer.
Service utilisant ChatClient pour attacher les tools à l’agent :
import org.springframework.ai.chat.client.ChatClient;
import org.springframework.stereotype.Service;
@Service
public class OrderAssistantService {
private final ChatClient chatClient;
public OrderAssistantService(ChatClient.Builder builder, OrderTools orderTools) {
this.chatClient = builder
.defaultTools(orderTools)
.build();
}
public String ask(String question) {
return chatClient.prompt(question).call().content();
}
}
Appeler ask("Où est ma commande ORD-1023 ?"), Spring AI fera en arrière-plan :
- Envoyer la question avec la description du tool
getOrderStatusau modèle. - Le modèle retourne la décision « appeler
getOrderStatusavecorderId="ORD-1023"» au lieu de répondre tout de suite. - Spring AI invoque automatiquement la méthode Java correspondante et récupère le résultat.
- Renvoyer le résultat au modèle pour que le modèle écrive la réponse finale en langage naturel.
Votre commande ORD-1023 est actuellement en cours de livraison et devrait être livrée dans 2 jours.
Ces 4 étapes sont exactement une boucle ReAct complète, sauf que Spring AI a caché la boucle for, vous n’avez pas besoin d’écrire la control loop vous-même comme dans l’exemple Java pur de la section 4.
Note : la version
spring-ai-starter-model-openaiet le nom de l’artefact peuvent changer avec le temps ; vérifiez toujours le BOM correspondant à la version de Spring Boot que vous utilisez avant d’ajouter la dépendance.
6. Types d’agents courants
- Single-agent ReAct : un seul agent, itère Thought-Action-Observation. Convient pour des tâches modérées, comme les deux exemples ci-dessus.
- Plan-and-Execute : l’agent établit d’abord un plan détaillé (liste d’étapes), puis l’exécute étape par étape, sans repenser continuellement comme ReAct. Convient pour les tâches multi-étapes avec structure claire (ex : « créer un rapport avec 5 sections »).
- Multi-agent : plusieurs agents spécialisés collaborent, généralement avec un agent « Supervisor » qui coordonne des agents « Worker » (ex : agent de recherche, agent de rédaction, agent de vérification), les résultats étant consolidés.
Le choix du type dépend de la complexité de la tâche : simple, utilisez single-agent ; beaucoup de domaines différents (recherche + rédaction + vérification), divisez en multi-agent pour mieux contrôler et déboguer chaque partie.
7. Erreurs courantes et quand NE PAS utiliser un Agent
- Boucle infinie, consommation de tokens : sans
maxStepsou budget de tokens, l’agent peut boucler indéfiniment parce que le LLM « croit » que le travail n’est pas fini. Toujours définir un nombre d’étapes maximum clair comme dansSimpleAgentà la section 4. - Description du tool floue : si la
descriptiondu tool n’est pas claire, le LLM risque d’appeler le mauvais tool ou de passer des paramètres du mauvais type. Écrire une description spécifique, précisant le format attendu des paramètres. - Manque de garde-fous pour les actions dangereuses : un agent pouvant appeler un tool qui supprime des données, vire de l’argent… sans étape de confirmation est un gros risque. Toujours ajouter une couche d’examen (human-in-the-loop ou vérification basée sur des règles) avant d’exécuter une action irréversible.
- Surengineering pour une tâche simple : si la question n’a besoin que d’un seul appel au LLM pour obtenir une réponse (ex : traduire une phrase), ne construisez pas toute une boucle agent avec tool calling. Ça ajoute de la latence et coûte plus cher en appelant le modèle plusieurs fois inutilement.
Note : si votre système n’a pas besoin d’effectuer des actions externes (API, base de données) et qu’il a juste besoin de générer du texte une fois, c’est un problème pour un LLM ordinaire — pas pour un agent. Ne compliquez pas sans nécessité.
8. Conclusion
Un AI Agent diffère d’un chatbot ordinaire par sa capacité à décider automatiquement d’effectuer des actions et à itérer le processus de raisonnement jusqu’à atteindre l’objectif, basé sur quatre composants : LLM, tool, memory et control loop. La boucle ReAct (Thought-Action-Observation) est le mécanisme le plus courant derrière la plupart des agents actuels, et vous pouvez la simuler vous-même en Java pur pour comprendre les principes avant de passer à des frameworks comme Spring AI pour la production. Le plus important : toujours définir une limite du nombre d’étapes, écrire des descriptions de tool claires, et ajouter des garde-fous pour les actions irréversibles — un agent est puissant mais peut aussi « en faire trop » s’il manque des contrôles.