Les modèles généralistes ne connaissent pas vos conventions de code. Il existe deux stratégies : les Modelfiles Ollama pour le cadrage comportemental et le fine-tuning Mistral pour l'apprentissage profond de vos patterns.
Ollama Modelfiles : l'approche rapide
# Modelfile pour assistant Angular + NestJS
FROM codestral:latest
SYSTEM """
Tu es un développeur senior spécialisé Angular 21 + NestJS 11.
Conventions : standalone components, Signals, class-validator DTOs.
Pas de commentaires triviaux, noms en anglais, tests obligatoires.
"""
PARAMETER temperature 0.3
PARAMETER top_p 0.9
PARAMETER num_ctx 32768
# Créer et tester
ollama create angular-nestjs -f Modelfile
ollama run angular-nestjs "Crée un service CRUD pour les articles"
Mistral Fine-tuning API
Préparer les données (format JSONL)
{"messages":[{"role":"system","content":"Assistant dev Angular 21 + NestJS 11."},{"role":"user","content":"Crée un guard JWT NestJS"},{"role":"assistant","content":"import { Injectable, CanActivate, ExecutionContext } from '@nestjs/common';..."}]}
Script de collecte automatisé
import os, json, glob
def build_dataset(source_dirs, output_file):
pairs = []
for src_dir in source_dirs:
for fp in glob.glob(f"{src_dir}/**/*.ts", recursive=True):
if "node_modules" in fp or "dist" in fp:
continue
with open(fp, "r") as f:
content = f.read()
if len(content) < 100 or len(content) > 8000:
continue
if fp.endswith(".service.ts"):
question = f"Crée un service NestJS comme {os.path.basename(fp)}"
elif fp.endswith(".component.ts"):
question = f"Crée un composant Angular comme {os.path.basename(fp)}"
else:
continue
pairs.append({"messages": [
{"role": "system", "content": "Assistant dev Angular 21 + NestJS 11."},
{"role": "user", "content": question},
{"role": "assistant", "content": content},
]})
with open(output_file, "w") as f:
for p in pairs:
f.write(json.dumps(p, ensure_ascii=False) + "\n")
print(f"{len(pairs)} paires générées")
build_dataset(["./apps/frontend/src", "./apps/backend/src"], "training.jsonl")
Lancer le fine-tuning
from mistralai import Mistral
client = Mistral(api_key="votre-clé")
# Upload
with open("training.jsonl", "rb") as f:
training_file = client.files.upload(
file={"file_name": "training.jsonl", "content": f},
purpose="fine-tune"
)
# Lancer le job
job = client.fine_tuning.jobs.create(
model="codestral-latest",
training_files=[{"file_id": training_file.id, "weight": 1}],
hyperparameters={"training_steps": 300, "learning_rate": 1e-5},
auto_start=True,
)
# Utiliser le modèle fine-tuné
response = client.chat.complete(
model=job.fine_tuned_model,
messages=[{"role": "user", "content": "Crée un interceptor NestJS pour le logging"}]
)
RAG vs Fine-tuning
| Critère | RAG | Fine-tuning |
|---|---|---|
| Objectif | Accéder à des infos spécifiques | Modifier le style de génération |
| Données changeantes | Idéal (mise à jour sans réentraînement) | Nécessite un nouveau fine-tuning |
| Coût | Inférence plus élevée (contexte large) | Coût initial, inférence moins chère |
| Volume requis | Quelques documents | 50-100+ exemples de qualité |
Recommandation : commencez par le RAG pour valider la valeur. Si les résultats sont bons mais que vous voulez réduire latence et coûts, passez au fine-tuning. L'idéal combine souvent les deux : un modèle fine-tuné enrichi par du RAG pour le code récent.
La personnalisation des LLM n'est plus réservée aux grandes entreprises. Avec Ollama et Mistral, tout développeur peut créer un assistant qui comprend sa stack. Commencez par un Modelfile simple, mesurez, puis envisagez le fine-tuning quand le ROI est clair.




