volver al blog

El patrón ReAct: razonar y actuar en el mismo bucle

agentesllmrazonamientoarquitectura

Razonar sin actuar es alucinar con estilo

Pide a un LLM que resuelva un problema real de un tirón y verás dos fallos recurrentes. Si le dejas pensar en voz alta pero sin tocar el mundo, produce un razonamiento impecable construido sobre datos inventados. Y si le das herramientas pero le prohíbes deliberar, encadena llamadas sin criterio hasta que se pierde. El primero alucina con estilo; el segundo actúa a ciegas.

ReAct —de Reasoning and Acting— parte de una idea simple: no hay que elegir. En cada paso, el modelo escribe un pensamiento, decide una acción, la ejecuta contra una herramienta y lee el resultado antes de volver a pensar. El razonamiento guía la siguiente acción; la acción corrige el siguiente razonamiento. Ese bucle es la base de casi todos los agentes que hoy funcionan en producción, aunque los frameworks lo escondan detrás de abstracciones.

El bucle en tres verbos

El ciclo tiene tres momentos que se repiten hasta que la tarea se cierra.

El pensamiento (thought) es texto donde el modelo razona sobre en qué punto está y qué le falta. No se ejecuta; sirve para orientar la decisión y para dejar una traza legible de por qué hizo lo que hizo.

La acción (action) es una llamada a herramienta con sus argumentos: buscar en un índice, consultar una API, ejecutar una consulta SQL. Es el único punto donde el agente toca datos reales.

La observación (observation) es lo que devuelve esa herramienta y vuelve al contexto. Aquí el mundo real contradice o confirma lo que el modelo suponía, y ese choque es justo lo que evita que el razonamiento se despegue de los hechos.

La clave está en el orden: observar antes de volver a pensar. Un agente que planifica los diez pasos de golpe y luego los ejecuta a ciegas no es ReAct; es una lista de la compra que nadie revisa. ReAct intercala, y por eso se recupera de los errores en lugar de arrastrarlos.

Cómo se ve por dentro

Los frameworks tipo LangChain o LlamaIndex traen ReAct empaquetado, pero conviene haberlo escrito a mano una vez para saber qué estás delegando. El núcleo cabe en unas pocas líneas.

def agente_react(pregunta, herramientas, modelo, max_pasos=6):
    # Historial acumulado: pensamiento, acción y observación de cada paso
    scratchpad = ""

    for paso in range(max_pasos):
        prompt = (
            f"Pregunta: {pregunta}\n{scratchpad}\n"
            "Piensa el siguiente paso y responde con Accion: <tool>[args] "
            "o con Respuesta: <final> si ya lo sabes."
        )
        salida = modelo.generar(prompt, stop=["Observacion:"])  # corta antes de inventarse la observación
        scratchpad += salida

        if "Respuesta:" in salida:
            return salida.split("Respuesta:")[-1].strip()

        # Parsea la acción y ejecútala de verdad; la observación NO la escribe el modelo
        nombre, args = parsear_accion(salida)
        observacion = herramientas[nombre](args)
        scratchpad += f"\nObservacion: {observacion}\n"

    return "Sin respuesta tras agotar los pasos."

Fíjate en dos detalles que separan una demo de algo usable. El stop=["Observacion:"] impide que el modelo se invente el resultado de la herramienta: el texto de la observación lo escribe tu código, no el LLM. Y el max_pasos es un cortacircuitos: sin él, un agente confundido entra en bucle y te vacía la cuenta de la API. Ninguno de los dos es opcional.

ReAct frente a las alternativas

No todo problema pide un agente ReAct. Elegir mal encarece y ralentiza sin ganar nada.

EnfoqueCómo decideCuándo encaja
Llamada directaUna sola generación, sin herramientasLa respuesta cabe en lo que el modelo ya sabe
Cadena fijaPasos predefinidos en ordenEl flujo es siempre el mismo y lo conoces de antemano
Plan y ejecuciónPlanifica todo, luego ejecutaTareas largas y estables donde replanificar sale caro
ReActPiensa y actúa alternando cada pasoEl camino depende de lo que vayas descubriendo

La regla práctica: usa ReAct cuando no puedas dibujar el diagrama de flujo por adelantado porque la ruta correcta depende de datos que solo obtienes al ejecutar. Si sí puedes dibujarlo, una cadena fija será más barata, más rápida y más fácil de depurar. Meter un agente donde bastaba una función es el error de diseño más común que veo.

Dónde se rompe

ReAct es robusto, pero tiene tres modos de fallo que conviene anticipar.

El primero es el bucle de terquedad: el modelo repite la misma acción fallida esperando otro resultado. La observación le dice “no encontrado” y él vuelve a buscar igual. Se ataja detectando acciones repetidas y forzando un cambio de estrategia o una salida limpia.

El segundo es la traza que crece sin límite. Cada paso añade pensamiento, acción y observación al contexto; en tareas largas eso infla el coste por token y diluye la atención del modelo. Resumir observaciones antiguas o descartar las irrelevantes mantiene el scratchpad a raya.

El tercero es la observación envenenada. Si una herramienta devuelve contenido de fuentes externas —una página web, un correo—, ese texto entra directo en el razonamiento del agente y puede contener instrucciones inyectadas. La observación no es un dato neutro; es una superficie de ataque. Trátala como entrada no confiable y no dejes que decida acciones sensibles sin una comprobación intermedia.

Qué llevarte

ReAct no es un framework ni una librería: es un patrón de control que puedes implementar en un bucle for. Entenderlo te da tres cosas. Sabes qué hacen por dentro LangChain, LlamaIndex o el harness que uses, y puedes depurarlos cuando fallan. Distingues cuándo un problema pide agente y cuándo pide una simple cadena, que es la mitad de la batalla del diseño. Y ves los puntos de fractura —bucles, contexto inflado, observaciones envenenadas— antes de que aparezcan en producción.

Si vas a montar tu primer agente, escríbelo a mano una vez con el bucle de arriba. Pon el cortacircuitos de pasos desde el minuto uno, corta la generación antes de la observación y trata todo lo que devuelvan las herramientas como entrada hostil. Cuando eso te quede natural, adopta un framework: ya sabrás qué te está resolviendo y qué sigue siendo tu responsabilidad.