Microsoft Ship AI Agent Framework: Explication Détaillée
1. Aperçu général
Microsoft vient de lancer officiellement (GA – Disponibilité générale) un framework unifié pour construire, orchestrer et exploiter les AI Agent, en fusionnant deux produits précédents que sont Semantic Kernel et AutoGen. Ce n’est pas seulement une actualité produit — elle redéfinit la façon dont vous devriez concevoir un système où le LLM « décide lui-même des actions » plutôt que de simplement répondre à une question.
Cet article explique en quoi l’AI Agent diffère d’un chatbot classique, ce que Microsoft a exactement déployé, puis vous construirez de vos mains un agent minimaliste avec Java 21 + Spring Boot 3 + Spring AI (intégré à Azure OpenAI) pour comprendre le mécanisme sous-jacent, bien que le framework original de Microsoft s’exécute sur .NET et Python.
2. Qu’est-ce qu’un AI Agent ?
Un chatbot classique reçoit une question, appelle le LLM une fois, retourne une réponse. L’Agent en diffère en ce qu’il itère le cycle de réflexion – action plusieurs fois, décide lui-même s’il faut ou non appeler un tool (API, base de données, fichier…), avant de fournir la réponse finale.
| Caractéristique | Chatbot | AI Agent |
|---|---|---|
| Nombre d’appels LLM | 1 fois/question | Plusieurs fois, itération autonome |
| Utilisation d’outils externes | Généralement non | Oui, outil sélectionné par le modèle |
| État | Sans état ou historique de conversation stocké | Avec mémoire, point de contrôle possible |
| Latence | Faible | Plus élevée (plusieurs allers-retours) |
| Fiabilité | Facile à contrôler | Nécessite des guardrail, intervention humaine |
2.1. La boucle Reason–Act (ReAct)
Le mécanisme central qu’utilisent la plupart des frameworks d’agent aujourd’hui est ReAct : le modèle « pense » (Thought), choisit une action (Action) c’est appeler un tool, reçoit le résultat (Observation), puis itère jusqu’à avoir suffisamment d’informations pour répondre (Final Answer).
Thought: L'utilisateur demande le statut de la commande ORD-001, je dois vérifier.
Action: lookupOrder("ORD-001")
Observation: Commande ORD-001 : statut SHIPPED, montant total 450000 VND
Thought: J'ai assez d'informations.
Final Answer: Votre commande ORD-001 est en cours de livraison, montant total 450.000đ.
C’est la partie que Microsoft Agent Framework (et Spring AI que vous utiliserez ci-dessous) automatise — vous n’avez pas besoin d’écrire cette boucle manuellement, il suffit de déclarer les outils et le prompt système.
3. Ce que Microsoft a déployé pour les AI Agent
Avant la fusion, Microsoft avait deux directions de développement en parallèle :
- Semantic Kernel : SDK orienté production, met l’accent sur les plugins type-safe, intégration d’entreprise (Azure, .NET), convient au déploiement stable.
- AutoGen : orientée recherche, forte sur la conversation multi-agent — plusieurs agents « discutent » ensemble pour résoudre des tâches complexes.
Le nouveau framework fusionne les deux points forts, comprenant les capacités principales :
- Modèles d’orchestration prêts à l’emploi : séquentiel (l’agent A termine, puis B), concurrent (plusieurs agents s’exécutent en parallèle, puis synthèse), hand-off (l’agent transfère la tâche à un agent spécialisé), group chat (plusieurs agents discutent avant de répondre).
- Exécution durable/avec état : l’agent peut faire un point de contrôle au milieu, reprendre si le processus plante — important pour les tâches longues (quelques minutes à quelques heures).
- Observabilité intégrée : traçage selon la norme OpenTelemetry, vous pouvez voir chaque étape Thought/Action/Observation en production.
- Human-in-the-loop : mettre l’agent en pause en attente d’approbation, avant d’exécuter des actions sensibles (remboursement, suppression de données…).
- Azure AI Foundry Agent Service : runtime hébergé pour déployer l’agent, avec un catalogue d’outils prêts (Bing search, code interpreter, file retrieval) et supporte Model Context Protocol (MCP) pour connecter les outils externes selon un standard ouvert, sans verrouillage fournisseur.
Le framework original s’exécute sur .NET/Python, mais les modèles sont universels. La section suivante réimplémente ce modèle exact en Java pour que vous voyiez comment il fonctionne au niveau du code.
4. L’architecture core d’un AI Agent
Un agent minimaliste a besoin de 4 composants : Planner (c’est le LLM), Tool (fonction que l’agent peut appeler), Memory (historique de conversation/résultats des outils), Executor (boucle d’orchestration). Spring AI encapsule déjà Executor et Planner via ChatClient, vous devez seulement déclarer les outils.
4.1. Dépendance Maven
<dependency>
<groupId>org.springframework.ai</groupId>
<artifactId>spring-ai-azure-openai-spring-boot-starter</artifactId>
<version>1.0.0</version>
</dependency>
Configuration de la connexion à Azure OpenAI (service GPT de Microsoft, déployé via Azure) :
spring.ai.azure.openai.api-key=${AZURE_OPENAI_KEY}
spring.ai.azure.openai.endpoint=${AZURE_OPENAI_ENDPOINT}
spring.ai.azure.openai.chat.options.deployment-name=gpt-4o-mini
4.2. Définition des Tools pour l’agent
Un Tool est une méthode Java ordinaire, marquée @Tool pour que le modèle sache qu’il peut l’appeler, et sait avec quels paramètres l’appeler.
public record Order(String id, String status, BigDecimal total) {}
public interface OrderService {
Order findById(String orderId);
}
@Service
public class OrderTools {
private final OrderService orderService;
public OrderTools(OrderService orderService) {
this.orderService = orderService;
}
@Tool(description = "Consulter le statut et le montant total d'une commande par code de commande")
public String lookupOrder(String orderId) {
Order order = orderService.findById(orderId);
return "Commande %s : statut %s, montant total %s VND"
.formatted(order.id(), order.status(), order.total());
}
}
description dans @Tool est ce que le modèle lit pour décider s’il faut ou non appeler lookupOrder — écrivez une description claire et spécifique, l’agent choisira l’outil plus précisément.
4.3. L’Agent appelle automatiquement les outils via ChatClient
@Service
public class SupportAgentService {
private final ChatClient chatClient;
public SupportAgentService(ChatClient.Builder builder, OrderTools orderTools) {
this.chatClient = builder
.defaultSystem("""
Vous êtes un assistant support client d'un shop en ligne.
Si la question concerne une commande, utilisez l'outil lookupOrder.
Répondez brièvement, amicalement, en français.
""")
.defaultTools(orderTools)
.build();
}
public String handle(String userMessage) {
return chatClient.prompt()
.user(userMessage)
.call()
.content();
}
}
La ligne .defaultTools(orderTools) enregistre l’ensemble des outils, ChatClient exécute automatiquement la boucle ReAct en interne : envoie le prompt avec la liste des outils au modèle, si le modèle demande d’appeler lookupOrder, Spring AI exécute automatiquement la méthode Java correspondante, retourne le résultat (Observation) au modèle, puis reçoit la réponse finale. Vous n’écrivez pas la boucle manuellement — c’est exactement ce que Microsoft Agent Framework et Spring AI font de la même manière en essence.
> handle("Où est ma commande ORD-001 ?")
Votre commande ORD-001 est en cours de livraison (SHIPPED), montant total 450.000đ !
Remarque : Le modèle n’appelle un outil que s’il « décide » d’en avoir besoin — toutes les questions n’activent pas un outil. Si l’utilisateur demande « livrez-vous à l’international ? », le modèle répondra directement sans appeler
lookupOrder.
5. Multi-agent : quand un agent ne suffit pas
L’une des capacités remarquables que Microsoft propose est le hand-off — transférer la conversation entre les agents spécialisés. Pour les petits problèmes, vous pouvez simuler avec un routeur simple, sans avoir besoin d’un framework multi-agent complexe :
@Service
public class AgentRouter {
private final SupportAgentService orderAgent;
private final RefundAgentService refundAgent;
public AgentRouter(SupportAgentService orderAgent, RefundAgentService refundAgent) {
this.orderAgent = orderAgent;
this.refundAgent = refundAgent;
}
public String route(String userMessage) {
String lower = userMessage.toLowerCase();
if (lower.contains("remboursement") || lower.contains("refund")) {
return refundAgent.handle(userMessage);
}
return orderAgent.handle(userMessage);
}
}
Ce routeur joue le rôle d’un « orchestrator » minimaliste. À plus grande échelle, le choix du quel agent traite devrait être laissé au LLM lui-même (classification d’intention par modèle), au lieu de hard-coder contains() — l’écriture manuelle ne convient que pour les démos ou les ensembles d’intentions très petits et stables.
6. Écrire des tests pour les outils et l’agent
La partie la plus facile à tester dans un système d’agent est l’outil — parce que c’est une pure méthode Java, ne dépend pas du LLM. Vous devez tester cette partie en profondeur, car l’agent n’est « intelligent » que dans la mesure où les outils qu’il appelle sont de qualité.
class OrderToolsTest {
@Test
void shouldReturnOrderSummaryWithStatusAndTotal() {
OrderService fakeOrderService = orderId ->
new Order(orderId, "SHIPPED", new BigDecimal("450000"));
OrderTools tools = new OrderTools(fakeOrderService);
String result = tools.lookupOrder("ORD-001");
assertThat(result)
.contains("ORD-001")
.contains("SHIPPED")
.contains("450000");
}
}
Comme OrderService n’a qu’une seule méthode findById, j’utilise une lambda pour faire une fausse implémentation, plutôt que d’avoir besoin d’une dépendance de framework de mocking — concis et suffisant pour ce test unitaire.
class AgentRouterTest {
@Test
void shouldRouteRefundKeywordToRefundAgent() {
SupportAgentService orderAgent = mock(SupportAgentService.class);
RefundAgentService refundAgent = mock(RefundAgentService.class);
when(refundAgent.handle(anyString())).thenReturn("Demande de remboursement enregistrée");
AgentRouter router = new AgentRouter(orderAgent, refundAgent);
String result = router.route("Je veux un remboursement pour la commande ORD-002");
assertThat(result).isEqualTo("Demande de remboursement enregistrée");
verify(refundAgent).handle(anyString());
verify(orderAgent, never()).handle(anyString());
}
}
Remarque : Vous ne devriez pas écrire de test « end-to-end appelant le vrai LLM » dans un test unitaire — le résultat n’est pas déterministe (le modèle peut répondre différemment chaque fois), coûte de l’argent pour appeler l’API, et rend CI lent/instable. Mockez ChatClient ou testez séparément la partie outil/routeur comme ci-dessus ; réservez un ensemble de tests d’intégration séparés (exécution manuelle ou nocturne) pour vérifier que l’agent choisit le bon outil dans des scénarios réels.
7. Erreurs courantes et quand ne pas utiliser d’agent
- Utiliser un agent pour ce qui peut être résolu par if-else : si la logique de sélection d’action est prédéterminée et fixe (exemple : toujours vérifier la commande quand il y a un code de commande sous la forme
ORD-\d+), écrire du code est généralement moins cher, plus rapide et beaucoup plus facile à tester, par rapport à laisser le LLM « réfléchir » chaque fois. - Ignorer les guardrail pour les actions sensibles : l’agent est autorisé à appeler des outils pour supprimer des données, rembourser, envoyer des emails aux clients — s’il n’y a pas d’étape de confirmation (human-in-the-loop) ou de limitation des permissions des outils, une injection de prompt ou une erreur de raisonnement du modèle peut causer des conséquences réelles.
- Ne pas limiter le nombre de boucles : si le modèle continue de choisir le mauvais outil ou n’a pas assez de données pour conclure, la boucle ReAct peut boucler indéfiniment, coûte des tokens et de l’argent. Définissez toujours un nombre d’étapes maximum et un timeout.
- Manque d’observabilité : quand l’agent répond mal, vous devez pouvoir revoir toute la chaîne Thought/Action/Observation pour déboguer — sans journalisation/traçage détaillé, il est presque impossible de découvrir ce que le modèle « pensait », conduisant au résultat incorrect.
- Latence et coût : chaque étape de la boucle est un appel au LLM. Une simple question peut coûter 2-3 appels au modèle (et chaque appel prend de quelques centaines de millisecondes à quelques secondes). Pour une API nécessitant une réponse instantanée (par exemple moins de 200ms), ce type d’agent ne convient pas.
8. Conclusion
Le fait que Microsoft fusionne Semantic Kernel et AutoGen en un seul framework montre une tendance claire : l’AI Agent passe de « démo intéressante » à une infrastructure de production, nécessite orchestration, état, observabilité et contrôle d’accès strict, comme tout autre système d’entreprise. Que vous utilisiez .NET, Python ou Java/Spring AI comme dans cet exemple, l’essence de l’architecture tourne toujours autour de quatre blocs : Planner, Tool, Memory, Executor — maîtriser ces quatre blocs, vous pouvez comprendre et appliquer n’importe quel framework d’agent qui apparaît à l’avenir.