AI Prompt Engineering · Leçon

Systèmes de prompts qui s’améliorent eux-mêmes

Boucles de rétroaction → critique → réécriture qui optimisent automatiquement les prompts.

Leçon 3 sur 413 étapes

Systèmes de prompts qui s’améliorent eux-mêmes est une leçon AI Prompt Engineering gratuite sur CoddyKit. Ceci est la leçon 3 sur 4. Tu peux lire la leçon complète ci-dessous gratuitement — puis la pratiquer en direct dans le navigateur avec un éditeur de code intégré et un tuteur IA 24/7. Elle fait partie du parcours d'apprentissage AI Prompt Engineering, et ta progression se synchronise sur le web et l'application CoddyKit. Le cours AI Prompt Engineering comprend 4 leçons au total.

La boucle d’auto-amélioration

Un système d’instructions capable de s’améliorer crée une boucle de rétroaction : exécuter l’instruction sur des cas d’essai, évaluer les résultats, critiquer l’instruction, la réécrire, puis recommencer. Chaque itération doit produire des résultats mesurablement meilleurs. Il s’agit d’une optimisation automatisée des instructions, sans intervention humaine à chaque boucle.

Vue d’ensemble de l’architecture de la boucle

La boucle d’auto-amélioration comporte cinq composants : Exécuteur (exécute l’instruction), Évaluateur (note les résultats), Critique (repère les faiblesses de l’instruction), Réécrivain (améliore l’instruction) et Historique (suit toutes les itérations). Chacun est implémenté sous la forme d’un appel à un LLM.

import anthropic

client = anthropic.Anthropic(api_key='YOUR_API_KEY')

class SelfImprovingPromptSystem:
    def __init__(self, initial_prompt, test_cases, eval_fn, max_iterations=5):
        self.current_prompt = initial_prompt
        self.test_cases = test_cases
        self.eval_fn = eval_fn
        self.max_iterations = max_iterations
        self.history = []  # [(iteration, prompt, score, critique)]

    def run(self):
        for i in range(self.max_iterations):
            print(f'=== Iteration {i+1}/{self.max_iterations} ===')
            score = self._evaluate_prompt()
            print(f'Score: {score:.2f}')
            self.history.append((i, self.current_prompt, score))
            if score >= 0.95:
                print('Target score reached. Stopping.')
                break
            critique = self._critique_prompt(score)
            self.current_prompt = self._rewrite_prompt(critique)
        return self.best_prompt()

    def best_prompt(self):
        return max(self.history, key=lambda x: x[2])[1]

L’exécuteur : exécuter l’instruction

L’exécuteur applique l’instruction actuelle à chaque cas d’essai et collecte les résultats. Il s’agit d’une boucle standard d’appels à un LLM — rien de particulier ici, mais il est essentiel de suivre quel cas d’essai a produit quel résultat.

def _execute_prompt(self, prompt):
    outputs = []
    for case in self.test_cases:
        response = client.messages.create(
            model='claude-haiku-4-5',  # use cheaper model for execution
            max_tokens=500,
            messages=[
                {'role': 'user', 'content': prompt + '\n\nInput: ' + case['input']}
            ]
        )
        outputs.append({
            'case_id': case['id'],
            'input': case['input'],
            'expected': case['expected'],
            'actual': response.content[0].text
        })
    return outputs

# Bind method to class (demonstration)
SelfImprovingPromptSystem._execute = _execute_prompt

# Sample test cases
test_cases = [
    {'id': 1, 'input': 'The meeting was cancelled.', 'expected': 'negative'},
    {'id': 2, 'input': 'Great product, love it!', 'expected': 'positive'},
    {'id': 3, 'input': 'It arrived on time.', 'expected': 'neutral'},
]
print(f'Test suite: {len(test_cases)} cases')

L’évaluateur : noter les résultats

L’évaluateur compare les résultats de l’exécuteur aux réponses attendues et leur attribue une note. Il peut utiliser une correspondance exacte, une correspondance approximative ou un LLM évaluateur distinct pour les tâches ouvertes.

def _evaluate_prompt(self):
    outputs = self._execute(self.current_prompt)
    correct = 0
    failed_cases = []
    for out in outputs:
        # Exact match for classification tasks
        if out['expected'].lower() in out['actual'].lower():
            correct += 1
        else:
            failed_cases.append(out)
    score = correct / len(outputs)
    self._last_failed_cases = failed_cases
    return score

