¿Cómo deciden los agentes qué hacer?
Un chatbot genera una respuesta por mensaje: el usuario pregunta, el modelo responde, conversación terminada. Un agente, por el contrario, debe tomar una secuencia de decisiones. En cada paso enfrenta preguntas que un modelo de un solo turno nunca encuentra: ¿qué herramienta debería llamar? ¿Qué argumentos debería pasar? ¿La acción anterior tuvo éxito o falló? ¿Tengo suficiente información para responder al usuario, o necesito otro paso? ¿Debería intentar un enfoque completamente diferente?
Esto requiere algo más allá de la coincidencia de patrones de los datos de entrenamiento. El agente necesita razonar sobre su estado actual: lo que sabe, lo que no sabe, lo que ha intentado y lo que debería intentar a continuación. Sin razonamiento explícito, un agente llamando herramientas es como alguien presionando botones al azar en una calculadora esperando obtener la respuesta correcta. Podría tropezar con una solución para tareas simples, pero para cualquier cosa que requiera múltiples pasos coordinados, fallará.
La idea clave proviene de un artículo de 2022 llamado ReAct (Yao et al., 2023) , que propuso una idea sorprendentemente simple: intercalar razonamiento (pensar en lenguaje natural) con acción (calling tools and observing results). Instead of going directly from user question to tool call, the model first writes down what it's thinking and why it's choosing a particular action. This "thinking out loud" turns out to be the difference between an agent that works and one that spins in circles.
ReAct: Pensar, luego actuar, luego observar
El patrón ReAct estructura el comportamiento del agente en un ciclo repetitivo de tres pasos: Pensamiento , Acción , y Observación . Let's walk through a concrete example. Suppose a user asks: "What is France's GDP per capita?" An agent with access to a search tool might proceed like this:
Pensamiento: I need to calculate GDP per capita, which is GDP / population.
I'll start by searching for France's population.
Acción: search("population of France 2024")
Observación: France population: 68.4 million (2024 estimate)
Pensamiento: Good, I have the population. Now I need France's GDP.
Acción: search("GDP of France 2024")
Observación: France GDP: $3.13 trillion (2024)
Pensamiento: I have both numbers. GDP per capita = $3.13T / 68.4M = ~$45,760.
I can now answer the user.
Answer: France's GDP per capita is approximately $45,760.
Observa lo que están haciendo los pasos de Pensamiento. El primer pensamiento descompone el problema (el PIB per cápita requiere dos datos) y elige cuál obtener primero. El segundo pensamiento reconoce el resultado e identifica lo que aún falta. El tercer pensamiento realiza el cálculo y decide que el agente tiene suficiente información para detenerse. Sin estos pensamientos, el modelo necesitaría planificar todo esto implícitamente en sus estados ocultos, lo que funciona para casos triviales pero falla a medida que las tareas se vuelven más complejas.
¿Por qué importan tanto los pensamientos explícitos? Tres razones:
- Depurabilidad: when an agent goes wrong, the thoughts tell you exactly where its razonamiento broke. Without thoughts, you see a secuencia of tool calls with no explanation, y diagnosing the failure requires guessing what the model was "thinking".
- Corrección de rumbo: the act of writing a thought forces the model to evaluate the current state. If the previous search returned irrelevant results, the thought step is where the model notices and adjusts ("That search didn't work, let me try a different query").
- Razonamiento en borrador: los pensamientos sirven como una memoria de trabajo. El modelo puede mantener cálculos intermedios, respuestas parciales y sub-objetivos restantes en el texto, en lugar de depender de su limitada memoria de trabajo implícita.
Es útil comparar ReAct con dos alternativas. Cadena de pensamiento (CoT) (Wei et al., 2022) hace que un modelo razone paso a paso, pero nunca toma acciones: todo el razonamiento ocurre de una sola vez, usando solo el conocimiento que ya está en los pesos del modelo. CoT puede descomponer un problema bellamente, pero si necesita datos externos (un precio de acciones, una consulta a base de datos, el contenido de un archivo), está atascado. El otro extremo es actuar sin razonar : el modelo llama herramientas directamente basándose en coincidencia de patrones, sin planificación explícita. Esto funciona para llamadas a herramientas de un solo paso pero se desmorona cuando los pasos posteriores dependen de resultados anteriores, porque el modelo no tiene mecanismo para evaluar el progreso o cambiar de estrategia.
El hallazgo clave del artículo de ReAct es que la combinación de razonamiento y acción supera a cualquiera de los dos por separado. En benchmarks como HotpotQA (respuesta a preguntas multi-salto) y FEVER (verificación de hechos), los agentes ReAct superan consistentemente tanto al razonamiento puro con CoT (que no puede buscar cosas) como a la acción pura (que no puede planificar ni corregir el rumbo). Los pensamientos explícitos no son solo una característica útil de depuración; mejoran materialmente el éxito de las tareas.
Planificación: Descomponer tareas en pasos
Las preguntas simples necesitan una llamada a herramienta. Las tareas complejas necesitan un plan : una descomposición de la solicitud del usuario en una secuencia de sub-objetivos, cada uno de los cuales puede involucrar una o más llamadas a herramientas. La forma en que un agente planifica tiene un efecto dramático en su robustez cuando las cosas salen mal.
Hay tres estrategias amplias de planificación:
- Planificación secuencial: generate the full plan upfront, then execute each step in order. For example: "Step 1: search for population. Step 2: search for GDP. Step 3: compute the ratio. Step 4: format the answer." This is simple and fast, but brittle. If step 2 returns unexpected data (say, GDP in euros instead of dollars), the pre-made plan has no way to insert a currency conversion step. The agent either ignores the problem or crashes.
- Planificación dinámica: plan one step at a time, observe the result, then decide the next step. This is exactly what the ReAct loop does: each Pensamiento step is a micro-planning decision based on everything observed so far. It's more robust because the agent can adapt ("The GDP was in euros, I need to convert to USD first"), but it's slower because each step requires a full model inference.
- Planificación jerárquica: break the task into independent subtasks, plan and execute each one separately, then combine the results. For example, a research agent might split "Compare the economies of France and Germany" into two parallel subtasks (one per country), each with its own ReAct loop. This can be faster (subtasks can run in parallel) and more modular, but requires a higher-level orchestrator to manage the subtasks and merge results.
En la práctica, la mayoría de los agentes en producción usan planificación dinámica . La razón es simple: las llamadas a herramientas del mundo real son impredecibles. Las APIs fallan, las búsquedas devuelven resultados irrelevantes, los cálculos producen tipos inesperados. Un agente que se compromete con un plan completo por adelantado no puede manejar ninguna de estas sorpresas. La planificación dinámica, donde el agente razona después de cada acción y decide qué hacer a continuación, es inherentemente más resiliente.
Esto se conecta con una tendencia más amplia en los modelos de lenguaje recientes. Pensamiento extendido (sometimes called "thinking tokens") gives models a dedicated razonamiento phase where they can think extensively before producing an output. Models like o1, DeepSeek-R1, y Claude with extended thinking use this to produce higher-quality plans. The intuition is straightforward: the more tokens a model spends razonamiento, the better its plan tends to be. For agents, this means the quality of each Pensamiento step improves when the model is allowed to think longer, leading to fewer wasted actions and faster task completion overall.
Autocorrección y recuperación de errores
Los agentes cometen errores. Las herramientas devuelven errores, las búsquedas no encuentran nada útil, los cálculos salen mal. La pregunta que separa a un agente útil de uno frustrante es: ¿puede recuperarse?
El mecanismo de recuperación más estudiado es Reflexion (Shinn et al., 2023) . After failing a task, a Reflexion agent doesn't just retry blindly. It first generates a natural-language reflection on what went wrong: "My search query was too specific and returned no results. I should try broader terms." or "I used the wrong formula. GDP per capita is GDP divided by population, not the other way around." This reflection is then added to the agent's context for the next attempt, giving it an explicit memory of past failures to avoid repeating them.
Más allá de Reflexion, los agentes usan varias estrategias de recuperación en la práctica:
- Auto-depuración: el agente ejecuta código, lee el traceback del error y corrige el bug. Este es el bucle central de los agentes de generación de código: escribir código, ejecutarlo, ver el error, revisar. Cada mensaje de error es una observación que retroalimenta el bucle de razonamiento, a menudo llevando a una solución correcta en 2-3 iteraciones.
- Respaldo de herramientas: if one tool fails, try another. "The API returned a 429 rate limit error. Let me try searching the web for the same information instead." or "The calculator can't handle symbolic math. Let me write a Python snippet to compute this." This requires the agent to razonar about tool capabilities, not just tool names.
- Reformulación de consultas: a search that returns no results often just needs a different query. The agent tries "population France 2024" instead of "current demographic statistics French Republic." The Pensamiento step is where the agent notices the mismatch and tries a simpler query.
- Humano en el bucle: when the agent is truly stuck (ambiguous instructions, missing credentials, conflicting information), the best behaviour is to ask the user for help rather than guessing. An agent that says "I found conflicting GDP numbers from two sources. Which one should I trust?" is far more useful than one that silently picks the wrong number.
El hilo común en todas estas estrategias es que el agente debe reconocer el fallo . Esto suena obvio, pero es donde muchos agentes fallan. Un agente que no verifica si una llamada a herramienta tuvo éxito seguirá adelante con datos basura, produciendo una respuesta segura pero incorrecta. Los mejores agentes fallan con gracia: saben cuándo están atascados e intentan un enfoque diferente o piden ayuda, en lugar de alucinar a través del problema.
ReAct en la práctica
Construyamos un bucle ReAct mínimo desde cero. El código a continuación simula un agente con dos herramientas simuladas (un motor de búsqueda y una calculadora) que responde preguntas de múltiples pasos pensando, actuando y observando en un bucle. No se necesitan llamadas a API ni bibliotecas externas; simulamos las decisiones del modelo con una traza codificada para mostrar la mecánica completa del bucle.
# A minimal ReAct loop — pure Python, no external dependencies
# We simulate the LLM's decisions to show the Pensamiento-Acción-Observación cycle
class MockSearchTool:
"""Simulates a search engine with canned results."""
def __init__(self):
self.data = {
"population of France 2024": "France population: 68.4 million (2024 estimate)",
"GDP of France 2024": "France GDP: $3.13 trillion (2024 estimate)",
"capital of France": "The capital of France is Paris.",
}
def search(self, query):
for key, value in self.data.items():
if key.lower() in query.lower():
return value
return "No results found."
class MockCalculator:
"""Evaluates simple arithmetic expressions."""
def calculate(self, expression):
try:
result = eval(expression) # safe here: we control the input
return str(result)
except Exception as e:
return f"Error: {e}"
# --- The ReAct Loop ---
def react_loop(question, planned_steps, max_iterations=10):
"""
Runs a ReAct loop with pre-planned steps (simulating LLM decisions).
In a real system, each 'thought' and 'action' would come from the LLM.
"""
search = MockSearchTool()
calc = MockCalculator()
tools = {"search": search.search, "calculate": calc.calculate}
print(f"Question: {question}")
print("=" * 60)
observations = []
for i, step in enumerate(planned_steps):
if i >= max_iterations:
print(f"
[Max iterations ({max_iterations}) reached]")
break
# THOUGHT
print(f"
Pensamiento {i+1}: {step['thought']}")
# Check if the agent decided to answer
if "answer" in step:
print(f"
Answer: {step['answer']}")
return step["answer"]
# ACTION
tool_name = step["tool"]
tool_arg = step["arg"]
print(f"Acción {i+1}: {tool_name}({repr(tool_arg)})")
# OBSERVATION
if tool_name in tools:
result = tools[tool_name](tool_arg)
else:
result = f"Error: tool '{tool_name}' not found"
print(f"Observación {i+1}: {result}")
observations.append(result)
return None
# Simulate: "What is France's GDP per capita?"
planned_steps = [
{
"thought": "GDP per capita = GDP / population. I need both numbers. "
"Let me search for France's population first.",
"tool": "search",
"arg": "population of France 2024"
},
{
"thought": "Got population: 68.4 million. Now I need France's GDP.",
"tool": "search",
"arg": "GDP of France 2024"
},
{
"thought": "Got GDP: $3.13 trillion. Let me compute: "
"3.13e12 / 68.4e6 = GDP per capita.",
"tool": "calculate",
"arg": "3.13e12 / 68.4e6"
},
{
"thought": "The calculation gives ~$45,760. I have enough to answer.",
"answer": "France's GDP per capita is approximately $45,760."
},
]
react_loop("What is France's GDP per capita?", planned_steps)
En un sistema real, los pasos planificados no estarían codificados. En su lugar, cada Pensamiento y Acción sería generado por un LLM, con el historial completo de la conversación (incluyendo todos los Pensamientos, Acciones y Observaciones anteriores) incluido en el prompt. El bucle se ejecuta hasta que el modelo decide producir una Respuesta final en lugar de otra Acción, o hasta que se alcanza un límite máximo de iteraciones.
Ahora veamos qué pasa cuando las cosas salen mal. El siguiente ejemplo muestra un agente manejando una búsqueda fallida reformulando su consulta, demostrando el comportamiento de autocorrección que discutimos:
# ReAct with error recovery — the agent adapts when a search fails
class MockSearchToolV2:
"""Search that only matches exact queries — forces reformulation."""
def __init__(self):
self.data = {
"population of France 2024": "68.4 million",
"GDP of France 2024 USD": "$3.13 trillion",
}
def search(self, query):
# Only exact substring match
for key, value in self.data.items():
if key.lower() in query.lower():
return value
return "No results found."
search = MockSearchToolV2()
# Simulate an agent that hits a dead end and recovers
steps_with_recovery = [
{
"thought": "I need France's GDP. Let me search for it.",
"tool": "search",
"arg": "French Republic gross domestic product"
},
{
"thought": "That search returned nothing. The query was too formal. "
"Let me try simpler keywords.",
"tool": "search",
"arg": "GDP of France 2024 USD"
},
{
"thought": "Got it: $3.13 trillion. Now I need population.",
"tool": "search",
"arg": "population of France 2024"
},
{
"thought": "Population is 68.4 million. "
"GDP per capita = $3.13T / 68.4M = ~$45,760.",
"answer": "France's GDP per capita is approximately $45,760."
},
]
print("Question: What is France's GDP per capita?")
print("(This time the first search FAILS)
")
print("=" * 60)
tools = {"search": search.search}
for i, step in enumerate(steps_with_recovery):
print(f"
Pensamiento {i+1}: {step['thought']}")
if "answer" in step:
print(f"
Answer: {step['answer']}")
break
result = tools[step["tool"]](step["arg"])
print(f"Acción {i+1}: {step['tool']}({repr(step['arg'])})")
print(f"Observación {i+1}: {result}")
if result == "No results found.":
print(" >> Agent notices failure — will reformulate next step")
The critical moment is between Observación 1 ("No results found") and Pensamiento 2 ("The query was too formal. Let me try simpler keywords"). In a pure acción-without-razonamiento agent, the model might repeat the same query, or give up, or hallucinate an answer. The explicit Pensamiento step is where the agent diagnoses the problem and adjusts its strategy.
En producción, los bucles ReAct encuentran varios modos de fallo comunes:
- Bucles infinitos: el agente sigue llamando a la misma herramienta con los mismos (o muy similares) argumentos, obteniendo el mismo resultado inútil cada vez. Esto ocurre cuando el razonamiento del modelo no es lo suficientemente fuerte para reconocer la repetición. Mitigación: establecer un conteo máximo de iteraciones (típicamente 5-15 pasos) y rastrear acciones recientes para detectar ciclos.
-
Herramientas alucinadas:
el agente intenta llamar a una herramienta que no existe en su inventario de herramientas. Por ejemplo, podría emitir
email("user@example.com", "Here are your results")cuando no se proporcionó ninguna herramienta de correo electrónico. Mitigación: validar cada acción contra la lista de herramientas antes de la ejecución, y devolver un error claro si la herramienta no existe. - Detención prematura: el agente responde antes de reunir suficiente información, produciendo una respuesta plausible pero incompleta o incorrecta. Esto ocurre frecuentemente cuando el modelo está demasiado ansioso por parecer útil. Mitigación: incluir instrucciones en el prompt del sistema de que el agente debe verificar que tiene todos los datos requeridos antes de responder.
- Mal uso de herramientas: el agente llama a la herramienta correcta pero con argumentos incorrectos (pasando una oración en lenguaje natural a una calculadora, o usando el nombre de parámetro incorrecto para una API). Mitigación: proporcionar descripciones claras de herramientas con esquemas de argumentos, y validar las entradas antes de la ejecución.
Una implementación robusta de agente aborda todos estos: un límite máximo de iteraciones previene bucles infinitos, la validación de herramientas atrapa herramientas alucinadas y argumentos mal usados, y los prompts de razonamiento explícito alientan al agente a verificar su trabajo antes de responder. El patrón ReAct no elimina estos modos de fallo, pero los hace visibles en la traza de pensamiento, lo que los hace mucho más fáciles de detectar, diagnosticar y corregir.
Quiz
Pon a prueba tu comprensión del patrón ReAct y los bucles de razonamiento de agentes.
¿Cuál es la diferencia clave entre el de cadena de pensamiento (CoT) y ReAct?
¿Por qué la planificación dinámica (razonar después de cada acción) tiende a funcionar mejor que la planificación secuencial (plan completo por adelantado) para agentes?
En el framework Reflexion, ¿qué hace el agente después de fallar en una tarea?
¿Cuál es el propósito principal de los pasos explícitos de 'Pensamiento' en un bucle ReAct?