Introduction
Mastra est le framework TypeScript-first pour construire des agents IA, des workflows et des pipelines RAG. Lancé par les créateurs de Gatsby.js et soutenu par Y Combinator (W25, 13M$), il a atteint 22 000+ étoiles GitHub et 300 000+ téléchargements npm hebdomadaires lors de sa version 1.0 en janvier 2026. Contrairement aux bibliothèques Python-first comme LangChain, Mastra est conçu de zéro pour l'écosystème TypeScript/JavaScript.
Dans ce tutoriel, vous allez construire un agent de support client capable de :
- Chercher dans une base de connaissances (RAG)
- Appeler des API externes comme outils
- Maintenir la mémoire des conversations entre les sessions
- Acheminer des tâches complexes via un workflow multi-étapes
Prérequis
Avant de commencer, assurez-vous d'avoir :
- Node.js 20+ installé (vérifiez avec
node -v) - Un gestionnaire de paquets : npm, pnpm, yarn ou bun
- Une clé API pour un LLM (OpenAI, Anthropic ou l'un des 94+ fournisseurs supportés)
- Des connaissances TypeScript de base
Ce que vous allez construire
Un agent de support complet nommé SupportBot qui gère les questions des utilisateurs, interroge une base de connaissances produit via RAG, remonte les tickets complexes via un workflow structuré et mémorise les conversations passées.
Étape 1 : Configuration du projet
Utilisez le CLI Mastra pour créer un nouveau projet :
npm create mastra@latestL'assistant vous demandera :
- Nom du projet —
support-agent - Fournisseur — choisissez OpenAI ou Anthropic
- Modèle par défaut —
gpt-4oouclaude-sonnet-4-6 - Composants — sélectionnez Agents, Tools, Workflows et Memory
Naviguez dans votre projet et installez les dépendances :
cd support-agent
npm installLa structure de votre projet ressemblera à ceci :
support-agent/
├── src/
│ └── mastra/
│ ├── agents/
│ │ └── support-agent.ts
│ ├── tools/
│ │ └── ticket-tool.ts
│ ├── workflows/
│ │ └── escalation-workflow.ts
│ └── index.ts
├── .env
├── package.json
└── tsconfig.json
Ajoutez votre clé API dans .env :
OPENAI_API_KEY=sk-...
# ou
ANTHROPIC_API_KEY=sk-ant-...Étape 2 : Créer votre premier agent
Ouvrez src/mastra/agents/support-agent.ts et définissez l'agent :
import { Agent } from "@mastra/core/agent";
import { openai } from "@ai-sdk/openai";
import { ticketTool, knowledgeBaseTool } from "../tools/ticket-tool";
export const supportAgent = new Agent({
name: "SupportBot",
instructions: `Vous êtes un agent de support client serviable pour la plateforme Noqta.
Vos responsabilités :
- Répondre aux questions sur la plateforme en utilisant l'outil de base de connaissances
- Créer des tickets de support pour les problèmes non résolus
- Être empathique, concis et orienté solution
- Escalader vers un humain si le problème est critique ou technique`,
model: openai("gpt-4o"),
tools: {
ticketTool,
knowledgeBaseTool,
},
});Étape 3 : Construire des outils personnalisés avec validation Zod
Les outils donnent à votre agent des capacités réelles. Chaque outil utilise Zod pour la validation type-safe des entrées/sorties.
Créez src/mastra/tools/ticket-tool.ts :
import { createTool } from "@mastra/core/tools";
import { z } from "zod";
// Outil pour chercher dans la base de connaissances
export const knowledgeBaseTool = createTool({
id: "search-knowledge-base",
description: "Rechercher dans la FAQ et la documentation du produit pour répondre aux questions",
inputSchema: z.object({
query: z.string().describe("La question de l'utilisateur à rechercher"),
limit: z.number().optional().default(3).describe("Nombre de résultats à retourner"),
}),
outputSchema: z.object({
results: z.array(
z.object({
title: z.string(),
content: z.string(),
relevance: z.number(),
})
),
}),
execute: async ({ context }) => {
const { query, limit } = context;
const results = await searchVectorDB(query, limit);
return { results };
},
});
// Outil pour créer un ticket de support
export const ticketTool = createTool({
id: "create-ticket",
description: "Créer un ticket de support quand un problème ne peut pas être résolu immédiatement",
inputSchema: z.object({
title: z.string().describe("Résumé court du problème"),
description: z.string().describe("Description détaillée du problème"),
priority: z.enum(["low", "medium", "high", "critical"]).describe("Niveau de priorité du problème"),
userEmail: z.string().email().describe("Adresse email du client"),
}),
outputSchema: z.object({
ticketId: z.string(),
status: z.string(),
estimatedResolution: z.string(),
}),
execute: async ({ context }) => {
const { title, description, priority, userEmail } = context;
const ticket = await createSupportTicket({ title, description, priority, userEmail });
return {
ticketId: ticket.id,
status: "created",
estimatedResolution: priority === "critical" ? "2 heures" : "24 heures",
};
},
});
async function searchVectorDB(query: string, limit: number) {
return [{ title: "FAQ", content: "Réponse exemple pour : " + query, relevance: 0.9 }];
}
async function createSupportTicket(data: object) {
return { id: "TKT-" + Math.random().toString(36).substr(2, 8).toUpperCase() };
}Étape 4 : Ajouter une mémoire persistante
Le système de mémoire de Mastra permet aux agents de mémoriser les conversations passées entre les sessions. Configurez-le avec un backend de stockage :
import { Agent } from "@mastra/core/agent";
import { Memory } from "@mastra/memory";
import { LibSQLStore } from "@mastra/memory/storage/libsql";
import { openai } from "@ai-sdk/openai";
const memory = new Memory({
storage: new LibSQLStore({
url: "file:./support-memory.db",
// En production : url: process.env.DATABASE_URL
}),
options: {
lastMessages: 20, // Inclure les 20 derniers messages dans le contexte
semanticRecall: {
topK: 5, // Récupérer les 5 souvenirs les plus pertinents
messageRange: 2, // Fenêtre de contexte autour des souvenirs rappelés
},
},
});
export const supportAgent = new Agent({
name: "SupportBot",
instructions: "...",
model: openai("gpt-4o"),
memory,
tools: { ticketTool, knowledgeBaseTool },
});Appelez l'agent avec un thread ID pour maintenir la continuité de session :
const response = await supportAgent.generate(
"Mon paiement a échoué mais j'ai quand même été débité",
{
resourceId: "user-123", // Identifie l'utilisateur
threadId: "session-456", // Identifie le fil de conversation
}
);
console.log(response.text);Les appels suivants avec le même threadId auront accès à l'historique complet de la conversation.
Étape 5 : Construire un workflow d'escalade multi-étapes
Pour les tâches complexes nécessitant un chemin d'exécution prévisible, utilisez le moteur de workflow Mastra :
import { createWorkflow, createStep } from "@mastra/core/workflows";
import { z } from "zod";
// Étape 1 : Analyser le ticket
const analyzeTicketStep = createStep({
id: "analyze-ticket",
description: "Classifier la priorité et la catégorie du ticket",
inputSchema: z.object({
userMessage: z.string(),
userEmail: z.string().email(),
}),
outputSchema: z.object({
priority: z.enum(["low", "medium", "high", "critical"]),
category: z.string(),
needsEscalation: z.boolean(),
}),
execute: async ({ inputData }) => {
const classification = await classifyWithLLM(inputData.userMessage);
return classification;
},
});
// Étape 2 : Router le ticket
const routeTicketStep = createStep({
id: "route-ticket",
description: "Acheminer le ticket vers la bonne équipe",
inputSchema: z.object({
priority: z.enum(["low", "medium", "high", "critical"]),
category: z.string(),
needsEscalation: z.boolean(),
}),
outputSchema: z.object({
assignedTeam: z.string(),
ticketId: z.string(),
}),
execute: async ({ inputData }) => {
const team = inputData.needsEscalation
? "ingenierie-niveau-2"
: "support-niveau-1";
const ticketId = await assignToTeam(team, inputData);
return { assignedTeam: team, ticketId };
},
});
// Étape 3 : Notifier l'utilisateur
const notifyUserStep = createStep({
id: "notify-user",
description: "Envoyer un email de confirmation à l'utilisateur",
inputSchema: z.object({
assignedTeam: z.string(),
ticketId: z.string(),
}),
outputSchema: z.object({
notificationSent: z.boolean(),
}),
execute: async ({ inputData }) => {
await sendConfirmationEmail(inputData.ticketId, inputData.assignedTeam);
return { notificationSent: true };
},
});
// Composer le workflow
export const escalationWorkflow = createWorkflow({
name: "ticket-escalation",
triggerSchema: z.object({
userMessage: z.string(),
userEmail: z.string().email(),
}),
})
.then(analyzeTicketStep)
.then(routeTicketStep)
.then(notifyUserStep)
.commit();
async function classifyWithLLM(message: string) {
return { priority: "high" as const, category: "billing", needsEscalation: true };
}
async function assignToTeam(team: string, data: object) {
return "TKT-" + Date.now();
}
async function sendConfirmationEmail(ticketId: string, team: string) {
console.log(`Email envoyé pour ${ticketId} à ${team}`);
}Étape 6 : Enregistrer tout dans Mastra
Reliez tous les composants dans src/mastra/index.ts :
import { Mastra } from "@mastra/core";
import { supportAgent } from "./agents/support-agent";
import { escalationWorkflow } from "./workflows/escalation-workflow";
export const mastra = new Mastra({
agents: { supportAgent },
workflows: { escalationWorkflow },
logger: {
type: "CONSOLE",
level: "INFO",
},
});Étape 7 : Tester avec Mastra Studio
Démarrez le serveur de développement et ouvrez Mastra Studio :
npm run devVisitez http://localhost:4111 dans votre navigateur. Mastra Studio vous offre :
- Interface de chat agent — testez votre agent avec de vrais messages
- Visualisateur de workflow — voyez vos étapes comme un organigramme
- Inspecteur d'outils — visualisez les appels d'outils en temps réel
- Navigateur de mémoire — inspectez l'historique des conversations stocké
Testez en envoyant : "Mon paiement a échoué mais j'ai quand même été débité. Mon email est test@example.com."
Observez l'agent :
- Chercher dans la base de connaissances les problèmes de paiement
- Créer automatiquement un ticket de support
- Retourner une réponse empathique avec l'identifiant du ticket
Étape 8 : Déployer en production
Les applications Mastra sont des serveurs Node.js standard. Déployez sur n'importe quel cloud :
Option A : Docker
FROM node:20-alpine
WORKDIR /app
COPY package*.json ./
RUN npm ci --only=production
COPY . .
RUN npm run build
EXPOSE 4111
CMD ["npm", "start"]Option B : Vercel (recommandé pour l'intégration Next.js)
npm install @mastra/vercel-functions
npx vercel deployOption C : Fly.io
fly launch --name support-agent
fly deployDéfinissez vos variables d'environnement sur la plateforme :
# Fly.io
fly secrets set OPENAI_API_KEY=sk-...
# Vercel
vercel env add OPENAI_API_KEYTester votre implémentation
Écrivez des tests d'intégration avec @mastra/testing :
import { createTestRun } from "@mastra/testing";
import { mastra } from "./src/mastra";
const testRun = createTestRun({ mastra });
test("l'agent crée un ticket pour les problèmes de facturation", async () => {
const result = await testRun.agent("supportAgent").generate(
"J'ai été débité deux fois pour le même abonnement",
{ resourceId: "test-user", threadId: "test-thread" }
);
expect(result.toolCalls).toContainEqual(
expect.objectContaining({ toolName: "create-ticket" })
);
expect(result.text).toContain("ticket");
});Dépannage
L'agent n'appelle pas les outils : Assurez-vous que les descriptions des outils sont suffisamment détaillées. Le LLM décide d'appeler un outil en fonction de son champ description — rendez-le spécifique et orienté action.
La mémoire ne persiste pas : Vérifiez que resourceId et threadId sont cohérents entre les appels. Des identifiants différents créent des fils de mémoire séparés.
Erreurs de validation Zod : Quand l'outputSchema d'un outil ne correspond pas à ce que retourne execute, Mastra lève une erreur de validation. Utilisez z.infer pour garder les types alignés.
Studio ne se charge pas : Assurez-vous que le port 4111 est libre. Utilisez MASTRA_PORT=4112 npm run dev pour le changer.
Prochaines étapes
Maintenant que vous avez un agent fonctionnel, envisagez de :
- Ajouter le RAG avec Pinecone — connecter une vraie base de données vectorielle
- Tâches en arrière-plan avec Inngest — exécuter des tâches agent longues de façon asynchrone
- Agents avec état via LangGraph — comparer les paradigmes de workflow
- Explorer la documentation Mastra pour les évaluations, l'observabilité et l'orchestration multi-agents
Conclusion
Mastra apporte l'écosystème TypeScript complet au développement d'agents IA — sécurité des types, validation Zod, outillage familier et intégration transparente avec Next.js et Node.js. À la fin de ce tutoriel, vous avez construit un agent de support prêt pour la production avec des outils, une mémoire persistante et un workflow d'escalade structuré. Ce modèle s'adapte des chatbots simples aux systèmes multi-agents entièrement autonomes servant des milliers d'utilisateurs.