# For open-ended tasks: LLM-as-judge evaluator
JUDGE_PROMPT = '''Rate the quality of this AI response (1-5).
Task: {task_description}
Input: {input}
Expected approach: {expected}
Actual response: {actual}

Return only the integer score (1-5). No explanation.'''

def llm_judge_score(task_desc, input_text, expected, actual):
    response = client.messages.create(
        model='claude-haiku-4-5', max_tokens=5,
        messages=[{'role': 'user', 'content':
            JUDGE_PROMPT.format(
                task_description=task_desc, input=input_text,
                expected=expected, actual=actual
            )}]
    )
    try:
        return int(response.content[0].text.strip()) / 5.0
    except ValueError:
        return 0.5

La critique : repérer les faiblesses de l’instruction

La critique analyse les cas d’échec et l’instruction actuelle afin de repérer des faiblesses précises. C’est l’étape clé des méta-instructions : le modèle critique sa propre instruction.

CRITIC_PROMPT = '''You are a prompt engineering expert analyzing why a prompt fails.

Current prompt:
{current_prompt}

Failed test cases (where the prompt gave wrong outputs):
{failed_cases}

For each failure, explain:
1. What went wrong in the output
2. Which part of the prompt caused or failed to prevent this
3. A specific, actionable fix

End with a prioritized list of the top 3 prompt improvements to make.
Be specific — quote the relevant prompt section and suggest the exact replacement.'''

def _critique_prompt(self, score):
    failed_json = '\n'.join(
        f'Input: {c["input"]}\nExpected: {c["expected"]}\nActual: {c["actual"]}'
        for c in self._last_failed_cases[:5]
    )
    response = client.messages.create(
        model='claude-opus-4-5', max_tokens=1000,
        messages=[{'role': 'user', 'content':
            CRITIC_PROMPT.format(
                current_prompt=self.current_prompt,
                failed_cases=failed_json
            )}]
    )
    return response.content[0].text

Le réécrivain : améliorer l’instruction

Le réécrivain s’appuie sur l’analyse de la critique pour produire une version améliorée de l’instruction. Contrainte essentielle : il doit s’agir d’une amélioration ciblée, et non d’une réécriture complète.

REWRITER_PROMPT = '''You are a prompt engineer. Improve the prompt based on the critique below.

Current prompt:
{current_prompt}

Critique and suggested improvements:
{critique}

Rules for rewriting:
1. Make TARGETED changes based on the critique — do not rewrite everything
2. Keep all parts of the prompt that were working well
3. Apply all prioritized fixes from the critique
4. Do not add unnecessary verbosity — conciseness is a quality
5. Output ONLY the improved prompt, no explanation

Improved prompt:'''

def _rewrite_prompt(self, critique):
    response = client.messages.create(
        model='claude-opus-4-5', max_tokens=1000,
        messages=[{'role': 'user', 'content':
            REWRITER_PROMPT.format(
                current_prompt=self.current_prompt,
                critique=critique
            )}]
    )
    new_prompt = response.content[0].text.strip()
    print(f'Prompt updated. Length: {len(new_prompt)} chars '
          f'(was {len(self.current_prompt)} chars)')
    return new_prompt

Boucle complète : assembler les composants

Voici la boucle complète d’auto-amélioration, avec tous les composants reliés et une détection élémentaire de la convergence.

def run_improvement_loop(initial_prompt, test_cases, max_iterations=5,
                          target_score=0.90):
    history = []
    current_prompt = initial_prompt
    last_failed_cases = []

    for i in range(max_iterations):
        print(f'\n--- Iteration {i+1} ---')

        # Execute
        outputs = execute_prompt(current_prompt, test_cases)

        # Evaluate
        score, failed_cases = evaluate_outputs(outputs)
        last_failed_cases = failed_cases
        print(f'Score: {score:.2f} ({len(failed_cases)} failures)')
        history.append({'iteration': i, 'prompt': current_prompt, 'score': score})

        if score >= target_score:
            print(f'Target score {target_score} reached!')
            break

        if not failed_cases:
            print('No failures to learn from. Stopping.')
            break

        # Critique and rewrite
        critique = critique_prompt(current_prompt, failed_cases)
        current_prompt = rewrite_prompt(current_prompt, critique)

    best = max(history, key=lambda x: x['score'])
    print(f'\nBest prompt at iteration {best["iteration"]+1} with score {best["score"]:.2f}')
    return best['prompt'], history

