Aller au contenu principal

Tree-of-thought : exploration structurée

Tree-of-thought : exploration structurée

Le Tree-of-Thought (ToT) est une technique de prompting qui structure le raisonnement du modèle comme un arbre de décision. Au lieu de suivre un seul chemin de pensée linéaire, le modèle explore plusieurs branches, évalue chacune, et conserve les plus prometteuses. C’est particulièrement efficace pour les problèmes nécessitant de la planification ou du backtracking.

Différence avec le Chain-of-Thought

Le Chain-of-Thought (CoT) suit un raisonnement linéaire : étape 1, étape 2, étape 3. Si le modèle prend une mauvaise direction à l’étape 2, tout le raisonnement est compromis. Le Tree-of-Thought explore plusieurs directions à chaque étape et élimine les impasses.

# Chain-of-Thought (linéaire)
# Étape 1 → Étape 2 → Étape 3 → Réponse

# Tree-of-Thought (arborescent)
#            Étape 1
#          /    |    \
#     Opt A  Opt B  Opt C    ← évaluation
#       |      |      ✗      ← élagage
#    Opt A1  Opt B1
#      |       |
#   Réponse  Réponse          ← sélection finale

Implémentation en un seul prompt

La version la plus simple utilise un prompt qui force le modèle à explorer plusieurs branches :

from openai import OpenAI

client = OpenAI()

def tree_of_thought_simple(problem: str) -> str:
    """ToT en un seul prompt."""
    prompt = f"""Résous ce problème en utilisant l'approche Tree-of-Thought.

Problème : {problem}

Étape 1 - Génère 3 approches différentes :
- Approche A : ...
- Approche B : ...
- Approche C : ...

Étape 2 - Évalue chaque approche (forces et faiblesses) :
- Approche A : ...
- Approche B : ...
- Approche C : ...

Étape 3 - Sélectionne la meilleure approche et développe-la :
Approche retenue : ...
Développement détaillé : ...

Étape 4 - Réponse finale :
..."""

    response = client.responses.create(
        model="gpt-5.4",
        input=prompt,
        temperature=0.7
    )
    return response.output_text

Implémentation multi-appels

Pour les problèmes complexes, séparez chaque étape en appels distincts :

def tree_of_thought(problem: str, breadth: int = 3,
                    depth: int = 3) -> dict:
    """ToT avec exploration multi-niveaux."""
    system = "Tu es un expert en résolution de problèmes structurée."

    # Étape 1 : Générer les branches initiales
    gen_prompt = (f"Problème : {problem}\n\n"
                  f"Propose {breadth} approches différentes pour résoudre "
                  f"ce problème. Pour chaque approche, donne un titre et "
                  f"une description en 2-3 phrases. Numérote-les 1 à {breadth}.")

    branches_response = client.responses.create(
        model="gpt-5.3",
        instructions=system,
        input=gen_prompt,
        temperature=0.8
    )
    branches = branches_response.output_text

    # Étape 2 : Évaluer chaque branche
    eval_prompt = (f"Problème : {problem}\n\n"
                   f"Voici {breadth} approches proposées :\n{branches}\n\n"
                   f"Évalue chaque approche sur 3 critères (note /10) :\n"
                   f"- Faisabilité\n- Efficacité\n- Simplicité\n\n"
                   f"Classe-les de la meilleure à la pire avec justification.")

    eval_response = client.responses.create(
        model="gpt-5.3",
        instructions=system,
        input=eval_prompt,
        temperature=0.3
    )
    evaluation = eval_response.output_text

    # Étape 3 : Développer la meilleure branche
    dev_prompt = (f"Problème : {problem}\n\n"
                  f"Évaluation des approches :\n{evaluation}\n\n"
                  f"Développe l'approche la mieux classée en détail. "
                  f"Fournis une solution complète et actionnable.")

    solution = client.responses.create(
        model="gpt-5.3",
        instructions=system,
        input=dev_prompt,
        temperature=0.3
    )

    return {
        "branches": branches,
        "evaluation": evaluation,
        "solution": solution.output_text
    }

Cas d’usage concret : architecture logicielle

problem = """
Notre API REST monolithique (Django, PostgreSQL) atteint ses limites :
- 500 requêtes/seconde max
- Temps de réponse > 2s sur les endpoints de recherche
- Déploiement = 30 minutes de downtime
- 3 développeurs dans l'équipe

Comment améliorer les performances et la disponibilité
sans réécrire toute l'application ?
"""

result = tree_of_thought(problem, breadth=4)
print(result["solution"])

Quand utiliser le Tree-of-Thought

  • Problèmes de planification : architecture, roadmap, stratégie
  • Problèmes avec contraintes : optimisation, allocation de ressources
  • Debugging complexe : quand plusieurs causes sont possibles
  • Décisions techniques : choix de framework, de base de données

Quand ne pas l’utiliser

  • Questions factuelles simples (pas besoin d’explorer)
  • Tâches créatives ouvertes (pas de critère d’évaluation clair)
  • Quand la latence est critique (plusieurs appels API)

Combiner avec les modèles de raisonnement

Les modèles o3-pro et o4-mini effectuent déjà un raisonnement interne structuré. Pour ces modèles, le ToT explicite est souvent redondant. Utilisez-le plutôt avec GPT-5.3 et GPT-5.4 :

# Avec GPT-5.3 : ToT explicite utile
result = tree_of_thought(problem, breadth=3)

# Avec o3-pro : le modèle raisonne déjà en profondeur
response = client.responses.create(
    model="o3-pro",
    input=problem,
    reasoning={"effort": "high"}
)

Mise en pratique

  1. Choisissez un problème d’architecture ou de design de votre contexte professionnel
  2. Implémentez le ToT multi-appels avec breadth=3
  3. Comparez le résultat avec un simple prompt direct
  4. Mesurez la qualité de la solution et le coût en tokens

Points clés à retenir

  • Le ToT explore plusieurs chemins de raisonnement et sélectionne le meilleur
  • Version simple en un prompt ou version avancée en multi-appels
  • Idéal pour la planification, l’architecture et le debugging complexe
  • Les modèles de raisonnement (o3-pro, o4-mini) ont un ToT implicite
  • Le surcoût en tokens est justifié pour les décisions à fort impact