…
Módulo 1 · Parte B de 3

El bucle ReAct

Un agente basado en un modelo de lenguaje ejecuta el mismo bucle de percibir, razonar y actuar que cualquier otro agente, con un detalle que da nombre al patrón: el modelo razona con palabras entre las acciones que aplica. Este patrón de comportamiento fue denominado por Yao et al. (2022) como ReAct, por razonamiento y acción. Dichos autores observaron que intercalar pasos breves de razonamiento con el uso de herramientas permite resolver muchas tareas con mayor fiabilidad que planificar todo de antemano o actuar sin razonar.

Una herramienta es código que un motor de ejecución puede ejecutar para el modelo: una función con nombre, descripción, esquema de entrada y un valor de retorno. Una llamada a herramienta es la solicitud estructurada que genera el modelo. El motor de ejecución interpreta la solicitud, ejecuta la función, y vuelve a llamar al modelo añadiendo el resultado devuelto por la función.

Este bucle sirve de base para la mayoría de los frameworks de agentes de propósito general, incluido createReactAgent de LangChain. El resto de este capítulo profundiza paso a paso en sus componentes.

El bucle no cambia. Al incorporar un modelo de lenguaje en la etapa de razonamiento, el agente interpreta los resultados y actúa mediante llamadas a herramientas.

El campo que decide el siguiente paso

Cada respuesta de Chat Completions incluye finish_reason, que indica por qué el modelo dejó de generar. En el bucle del agente, lee ese campo junto con el contenido y las solicitudes de herramientas para decidir si ejecutar una herramienta, devolver la respuesta o gestionar un error. Antes de estudiar sus valores, realiza dos llamadas y compara las respuestas.

La primera llamada no ofrece herramientas. En la segunda, se ofrece una herramienta al modelo y se le pregunta la hora actual. El modelo decide si solicita el reloj. Compara las preguntas, las respuestas y finish_reason. Si ambas devuelven "stop", revisa la segunda respuesta: ¿admite que no puede consultar la hora o da una respuesta sin comprobarla? Cambia el modelo o la pregunta y vuelve a ejecutar. Una solicitud de herramienta indica trabajo para tu código; esta vista previa no lo ejecuta.

En una implementación moderna de ReAct, un enrutador sencillo o router lee este campo. Si el modelo solicita una herramienta, el router ejecuta la función, añade el resultado al historial y vuelve a llamar al modelo. Si el modelo finaliza, el router devuelve la respuesta.

El modelo puede revisar su plan después de leer el resultado de una herramienta. Cuando una herramienta devuelve algo inesperado, el resultado entra en la siguiente ronda de razonamiento y el modelo puede reevaluar la situación.

¿Relacionar el modelo, la memoria, las herramientas y el enrutador?

Componentes de un agente basado en un LLM

Al examinar el agente con más detalle aparece la descomposición que Lilian Weng presentó en 2023. El modelo de lenguaje ocupa el centro; a su alrededor se organizan la memoria, la planificación, las herramientas y las acciones que interactúan con el entorno.

En el ciclo de herramientas que aparece a continuación, estas responsabilidades se reparten así:

  • La memoria es un array messages[].
  • La planificación ocurre cuando el modelo usa el contexto recibido para elegir su siguiente respuesta o solicitud de herramienta.
  • Las herramientas son las funciones expuestas por el motor de ejecución.
  • La acción es la llamada a herramienta que ejecuta dicho motor.

El entorno de ejecución mantiene los mensajes y ejecuta las herramientas. Su router lee finish_reason para decidir si procesa las solicitudes de herramientas o devuelve una respuesta.

Adaptado de Lilian Weng (2023): el modelo actúa como controlador central, conectado con la memoria, la planificación, las herramientas y las acciones.
Los componentes son independientes. Puedes sustituir el modelo, las herramientas o el router por separado. Mientras cada componente respete el contrato esperado, el resto del bucle seguirá funcionando.

Si este ciclo falla, inspecciona los valores que se transfieren entre sus componentes. Comprueba si:

  • el modelo devuelve un valor incorrecto de finish_reason;
  • falta alguna parte de la conversación (que llamaremos turno) en el array de mensajes;
  • una herramienta devuelve un valor inesperado;
  • el router interpreta la señal de forma incorrecta.

Construir el bucle del agente desde cero con una herramienta

Construyamos un ejemplo sencillo desde cero. Solo necesitamos la herramienta get_current_time, un prompt para el sistema y un bucle while. Empieza preguntando «¿Qué hora es en UTC?» y luego prueba otras preguntas:

