Du chatbot a l'agent
Jusqu'ici, le LLM fait une seule chose : generer du texte. Il peut repondre a des questions, mais il ne peut pas agir. Il ne peut pas envoyer un email, chercher sur le web, ni appeler une API de comparaison d'offres.
Chatbot vs Agent
CHATBOT (sans tools) AGENT (avec tools)
────────────────── ─────────────────
User → LLM → Texte User → LLM → "je dois chercher"
→ [appel outil: search]
→ resultats
→ LLM → "je dois calculer"
→ [appel outil: calculate]
→ resultat
→ LLM → Reponse finale
Tool calling — donner des outils au LLM
Voici comment ca marche concretement avec le Vercel AI SDK.
Tu definis les outils disponibles
Chaque outil a un nom, une description (pour que le LLM sache quand l'utiliser), un schema d'entree (Zod), et une fonction d'execution.
Le LLM decide d'appeler un outil
En se basant sur la description de l'outil et le contexte de la conversation, le LLM produit un "tool call" : le nom de l'outil + les parametres.
Ton code execute l'outil
Le SDK intercepte le tool call, execute ta fonction, et renvoie le resultat au LLM.
Le LLM integre le resultat
Le LLM recoit le resultat de l'outil et genere sa reponse finale en l'integrant.
import { generateText, tool } from "ai";
import { z } from "zod";
const result = await generateText({
model: "anthropic/claude-sonnet-4.6",
tools: {
comparerOffres: tool({
description: "Compare les offres d'electricite pour une adresse et une consommation donnees",
inputSchema: z.object({
codePostal: z.string().describe("Code postal du logement"),
consommationKwh: z.number().describe("Consommation annuelle en kWh"),
type: z.enum(["electricite", "gaz"]).describe("Type d'energie"),
}),
execute: async ({ codePostal, consommationKwh, type }) => {
// En prod, ca appelle une vraie API
return {
offres: [
{ fournisseur: "TotalEnergies", prix: 0.19, abonnement: 12, total: consommationKwh * 0.19 + 144 },
{ fournisseur: "Engie", prix: 0.21, abonnement: 10, total: consommationKwh * 0.21 + 120 },
{ fournisseur: "EDF", prix: 0.22, abonnement: 11, total: consommationKwh * 0.22 + 132 },
]
};
},
}),
},
prompt: "Je consomme 6000 kWh par an et j'habite a Lyon (69000). Quelle est la meilleure offre d'electricite ?",
});
// Le LLM va :
// 1. Voir qu'il a un outil "comparerOffres" qui correspond au besoin
// 2. L'appeler avec { codePostal: "69000", consommationKwh: 6000, type: "electricite" }
// 3. Recevoir les 3 offres
// 4. Presenter la meilleure au clientLa boucle agent : reflexion → action → observation
Un agent, c'est un LLM qui peut appeler des outils en bouclejusqu'a ce qu'il ait assez d'information pour repondre. C'est la difference entre un tool call unique et un vrai agent.
Boucle agent (ReAct pattern)
┌─────────────────────────────┐
│ │
▼ │
[ REFLEXION ] │
"De quoi ai-je besoin ?" │
| │
[ ACTION ] │
Appeler un outil │
| │
[ OBSERVATION ] │
Lire le resultat │
| │
Ai-je assez d'info ? ──── NON ────────┘
|
OUI
|
[ REPONSE FINALE ]
Exemple concret pour Selectra :
Client: "J'habite au 12 rue de la Paix a Paris, je veux changer de fournisseur"
── Step 1 (Reflexion) ──
Agent: Je dois d'abord trouver le numero PDL de cette adresse.
── Step 1 (Action) ──
→ Tool call: chercherPDL({ adresse: "12 rue de la Paix, 75002 Paris" })
── Step 1 (Observation) ──
← Resultat: { pdl: "09876543210987", puissance: 6, compteur: "Linky" }
── Step 2 (Reflexion) ──
Agent: J'ai le PDL. Maintenant j'ai besoin de la consommation pour comparer.
Le client ne me l'a pas dit. Je vais estimer avec la puissance.
── Step 2 (Action) ──
→ Tool call: estimerConsommation({ puissance: 6, type: "appartement", ville: "Paris" })
── Step 2 (Observation) ──
← Resultat: { estimationKwh: 5500 }
── Step 3 (Reflexion) ──
Agent: J'ai le PDL et la conso. Je peux comparer les offres.
── Step 3 (Action) ──
→ Tool call: comparerOffres({ codePostal: "75002", consommationKwh: 5500, type: "electricite" })
── Step 3 (Observation) ──
← Resultat: { offres: [...] }
── Step 4 (Reponse finale) ──
Agent: "Voici les 3 meilleures offres pour votre logement au 12 rue de la Paix..."L'agent a fait 3 appels d'outils de sa propre initiative, chacun base sur le resultat du precedent. C'est ca la puissance de la boucle agent.
L'Agent class du AI SDK
Le Vercel AI SDK fournit une classe Agentqui gere la boucle automatiquement. Plus besoin d'ecrire la boucle manuellement.
import { Agent, tool, stepCountIs } from "ai";
import { z } from "zod";
const selectraAgent = new Agent({
model: "anthropic/claude-sonnet-4.6",
instructions: `Tu es l'agent de qualification Selectra.
Tu collectes les informations du client et cherches les meilleures offres.
Utilise les outils disponibles pour trouver le PDL, estimer la conso, et comparer les offres.
Pose UNE question a la fois au client.`,
tools: {
chercherPDL: tool({
description: "Recherche le numero PDL a partir d'une adresse",
inputSchema: z.object({
adresse: z.string().describe("Adresse complete du logement"),
}),
execute: async ({ adresse }) => {
// Appel API Enedis/Grdf
return { pdl: "09876543210987", puissance: 6 };
},
}),
comparerOffres: tool({
description: "Compare les offres d'energie pour un client",
inputSchema: z.object({
codePostal: z.string(),
consommationKwh: z.number(),
}),
execute: async ({ codePostal, consommationKwh }) => {
// Appel API comparateur Selectra
return { offres: [/* ... */] };
},
}),
transfererConseiller: tool({
description: "Transfere le client a un conseiller humain avec les infos collectees",
inputSchema: z.object({
ficheClient: z.object({
nom: z.string().optional(),
adresse: z.string(),
pdl: z.string(),
intent: z.string(),
offresProposees: z.array(z.string()),
}),
}),
execute: async ({ ficheClient }) => {
// Envoie la fiche au CRM
return { status: "transfert_en_cours", conseiller: "Marie D." };
},
}),
},
});
// Utilisation
const result = await selectraAgent.generate({
prompt: "Bonjour, je demenage au 42 rue Victor Hugo a Lyon",
stopWhen: stepCountIs(10), // max 10 etapes
});| Concept | Avant (manuel) | Avec Agent class |
|---|---|---|
| Boucle | While loop que tu ecris toi-meme | Geree automatiquement |
| Condition d'arret | if (pas de tool call) break | stopWhen: stepCountIs(N) |
| System prompt | Dans streamText() | instructions: dans le constructeur |
| Streaming | streamText() + gestion manuelle | agent.stream() |
MCP — le protocole universel pour les outils
Jusqu'ici, tu definis tes outils dans le code. Mais imagine que tu veux donner a ton agent acces a 50 outils provenant de services differents (Slack, Google Calendar, CRM, etc.). Definir chaque tool manuellement, c'est penible.
Architecture MCP
┌──────────────┐ ┌──────────────────┐ │ Ton Agent │────▶│ MCP Server: CRM │ │ (AI SDK) │ │ - getClient() │ │ │ │ - updateFiche() │ │ │ └──────────────────┘ │ │ │ │ ┌──────────────────┐ │ │────▶│ MCP Server: Slack│ │ │ │ - sendMessage() │ │ │ │ - getChannel() │ │ │ └──────────────────┘ │ │ │ │ ┌──────────────────┐ │ │────▶│ MCP Server: Vercel│ │ │ │ - listDeploys() │ └──────────────┘ └──────────────────┘ L'agent peut utiliser les outils de TOUS les serveurs connectes.
Pour Selectra, tu pourrais imaginer un serveur MCP qui expose les outils du CRM interne : recherche client, mise a jour fiche, historique des appels, etc. L'agent vocal s'y connecte et a acces a tout sans code supplementaire.
Patterns d'agents en production
| Pattern | Description | Cas d'usage Selectra |
|---|---|---|
| Router | L'agent detecte l'intent et route vers le bon sous-agent | Intent classifier → agent nouveau_logement OU agent changement OU agent suivi |
| Sequential | Les etapes s'executent dans l'ordre | Qualification → Comparaison → Presentation → Transfert |
| Parallel | Plusieurs outils appeles en parallele | Chercher PDL + estimer conso en meme temps |
| Human-in-the-loop | L'agent demande validation avant d'agir | "Je vous transfère à un conseiller. C'est OK ?" |
Quiz final
Module 04 termine
Tu maitrises le tool calling, la boucle agent, l'Agent class, et MCP. Tu as vu comment l'agent Selectra utilise 3 outils en sequence pour qualifier un client. Prochain module : Agents Vocaux — on assemble tout pour construire l'agent qui parle.