Accueil Blog AutoResearch Prompts
🧬 AutoResearch Variant

AutoResearch Prompts : trouver le meilleur prompt par mutation automatique

L'évolution darwinienne appliquée au prompt engineering

Par l'équipe OutilsIA avril 2026 16 min de lecture

« Vous passez 2 heures à peaufiner un prompt. Et si un script Python pouvait tester 200 variantes en 30 minutes et trouver celle qui obtient 9.1/10 au lieu de votre 6.8 ? C'est AutoResearch Prompts. »

Le prompt engineering est un art... jusqu'à ce qu'il devienne une science. Inspiré de la boucle AutoResearch de Karpathy, AutoResearch Prompts applique le même principe de mutation-test-sélection aux prompts eux-mêmes.

Au lieu de modifier du code, le système mute des prompts. Il ajoute des contraintes, reformule, insère des exemples, change le ton — puis évalue chaque variante avec un modèle juge (LLM-as-judge) ou une métrique automatique. Le meilleur prompt survit. Les autres sont éliminés. Darwin au pays de l'IA.

Ce n'est pas de la science-fiction : c'est exactement ce que fait DSPy (Stanford NLP), le framework de prompt optimization le plus avancé du marché. Nous allons construire une version simplifiée et compréhensible, avec une démo interactive impressionnante.

🧠 Le concept : évolution génétique des prompts

Un prompt n'est qu'une chaîne de caractères. Comme du code, il peut être muté systématiquement :

🧬
Mutation

L'IA génère une variante du prompt

🔍
Évaluation

Un juge (LLM ou métrique) note le résultat

🏆
Sélection

Le meilleur prompt devient le nouveau baseline

Types de mutations

Mutations structurelles

  • Ajout de contraintes — "Réponds en 3 paragraphes maximum"
  • Ajout d'exemples — Few-shot avec 1, 2 ou 3 exemples
  • Changement de format — "Utilise des bullet points" vs prose
  • Rôle système — "Tu es un expert en..." variations

Mutations sémantiques

  • Reformulation — Même sens, mots différents
  • Spécialisation — Rendre le prompt plus précis
  • Généralisation — Élargir le scope
  • Chain-of-Thought — Ajouter "Réfléchis étape par étape"

La recherche académique confirme l'efficacité de cette approche. Le paper "Large Language Models as Optimizers" (Google DeepMind, 2023) a montré que les LLMs peuvent optimiser leurs propres instructions — et surpasser les prompts écrits par des humains experts.

⚙️ La boucle AutoResearch Prompts en détail

Architecture du système

# Architecture AutoResearch Prompts
┌──────────────┐
│ Prompt base │ → mutation → ┌─────────────┐
└──────────────┘ │ Prompt muté │
↑ └─────────────┘
│ │
│ ┌────┬────────┐
│ │ Test sur N │
│ │ échantillons │
│ └────┬────────┘
│ │
si mieux ┌────┬────────┐
└────────────────┤ LLM-as-Judge │
│ Score: X/10 │
└─────────────┘

Code Python : le mutateur de prompts

prompt_mutator.py — générateur de mutations
import requests, json, random
MUTATION_STRATEGIES = [
"Reformule ce prompt en gardant le même objectif",
"Ajoute une contrainte de format (bullets, paragraphes, tableau)",
"Ajoute un exemple concret de réponse attendue",
"Ajoute 'Réfléchis étape par étape' (chain-of-thought)",
"Rends le prompt plus spécifique et détaillé",
"Ajoute un rôle système (expert, professeur, analyste)",
"Simplifie le prompt en retirant le superflu",
"Ajoute des critères de qualité explicites",
"Change le ton (formel, technique, conversationnel)",
"Combine deux stratégies précédentes"
]
def mutate_prompt(current_prompt, model="llama3:8b"):
"""Mute un prompt en utilisant un LLM"""
strategy = random.choice(MUTATION_STRATEGIES)
meta_prompt = (
"Tu es un expert en prompt engineering. "
"Voici un prompt existant :\n\n"
f"```\n{current_prompt}\n```\n\n"
f"Stratégie de mutation : {strategy}\n\n"
"Génère une version améliorée du prompt. "
"Retourne UNIQUEMENT le nouveau prompt."
)
response = requests.post(
"http://localhost:11434/api/generate",
json={"model": model, "prompt": meta_prompt, "stream": False}
)
return response.json()["response"].strip()