Gestion des coûts dans les boucles d’auto-amélioration

Les boucles d’auto-amélioration peuvent être coûteuses : chaque itération effectue plusieurs appels à l’API. Les stratégies de gestion des coûts permettent de maintenir un budget raisonnable.

# Cost optimization strategies

# 1. Use cheap model for execution, expensive model for critique/rewrite
def execute_prompt(prompt, test_cases):
    # Use cheapest capable model
    model = 'claude-haiku-4-5'
    # ... execute ...
    pass

def critique_prompt(prompt, failed_cases):
    # Use best model for reasoning about why the prompt fails
    model = 'claude-opus-4-5'
    # ... critique ...
    pass

# 2. Limit test suite size (sample from larger set)
import random

def get_evaluation_sample(full_test_suite, sample_size=20):
    if len(full_test_suite) <= sample_size:
        return full_test_suite
    return random.sample(full_test_suite, sample_size)

# 3. Early stopping: stop if score doesn't improve
def has_converged(history, patience=2, min_delta=0.02):
    if len(history) < patience + 1:
        return False
    recent_scores = [h['score'] for h in history[-patience:]]
    best_recent = max(recent_scores)
    baseline = history[-(patience+1)]['score']
    return (best_recent - baseline) < min_delta

print('Cost optimization: cheap model for execution, expensive for critique')

Suivi de la traçabilité des instructions

Dans une boucle d’auto-amélioration, chaque version d’une instruction doit pouvoir être reliée à l’analyse des échecs qui l’a déclenchée. Cette traçabilité aide à déboguer les régressions inattendues et facilite la revue humaine.

class PromptLineage:
    def __init__(self):
        self.lineage = []

    def record(self, iteration, prompt, score, critique=None,
                failed_case_ids=None):
        self.lineage.append({
            'iteration': iteration,
            'prompt': prompt,
            'score': score,
            'critique_summary': critique[:100] if critique else None,
            'failed_case_ids': failed_case_ids or [],
            'prompt_length': len(prompt.split())
        })

    def print_history(self):
        print('Prompt improvement history:')
        for entry in self.lineage:
            print(
                f'  Iter {entry["iteration"]}: '
                f'score={entry["score"]:.2f} '
                f'words={entry["prompt_length"]} '
                f'failures={len(entry["failed_case_ids"])}'
            )

    def get_best(self):
        return max(self.lineage, key=lambda x: x['score'])

lineage = PromptLineage()
lineage.record(0, 'Initial simple prompt', 0.60)
lineage.record(1, 'Improved with examples', 0.75, 'Missing edge cases')
lineage.record(2, 'Added edge case handling', 0.92, 'Minor format issue')
lineage.print_history()

Visualisation de l’historique des versions d’instruction

Visualiser l’évolution de la note au fil des itérations aide à déterminer si la boucle converge et à quelle vitesse. Un simple graphique textuel rend les tendances immédiatement visibles, sans bibliothèque graphique.

def visualize_improvement_history(history):
    '''
    history: list of (iteration, prompt, score)
    Prints an ASCII chart of score progression.
    '''
    if not history:
        print('No history to visualize.')
        return

    max_score = 1.0
    bar_width = 40
    print('\nScore Progression:')
    print('-' * (bar_width + 20))

    for iteration, prompt, score in history:
        filled = int(score * bar_width)
        bar = '#' * filled + '-' * (bar_width - filled)
        marker = ' <-- BEST' if score == max(h[2] for h in history) else ''
        print(f'Iter {iteration:2d}: [{bar}] {score:.3f}{marker}')

    final_score = history[-1][2]
    best_score = max(h[2] for h in history)
    gain = best_score - history[0][2]
    print('-' * (bar_width + 20))
    print(f'Initial: {history[0][2]:.3f} -> Best: {best_score:.3f} (gain: +{gain:.3f})')

# Example
sample_history = [
    (0, 'v0', 0.60),
    (1, 'v1', 0.72),
    (2, 'v2', 0.78),
    (3, 'v3', 0.77),
    (4, 'v4', 0.85)
]
visualize_improvement_history(sample_history)

Détection des régressions

Une instruction réécrite peut corriger certains échecs tout en faisant échouer des cas qui réussissaient auparavant : c’est une régression. Vérifiez toujours les régressions après chaque itération en comparant les cas d’essai précis dont l’état a changé.