Razonar, actuar, observar y repetir. El bucle termina cuando finish_reason vale "stop".
Lo que acaba de suceder dentro del array de mensajes.
Cuando el modelo solicita el reloj, el bucle añade estos turnos a state.messages: La siguiente llamada al modelo recibe esos mensajes, incluido el resultado del reloj. Examina su respuesta para comprobar si responde o solicita otra herramienta. Este array creciente es la única «memoria» del agente. Guardar y volver a cargar ese array conserva el historial de conversación proporcionado; los hechos externos y el comportamiento del modelo pueden cambiar.
¿Revisar evidencias y mitigaciones de la degradación del contexto?

Degradación del contexto: por qué un bucle más largo puede experimentar problemas de comprensión

La degradación del contexto ocurre cuando aparecen contradicciones, observaciones obsoletas y convenciones deficientes que se acumulan en el historial y que pueden perjudicar la siguiente decisión. El efecto también tiene un componente posicional: Liu et al. (2023) mostraron que los modelos pueden desaprovechar información situada en la zona intermedia de un contexto largo. Cuanto más se aleja una señal importante del mensaje o turno actual, mayor es la probabilidad de que el bucle la ignore o la contradiga.

Redibujado a partir de Liu et al. (2023). A medida que el bucle añade mensajes al historial, la información necesaria se desplaza hacia la zona intermedia, donde el modelo tiende a utilizarla peor.

Los mecanismos de contención habituales ante este problema consisten en mantener cada decisión lo más cercana a la evidencia que necesita:

  • planificar antes de que el bucle acumule observaciones;
  • delegar subtareas para que cada subagente trabaje con un contexto breve;
  • resumir las conversaciones anteriores antes de que empiecen a degradar las decisiones.

Aplicar el mismo bucle al curso

El bucle anterior tiene una única herramienta fijada directamente en el código. La función createReactAgent de LangChain generaliza esta estructura para admitir varias herramientas, interfaces estándar e integraciones de observabilidad o monitorización. El agente siguiente utiliza una sola herramienta, read_course_page, que entrega al agente cualquier página de este curso como Markdown. El modelo decide qué páginas necesita consultar para responder.

Ejecuta la celda para abrir el chat y pregunta «¿Cómo decide el ciclo del reloj cuándo detenerse?» Puedes dejar vacía la selección de páginas; el agente elegirá cuáles consultar. Para elegir el contexto, abre Opciones de modelo y contexto y selecciona un título en Páginas antes del primer mensaje. Al pasar el puntero por el título aparece su ID de origen, por ejemplo 01b-react. Si cambias la selección después, inicia una Nueva conversación. Despliega un indicador de fuente para comparar la respuesta con lo que el agente leyó.

Antes de continuar

Vuelve al lienzo del bucle del reloj y modifica sus entradas para realizar estas comparaciones.

  1. Fuerza al modelo a llamar a la herramienta aunque no la necesite. Intenta una pregunta que la herramienta realmente no pueda responder («¿capital de Francia?») y observa finish_reason. ¿Fue "stop" o "tool_calls"? Ahora edita el prompt del sistema para exigir una llamada antes de responder («Debes llamar siempre una vez a get_current_time y responder después»). ¿Cumple el modelo la instrucción? ¿Qué indica el resultado sobre la capacidad del prompt de sistema para dirigir un modelo que confía en sus datos de entrenamiento?
  2. Cuenta los pasos de una pregunta que necesita una herramienta. "¿Cuántos minutos faltan para las 17:00 UTC?" necesita una lectura del reloj y un cálculo. Ejecútala varias veces. ¿El modelo llamó a get_current_time una, dos o tres veces? ¿Por qué volvería a solicitar un resultado que ya tiene? ¿Cómo cambiarías el prompt del sistema para evitarlo?
¿Qué debería aprender de estas comparaciones?

La primera comparación distingue las instrucciones del prompt del control de flujo impuesto por el programa. Compara la herramienta solicitada y finish_reason antes de decidir si se siguió la instrucción. Una solicitud no demuestra por sí sola que se ejecutara el reloj.

La segunda comparación pregunta si cada llamada adicional aporta evidencia útil. Examina los resultados del reloj y su orden en messages. Si la secuencia no está clara, vuelve al diagrama del ciclo y despliega la traza antes de cambiar el prompt. El resultado puede variar entre ejecuciones; explícalo a partir de tu propia traza.

¿Rastrear estos mecanismos hasta sus fuentes primarias?

Referencias

Consulta la lista completa en Para ir más lejos · Referencias.

← Módulo 1a: El agente