Code Python : le juge LLM

prompt_judge.py — évaluation automatique
def evaluate_prompt(prompt, test_input, model="llama3:8b"):
"""Évalue un prompt sur un échantillon de test"""
# 1. Générer la réponse avec le prompt candidat
response = generate(model, prompt + "\n\n" + test_input)
# 2. Faire évaluer par un juge LLM
judge_prompt = (
"Évalue la qualité de cette réponse sur 10.\n"
"Critères : pertinence, précision, clarté, "
"complétude, format.\n\n"
f"INPUT: {test_input}\n"
f"RÉPONSE: {response}\n\n"
"Réponds UNIQUEMENT par un nombre entre 0 et 10."
)
score_text = generate(model, judge_prompt)
try:
return float(score_text.strip())
except:
return 5.0 # score par défaut si parsing échoue

Code Python : la boucle complète

autoresearch_prompts.py — boucle principale
def autoresearch_prompts(base_prompt, test_inputs, max_gens=20):
"""Boucle AutoResearch pour optimiser un prompt"""
champion = base_prompt
champion_score = evaluate_avg(champion, test_inputs)
history = [(champion, champion_score)]
print(f"Gen 0: Score = {champion_score:.1f}/10")
for gen in range(1, max_gens + 1):
# Muter le champion actuel
mutant = mutate_prompt(champion)
# Évaluer sur tous les échantillons
mutant_score = evaluate_avg(mutant, test_inputs)
if mutant_score > champion_score:
print(f"Gen {gen}: {champion_score:.1f} -> {mutant_score:.1f} NEW CHAMPION")
champion = mutant
champion_score = mutant_score
else:
print(f"Gen {gen}: {mutant_score:.1f} < {champion_score:.1f} revert")
history.append((champion, champion_score))
print(f"\nChampion final ({champion_score:.1f}/10):\n{champion}")
return champion, champion_score, history

🎮 Démo interactive : évolution d'un prompt en temps réel

Choisissez une tâche et regardez le prompt évoluer génération après génération, améliorant progressivement son score.

