4.2 ReAct i Chain-of-Thought¶
En Resum
ReAct (Reason + Act) i Chain-of-Thought (CoT) són dos patrons fonamentals que permeten als LLM raonar explícitament pas a pas, millorant dràsticament la qualitat en tasques complexes.
🧪 Chain-of-Thought (CoT): Raonar Pas a Pas¶
El Problema sense CoT¶
Els LLM fallen en tasques de raonament multi-pas quan se'ls demana una resposta directa:
❌ SENSE CHAIN-OF-THOUGHT:
Pregunta: "Si tenim 23 alumnes i 3 professors,
i cada grup ha de tenir el mateix nombre
d'estudiants i com a mínim 1 professor,
quants grups podem formar maximitzant la participació?"
Resposta LLM (directa): "Podem formar 3 grups." ← Incorrecte o sense justificació!
Amb CoT: El Model Mostra el Raonament¶
✅ AMB CHAIN-OF-THOUGHT (simplement afegint "Pensa pas a pas"):
Pregunta: "(...) Pensa pas a pas."
Resposta LLM:
1. Tenim 23 alumnes i 3 professors.
2. Cada grup necessita com a mínim 1 professor → màxim 3 grups.
3. Si fem 3 grups, cada professor supervisa 1 grup.
4. Distribució d'alumnes: 23 ÷ 3 = 7 grups de 7, un grup de 9 (23 = 7+7+9).
5. Per maximitzar la participació = distribuir el més igual possible.
6. 3 grups: 8 + 8 + 7 alumnes (la distribució més equitativa).
Resposta final: 3 grups de 7-8 alumnes, un professor per grup.
Tipus de CoT¶
Simplement afegir la frase màgica al final del prompt:
Proporcionar exemples de raonament per guiar el model:
El model genera automàticament exemples de raonament:
from langchain_openai import ChatOpenAI
from langchain.prompts import ChatPromptTemplate
# Primera crida: generar exemples de raonament
llm = ChatOpenAI(model="gpt-4o", temperature=0.7)
examples_prompt = ChatPromptTemplate.from_template("""
Genera 3 exemples de problemes similars a: "{problema}"
Per a cada exemple, mostra el raonament pas a pas.
Format: Problema | Raonament pas a pas | Resposta
""")
# Segona crida: resoldre amb els exemples generats
solve_prompt = ChatPromptTemplate.from_template("""
{exemples}
Seguint el mateix patró de raonament, resol:
{problema}
Raonament pas a pas:
""")
🔄 ReAct: Raonament + Acció¶
El Framework ReAct¶
ReAct (Reasoning + Acting) és un patró publicat per Google Research al paper "ReAct: Synergizing Reasoning and Acting in Language Models" (Yao et al., 2022). La idea: alternar explícitament entre pensar (Thought) i actuar (Action/Observation).
Thought: Raonament intern del model
Action: Quina eina cridar i amb quins arguments
Observation: Resultat de l'eina
... (repetir fins que es pugui respondre)
Final Answer: Resposta definitiva
Exemple Real d'un Agent ReAct¶
# Exemple de TRAÇA REAL d'un agent ReAct amb verbose=True
# pip install langchain langchain-openai wikipedia --break-system-packages
from langchain_openai import ChatOpenAI
from langchain.agents import create_react_agent, AgentExecutor
from langchain.tools import WikipediaQueryRun
from langchain_community.utilities import WikipediaAPIWrapper
from langchain import hub
llm = ChatOpenAI(model="gpt-4o-mini", temperature=0)
tools = [
WikipediaQueryRun(api_wrapper=WikipediaAPIWrapper()),
]
prompt = hub.pull("hwchase17/react")
agent = create_react_agent(llm, tools, prompt)
executor = AgentExecutor(agent=agent, tools=tools, verbose=True)
result = executor.invoke({
"input": "Quina és la diferència d'edat entre Linus Torvalds "
"i Guido van Rossum?"
})
> Entering new AgentExecutor chain...
Thought: Necessito saber l'any de naixement de Linus Torvalds
i de Guido van Rossum per calcular la diferència d'edat.
Buscaré informació sobre Linus Torvalds primer.
Action: wikipedia
Action Input: Linus Torvalds
Observation: Linus Benedict Torvalds (born December 28, 1969) is a
Finnish-American software engineer who created the Linux kernel...
Thought: Linus Torvalds va néixer el 28 de desembre de 1969.
Ara busco Guido van Rossum.
Action: wikipedia
Action Input: Guido van Rossum
Observation: Guido van Rossum (born January 31, 1956) is a Dutch
programmer best known as the creator of Python...
Thought: Guido van Rossum va néixer el 31 de gener de 1956.
Ara puc calcular la diferència d'edat:
1969 - 1956 = 13 anys.
Però he de ser més precís: Torvalds va néixer al desembre,
van Rossum al gener. Per tant, durant la major part de l'any,
la diferència és de 13 anys.
Final Answer: La diferència d'edat entre Linus Torvalds (nascut el 28
de desembre de 1969) i Guido van Rossum (nascut el 31 de gener de
1956) és de 13 anys. Van Rossum és 13 anys més gran.
> Finished chain.
🌳 Tree of Thoughts (ToT): Explorar Múltiples Camins¶
Publicat per Princeton el 2023, ToT és una extensió de CoT que explora múltiples raonaments en paral·lel i selecciona el millor.
CoT: Problema → Pensament1 → Pensament2 → Pensament3 → Resposta
(Una sola cadena de raonament)
ToT: Problema → Pensament1a → Pensament2a → Resposta A
→ Pensament2b → Resposta B (seleccionada!)
→ Pensament1b → Pensament2c → Resposta C
(Explora un arbre de possibilitats, selecciona la millor)
# Implementació simplificada de ToT amb LangChain
# (Versió conceptual — implementació real és més complexa)
from langchain_openai import ChatOpenAI
from langchain.prompts import ChatPromptTemplate
llm = ChatOpenAI(model="gpt-4o", temperature=0.7)
def tree_of_thoughts(problem: str, n_thoughts: int = 3) -> str:
"""
Genera múltiples raonaments per a un problema
i selecciona el millor.
"""
# Pas 1: Generar múltiples pensaments inicials
generate_prompt = ChatPromptTemplate.from_template("""
Problema: {problem}
Genera {n} enfocaments completament DIFERENTS per resoldre'l.
Per a cada enfocament, explica la idea bàsica en 2 frases.
Format: ENFOCAMENT 1: ... | ENFOCAMENT 2: ... | ENFOCAMENT 3: ...
""")
thoughts_response = llm.invoke(
generate_prompt.format_messages(problem=problem, n=n_thoughts)
)
# Pas 2: Avaluar i seleccionar el millor pensament
evaluate_prompt = ChatPromptTemplate.from_template("""
Problema: {problem}
Enfocaments proposats:
{thoughts}
Avalua cada enfocament (viabilitat, completesa, simplicitat).
Selecciona el millor i desenvolupa'l completament.
Explica per qué l'has seleccionat.
""")
final_response = llm.invoke(
evaluate_prompt.format_messages(
problem=problem,
thoughts=thoughts_response.content
)
)
return final_response.content
# Exemple d'ús
result = tree_of_thoughts(
"Dissenyar un sistema per detectar i alertar sobre failures "
"en microserveis sense degradar el rendiment."
)
print(result)
📊 Comparació dels Patrons de Raonament¶
| Patró | Quan Usar | Avantatges | Inconvenients |
|---|---|---|---|
| Directe | Preguntes simples i factuals | Ràpid, barat | Falla en raonament complex |
| Zero-Shot CoT | Tasques de raonament generals | Simple, eficaç | Pot generar raonaments erronis |
| Few-Shot CoT | Tasques amb patrons repetitius | Alta qualitat, consistent | Requereix exemples manuals |
| ReAct | Tasques que requereixen informació externa | Pot cercar dades actuals | Més lent, usa més tokens |
| ToT | Problemes complexos amb múltiples solucions | Explora alternatives | Molt car en tokens |
💻 Implementació Avançada: Agent ReAct amb Múltiples Eines¶
# Agent complet amb múltiples eines i ReAct
# pip install langchain langchain-openai duckduckgo-search wikipedia python-dotenv
import os
from dotenv import load_dotenv
from langchain_openai import ChatOpenAI
from langchain.agents import create_react_agent, AgentExecutor
from langchain.tools import (
DuckDuckGoSearchResults,
WikipediaQueryRun,
)
from langchain_community.utilities import WikipediaAPIWrapper
from langchain.tools import tool
from langchain import hub
import math
load_dotenv() # Carrega OPENAI_API_KEY del fitxer .env
# ── EINES PERSONALITZADES ─────────────────────────────────────
@tool
def calculadora(expressio: str) -> str:
"""
Calcula expressions matemàtiques.
Útil per a sumes, restes, multiplicacions, divisions, potències.
Exemples: '25 * 4', 'sqrt(144)', '2**10'
"""
try:
# Atenció: eval() amb expressions de l'usuari és insegur en producció!
# Usar una llibreria com numexpr o sympy en entorns reals.
resultat = eval(expressio, {"__builtins__": {}}, {"sqrt": math.sqrt, "pi": math.pi})
return f"Resultat: {resultat}"
except Exception as e:
return f"Error en el càlcul: {str(e)}"
@tool
def data_actual(query: str) -> str:
"""
Retorna la data i hora actuals.
Útil quan cal saber quina data és avui.
"""
from datetime import datetime
now = datetime.now()
return f"Data i hora actuals: {now.strftime('%A, %d de %B de %Y, %H:%M')}"
# ── CONFIGURACIÓ DE L'AGENT ────────────────────────────────────
llm = ChatOpenAI(
model="gpt-4o",
temperature=0,
max_tokens=2000
)
tools = [
DuckDuckGoSearchResults(name="cerca_web"),
WikipediaQueryRun(api_wrapper=WikipediaAPIWrapper()),
calculadora,
data_actual,
]
# Prompt personalitzat que indica la llengua
prompt = hub.pull("hwchase17/react")
agent = create_react_agent(llm, tools, prompt)
executor = AgentExecutor(
agent=agent,
tools=tools,
verbose=True,
max_iterations=8,
handle_parsing_errors=True,
early_stopping_method="generate"
)
# ── TASQUES DE PROVA ──────────────────────────────────────────
tasques = [
"Quants dies han passat des de la creació de Linux fins avui?",
"Quin és el logaritme en base 2 de 1024?",
"Quin és el país amb més habitants del món i quina és la seva capital?",
]
for tasca in tasques:
print(f"\n{'='*60}")
print(f"📝 TASCA: {tasca}")
print('='*60)
result = executor.invoke({"input": tasca})
print(f"\n✅ RESPOSTA FINAL: {result['output']}")
✅ Activitats de Consolidació¶
Exercici 4.2.1 — Observar el ReAct
Executa l'exemple del "Agent ReAct Complet" amb verbose=True i analitza:
- Quantes iteracions (Thought → Action → Observation) ha necessitat?
- En algun moment el model ha comès un error de raonament? Com l'ha corregit?
- Ha usat la calculadora quan hauria pogut usar la cerca web o viceversa?
Exercici 4.2.2 — Afegir una Eina Pròpia
Afegeix almenys dues eines noves a l'agent:
- Una eina que llegeixi un fitxer de text local
- Una eina que retorni el temps actual d'una ciutat via API (p.ex. wttr.in)
Prova l'agent amb tasques que requereixin usar ambdues eines.
Exercici 4.2.3 — Comparació CoT vs Directe
Per a les tasques següents, compara la resposta del model (a) directament i (b) amb "Pensa pas a pas":
- "Un tren va de A a B a 120km/h. La distància és 360km. Si surt a les 9:00, a quina hora arriba?"
- "Si tinc 100€ i faig 3 inversions successives amb guany del 10% cada una, quant tinc al final?"
Documenta si CoT millora la precisió i per qué.
📚 Referències¶
- Yao, S. et al. (2022). "ReAct: Synergizing Reasoning and Acting in Language Models". arXiv:2210.03629
- Wei, J. et al. (2022). "Chain-of-Thought Prompting Elicits Reasoning in Large Language Models". arXiv:2201.11903
- Yao, S. et al. (2023). "Tree of Thoughts: Deliberate Problem Solving with Large Language Models". arXiv:2305.10601