ReAct et Patterns d'Agents IA

Le Pattern ReAct : Reasoning + Acting
ReAct (Yao et al., 2022) est le pattern d’agent le plus populaire et le plus efficace pour la majorité des cas d’usage.
Principe Fondamental
Au lieu de générer directement une réponse, l’agent :
- PENSE (Thought) : Raisonne sur la situation
- AGIT (Action) : Exécute un outil
- OBSERVE (Observation) : Analyse le résultat
- Répète jusqu’à résolution
┌─────────────────────────────────────────────────┐
│ BOUCLE ReAct │
├─────────────────────────────────────────────────┤
│ │
│ 💭 THOUGHT → 🔧 ACTION → 👁️ OBSERVATION │
│ ↑ ↓ │
│ └───────────────────────────────┘ │
│ (Répéter) │
│ │
└─────────────────────────────────────────────────┘
Exemple Concret
Question : “Combien d’habitants vivent dans la capitale du Japon ?”
Sans ReAct (erreur courante) :
LLM: La capitale du Japon est Tokyo, qui compte environ 14 millions d'habitants.
❌ Faux : Tokyo compte ~37 millions d’habitants (aire métropolitaine)
Avec ReAct (correct) :
Thought 1: Je dois d'abord identifier la capitale du Japon.
Action 1: search("capitale du Japon")
Observation 1: La capitale du Japon est Tokyo.
Thought 2: Maintenant je dois trouver la population actuelle de Tokyo.
Action 2: search("population Tokyo 2024")
Observation 2: L'aire métropolitaine de Tokyo compte 37,4 millions d'habitants en 2024.
Thought 3: J'ai maintenant la réponse exacte.
Answer: Environ 37,4 millions d'habitants vivent dans la capitale du Japon (Tokyo).
✅ Correct
Résultats Académiques
Paper original (2022) :
| Dataset | Baseline | ReAct | Gain |
|---|---|---|---|
| HotpotQA (questions multi-étapes) | 61% | 82% | +34% |
| FEVER (fact verification) | 56% | 74% | +32% |
| WebShop (navigation) | 39% | 71% | +82% |
Pourquoi ça marche ?
- Le raisonnement explicite réduit les erreurs
- Les observations externes corrigent les hallucinations
- La décomposition en étapes améliore la robustesse
Implémentation Complète de ReAct
import openai
import json
from typing import Dict, List, Any, Optional
from dataclasses import dataclass
@dataclass
class Step:
"""Une étape du raisonnement ReAct"""
thought: str
action: Optional[str] = None
action_input: Optional[Dict] = None
observation: Optional[str] = None
class ReActAgent:
"""Agent utilisant le pattern ReAct"""
def __init__(
self,
llm_model: str = "gpt-4",
tools: Dict[str, callable] = None,
max_iterations: int = 10,
verbose: bool = True
):
self.model = llm_model
self.tools = tools or {}
self.max_iterations = max_iterations
self.verbose = verbose
def run(self, query: str) -> str:
"""Exécute l'agent avec le pattern ReAct"""
steps: List[Step] = []
context = self._build_initial_context(query)
for iteration in range(self.max_iterations):
if self.verbose:
print(f"\n{'='*60}")
print(f"🔄 Itération {iteration + 1}/{self.max_iterations}")
print(f"{'='*60}")
# 1. REASONING : Générer pensée et action
response = self._generate_step(context, steps)
# Parser la réponse
thought = response.get("thought", "")
action_name = response.get("action")
action_input = response.get("action_input", {})
if self.verbose:
print(f"\n💭 Pensée : {thought}")
# Vérifier si l'agent a terminé
if action_name == "finish" or action_name is None:
final_answer = response.get("final_answer", thought)
if self.verbose:
print(f"\n✅ Réponse finale : {final_answer}")
return final_answer
# 2. ACTION : Exécuter l'outil
if action_name not in self.tools:
observation = f"❌ Erreur : l'outil '{action_name}' n'existe pas. Outils disponibles : {list(self.tools.keys())}"
else:
if self.verbose:
print(f"\n🔧 Action : {action_name}({action_input})")
try:
observation = self.tools[action_name](**action_input)
except Exception as e:
observation = f"❌ Erreur lors de l'exécution : {str(e)}"
if self.verbose:
print(f"👁️ Observation : {observation}")
# 3. OBSERVATION : Enregistrer le résultat
step = Step(
thought=thought,
action=action_name,
action_input=action_input,
observation=observation
)
steps.append(step)
# Mettre à jour le contexte
context = self._update_context(context, step)
return "⚠️ Limite d'itérations atteinte sans réponse définitive."
def _build_initial_context(self, query: str) -> str:
"""Construit le contexte initial avec le prompt ReAct"""
tools_description = self._format_tools()
prompt = f"""Tu es un agent de résolution de problèmes utilisant le pattern ReAct.
Outils disponibles :
{tools_description}
Pour chaque étape, tu dois raisonner en suivant ce format EXACT :
Thought: [ton raisonnement sur la situation actuelle]
Action: [nom de l'outil à utiliser, ou "finish" si tu as la réponse finale]
Action Input: {{"param1": "value1", "param2": "value2"}}
Quand tu as la réponse finale, utilise :
Thought: [explication finale]
Action: finish
Final Answer: [ta réponse complète]
Question : {query}
Commence maintenant."""
return prompt
def _format_tools(self) -> str:
"""Formate la description des outils pour le prompt"""
descriptions = []
for tool_name, tool_fn in self.tools.items():
# Extraire la docstring
doc = tool_fn.__doc__ or "Pas de description"
descriptions.append(f"- {tool_name}: {doc.strip()}")
return "\n".join(descriptions)
def _generate_step(self, context: str, steps: List[Step]) -> Dict[str, Any]:
"""Génère la prochaine pensée et action via le LLM"""
# Construire l'historique
messages = [{"role": "user", "content": context}]
# Ajouter les étapes précédentes
for step in steps:
step_text = f"Thought: {step.thought}\nAction: {step.action}\nAction Input: {json.dumps(step.action_input)}\nObservation: {step.observation}"
messages.append({"role": "assistant", "content": step_text})
# Demander la prochaine étape
messages.append({"role": "user", "content": "Quelle est ta prochaine pensée et action ?"})
response = openai.chat.completions.create(
model=self.model,
messages=messages,
temperature=0.0 # Déterministe pour la reproductibilité
)
# Parser la réponse du LLM
content = response.choices[0].message.content
return self._parse_react_response(content)
def _parse_react_response(self, content: str) -> Dict[str, Any]:
"""Parse la réponse du LLM au format ReAct"""
result = {
"thought": "",
"action": None,
"action_input": {},
"final_answer": None
}
lines = content.split('\n')
current_key = None
for line in lines:
line = line.strip()
if line.startswith("Thought:"):
result["thought"] = line.replace("Thought:", "").strip()
current_key = "thought"
elif line.startswith("Action:"):
action = line.replace("Action:", "").strip()
result["action"] = action
current_key = "action"
elif line.startswith("Action Input:"):
input_str = line.replace("Action Input:", "").strip()
try:
result["action_input"] = json.loads(input_str)
except:
# Fallback : traiter comme un string simple
result["action_input"] = {"input": input_str}
current_key = "action_input"
elif line.startswith("Final Answer:"):
result["final_answer"] = line.replace("Final Answer:", "").strip()
current_key = "final_answer"
elif current_key and line:
# Continuer la valeur actuelle (multi-lignes)
result[current_key] += " " + line
return result
def _update_context(self, context: str, step: Step) -> str:
"""Met à jour le contexte avec la dernière observation"""
# Dans une implémentation réelle, gérer la limite de tokens
return context
# ============= OUTILS D'EXEMPLE =============
def search_wikipedia(query: str) -> str:
"""Recherche sur Wikipédia français et retourne un résumé."""
import wikipedia
wikipedia.set_lang("fr")
try:
page = wikipedia.page(query, auto_suggest=True)
return page.summary[:500] + "..."
except wikipedia.DisambiguationError as e:
return f"Plusieurs résultats : {', '.join(e.options[:3])}"
except wikipedia.PageError:
return f"Aucun résultat trouvé pour '{query}'"
except Exception as e:
return f"Erreur : {str(e)}"
def calculator(expression: str) -> str:
"""Effectue un calcul mathématique. Exemple : expression='2+2' retourne '4'."""
try:
result = eval(expression) # ⚠️ Utiliser ast.literal_eval en production
return str(result)
except Exception as e:
return f"Erreur de calcul : {str(e)}"
def get_current_date() -> str:
"""Retourne la date actuelle."""
from datetime import datetime
return datetime.now().strftime("%Y-%m-%d")
# ============= EXEMPLE D'UTILISATION =============
if __name__ == "__main__":
# Créer l'agent avec des outils
agent = ReActAgent(
llm_model="gpt-4",
tools={
"search": search_wikipedia,
"calculator": calculator,
"get_date": get_current_date
},
max_iterations=10,
verbose=True
)
# Exemple 1 : Question nécessitant recherche + calcul
result = agent.run("""
Trouve l'année de naissance de Marie Curie,
puis calcule combien d'années se sont écoulées depuis.
""")
print(f"\n\n{'#'*60}")
print(f"RÉSULTAT FINAL : {result}")
print(f"{'#'*60}")
Sortie Exemple
============================================================
🔄 Itération 1/10
============================================================
💭 Pensée : Je dois d'abord rechercher l'année de naissance de Marie Curie
🔧 Action : search({'query': 'Marie Curie'})
👁️ Observation : Marie Curie, née Maria Salomea Skłodowska le 7 novembre 1867 à Varsovie...
============================================================
🔄 Itération 2/10
============================================================
💭 Pensée : Marie Curie est née en 1867. Maintenant je dois calculer combien d'années se sont écoulées.
🔧 Action : get_date({})
👁️ Observation : 2024-11-20
============================================================
🔄 Itération 3/10
============================================================
💭 Pensée : Nous sommes en 2024. Je dois calculer 2024 - 1867
🔧 Action : calculator({'expression': '2024 - 1867'})
👁️ Observation : 157
============================================================
🔄 Itération 4/10
============================================================
✅ Réponse finale : Marie Curie est née en 1867. 157 années se sont écoulées depuis sa naissance.
############################################################
RÉSULTAT FINAL : Marie Curie est née en 1867. 157 années se sont écoulées depuis sa naissance.
############################################################
Autres Patterns d’Agents
Plan-and-Execute
Principe : Planifier d’abord, exécuter ensuite
1️⃣ PLAN : Décomposer en sous-tâches
2️⃣ EXECUTE : Exécuter chaque tâche séquentiellement
3️⃣ SYNTHESIZE: Combiner les résultats
Quand l’utiliser :
- Tâches complexes nécessitant 5+ étapes
- Budget token important
- Besoin de visibilité sur le plan
Implémentation :
class PlanAndExecuteAgent:
"""Agent qui planifie puis exécute"""
def __init__(self, llm_model="gpt-4", tools=None):
self.model = llm_model
self.executor = ReActAgent(llm_model=llm_model, tools=tools)
def run(self, query: str) -> str:
# Phase 1 : PLANIFICATION
plan = self._create_plan(query)
print(f"\n📋 PLAN CRÉÉ ({len(plan)} étapes) :")
for i, step in enumerate(plan, 1):
print(f" {i}. {step}")
# Phase 2 : EXÉCUTION
results = []
for i, step in enumerate(plan, 1):
print(f"\n▶️ ÉTAPE {i}/{len(plan)} : {step}")
result = self.executor.run(step)
results.append(result)
print(f"✅ Résultat : {result[:100]}...")
# Phase 3 : SYNTHÈSE
final_answer = self._synthesize(query, plan, results)
return final_answer
def _create_plan(self, query: str) -> List[str]:
"""Crée un plan détaillé étape par étape"""
response = openai.chat.completions.create(
model=self.model,
messages=[{
"role": "user",
"content": f"""Décompose cette tâche en étapes simples et séquentielles.
Chaque étape doit être une question ou action spécifique.
Tâche : {query}
Réponds uniquement avec une liste numérotée :
1. [première étape]
2. [deuxième étape]
..."""
}],
temperature=0.0
)
plan_text = response.choices[0].message.content
# Parser la liste
steps = []
for line in plan_text.split('\n'):
line = line.strip()
# Extraire les lignes qui commencent par un numéro
if line and line[0].isdigit():
# Retirer le numéro et le point
step = line.split('.', 1)[1].strip()
steps.append(step)
return steps
def _synthesize(self, original_query: str, plan: List[str], results: List[str]) -> str:
"""Synthétise les résultats en une réponse finale"""
plan_results = "\n".join([
f"{i+1}. {plan[i]}\n → {results[i]}"
for i in range(len(plan))
])
response = openai.chat.completions.create(
model=self.model,
messages=[{
"role": "user",
"content": f"""Synthétise ces résultats en une réponse complète.
Question originale : {original_query}
Étapes et résultats :
{plan_results}
Fournis une réponse finale cohérente et complète."""
}],
temperature=0.0
)
return response.choices[0].message.content
# Exemple d'utilisation
agent = PlanAndExecuteAgent(
llm_model="gpt-4",
tools={
"search": search_wikipedia,
"calculator": calculator
}
)
result = agent.run("""
Analyse l'impact économique de l'IA en 2024 :
- PIB généré par l'IA
- Nombre d'emplois créés vs détruits
- Top 3 des secteurs impactés
""")
Sortie :
📋 PLAN CRÉÉ (4 étapes) :
1. Recherche le PIB généré par l'IA en 2024
2. Trouve les statistiques sur les emplois créés et détruits par l'IA
3. Identifie les 3 secteurs les plus impactés par l'IA
4. Synthétise les informations en une analyse cohérente
▶️ ÉTAPE 1/4 : Recherche le PIB généré par l'IA en 2024
...
✅ Résultat : Selon les estimations, l'IA a généré environ 1,2 trillion de dollars...
[etc.]
Avantages :
- ✅ Structure claire et prévisible
- ✅ Facile à déboguer (plan visible)
- ✅ Parallélisation possible si étapes indépendantes
Inconvénients :
- ❌ Moins flexible (plan fixé d’avance)
- ❌ Plus coûteux (2x d’appels LLM)
- ❌ Pas d’adaptation si une étape échoue
Reflexion (Auto-Correction)
Principe : L’agent critique et améliore ses propres réponses
1️⃣ GENERATE : Générer une réponse initiale
2️⃣ REFLECT : Critiquer la réponse
3️⃣ IMPROVE : Améliorer basé sur la critique
4️⃣ Répéter jusqu'à satisfaction
Implémentation :
class ReflexionAgent:
"""Agent avec capacité d'auto-réflexion"""
def __init__(self, llm_model="gpt-4", max_reflections=3):
self.model = llm_model
self.max_reflections = max_reflections
def run(self, query: str) -> str:
# Génération initiale
current_answer = self._generate_initial_answer(query)
print(f"📝 Réponse initiale : {current_answer[:200]}...")
# Boucle de réflexion
for i in range(self.max_reflections):
print(f"\n🔍 RÉFLEXION {i+1}/{self.max_reflections}")
# Auto-critique
critique = self._reflect(query, current_answer)
print(f"💭 Critique : {critique['feedback']}")
if critique["is_satisfactory"]:
print(f"✅ Réponse satisfaisante après {i+1} réflexions")
break
# Amélioration
improved = self._improve(query, current_answer, critique["feedback"])
print(f"✨ Amélioration : {improved[:200]}...")
current_answer = improved
return current_answer
def _generate_initial_answer(self, query: str) -> str:
"""Génère une première réponse"""
response = openai.chat.completions.create(
model=self.model,
messages=[{"role": "user", "content": query}]
)
return response.choices[0].message.content
def _reflect(self, query: str, answer: str) -> Dict:
"""Critique la réponse actuelle"""
response = openai.chat.completions.create(
model=self.model,
messages=[{
"role": "user",
"content": f"""Tu es un critique expert. Évalue cette réponse :
Question : {query}
Réponse : {answer}
Critères d'évaluation :
1. Exactitude factuelle
2. Complétude (tous les aspects couverts)
3. Clarté et structure
4. Exemples et preuves
Réponds en JSON :
{{
"is_satisfactory": true/false,
"feedback": "Critique détaillée avec suggestions d'amélioration"
}}"""
}],
response_format={"type": "json_object"}
)
return json.loads(response.choices[0].message.content)
def _improve(self, query: str, current: str, feedback: str) -> str:
"""Améliore la réponse basée sur le feedback"""
response = openai.chat.completions.create(
model=self.model,
messages=[{
"role": "user",
"content": f"""Améliore cette réponse en tenant compte du feedback.
Question : {query}
Réponse actuelle : {current}
Feedback : {feedback}
Fournis une version améliorée qui adresse tous les points du feedback."""
}]
)
return response.choices[0].message.content
# Exemple
agent = ReflexionAgent(llm_model="gpt-4", max_reflections=3)
result = agent.run("Explique comment fonctionne un transformeur en IA")
Avantages :
- ✅ Qualité supérieure (+15-30%)
- ✅ Auto-correction des erreurs
- ✅ Utile pour tâches créatives (rédaction, code)
Inconvénients :
- ❌ 3-5x plus coûteux
- ❌ Plus lent (latence élevée)
- ❌ Peut boucler sans amélioration
Tree of Thoughts (ToT)
Principe : Explorer plusieurs branches de raisonnement en parallèle
Question
|
┌────────────┼────────────┐
↓ ↓ ↓
Pensée A Pensée B Pensée C
| | |
┌─────┼─────┐ | ┌────┼────┐
↓ ↓ ↓ ↓ ↓ ↓ ↓
A1 A2 A3 B1 C1 C2 C3
→ Évaluer chaque branche
→ Garder les meilleures
→ Continuer jusqu'à solution
Implémentation simplifiée :
class TreeOfThoughtsAgent:
"""Agent utilisant Tree of Thoughts"""
def __init__(self, llm_model="gpt-4", branches=3, depth=3):
self.model = llm_model
self.branches = branches # Nombre de pensées à générer
self.depth = depth # Profondeur de l'arbre
def run(self, query: str) -> str:
# Générer plusieurs chemins de raisonnement
paths = self._explore(query, current_depth=0)
# Évaluer tous les chemins
best_path = self._select_best_path(paths)
# Synthétiser la réponse finale
return self._synthesize_answer(best_path)
def _explore(self, state: str, current_depth: int, path: List = None) -> List:
"""Explore l'arbre de pensées"""
if path is None:
path = []
if current_depth >= self.depth:
return [path]
# Générer N pensées alternatives
thoughts = self._generate_thoughts(state, n=self.branches)
all_paths = []
for thought in thoughts:
new_path = path + [thought]
# Évaluer si cette pensée est prometteuse
score = self._evaluate_thought(thought)
if score > 0.3: # Seuil de pruning
# Continuer l'exploration
sub_paths = self._explore(thought, current_depth + 1, new_path)
all_paths.extend(sub_paths)
return all_paths
def _generate_thoughts(self, state: str, n: int) -> List[str]:
"""Génère N pensées alternatives"""
response = openai.chat.completions.create(
model=self.model,
messages=[{
"role": "user",
"content": f"""Génère {n} approches différentes pour résoudre ceci :
{state}
Réponds avec {n} pensées numérotées."""
}],
n=n, # Générer N completions
temperature=0.8 # Plus de diversité
)
thoughts = [choice.message.content for choice in response.choices]
return thoughts
def _evaluate_thought(self, thought: str) -> float:
"""Évalue la qualité d'une pensée (0-1)"""
response = openai.chat.completions.create(
model=self.model,
messages=[{
"role": "user",
"content": f"""Évalue cette pensée sur 10 :
{thought}
Réponds uniquement avec un chiffre entre 0 et 10."""
}]
)
try:
score = float(response.choices[0].message.content.strip())
return score / 10.0
except:
return 0.5 # Score par défaut
def _select_best_path(self, paths: List[List]) -> List:
"""Sélectionne le meilleur chemin"""
# Simplification : retourner le chemin le plus long
return max(paths, key=len)
def _synthesize_answer(self, path: List) -> str:
"""Synthétise la réponse finale depuis le chemin"""
reasoning_chain = "\n".join([f"Étape {i+1}: {thought}" for i, thought in enumerate(path)])
response = openai.chat.completions.create(
model=self.model,
messages=[{
"role": "user",
"content": f"""Basé sur ce raisonnement, fournis la réponse finale :
{reasoning_chain}"""
}]
)
return response.choices[0].message.content
Avantages :
- ✅ Explore plusieurs solutions
- ✅ Excellent pour problèmes complexes (maths, logique)
- ✅ +25% précision sur Game of 24, Crosswords
Inconvénients :
- ❌ Extrêmement coûteux (10-50x)
- ❌ Très lent (plusieurs minutes)
- ❌ Overkill pour la plupart des cas
Comparaison des Patterns
| Pattern | Coût | Latence | Précision | Cas d’Usage Idéal |
|---|---|---|---|---|
| ReAct | 💰 (Base) | ⚡ 5-20s | ⭐⭐⭐⭐ | Usage général, recherche, calcul |
| Plan-and-Execute | 💰💰 (2x) | ⚡⚡ 10-40s | ⭐⭐⭐⭐ | Tâches structurées, workflows |
| Reflexion | 💰💰💰 (3-5x) | ⚡⚡⚡ 15-60s | ⭐⭐⭐⭐⭐ | Rédaction, code, créativité |
| Tree of Thoughts | 💰💰💰💰💰 (10-50x) | ⚡⚡⚡⚡ 60-300s | ⭐⭐⭐⭐⭐ | Problèmes complexes, maths |
Choix du pattern : Commencez toujours par ReAct. Si la qualité n’est pas suffisante, passez à Plan-and-Execute pour les tâches structurées ou Reflexion pour maximiser la qualité. Tree of Thoughts n’est pertinent que pour la recherche académique.
Recommandation :
- 90% des cas : Utiliser ReAct
- Tâches complexes : Plan-and-Execute
- Haute qualité : Reflexion (si budget permet)
- Recherche/Expérimentation : Tree of Thoughts
Optimisations de ReAct
Few-Shot Learning
Améliorer les performances avec des exemples :
FEW_SHOT_EXAMPLES = """
Exemple 1 :
Question: Quelle est la population de Tokyo ?
Thought: Je dois rechercher la population actuelle de Tokyo.
Action: search
Action Input: {"query": "population Tokyo 2024"}
Observation: Tokyo compte 37,4 millions d'habitants (aire métropolitaine).
Thought: J'ai trouvé l'information.
Action: finish
Final Answer: Tokyo compte environ 37,4 millions d'habitants.
Exemple 2 :
Question: Combien font 15% de 240 ?
Thought: C'est un calcul simple, je vais utiliser la calculatrice.
Action: calculator
Action Input: {"expression": "240 * 0.15"}
Observation: 36.0
Thought: Le résultat est 36.
Action: finish
Final Answer: 15% de 240 = 36.
Maintenant, résous cette question :
"""
# Ajouter au prompt initial
prompt = FEW_SHOT_EXAMPLES + f"\nQuestion: {user_query}"
Résultat : +10-15% de précision
Self-Consistency
Exécuter l’agent N fois et voter :
def run_with_self_consistency(agent, query, n=5):
"""Exécute l'agent N fois et prend la réponse majoritaire"""
answers = []
for i in range(n):
answer = agent.run(query)
answers.append(answer)
# Vote majoritaire
from collections import Counter
most_common = Counter(answers).most_common(1)[0]
return {
"answer": most_common[0],
"confidence": most_common[1] / n,
"all_answers": answers
}
# Utilisation
result = run_with_self_consistency(agent, "Question difficile", n=5)
print(f"Réponse : {result['answer']} (confiance: {result['confidence']*100}%)")
Résultat : +5-10% précision, mais 5x plus coûteux
Dynamic Few-Shot (RAG)
Récupérer les exemples les plus pertinents dynamiquement :
from sentence_transformers import SentenceTransformer
import numpy as np
class DynamicFewShotAgent(ReActAgent):
"""Agent avec exemples few-shot dynamiques"""
def __init__(self, *args, example_bank=None, **kwargs):
super().__init__(*args, **kwargs)
self.example_bank = example_bank or []
self.encoder = SentenceTransformer('all-MiniLM-L6-v2')
# Encoder tous les exemples
self.example_embeddings = self.encoder.encode([ex["query"] for ex in self.example_bank])
def _build_initial_context(self, query: str) -> str:
"""Surcharge pour ajouter des exemples pertinents"""
# Trouver les 3 exemples les plus similaires
query_embedding = self.encoder.encode([query])
similarities = np.dot(self.example_embeddings, query_embedding.T).flatten()
top_indices = similarities.argsort()[-3:][::-1]
# Construire le prompt avec les exemples
examples = "\n\n".join([self._format_example(self.example_bank[i]) for i in top_indices])
return f"""{examples}
Maintenant, résous cette question :
{query}"""
def _format_example(self, example: Dict) -> str:
return f"""Question: {example['query']}
{example['trajectory']}
Final Answer: {example['answer']}"""
Exercices Pratiques
Implémenter un ReAct Agent Minimal
Créez un agent ReAct capable de :
- Rechercher sur Wikipédia
- Faire des calculs
- Obtenir la date/heure actuelle
Testez avec : “Combien d’années se sont écoulées depuis la découverte de l’Amérique par Christophe Colomb ?”
Plan-and-Execute
Implémentez un agent Plan-and-Execute et testez avec une tâche complexe nécessitant 5+ étapes.
Comparaison
Comparez ReAct vs Plan-and-Execute sur 10 questions. Mesurez :
- Nombre d’appels LLM
- Latence totale
- Précision des réponses
Ressources
Papers
- ReAct (2022) : Synergizing Reasoning and Acting in Language Models
- Tree of Thoughts (2023) : Deliberate Problem Solving
- Reflexion (2023) : Language Agents with Verbal Reinforcement Learning
Benchmarks
- HotpotQA : Questions multi-étapes
- FEVER : Vérification de faits
- WebShop : Navigation et achat
Prochaines Étapes
Dans le prochain article, nous explorerons LangChain Agents :
- Types d’agents pré-construits
- Personnalisation des prompts
- Gestion de la mémoire
- Debugging et optimisation
Points clés à retenir :
- ReAct est le pattern recommandé pour 90% des cas
- Le raisonnement explicite réduit drastiquement les erreurs
- Plan-and-Execute pour les tâches complexes structurées
- Reflexion pour maximiser la qualité (si budget permet)
- Tree of Thoughts seulement pour problèmes très complexes
Navigation
← Retour à la série Agents IA | Module suivant : Agents avec LangChain →