écrits/tutorial/2026/05
Tutorial25 mai 2026·30 min

Construire des agents IA prêts pour la production avec Mastra et TypeScript

Apprenez à construire, déployer et faire évoluer des agents IA prêts pour la production avec Mastra, le framework TypeScript pour l'IA avec plus de 22K étoiles GitHub. Couvre les agents, les outils, la mémoire, les workflows et le RAG.

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@latest

L'assistant vous demandera :

  • Nom du projetsupport-agent
  • Fournisseur — choisissez OpenAI ou Anthropic
  • Modèle par défautgpt-4o ou claude-sonnet-4-6
  • Composants — sélectionnez Agents, Tools, Workflows et Memory

Naviguez dans votre projet et installez les dépendances :

cd support-agent
npm install

La 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 dev

Visitez 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 :

  1. Chercher dans la base de connaissances les problèmes de paiement
  2. Créer automatiquement un ticket de support
  3. 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 deploy

Option C : Fly.io

fly launch --name support-agent
fly deploy

Définissez vos variables d'environnement sur la plateforme :

# Fly.io
fly secrets set OPENAI_API_KEY=sk-...
 
# Vercel
vercel env add OPENAI_API_KEY

Tester 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 :

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.