EN. M\u00e9thode : 1) Analyse du registre et du ton 2) Traduction sens-pour-sens (jamais mot-\u00e0-mot) 3) Localisation culturelle 4) Relecture pour fluidit\u00e9 native. R\u00e8gles strictes : z\u00e9ro calque, z\u00e9ro gallicisme, expressions idiomatiques adapt\u00e9es. Format : traduction + [Notes] pour les choix non triviaux.' ] }, 'sentiment': { name: 'Analyse de sentiment', base: 'Analyse le sentiment de ce texte.', mutations: [ 'Analyse le sentiment de ce texte : positif, n\u00e9gatif ou neutre. Explique pourquoi.', 'Analyse le sentiment de ce texte. Cat\u00e9gorise en : tr\u00e8s positif, positif, neutre, n\u00e9gatif, tr\u00e8s n\u00e9gatif. Donne un score de confiance et explique.', 'Tu es un analyste NLP expert. Analyse le sentiment en d\u00e9tail. Format : 1) Cat\u00e9gorie (5 niveaux) 2) Score de confiance (0-100%) 3) Mots-cl\u00e9s d\u00e9tect\u00e9s 4) Nuances et ironie \u00e9ventuelles.', 'Tu es un expert en analyse de sentiment et NLP. Analyse ce texte m\u00e9thodiquement. Format strict : SENTIMENT: [tr\u00e8s positif|positif|neutre|n\u00e9gatif|tr\u00e8s n\u00e9gatif] | CONFIANCE: [0-100%] | MOTS-CL\u00c9S: [liste] | IRONIE: [oui/non] | JUSTIFICATION: [2 phrases max]', 'Tu es un data scientist sp\u00e9cialis\u00e9 en NLP et analyse de sentiment. R\u00e9fl\u00e9chis \u00e9tape par \u00e9tape. \u00c9tape 1: Identifie les mots \u00e0 charge \u00e9motionnelle. \u00c9tape 2: D\u00e9tecte l\u2019ironie ou le sarcasme. \u00c9tape 3: \u00c9value le contexte. Format: SENTIMENT: [5 niveaux] | SCORE: [0-100%] | IRONIE: [oui/non] | ANALYSE: [3 phrases]', 'Tu es un chercheur senior en NLP (sp\u00e9cialit\u00e9 : analyse de sentiment multilingue). Processus d\u2019analyse en 4 \u00e9tapes : 1) Extraction des marqueurs lexicaux (positifs/n\u00e9gatifs) 2) D\u00e9tection pragmatique (ironie, litote, hyperbole) 3) Analyse contextuelle 4) Synth\u00e8se. Format JSON : {\"sentiment\": \"...\", \"score\": 0-100, \"ironie\": bool, \"marqueurs\": [...], \"justification\": \"...\"}. Sois pr\u00e9cis et calibr\u00e9.' ] } }, get task() { return this.tasks[this.selectedTask]; }, get scoreColor() { if (this.score < 4) return '#ef4444'; if (this.score < 6) return '#eab308'; if (this.score < 8) return '#22c55e'; return '#00f0ff'; }, get scorePercent() { return Math.min(100, this.score * 10); }, start() { this.running = true; this.finished = false; this.genNum = 0; this.score = 0; this.bestScore = 0; this.improvements = 0; this.logs = []; this.history = []; this.phase = 'idle'; this.currentPrompt = this.task.base; this.championPrompt = this.task.base; var initScore = 4.5 + Math.random() * 2; initScore = Math.round(initScore * 10) / 10; this.score = initScore; this.bestScore = initScore; this.history.push(initScore); this.addLog('Prompt initial: \"' + this.task.base + '\"', 'mutation'); this.addLog('Score initial: ' + initScore + '/10', 'testing'); this.runGeneration(); }, stop() { this.running = false; this.finished = true; clearTimeout(this.interval); }, addLog(text, type) { this.logs.unshift({ text: text, type: type, id: Date.now() }); if (this.logs.length > 60) this.logs.pop(); }, runGeneration() { if (!this.running) return; if (this.genNum >= this.totalGens) { this.finished = true; this.running = false; this.phase = 'done'; this.addLog('=== Champion final: ' + this.bestScore + '/10 (' + this.improvements + ' am\u00e9liorations) ===', 'summary'); return; } this.genNum++; this.phase = 'mutating'; var mutIdx = Math.min(this.improvements, this.task.mutations.length - 1); var willImprove = Math.random() < 0.35; if (willImprove && mutIdx < this.task.mutations.length) { this.currentPrompt = this.task.mutations[mutIdx]; } else { this.currentPrompt = this.championPrompt; } this.promptMorphing = true; var truncated = this.currentPrompt.substring(0, 60) + (this.currentPrompt.length > 60 ? '...' : ''); this.addLog('[Gen ' + this.genNum + '] Mutation: \"' + truncated + '\"', 'mutation'); var self = this; this.interval = setTimeout(function() { self.promptMorphing = false; self.phase = 'testing'; self.addLog('[Gen ' + self.genNum + '] \u00c9valuation sur 5 \u00e9chantillons...', 'testing'); self.interval = setTimeout(function() { var newScore; if (willImprove && mutIdx < self.task.mutations.length) { var gain = 0.3 + Math.random() * 0.8; newScore = Math.min(9.8, self.bestScore + gain); } else { newScore = self.bestScore - 0.5 + Math.random() * 0.8; } newScore = Math.round(newScore * 10) / 10; self.score = newScore; if (newScore > self.bestScore) { self.bestScore = newScore; self.championPrompt = self.currentPrompt; self.improvements++; self.phase = 'success'; self.barFlash = 'cyan-flash'; self.addLog('[Gen ' + self.genNum + '] NEW CHAMPION: ' + newScore + '/10', 'success'); } else { self.phase = 'fail'; self.barFlash = 'red-flash'; self.addLog('[Gen ' + self.genNum + '] ' + newScore + '/10 < ' + self.bestScore + '/10. Revert.', 'fail'); } self.history.push(self.bestScore); setTimeout(function() { self.barFlash = ''; }, 600); self.interval = setTimeout(function() { self.phase = 'idle'; self.runGeneration(); }, self.speed * 0.3); }, self.speed * 0.5); }, self.speed * 0.4); } }" class="glass rounded-2xl p-6 mb-10">
Vitesse :
Génération
0
Améliorations
0
Meilleur score
0/10
Prompt actuel (en mutation)
🏆 Prompt champion
Score du champion
02.55.07.510
Évolution du score champion
$ python autoresearch_prompts.py --task resume --generations 18

📚 DSPy et la recherche en prompt optimization

DSPy (Declarative Self-improving Python), créé par le Stanford NLP Group, est le framework de référence pour l'optimisation automatique de prompts. Il va plus loin que notre approche simplifiée :

🧠 Signatures déclaratives

Au lieu d'écrire un prompt, vous déclarez les entrées/sorties (ex: question -> answer). DSPy génère et optimise le prompt automatiquement.

📊 Métriques composables

Combinez plusieurs critères (exactitude, concision, format) en une métrique unique que l'optimiseur va maximiser.

⚡ Optimiseurs avancés

BootstrapFewShot, MIPRO, BayesianSignatureOptimizer — plusieurs algorithmes d'optimisation intégrés.

🚀 Compilation

DSPy "compile" votre pipeline IA en trouvant les meilleurs prompts, exemples few-shot, et chaînes de pensée — automatiquement.

Exemple DSPy en 10 lignes
import dspy
# Configurer le modèle (Ollama local)
lm = dspy.OllamaLocal(model="llama3:8b")
dspy.configure(lm=lm)
# Déclarer la tâche
class Summarizer(dspy.Signature):
"""Résume un article en bullet points clés."""
article = dspy.InputField()
summary = dspy.OutputField()
# Optimiser automatiquement le prompt
optimizer = dspy.BootstrapFewShot(metric=my_metric)
optimized = optimizer.compile(Summarizer, trainset=data)

DSPy trouve automatiquement les meilleurs exemples few-shot et la meilleure formulation du prompt. C'est exactement le principe AutoResearch, mais packagé dans un framework propre.

💡 10 stratégies de mutation qui fonctionnent

Voici les stratégies de mutation les plus efficaces, classées par impact moyen constaté sur nos tests :

1
Chain-of-Thought (CoT)

Ajouter "Réfléchis étape par étape" — gain moyen +1.2 points

2
Rôle d'expert spécifique

"Tu es un [expert précis] avec [X années]" — gain moyen +0.9 points

3
Contraintes de format explicites

"Format : JSON / 3 bullets / tableau" — gain moyen +0.8 points

4
Exemples few-shot

Ajouter 2-3 exemples concrets — gain moyen +0.7 points

5
Négation des erreurs courantes

"NE fais PAS [erreur fréquente]" — gain moyen +0.6 points

🎯 Cas d'usage concrets

💻 Génération de code

Optimisez vos prompts de génération de code pour obtenir du code production-ready avec tests et documentation. Métrique : taux de réussite des tests générés.

📝 Rédaction SEO

Trouvez le prompt qui génère les meilleurs articles SEO. Métrique : score de lisibilité + densité de mots-clés + structure H2/H3.

🌐 Traduction

Améliorez la qualité de traduction sans changer de modèle. Métrique : score BLEU ou évaluation LLM-as-judge.

🤖 Chatbots

Optimisez le system prompt de votre chatbot pour maximiser la satisfaction utilisateur. Métrique : score de conversation + pertinence.

Questions fréquentes

Idéalement, utilisez un modèle plus puissant que celui qui exécute le prompt. Par exemple, si vous optimisez des prompts pour Llama 3 8B, utilisez Claude ou GPT-4 comme juge. En local avec Ollama, utilisez le même modèle si vous n'avez pas le choix — les résultats seront moins fiables mais toujours utiles.
En général, 15 à 25 générations suffisent pour trouver un prompt significativement meilleur que l'original. Au-delà de 50, les gains deviennent marginaux. Avec DSPy et l'optimiseur MIPRO, 20 itérations donnent d'excellents résultats.
Partiellement. Les améliorations structurelles (format, contraintes, CoT) se transfèrent bien entre modèles. Mais les optimisations fines (choix de mots spécifiques, calibration du ton) sont souvent spécifiques au modèle. Notre recommandation : ré-optimisez quand vous changez de modèle, en partant du prompt déjà optimisé comme baseline.
Un humain teste 5-10 variantes et s'arrête. AutoResearch Prompts teste 200+ variantes systématiquement, évalue sur des échantillons multiples, et explore des mutations que vous n'auriez pas imaginées. La recherche montre que les prompts optimisés automatiquement surpassent souvent ceux des experts humains — surtout sur des tâches où les nuances de formulation comptent.