Mistral AI API avec TypeScript : Créer des Applications Intelligentes

Mistral AI, la startup française devenue l'un des leaders mondiaux de l'IA générative, propose des modèles de langage performants et accessibles via une API simple. Dans ce tutoriel, nous allons explorer comment intégrer l'API Mistral AI dans une application TypeScript, en couvrant le chat conversationnel, la génération structurée, les appels de fonctions (function calling) et la recherche augmentée par génération (RAG).
Pourquoi Mistral AI ? Les modèles Mistral offrent un excellent rapport qualité-prix, une faible latence, et sont disponibles en open-weight. Mistral Large rivalise avec GPT-4 et Claude sur de nombreux benchmarks, tandis que Mistral Small est idéal pour les tâches rapides à moindre coût.
Ce que vous allez apprendre
- Configurer le SDK Mistral AI avec TypeScript
- Créer un chatbot conversationnel avec historique
- Utiliser la génération structurée (JSON mode)
- Implémenter le function calling pour connecter votre IA au monde réel
- Construire un système RAG simple avec les embeddings Mistral
- Gérer le streaming de réponses pour une UX fluide
- Bonnes pratiques de production (rate limiting, gestion des erreurs, coûts)
Prérequis
Avant de commencer, assurez-vous d'avoir :
- Node.js 20+ installé
- TypeScript 5+ configuré
- Un compte Mistral AI avec une clé API (créez-en un sur console.mistral.ai)
- Connaissances de base en TypeScript et async/await
- Un éditeur de code (VS Code recommandé)
Les modèles Mistral en 2026
Mistral propose plusieurs modèles adaptés à différents cas d'usage :
| Modèle | Cas d'usage | Contexte | Points forts |
|---|---|---|---|
| Mistral Large | Raisonnement complexe, code | 128K tokens | Performances proches de GPT-4o |
| Mistral Medium | Usage général | 32K tokens | Bon équilibre coût/performance |
| Mistral Small | Tâches simples, classification | 32K tokens | Très rapide, économique |
| Codestral | Génération de code | 32K tokens | Spécialisé code, FIM support |
| Mistral Embed | Embeddings | 8K tokens | Recherche sémantique |
Étape 1 : Initialisation du projet
Créons un projet TypeScript propre avec toutes les dépendances nécessaires :
mkdir mistral-ts-app && cd mistral-ts-app
npm init -y
npm install @mistralai/mistralai zod dotenv
npm install -D typescript tsx @types/nodeInitialisez la configuration TypeScript :
npx tsc --initModifiez votre tsconfig.json pour un setup moderne :
{
"compilerOptions": {
"target": "ES2022",
"module": "ESNext",
"moduleResolution": "bundler",
"strict": true,
"esModuleInterop": true,
"outDir": "./dist",
"rootDir": "./src",
"resolveJsonModule": true,
"declaration": true
},
"include": ["src/**/*"]
}Créez la structure du projet :
mkdir -p src/{chat,structured,functions,rag,utils}Étape 2 : Configuration du client Mistral
Créez un fichier .env à la racine du projet :
MISTRAL_API_KEY=votre_cle_api_iciPuis créez le client Mistral dans src/utils/client.ts :
// src/utils/client.ts
import { Mistral } from "@mistralai/mistralai";
import dotenv from "dotenv";
dotenv.config();
const apiKey = process.env.MISTRAL_API_KEY;
if (!apiKey) {
throw new Error(
"MISTRAL_API_KEY manquante. Ajoutez-la dans votre fichier .env"
);
}
export const mistral = new Mistral({ apiKey });
// Modèles disponibles
export const MODELS = {
LARGE: "mistral-large-latest",
MEDIUM: "mistral-medium-latest",
SMALL: "mistral-small-latest",
CODESTRAL: "codestral-latest",
EMBED: "mistral-embed",
} as const;Testons rapidement la connexion :
// src/test-connection.ts
import { mistral, MODELS } from "./utils/client";
async function testConnection() {
const response = await mistral.chat.complete({
model: MODELS.SMALL,
messages: [
{ role: "user", content: "Réponds en un mot : ça marche ?" },
],
});
console.log("Réponse:", response.choices?.[0]?.message?.content);
}
testConnection();Exécutez avec :
npx tsx src/test-connection.tsÉtape 3 : Chatbot conversationnel avec historique
Construisons un chatbot qui maintient le contexte de la conversation :
// src/chat/chatbot.ts
import { mistral, MODELS } from "../utils/client";
import readline from "readline";
interface Message {
role: "system" | "user" | "assistant";
content: string;
}
class MistralChatbot {
private history: Message[] = [];
private model: string;
constructor(systemPrompt: string, model = MODELS.LARGE) {
this.model = model;
this.history.push({
role: "system",
content: systemPrompt,
});
}
async chat(userMessage: string): Promise<string> {
this.history.push({ role: "user", content: userMessage });
const response = await mistral.chat.complete({
model: this.model,
messages: this.history,
temperature: 0.7,
maxTokens: 1024,
});
const assistantMessage =
response.choices?.[0]?.message?.content ?? "";
this.history.push({
role: "assistant",
content: assistantMessage,
});
return assistantMessage;
}
// Limiter l'historique pour éviter de dépasser le contexte
trimHistory(maxMessages: number = 20) {
if (this.history.length > maxMessages + 1) {
const systemMessage = this.history[0];
this.history = [
systemMessage,
...this.history.slice(-(maxMessages)),
];
}
}
}
// Interface terminal interactive
async function main() {
const bot = new MistralChatbot(
"Tu es un assistant technique expert en développement web. " +
"Tu réponds de manière concise et précise en français."
);
const rl = readline.createInterface({
input: process.stdin,
output: process.stdout,
});
console.log("Chatbot Mistral prêt ! Tapez 'quit' pour quitter.\n");
const askQuestion = () => {
rl.question("Vous: ", async (input) => {
if (input.toLowerCase() === "quit") {
rl.close();
return;
}
const response = await bot.chat(input);
console.log(`\nAssistant: ${response}\n`);
bot.trimHistory();
askQuestion();
});
};
askQuestion();
}
main();Lancez le chatbot :
npx tsx src/chat/chatbot.tsÉtape 4 : Streaming de réponses
Pour une expérience utilisateur fluide, les réponses peuvent être streamées token par token :
// src/chat/streaming.ts
import { mistral, MODELS } from "../utils/client";
async function streamChat(prompt: string) {
const stream = await mistral.chat.stream({
model: MODELS.LARGE,
messages: [
{
role: "system",
content: "Tu es un assistant créatif qui écrit des histoires courtes.",
},
{ role: "user", content: prompt },
],
});
process.stdout.write("Assistant: ");
for await (const event of stream) {
const content = event.data?.choices?.[0]?.delta?.content;
if (content) {
process.stdout.write(content);
}
}
console.log("\n");
}
streamChat(
"Raconte une histoire de 3 phrases sur un développeur qui découvre l'IA."
);Performance : Le streaming réduit le temps perçu de réponse car l'utilisateur voit les premiers tokens immédiatement, au lieu d'attendre la génération complète.
Étape 5 : Génération structurée (JSON Mode)
L'un des atouts de Mistral est la capacité de générer des réponses JSON structurées, parfait pour les APIs :
// src/structured/json-generation.ts
import { mistral, MODELS } from "../utils/client";
import { z } from "zod";
// Définir le schéma de sortie avec Zod
const ProductReviewSchema = z.object({
sentiment: z.enum(["positif", "négatif", "neutre"]),
score: z.number().min(0).max(10),
points_forts: z.array(z.string()),
points_faibles: z.array(z.string()),
resume: z.string(),
});
type ProductReview = z.infer<typeof ProductReviewSchema>;
async function analyzeReview(reviewText: string): Promise<ProductReview> {
const response = await mistral.chat.complete({
model: MODELS.LARGE,
messages: [
{
role: "system",
content: `Tu es un analyseur de reviews produit.
Réponds UNIQUEMENT en JSON valide avec ce format exact :
{
"sentiment": "positif" | "négatif" | "neutre",
"score": number (0-10),
"points_forts": string[],
"points_faibles": string[],
"resume": string
}`,
},
{
role: "user",
content: `Analyse cette review : "${reviewText}"`,
},
],
responseFormat: { type: "json_object" },
temperature: 0.1,
});
const content = response.choices?.[0]?.message?.content ?? "{}";
const parsed = JSON.parse(content);
// Valider avec Zod
return ProductReviewSchema.parse(parsed);
}
async function main() {
const reviews = [
"Excellent produit ! La qualité est au rendez-vous, livraison rapide. Seul bémol, le prix est un peu élevé.",
"Très déçu. Le produit ne correspond pas à la description, et le service client est inexistant.",
"Correct pour le prix. Rien d'exceptionnel mais fait le travail.",
];
for (const review of reviews) {
console.log(`\nReview: "${review.substring(0, 50)}..."`);
const analysis = await analyzeReview(review);
console.log("Analyse:", JSON.stringify(analysis, null, 2));
}
}
main();Étape 6 : Function Calling (appels de fonctions)
Le function calling permet à Mistral d'invoquer des fonctions de votre code pour interagir avec le monde extérieur. C'est la fonctionnalité clé pour construire des agents IA :
// src/functions/weather-agent.ts
import { mistral, MODELS } from "../utils/client";
// Définir les outils disponibles
const tools = [
{
type: "function" as const,
function: {
name: "get_weather",
description: "Obtenir la météo actuelle pour une ville donnée",
parameters: {
type: "object",
properties: {
city: {
type: "string",
description: "Le nom de la ville (ex: Paris, Tunis)",
},
unit: {
type: "string",
enum: ["celsius", "fahrenheit"],
description: "Unité de température",
},
},
required: ["city"],
},
},
},
{
type: "function" as const,
function: {
name: "get_exchange_rate",
description: "Obtenir le taux de change entre deux devises",
parameters: {
type: "object",
properties: {
from: { type: "string", description: "Devise source (ex: EUR)" },
to: { type: "string", description: "Devise cible (ex: TND)" },
},
required: ["from", "to"],
},
},
},
];
// Implémentations des fonctions
function getWeather(city: string, unit = "celsius") {
// En production, appelez une vraie API météo
const mockData: Record<string, { temp: number; condition: string }> = {
tunis: { temp: 24, condition: "Ensoleillé" },
paris: { temp: 15, condition: "Nuageux" },
london: { temp: 12, condition: "Pluvieux" },
};
const data = mockData[city.toLowerCase()] ?? {
temp: 20,
condition: "Inconnu",
};
return JSON.stringify({
city,
temperature: data.temp,
unit,
condition: data.condition,
});
}
function getExchangeRate(from: string, to: string) {
const rates: Record<string, number> = {
"EUR-TND": 3.35,
"USD-TND": 3.10,
"EUR-USD": 1.08,
};
const key = `${from.toUpperCase()}-${to.toUpperCase()}`;
const rate = rates[key] ?? 1.0;
return JSON.stringify({ from, to, rate, timestamp: new Date().toISOString() });
}
// Dispatcher de fonctions
function executeFunction(name: string, args: string): string {
const parsedArgs = JSON.parse(args);
switch (name) {
case "get_weather":
return getWeather(parsedArgs.city, parsedArgs.unit);
case "get_exchange_rate":
return getExchangeRate(parsedArgs.from, parsedArgs.to);
default:
return JSON.stringify({ error: `Fonction inconnue: ${name}` });
}
}
async function agentChat(userMessage: string) {
console.log(`\nUtilisateur: ${userMessage}`);
const messages: any[] = [
{
role: "system",
content:
"Tu es un assistant qui peut consulter la météo et les taux de change. " +
"Utilise les outils disponibles pour répondre avec des données précises.",
},
{ role: "user", content: userMessage },
];
// Première requête : le modèle décide s'il faut appeler des fonctions
let response = await mistral.chat.complete({
model: MODELS.LARGE,
messages,
tools,
});
let choice = response.choices?.[0];
// Boucle d'exécution des fonctions
while (choice?.finishReason === "tool_calls" && choice.message?.toolCalls) {
const toolCalls = choice.message.toolCalls;
// Ajouter le message de l'assistant avec les appels de fonctions
messages.push(choice.message);
// Exécuter chaque fonction appelée
for (const toolCall of toolCalls) {
const functionName = toolCall.function.name;
const functionArgs = toolCall.function.arguments;
console.log(` [Appel] ${functionName}(${functionArgs})`);
const result = executeFunction(functionName, functionArgs);
messages.push({
role: "tool",
toolCallId: toolCall.id,
content: result,
});
}
// Renvoyer les résultats au modèle
response = await mistral.chat.complete({
model: MODELS.LARGE,
messages,
tools,
});
choice = response.choices?.[0];
}
console.log(`Assistant: ${choice?.message?.content}\n`);
}
async function main() {
await agentChat("Quel temps fait-il à Tunis et quel est le taux EUR/TND ?");
await agentChat("Compare la météo entre Paris et Tunis.");
}
main();Sécurité : En production, validez toujours les arguments des fonctions avant de les exécuter. Ne faites jamais confiance aux entrées du modèle sans validation — utilisez Zod ou un autre validateur de schéma.
Étape 7 : RAG avec les Embeddings Mistral
La Retrieval-Augmented Generation (RAG) permet de répondre à des questions en s'appuyant sur vos propres documents. Voici une implémentation complète :
// src/rag/vector-store.ts
interface Document {
id: string;
content: string;
metadata: Record<string, string>;
embedding?: number[];
}
// Calcul de similarité cosinus
function cosineSimilarity(a: number[], b: number[]): number {
let dotProduct = 0;
let normA = 0;
let normB = 0;
for (let i = 0; i < a.length; i++) {
dotProduct += a[i] * b[i];
normA += a[i] * a[i];
normB += b[i] * b[i];
}
return dotProduct / (Math.sqrt(normA) * Math.sqrt(normB));
}
export class SimpleVectorStore {
private documents: Document[] = [];
add(doc: Document) {
this.documents.push(doc);
}
search(queryEmbedding: number[], topK = 3): Document[] {
const scored = this.documents
.filter((doc) => doc.embedding)
.map((doc) => ({
doc,
score: cosineSimilarity(queryEmbedding, doc.embedding!),
}))
.sort((a, b) => b.score - a.score);
return scored.slice(0, topK).map((s) => s.doc);
}
}Maintenant, le système RAG complet :
// src/rag/rag-system.ts
import { mistral, MODELS } from "../utils/client";
import { SimpleVectorStore } from "./vector-store";
class MistralRAG {
private store = new SimpleVectorStore();
// Générer les embeddings pour un texte
async embed(texts: string[]): Promise<number[][]> {
const response = await mistral.embeddings.create({
model: MODELS.EMBED,
inputs: texts,
});
return response.data.map((d) => d.embedding);
}
// Indexer des documents
async indexDocuments(
documents: { id: string; content: string; metadata: Record<string, string> }[]
) {
const contents = documents.map((d) => d.content);
const embeddings = await this.embed(contents);
documents.forEach((doc, i) => {
this.store.add({
...doc,
embedding: embeddings[i],
});
});
console.log(`${documents.length} documents indexés.`);
}
// Répondre à une question avec le contexte
async query(question: string): Promise<string> {
// 1. Encoder la question
const [queryEmbedding] = await this.embed([question]);
// 2. Chercher les documents pertinents
const relevantDocs = this.store.search(queryEmbedding, 3);
const context = relevantDocs
.map((doc) => `[${doc.metadata.source}]\n${doc.content}`)
.join("\n\n---\n\n");
// 3. Générer la réponse avec le contexte
const response = await mistral.chat.complete({
model: MODELS.LARGE,
messages: [
{
role: "system",
content: `Tu es un assistant qui répond aux questions en te basant UNIQUEMENT sur le contexte fourni. Si le contexte ne contient pas la réponse, dis-le clairement.
Contexte :
${context}`,
},
{ role: "user", content: question },
],
temperature: 0.2,
});
return response.choices?.[0]?.message?.content ?? "Pas de réponse";
}
}
// Exemple d'utilisation
async function main() {
const rag = new MistralRAG();
// Indexer des documents (simulant une base de connaissances)
await rag.indexDocuments([
{
id: "1",
content:
"Next.js 15 introduit le Partial Prerendering (PPR), qui combine " +
"le rendu statique et dynamique dans une même page. Les composants " +
"statiques sont servis instantanément depuis le CDN, tandis que les " +
"parties dynamiques sont streamées via React Suspense.",
metadata: { source: "docs-nextjs" },
},
{
id: "2",
content:
"Mistral AI propose des modèles open-weight comme Mistral 7B et " +
"Mixtral 8x7B. Ces modèles peuvent être déployés en local via " +
"Ollama ou vLLM, offrant une alternative aux APIs cloud pour les " +
"cas nécessitant confidentialité des données.",
metadata: { source: "docs-mistral" },
},
{
id: "3",
content:
"Le function calling de Mistral permet au modèle de déterminer " +
"automatiquement quelles fonctions appeler et avec quels arguments. " +
"Cela permet de créer des agents IA qui interagissent avec des APIs " +
"externes, des bases de données ou des services tiers.",
metadata: { source: "docs-mistral" },
},
{
id: "4",
content:
"Pour optimiser les coûts de l'API Mistral, utilisez le caching " +
"des réponses fréquentes, choisissez le modèle le plus petit " +
"adapté à votre tâche, et limitez le nombre de tokens max dans " +
"les réponses. Mistral Small coûte environ 10x moins que Mistral Large.",
metadata: { source: "guide-optimisation" },
},
]);
// Poser des questions
const questions = [
"Comment fonctionne le function calling de Mistral ?",
"Quel modèle Mistral est le moins cher ?",
"Comment déployer Mistral en local ?",
];
for (const q of questions) {
console.log(`\nQuestion: ${q}`);
const answer = await rag.query(q);
console.log(`Réponse: ${answer}`);
}
}
main();Étape 8 : Bonnes pratiques pour la production
Gestion des erreurs et retry
// src/utils/resilient-client.ts
import { mistral, MODELS } from "./client";
interface RetryOptions {
maxRetries: number;
baseDelay: number;
maxDelay: number;
}
const DEFAULT_RETRY: RetryOptions = {
maxRetries: 3,
baseDelay: 1000,
maxDelay: 10000,
};
async function withRetry<T>(
fn: () => Promise<T>,
options = DEFAULT_RETRY
): Promise<T> {
let lastError: Error | undefined;
for (let attempt = 0; attempt <= options.maxRetries; attempt++) {
try {
return await fn();
} catch (error: any) {
lastError = error;
// Ne pas retry les erreurs client (4xx sauf 429)
if (error.status >= 400 && error.status < 500 && error.status !== 429) {
throw error;
}
if (attempt < options.maxRetries) {
const delay = Math.min(
options.baseDelay * Math.pow(2, attempt),
options.maxDelay
);
console.warn(
`Tentative ${attempt + 1} échouée, retry dans ${delay}ms...`
);
await new Promise((resolve) => setTimeout(resolve, delay));
}
}
}
throw lastError;
}
// Client résilient
export async function resilientChat(
messages: Array<{ role: string; content: string }>,
model = MODELS.LARGE
) {
return withRetry(() =>
mistral.chat.complete({
model,
messages: messages as any,
})
);
}Suivi des coûts
// src/utils/cost-tracker.ts
const PRICING = {
"mistral-large-latest": { input: 2.0, output: 6.0 },
"mistral-medium-latest": { input: 0.75, output: 2.25 },
"mistral-small-latest": { input: 0.2, output: 0.6 },
"mistral-embed": { input: 0.1, output: 0 },
} as const;
class CostTracker {
private totalCost = 0;
private calls = 0;
track(model: string, inputTokens: number, outputTokens: number) {
const pricing = PRICING[model as keyof typeof PRICING];
if (!pricing) return;
const cost =
(inputTokens / 1_000_000) * pricing.input +
(outputTokens / 1_000_000) * pricing.output;
this.totalCost += cost;
this.calls++;
return cost;
}
getSummary() {
return {
totalCost: `$${this.totalCost.toFixed(4)}`,
totalCalls: this.calls,
averageCost: `$${(this.totalCost / this.calls).toFixed(4)}`,
};
}
}
export const costTracker = new CostTracker();Rate Limiting
// src/utils/rate-limiter.ts
class RateLimiter {
private tokens: number;
private lastRefill: number;
private readonly maxTokens: number;
private readonly refillRate: number; // tokens par seconde
constructor(maxTokens: number, refillRate: number) {
this.maxTokens = maxTokens;
this.tokens = maxTokens;
this.refillRate = refillRate;
this.lastRefill = Date.now();
}
async acquire(): Promise<void> {
this.refill();
if (this.tokens >= 1) {
this.tokens -= 1;
return;
}
// Attendre qu'un token soit disponible
const waitTime = (1 / this.refillRate) * 1000;
await new Promise((resolve) => setTimeout(resolve, waitTime));
this.refill();
this.tokens -= 1;
}
private refill() {
const now = Date.now();
const elapsed = (now - this.lastRefill) / 1000;
this.tokens = Math.min(
this.maxTokens,
this.tokens + elapsed * this.refillRate
);
this.lastRefill = now;
}
}
// 5 requêtes/seconde max
export const apiLimiter = new RateLimiter(5, 5);Étape 9 : Projet complet - Assistant de documentation
Combinons tout dans un assistant qui répond aux questions sur votre documentation :
// src/assistant.ts
import { mistral, MODELS } from "./utils/client";
import { SimpleVectorStore } from "./rag/vector-store";
import { costTracker } from "./utils/cost-tracker";
import fs from "fs";
import path from "path";
class DocumentationAssistant {
private store = new SimpleVectorStore();
// Charger et découper les fichiers markdown
async loadDocs(docsDir: string) {
const files = fs
.readdirSync(docsDir)
.filter((f) => f.endsWith(".md"));
const chunks: { id: string; content: string; metadata: Record<string, string> }[] = [];
for (const file of files) {
const content = fs.readFileSync(
path.join(docsDir, file),
"utf-8"
);
// Découper par sections (## headings)
const sections = content.split(/^## /m).filter(Boolean);
sections.forEach((section, i) => {
chunks.push({
id: `${file}-${i}`,
content: section.trim().substring(0, 1000),
metadata: { source: file, section: String(i) },
});
});
}
// Générer les embeddings par lots de 10
for (let i = 0; i < chunks.length; i += 10) {
const batch = chunks.slice(i, i + 10);
const texts = batch.map((c) => c.content);
const embedResponse = await mistral.embeddings.create({
model: MODELS.EMBED,
inputs: texts,
});
batch.forEach((chunk, j) => {
this.store.add({
...chunk,
embedding: embedResponse.data[j].embedding,
});
});
}
console.log(`${chunks.length} chunks indexés depuis ${files.length} fichiers.`);
}
async answer(question: string): Promise<string> {
// Encoder la question
const embedResponse = await mistral.embeddings.create({
model: MODELS.EMBED,
inputs: [question],
});
const queryEmbedding = embedResponse.data[0].embedding;
const docs = this.store.search(queryEmbedding, 5);
const context = docs
.map((d) => `Source: ${d.metadata.source}\n${d.content}`)
.join("\n\n---\n\n");
const response = await mistral.chat.complete({
model: MODELS.LARGE,
messages: [
{
role: "system",
content:
"Tu es un assistant de documentation technique. " +
"Réponds de manière précise en citant les sources. " +
"Si tu ne trouves pas la réponse dans le contexte, dis-le.\n\n" +
`Contexte:\n${context}`,
},
{ role: "user", content: question },
],
temperature: 0.1,
maxTokens: 2048,
});
// Suivre les coûts
const usage = response.usage;
if (usage) {
costTracker.track(
MODELS.LARGE,
usage.promptTokens,
usage.completionTokens
);
}
return response.choices?.[0]?.message?.content ?? "Pas de réponse";
}
}
export { DocumentationAssistant };Dépannage
Erreurs courantes
| Erreur | Cause | Solution |
|---|---|---|
401 Unauthorized | Clé API invalide | Vérifiez votre MISTRAL_API_KEY |
429 Too Many Requests | Rate limit atteint | Implémentez le rate limiting et retry |
400 Bad Request | Format de message invalide | Vérifiez la structure des messages |
| JSON invalide en mode structuré | Le modèle a mal formaté | Réduisez la température, améliorez le prompt |
| Réponses incohérentes en RAG | Chunks trop petits ou hors sujet | Ajustez la taille des chunks et le nombre de résultats |
Optimisation des performances
- Utilisez le bon modèle : Mistral Small pour la classification, Large pour le raisonnement complexe
- Cachez les embeddings : ne recalculez pas les embeddings de documents qui ne changent pas
- Batch les requêtes : utilisez les embeddings en batch plutôt qu'un par un
- Limitez les tokens : fixez
maxTokensau minimum nécessaire - Streaming : utilisez le streaming pour les réponses longues
Prochaines étapes
- Explorez Codestral pour la génération et complétion de code
- Intégrez Mistral avec LangChain.js pour des workflows complexes
- Déployez votre assistant avec Hono ou Express comme API REST
- Ajoutez une base vectorielle persistante comme Pinecone ou Qdrant
- Expérimentez avec le fine-tuning de Mistral pour votre domaine
Conclusion
Vous avez appris à utiliser l'API Mistral AI avec TypeScript pour construire des applications intelligentes complètes. De la simple conversation au RAG en passant par le function calling, Mistral offre un écosystème riche et performant pour intégrer l'IA dans vos projets.
Les modèles Mistral se distinguent par leur excellent rapport qualité-prix et leur flexibilité — que vous choisissiez l'API cloud ou le déploiement local avec les modèles open-weight. Avec les bonnes pratiques de production (retry, rate limiting, suivi des coûts), vous êtes prêt à déployer en toute confiance.
Discutez de votre projet avec nous
Nous sommes ici pour vous aider avec vos besoins en développement Web. Planifiez un appel pour discuter de votre projet et comment nous pouvons vous aider.
Trouvons les meilleures solutions pour vos besoins.
Articles connexes

Créer des applications IA avec Google Gemini API et TypeScript
Apprenez à créer des applications IA prêtes pour la production avec Google Gemini API et TypeScript. Ce tutoriel couvre la génération de texte, les entrées multimodales, le streaming, les appels de fonctions et les sorties structurées.

Framework Mastra AI : Construire des agents et workflows intelligents en TypeScript
Apprenez à construire des agents IA, des outils et des workflows avec le framework Mastra en TypeScript. Ce tutoriel pratique couvre la création d'agents, les outils personnalisés, les workflows multi-étapes, les pipelines RAG et le déploiement.

Construire un Bot Telegram avec grammY et TypeScript : du zéro au déploiement
Apprenez à construire un bot Telegram riche en fonctionnalités avec grammY et TypeScript. Ce tutoriel couvre la création du bot, les commandes, les claviers interactifs, les middlewares, les sessions et le déploiement en production.