Installez Ollama et exécutez des LLM (Llama, Mistral, Gemma) en local sans cloud : API REST intégrée, modèles disponibles et intégration dans vos apps.
Installation et démarrage
Ollama installe un service en arrière-plan qui expose une API REST locale sur le port 11434. Sur macOS, il se lance automatiquement au démarrage du système. Sur Linux et Windows, le service peut être configuré comme daemon systemd.
# macOS / Linux (une seule commande)
curl -fsSL https://ollama.com/install.sh | sh
# Windows : télécharger l'installateur .exe sur ollama.com
# → installe et démarre le service automatiquement
# Vérifier que le service tourne
curl http://localhost:11434 # répond : "Ollama is running"
ollama --version # version installée
ollama list # liste des modèles téléchargés (vide au départ)
Gérer les modèles
# Télécharger un modèle (depuis Ollama Hub : ollama.com/library)
ollama pull llama3.2 # Llama 3.2 3B (~2 GB)
ollama pull llama3.1:8b # Llama 3.1 8B (~4.7 GB)
ollama pull mistral # Mistral 7B v0.3 (~4.1 GB)
ollama pull qwen2.5-coder:7b # Qwen 2.5 Coder 7B — excellent pour le code
# Spécifier la quantification (taille vs qualité)
ollama pull llama3.1:8b-q4_0 # 4-bit (plus petit, légèrement moins précis)
ollama pull llama3.1:8b-q8_0 # 8-bit (meilleure qualité, ~8 GB)
# Commandes de gestion
ollama list # modèles installés avec taille
ollama show llama3.1:8b # infos détaillées (paramètres, famille)
ollama rm llama3.2 # supprimer un modèle
ollama cp llama3.2 mon-llama # copier (base pour créer un Modelfile)
# Lancer un chat interactif
ollama run llama3.1:8b
# /help dans le chat pour les commandes spéciales
# /set parameter temperature 0.1 → changer la température en live
# /show modelfile → voir le Modelfile du modèle
# One-shot (stdin)
ollama run qwen2.5-coder:7b "Explique ce code TypeScript:" < mon-fichier.ts
Accélération GPU
Ollama détecte automatiquement les GPU disponibles et les utilise. Un GPU accélère l'inférence de 10 à 50× selon le modèle et le matériel. Sans GPU, l'inférence se fait sur CPU (plus lent mais fonctionnel).
# NVIDIA : prérequis CUDA 12.3+ et pilotes récents
nvidia-smi # vérifier que le GPU est détecté
ollama run llama3.1:8b # utilise le GPU automatiquement
# AMD : ROCm (Linux uniquement, Windows en développement)
# Apple Silicon : Metal GPU intégré — Ollama l'utilise automatiquement
# → sur M1/M2/M3, performances excellentes pour les modèles 7-13B
# Vérifier si le GPU est utilisé
ollama run llama3.1:8b
# → dans les logs Ollama (/var/log/ollama.log ou journalctl -u ollama)
# → "llm server loaded model ... with N GPU layers"
# Configurer le nombre de layers GPU (si VRAM insuffisante)
# Par défaut Ollama met le maximum possible en GPU
OLLAMA_GPU_LAYERS=20 ollama run llama3.1:70b # 20 layers GPU, reste CPU
# Si plusieurs GPU disponibles
OLLAMA_GPU_DEVICE=0 ollama serve # utiliser seulement GPU 0
# Tableau indicatif : VRAM minimum par modèle en Q4
# Llama 3.2 3B : 2 GB VRAM (RTX 3060 ou plus)
# Llama 3.1 8B : 5 GB VRAM (RTX 3060 12GB ou RTX 4060)
# Llama 3.1 70B : 40 GB VRAM (2× RTX 3090 ou A100)
# Mistral 7B : 5 GB VRAM
Modelfile — personnaliser un modèle
Un Modelfile permet de créer un modèle dérivé avec un system prompt fixe, des paramètres personnalisés, et des messages de contexte. C'est l'équivalent d'un fine-tuning léger via le system prompt.
# Modelfile — Angular Expert Assistant
FROM llama3.1:8b
# System prompt : définit le comportement permanent du modèle
SYSTEM """
Tu es un expert Angular 18+ spécialisé en TypeScript, Signals, et architecture frontend.
Règles :
- Réponds toujours en français sauf pour les noms techniques
- Utilise Angular standalone components (pas de NgModule)
- Utilise les Signals (signal(), computed(), effect()) plutôt que RxJS Subject pour l'état
- Les exemples de code doivent être complets et fonctionnels, avec types TypeScript stricts
- Si une API Angular est dépréciée, mentionne-le et propose l'alternative moderne
"""
# Paramètres du modèle
PARAMETER temperature 0.3 # 0.3 pour du code précis (moins créatif)
PARAMETER num_ctx 8192 # fenêtre de contexte (tokens)
PARAMETER top_p 0.9
PARAMETER num_predict 4096 # longueur max de la réponse
# Message de bienvenue
MESSAGE user "Bonjour"
MESSAGE assistant "Bonjour ! Je suis ton assistant Angular. Comment puis-je t'aider ?"
# Créer le modèle personnalisé
ollama create angular-expert -f ./Modelfile
# Lancer le modèle personnalisé
ollama run angular-expert
# Partager le Modelfile avec l'équipe (versionner dans git)
# Chaque développeur crée son instance locale avec la même commande
API REST — format natif et OpenAI-compatible
Ollama expose deux formats d'API : son propre format (/api/chat, /api/generate) et un format compatible OpenAI (/v1/chat/completions). La compatibilité OpenAI permet d'utiliser les SDK existants.
# API Ollama native — chat avec streaming désactivé
curl http://localhost:11434/api/chat \
-H "Content-Type: application/json" \
-d '{
"model": "llama3.1:8b",
"messages": [
{ "role": "system", "content": "Tu es un expert Angular." },
{ "role": "user", "content": "Explique les Signals Angular en 5 points." }
],
"stream": false,
"options": {
"temperature": 0.7,
"num_ctx": 4096
}
}'
# Format compatible OpenAI — drop-in replacement
curl http://localhost:11434/v1/chat/completions \
-H "Content-Type: application/json" \
-H "Authorization: Bearer ollama" \
-d '{
"model": "llama3.1:8b",
"messages": [{ "role": "user", "content": "Hello" }],
"temperature": 0.5,
"max_tokens": 1000
}'
# API Embeddings (pour RAG)
curl http://localhost:11434/api/embed \
-d '{
"model": "nomic-embed-text",
"input": "Les Signals Angular permettent une réactivité fine-grained"
}'
Intégration Node.js / TypeScript
// Option 1 : SDK Ollama officiel
import ollama from 'ollama';
// Chat complet
const response = await ollama.chat({
model: 'llama3.1:8b',
messages: [
{ role: 'system', content: 'Tu es un expert Angular.' },
{ role: 'user', content: "Qu'est-ce qu'un Signal Angular ?" }
],
options: { temperature: 0.3 }
});
console.log(response.message.content);
console.log(`Durée: ${response.total_duration / 1e9}s`); // en nanoseconds
console.log(`Tokens/s: ${response.eval_count / (response.eval_duration / 1e9)}`);
// Option 2 : SDK OpenAI pointant vers Ollama
// Avantage : swapper entre Ollama et OpenAI en changeant baseURL + apiKey
import OpenAI from 'openai';
const isLocal = process.env.NODE_ENV === 'development';
const client = new OpenAI({
baseURL: isLocal ? 'http://localhost:11434/v1' : 'https://api.openai.com/v1',
apiKey: isLocal ? 'ollama' : process.env.OPENAI_API_KEY
});
const model = isLocal ? 'llama3.1:8b' : 'gpt-4o-mini';
const completion = await client.chat.completions.create({
model,
messages: [{ role: 'user', content: 'Explique les génériques TypeScript' }],
temperature: 0.5
});
console.log(completion.choices[0].message.content);
Streaming et réponse progressive
// Streaming avec SDK Ollama — affichage token par token
import ollama from 'ollama';
const stream = await ollama.chat({
model: 'llama3.1:8b',
messages: [{ role: 'user', content: 'Génère un service Angular complet pour gérer des produits.' }],
stream: true // active le streaming
});
let fullResponse = '';
process.stdout.write('Réponse: ');
for await (const chunk of stream) {
const text = chunk.message.content;
process.stdout.write(text);
fullResponse += text;
if (chunk.done) {
console.log('\n---');
console.log(`Tokens générés: ${chunk.eval_count}`);
console.log(`Vitesse: ${(chunk.eval_count / (chunk.eval_duration / 1e9)).toFixed(1)} tokens/s`);
}
}
// Streaming dans un endpoint Express (Server-Sent Events)
app.get('/api/chat/stream', async (req, res) => {
res.setHeader('Content-Type', 'text/event-stream');
res.setHeader('Cache-Control', 'no-cache');
const { prompt } = req.query;
const stream = await ollama.chat({
model: 'llama3.1:8b',
messages: [{ role: 'user', content: String(prompt) }],
stream: true
});
for await (const chunk of stream) {
res.write(`data: ${JSON.stringify({ text: chunk.message.content, done: chunk.done })}\n\n`);
}
res.end();
});
Sortie structurée JSON
Ollama supporte le structured output via un JSON Schema. Le modèle est contraint à retourner un JSON qui respecte exactement le schéma — aucun texte libre autour.
import ollama from 'ollama';
// Extraire des entités structurées depuis du texte libre
const schema = {
type: 'object',
properties: {
components: {
type: 'array',
items: {
type: 'object',
properties: {
name: { type: 'string' },
purpose: { type: 'string' },
inputs: { type: 'array', items: { type: 'string' } }
},
required: ['name', 'purpose']
}
},
services: { type: 'array', items: { type: 'string' } },
complexity: { type: 'string', enum: ['low', 'medium', 'high'] }
},
required: ['components', 'services', 'complexity']
};
const response = await ollama.chat({
model: 'llama3.1:8b',
messages: [{
role: 'user',
content: `Analyse cette feature Angular et retourne les composants et services nécessaires:
"Un tableau de bord admin avec liste des utilisateurs, filtres, pagination, et modal d'édition."`
}],
format: schema // forcer le schéma JSON
});
const result = JSON.parse(response.message.content);
// result.components, result.services, result.complexity sont garantis typés correctement
Embeddings pour la recherche locale
// Modèles d'embedding dédiés (plus rapides, moins de RAM)
// ollama pull nomic-embed-text → 137M params, 768 dims, ~274 MB
// ollama pull mxbai-embed-large → 335M params, 1024 dims, ~669 MB
import ollama from 'ollama';
// Générer un embedding
async function embed(text: string): Promise<number[]> {
const result = await ollama.embed({
model: 'nomic-embed-text',
input: text
});
return result.embeddings[0]; // tableau de 768 nombres
}
// Batch embedding (plusieurs textes en un appel)
async function embedBatch(texts: string[]): Promise<number[][]> {
const result = await ollama.embed({
model: 'nomic-embed-text',
input: texts // tableau de strings
});
return result.embeddings;
}
// RAG simple : indexer une documentation locale
const docs = [
{ id: 1, text: 'Signal Angular - writable signal créé avec signal(initialValue)' },
{ id: 2, text: 'computed() - signal dérivé en lecture seule, recalculé automatiquement' },
{ id: 3, text: 'effect() - exécute du code quand les signaux dépendants changent' }
];
// Indexation (une fois, résultats à cacher sur disque)
const indexed = await Promise.all(
docs.map(async doc => ({ ...doc, embedding: await embed(doc.text) }))
);
// Recherche sémantique locale (100% offline)
function cosineSim(a: number[], b: number[]) {
const dot = a.reduce((s, v, i) => s + v * b[i], 0);
const magA = Math.sqrt(a.reduce((s, v) => s + v * v, 0));
const magB = Math.sqrt(b.reduce((s, v) => s + v * v, 0));
return dot / (magA * magB);
}
async function search(query: string) {
const queryEmb = await embed(query);
return indexed
.map(doc => ({ ...doc, score: cosineSim(queryEmb, doc.embedding) }))
.sort((a, b) => b.score - a.score)[0];
}
const result = await search('comment créer un signal réactif');
console.log(result.text, result.score);
// → "Signal Angular - writable signal créé avec signal(initialValue)" 0.91
Modèles — guide de sélection
| Modèle | Taille | RAM GPU | Points forts | Cas d'usage |
|---|---|---|---|---|
llama3.2:3b | ~2 GB | 3 GB | Rapide, léger | Chatbot simple, analyse rapide |
llama3.1:8b | ~4.7 GB | 6 GB | Excellent général, français correct | Usage général, code basique |
mistral:7b | ~4.1 GB | 5 GB | Français excellent, instruction-following | Assistance en français, extraction |
qwen2.5-coder:7b | ~4.7 GB | 6 GB | Code multilangage, TypeScript | Génération code, revue de code |
deepseek-coder-v2:16b | ~9 GB | 11 GB | Code avancé, raisonnement | Architectures complexes, debug |
nomic-embed-text | ~274 MB | 1 GB | Rapide, 768 dims | RAG, recherche sémantique locale |
llama3.1:70b | ~40 GB | 42 GB | Qualité proche GPT-4 | Tâches complexes, si GPU puissant |