def detect_regressions(old_outputs, new_outputs):
    old_results = {o['case_id']: o['correct'] for o in old_outputs}
    new_results = {o['case_id']: o['correct'] for o in new_outputs}

    regressions = []
    improvements = []

    for case_id in old_results:
        was_correct = old_results[case_id]
        is_correct = new_results.get(case_id, False)
        if was_correct and not is_correct:
            regressions.append(case_id)
        elif not was_correct and is_correct:
            improvements.append(case_id)

    print(f'Fixed: {len(improvements)} cases. Regressed: {len(regressions)} cases.')
    if regressions:
        print(f'WARNING: Regression on cases: {regressions}')
        print('Consider reverting to previous prompt version.')
    return regressions, improvements

# Example
old = [{'case_id': 1, 'correct': True}, {'case_id': 2, 'correct': False}]
new = [{'case_id': 1, 'correct': False}, {'case_id': 2, 'correct': True}]
detect_regressions(old, new)  # Fixed: 1, Regressed: 1

Vérification rapide

Dans une boucle d’instructions capable de s’améliorer, quel est le rôle du composant Critique ?

Résumé des systèmes d’instructions capables de s’améliorer

Les systèmes d’instructions capables de s’améliorer automatisent le cycle d’optimisation des instructions :

  • Structure de la boucle : Exécuter → Évaluer → Critiquer → Réécrire → répéter
  • Exécuteur : exécute l’instruction sur des cas d’essai (utiliser un modèle peu coûteux)
  • Évaluateur : note les résultats avec une correspondance exacte ou un LLM évaluateur
  • Critique : méta-instruction qui repère les faiblesses précises de l’instruction à partir des échecs
  • Réécrivain : amélioration ciblée fondée sur la critique (utiliser le meilleur modèle)
  • Convergence : s’arrêter lorsque la note cible est atteinte ou que la note cesse de progresser
  • Détection des régressions : vérifier systématiquement que les améliorations ne font pas échouer des cas réussis
Gratuit pour commencer

Apprends AI Prompt Engineering avec un tuteur IA — gratuit

Écris et exécute du vrai code dans ton navigateur, obtiens de l'aide instantanée d'un tuteur IA disponible 24h/24, et reprends là où tu t'es arrêté sur le web ou dans l'app.

Cours
53
Leçons
199

Questions Fréquemment Posées

La leçon « Systèmes de prompts qui s’améliorent eux-mêmes » est-elle gratuite ?

Oui — le texte complet de « Systèmes de prompts qui s’améliorent eux-mêmes » est gratuit à lire ici sur le web. Pour la pratiquer de manière interactive (un éditeur de code intégré et un tuteur IA 24/7) et déverrouiller le reste du cours AI Prompt Engineering, passe à CoddyKit PRO. Le cours AI Prompt Engineering comprend 4 leçons au total.

Qu'est-ce que j'apprendrai dans « Systèmes de prompts qui s’améliorent eux-mêmes » ?

Boucles de rétroaction → critique → réécriture qui optimisent automatiquement les prompts. Tu pratiques AI Prompt Engineering avec du code pratique que tu exécutes directement dans le navigateur, et un tuteur IA 24/7 répond à tes questions au fur et à mesure que tu avances dans la leçon.

Dois-je avoir de l'expérience pour commencer AI Prompt Engineering ?

Aucune expérience préalable n'est requise. AI Prompt Engineering sur CoddyKit est structuré pour les débutants jusqu'aux apprenants avancés, donc tu peux commencer ici ou depuis le début et avancer à ton rythme. Ceci est la leçon 3 sur 4.

Combien de temps prend la leçon « Systèmes de prompts qui s’améliorent eux-mêmes » ?

La plupart des leçons CoddyKit prennent environ 5–10 minutes. Chacune est courte et interactive, tu progresses régulièrement et tu repiques exactement où tu t'es arrêté sur le web et l'app.

Peux-tu écrire et exécuter du code dans cette leçon AI Prompt Engineering ?

Oui. Chaque leçon AI Prompt Engineering inclut un éditeur de code intégré, tu écris et exécutes du vrai code directement dans ton navigateur et tu reçois des retours IA instantanés — aucune configuration locale requise.

Toutes les leçons de ce cours

  1. Qu’est-ce que le méta-prompting ?
  2. Des prompts qui génèrent des prompts
  3. Systèmes de prompts qui s’améliorent eux-mêmes
  4. Évaluation et sélection dans l’auto-amélioration
← Retour à AI Prompt Engineering