Wiki IA
LLM et IA Générative

Modèles de Raisonnement

Nouvelle génération de LLM avec raisonnement explicite - o1, o3, chain-of-thought et techniques de réflexion

Modèles de Raisonnement

Les modèles de raisonnement représentent une évolution majeure des LLM. Au lieu de répondre immédiatement, ils "réfléchissent" étape par étape avant de donner leur réponse finale.

L'évolution du raisonnement

OpenAI o1 et o3

Architecture conceptuelle

Performances révolutionnaires

BenchmarkGPT-4o1-previewo1o3
AIME (maths compétition)13%74%83%96.7%
GPQA (PhD science)53%73%78%87.7%
Codeforces11%62%89%99%+
ARC-AGI5%21%32%87.5%

Utilisation de o1

from openai import OpenAI

client = OpenAI()

# o1 n'utilise PAS de system prompt
# Il gère lui-même son raisonnement
response = client.chat.completions.create(
    model="o1-preview",
    messages=[{
        "role": "user",
        "content": """
        Un train part de Paris à 8h00 à 120 km/h.
        Un autre train part de Lyon (450 km) à 9h00 à 150 km/h vers Paris.
        À quelle heure et où se croisent-ils ?
        """
    }],
    # Pas de temperature - o1 la gère en interne
)

print(response.choices[0].message.content)
# Le modèle a "réfléchi" pendant plusieurs secondes
# avant de donner une réponse structurée et correcte

Quand utiliser o1 vs GPT-4

Chain-of-Thought (CoT)

Principe

Le CoT force le modèle à expliciter son raisonnement.

# SANS Chain-of-Thought
prompt_simple = "Roger a 5 balles. Il en achète 2 boîtes de 3. Combien en a-t-il ?"
# Réponse: "11" (parfois faux avec les LLM basiques)

# AVEC Chain-of-Thought
prompt_cot = """
Roger a 5 balles. Il en achète 2 boîtes de 3. Combien en a-t-il ?

Réfléchissons étape par étape:
"""
# Réponse:
# "1. Roger commence avec 5 balles
#  2. Il achète 2 boîtes de 3 balles = 2 × 3 = 6 balles
#  3. Total = 5 + 6 = 11 balles
#  Réponse: 11 balles"

Variantes de CoT

Self-Consistency

def self_consistency(prompt, n_samples=5):
    """
    Génère plusieurs raisonnements et vote pour la réponse
    """
    responses = []
    for _ in range(n_samples):
        response = llm.generate(
            prompt + "\nRéfléchis étape par étape:",
            temperature=0.7,  # Diversité
        )
        answer = extract_final_answer(response)
        responses.append(answer)

    # Vote majoritaire
    from collections import Counter
    most_common = Counter(responses).most_common(1)[0][0]
    return most_common

# Exemple
result = self_consistency(
    "Si 3 poules pondent 3 œufs en 3 jours, "
    "combien d'œufs pondent 12 poules en 12 jours ?",
    n_samples=5
)
# Plus fiable que une seule génération

Tree-of-Thoughts

class TreeOfThoughts:
    def __init__(self, llm, max_depth=3, branches=3):
        self.llm = llm
        self.max_depth = max_depth
        self.branches = branches

    def solve(self, problem):
        """Explore un arbre de raisonnements"""
        root = {"thought": "Début", "children": []}
        self._expand(root, problem, depth=0)
        return self._find_best_path(root)

    def _expand(self, node, problem, depth):
        if depth >= self.max_depth:
            return

        # Générer plusieurs pensées possibles
        prompt = f"""
        Problème: {problem}
        Raisonnement jusqu'ici: {self._get_path(node)}

        Propose {self.branches} prochaines étapes de raisonnement différentes:
        """
        thoughts = self.llm.generate(prompt)

        for thought in thoughts:
            child = {"thought": thought, "children": []}
            node["children"].append(child)

            # Évaluer si cette pensée est prometteuse
            if self._evaluate(thought, problem) > 0.5:
                self._expand(child, problem, depth + 1)

Réflexion et auto-correction

Reflexion Pattern

class ReflexionAgent:
    def __init__(self, llm, max_attempts=3):
        self.llm = llm
        self.max_attempts = max_attempts
        self.memory = []

    def solve(self, task):
        for attempt in range(self.max_attempts):
            # Générer une solution
            solution = self._generate_solution(task)

            # Tester la solution
            result = self._test(solution)

            if result.success:
                return solution

            # Réfléchir sur l'échec
            reflection = self._reflect(task, solution, result.error)
            self.memory.append({
                "attempt": attempt,
                "solution": solution,
                "error": result.error,
                "reflection": reflection,
            })

        return self._best_attempt()

    def _reflect(self, task, solution, error):
        prompt = f"""
        Tâche: {task}
        Solution tentée: {solution}
        Erreur: {error}

        Analyse pourquoi cette solution a échoué.
        Que devrais-je faire différemment ?
        """
        return self.llm.generate(prompt)

Comparaison des approches

TechniqueLatenceCoûtComplexitéCas d'usage
Direct1s$SimpleQuestions simples
Zero-shot CoT3s$$FaibleMaths, logique
Few-shot CoT5s$$$MoyenneDomaines spécifiques
Self-Consistency15s$$$$MoyenneHaute fiabilité
Tree-of-Thoughts30s$$$$$ÉlevéeExploration
o1/o330-60s$$$$AutomatiqueProblèmes difficiles

Implémentation pratique

Prompt engineering pour le raisonnement

def create_reasoning_prompt(problem, method="cot"):
    if method == "cot":
        return f"""
{problem}

Résous ce problème étape par étape:
1. Identifie les informations données
2. Détermine ce qu'on cherche
3. Établis un plan de résolution
4. Exécute chaque étape
5. Vérifie ta réponse

Réflexion:
"""
    elif method == "structured":
        return f"""
{problem}

## Données
[Liste les informations du problème]

## Objectif
[Ce qu'on cherche à trouver]

## Méthode
[Approche choisie]

## Calculs
[Étapes détaillées]

## Vérification
[Vérifie la cohérence]

## Réponse finale
[Réponse claire]
"""

Évaluation du raisonnement

def evaluate_reasoning(response):
    """Évalue la qualité du raisonnement"""
    criteria = {
        "has_steps": bool(re.search(r'\d+\.', response)),
        "shows_work": len(response) > 200,
        "has_verification": "vérif" in response.lower(),
        "has_conclusion": "réponse" in response.lower() or "donc" in response.lower(),
    }

    score = sum(criteria.values()) / len(criteria)
    return {
        "score": score,
        "criteria": criteria,
    }

Limites et considérations

Limites du raisonnement

  • Le raisonnement peut être incorrect même s'il semble logique
  • Plus de tokens ≠ meilleur raisonnement
  • Les modèles peuvent "rationaliser" plutôt que raisonner
  • Coût et latence significativement plus élevés
  • Pas adapté pour toutes les tâches

Bonnes pratiques

  • Toujours vérifier les réponses critiques
  • Utiliser pour problèmes réellement complexes
  • Combiner avec validation externe
  • Monitorer les coûts

Pour aller plus loin

On this page