Agente
Un agente es una entidad que interactúa con un entorno determinado a cualquier nivel significativo. Una persona en su día a día es un agente en este sentido, así como también lo son un termostato que mantiene la temperatura de una sala o un coche autónomo que se desplaza por el tránsito.
Todos ellos perciben el entorno por medio de sensores y actúan sobre él por medio de actuadores. Cada acción influye, por tanto, en la siguiente observación del entorno formando un bucle continuo: el bucle de percibir, razonar y actuar, que dura mientras el agente interactúa en dicho entorno. Todos los agentes construidos en el curso siguen este bucle. Lo que cambia es cuánto pueden entender el entorno y hasta dónde llegan sus acciones.
Las tres etapas del bucle de un agente
Cada iteración pasa por tres etapas, con nombres simples y funciones distintas.
La percepción reúne lo que el agente puede conocer, el razonamiento decide qué hacer y la acción cambia el entorno. La percepción y la acción suelen proceder de un modelo de interacción existente, ya controle una aspiradora, automatización web, una entidad de juego o un humanoide. El razonamiento puede cambiar sin alterar ese límite, lo que separa la capacidad del alcance.
¿Explorar el ciclo y las arquitecturas clásicas?
Abre esta sección para consultar ejemplos concretos y una taxonomía más completa de arquitecturas.
- La percepción proporciona todo lo que el agente sabe sobre el entorno. Un termostato solo lee un número: la temperatura actual. Un vehículo autónomo combina cámaras, radar y un mapa en un modelo de la carretera. Un agente solo trabaja con lo que captura la percepción, porque las etapas siguientes no acceden al entorno directamente. Cualquier aspecto no detectado durante la percepción permanece invisible para el resto del agente.
- El razonamiento transforma una percepción en una decisión. Un termostato compara la temperatura con un objetivo, mientras que un motor de ajedrez evalúa millones de movimientos y un vehículo autónomo ejecuta una política aprendida. Los agentes de este curso razonan mediante un modelo de lenguaje. Las herramientas, la memoria y la planificación se apoyan en este paso.
- Una acción modifica el entorno para el propio agente y para otros participantes del mismo. Esta puede ser tan pequeña como accionar un relé o tan compleja como conducir un coche. Más adelante en este curso, el modelo de lenguaje realiza llamadas a diferentes funciones de software que han sido expuestas de alguna forma para dicho modelo. Estas funciones reciben el nombre de herramientas (del inglés tool) ya que para el modelo representan acciones disponibles. Llamar a una herramienta significa solicitar que el código de esa función sea ejecutado como acción. El conjunto de acciones también define el alcance máximo del agente: por bueno que sea el razonamiento, el agente solo afecta al mundo mediante las acciones permitidas.
Las implementaciones clásicas de agentes difieren en la etapa de decisión (que como indicamos anteriormente tiene lugar durante la etapa de razonamiento). El libro Artificial Intelligence: A Modern Approach, de Russell y Norvig, organiza estas implementaciones en un espectro que va del agente basado en reflejo a un agente de aprendizaje capaz de mejorar sus propias reglas. Este curso comienza con lógica rígida y después añade un modelo de lenguaje y contexto proyectado, acercando el bucle al de un agente orientado a objetivos y basado en un modelo. En los módulos siguientes, el bucle continúa sobre un estado cambiante, siguiendo el patrón que sirve de base para los agentes de aprendizaje.
¿Ejecutar el ciclo de agente basado en reglas más pequeño?
Un agente sin modelo de lenguaje
La función de decisión más simple es la instrucción if. En el siguiente ejemplo, dicha instrucción guía una pista
unidimensional limitada por paredes entre las posiciones 0 y 9. Pulsa Ejecutar y observa cómo la posición de la pista rebota entre las paredes mientras el bucle se ejecuta.
Dos aspectos del código anterior merecen especial atención:
- El entorno (las paredes y la posición actual) vive en
state.env, mientras que el estado interno del agente (su dirección) vive enstate.agent. Mantenerlos separados permite que otros agentes operen en el mismo entorno con un estado interno distinto. - El paso de razonamiento es una sola instrucción
if. Sustituirla por un árbol de decisión, una red neuronal o un modelo de lenguaje solo cambiará lo que ocurre entre percepción y acción. La estructura del bucle, el estado y la acción permanecerían iguales.
Lo que cambia cuando el razonamiento llama a un LLM
La interfaz de Chat Completions se invoca como cualquier otra función: recibe una lista de mensajes y el nombre de un modelo, y devuelve el mensaje generado por el modelo junto con metadatos.
chat(). Es la función auxiliar del curso que se ejecutará más adelante en esta página. El fragmento siguiente muestra el formato de la llamada y los campos devueltos.const reply = await chat({
model: "nvidia/nemotron-3.5-lightning-30b-a3b",
messages: [{ role: "user", content: "Hi" }],
});
// reply.choices[0].message → { content, reasoning_content }
// reply.choices[0].finish_reason → "stop" | "tool_calls" | "length"
Tres aspectos de esta función determinan cómo deben funcionar los agentes construidos sobre ella:
- Las llamadas no comparten estado. El servidor no conserva nada entre solicitudes. Para que el modelo recuerde algún mensaje anterior, hay que enviárselo de nuevo. La "memoria" es una lista de mensajes que el código mantiene y reenvía.
- La salida de razonamiento es opcional. Algunos modelos y modos devuelven texto de razonamiento en
reasoning_content; otros solo devuelven la respuesta o solicitudes de herramientas. Examina los campos que realmente se devolvieron. El bucle leecontent, el motivo de finalización y las solicitudes de herramientas antes de elegir el siguiente paso. - finish_reason es la condición de salida del bucle.
"stop"significa que el modelo escribió su respuesta final."tool_calls"significa que quiere que el código ejecute una función con nombre y devuelva el resultado."length"significa que el presupuesto de tokens se agotó antes de terminar. Lee este campo junto con el contenido devuelto y las solicitudes de herramientas antes de decidir el siguiente paso.
¿Comparar dónde conservan las API el estado de la conversación?
Este curso usa la
Chat Completions API
que mantiene la conversación como un array messages[] en el código y reenvía el array completo en cada llamada. La API más reciente,
Respuestas API
puede, en cambio, mantener la conversación en el servidor: se envían solo la nueva entrada y una referencia a la llamada anterior. En ambos casos, el modelo sigue sin estado. La conversación vive fuera de él, en un estado que se conserva en el código o el servidor.
Un ejemplo real en el navegador
Pulsa Ejecutar para enviar una única solicitud. No hay un bucle alrededor ni se conserva nada de una llamada anterior.
¿Inspeccionar la solicitud y la respuesta HTTP sin procesar?
Lo que chat() realmente envía
chat() es una función auxiliar que envuelve un único
POST HTTP común en un formato compatible con OpenAI. Esta solicitud añade tres cosas:
- el endpoint donde el modelo acepta peticiones,
- las cabeceras de la solicitud; un endpoint personalizado puede requerir una cabecera
Authorization, - y como contenido un JSON con
modelymessages.
La siguiente celda construye esa llamada manualmente. Abre request para examinar la URL, las cabeceras y el cuerpo, con cualquier valor de autorización oculto. Abre raw response para examinar el objeto completo devuelto por chat().
El endpoint del modelo utiliza este formato. El gateway de OpenClaw del módulo 3 expone un protocolo distinto para los turnos del agente, las sesiones y las operaciones del entorno de ejecución.
Configura un endpoint compatible en el panel del modelo antes de ejecutar la celda. Los endpoints alojados por NVIDIA requieren una clave de API de NVIDIA. Comprueba el acceso y la cuota del servicio seleccionado. El panel muestra el endpoint activo y la configuración de credenciales; examina la solicitud con los datos sensibles ocultos que aparece abajo antes de enviarla.
La ruta seleccionada determina qué servicio recibe la solicitud y su credencial. Una llamada desde el navegador requiere que el endpoint permita el origen del curso. El curso puede usar su servicio de retransmisión configurado si el proveedor no permite esa solicitud directa desde el navegador. Examina la ruta activa y las cabeceras de la solicitud en el panel del modelo.
Examina el helper de streaming.chatStream() procesa el texto de la respuesta, cualquier texto de razonamiento devuelto, los metadatos de uso y la señal de fin de la transmisión. Conecta la respuesta con el panel de la lección y el botón Stop. Abre el código fuente del helper desde el menú de la celda para examinar la solicitud y el manejo de eventos.
¿Comparar formas de razonar sobre el laberinto dentro de un ciclo fijo?
Cambiar la función de decisión sin cambiar el bucle
Los siguientes ejemplos mantienen el ciclo de percibir, razonar y actuar y varían su función de decisión. Compara reglas fijas y algoritmos de búsqueda antes de usar chat() para elegir un movimiento.
Ejecuta los nodos en orden. Cada uno aplica una regla de decisión diferente al mismo bucle que resuelve el laberinto:
- La regla constante "siempre este" alcanza el objetivo en un pasillo recto, después se bloquea en la primera pared del laberinto, ya que un rumbo fijo no puede girar.
- La búsqueda en profundidad (DFS) sigue una rama hasta el final antes de retroceder.
- búsqueda en anchura (BFS) explora la frontera por niveles y encuentra el camino más corto en una rejilla sin pesos en sus celdas.
- El A* utiliza una heurística de distancia para priorizar caminos prometedores sin perder la garantía de encontrar el camino más corto.
Cómo usar un modelo de lenguaje para elegir movimientos
El controlador registra las celdas visitadas y una ruta de regreso, descarta las ramas visitadas y recorre los pasillos. En los cruces, el modelo lee el mapa y elige el orden de las ramas mediante choose_direction. El controlador gestiona la exploración en profundidad; no proporciona al modelo una ruta resuelta.
Ejecuta las celdas en este orden y luego cambia un control cada vez:
- Comienza por el nodo motor. Este exporta las utilidades y un resolutor compartido
state.runMaze, que recorre los pasillos del laberinto automáticamente y que llama al modelo solamente en las bifurcaciones. - Ejecuta el nodo editable del agente de laberinto que aparece a continuación.
DIRECTIVEes la instrucción principal del sistema; el objeto de opciones controla el modelo, el tamaño del laberinto, el mapa textual, el historial de movimientos, la ruta de coordenadas y la repetición del esquema de la herramienta. - Comienza con los valores predeterminados que funcionan. Después, cambia
modelpara comparar rutas con capacidades verificadas, elimina el historial o utilizaadvancedpara ampliar el laberinto cuando el caso sencillo ya funcione.
choose_direction declara los valores de dirección permitidos. El modelo solicita una dirección y el controlador comprueba el nombre de la herramienta y sus argumentos antes de moverse. Examina la solicitud y la respuesta para distinguir el esquema declarado de la validación que realiza tu código.El bucle en detalle
En el ejemplo del laberinto, el controlador construye una solicitud para chat() y valida el movimiento devuelto antes de aplicarlo. Las etapas siguientes muestran ese intercambio.
- Muestra local. El código lee una parte del entorno. Aquí lee la celda actual del laberinto y sus movimientos válidos. La solicitud también puede incluir el mapa completo y los turnos anteriores, según los controles seleccionados.
- Percepción local. Esta parte se convierte en un contexto completo y preparado: el prompt de sistema, el historial acumulado de
messages[], los resultados anteriores de herramientas y la parte que acabas de muestrear. En este ejemplo, el laberinto se representa como texto en los mensajes enviados al modelo. - Actuación local. El modelo transforma este texto en otro texto: una
señal de intención, idealmente una llamada a herramienta tipada como
{ "move": "east" }en vez de prosa libre. La intención solo solicita una acción, y nunca ejecuta una. El código leará y aplicará una actualización en el entorno (doMove(...)), validándolo primero. - Impacto local. La actualización cambia el entorno. Nada permanece dentro del modelo. El estado permanente está en el entorno y en el contexto que el código reconstruirá. En la siguiente iteración, el muestreo local leerá el nuevo entorno y el bucle comienza de nuevo.
En este ejemplo, chat() recibe texto que describe el laberinto y devuelve una solicitud de movimiento. El controlador proporciona las observaciones, valida la solicitud y cambia el estado del laberinto. La llamada al modelo no ejecuta el movimiento.
Examina ambos límites: el contexto que recibe el modelo y la validación que realiza tu código antes de aplicar una acción solicitada.
Antes de continuar
Puedes responder cada pregunta ajustando el control en la celda anterior del laberinto con LLM y ejecutándola de nuevo.
- Compara el historial de conversación. Configura
includeHistory:falsey vuelve a ejecutar con el mismo perfil y laberinto. Compara el orden de las ramas, las decisiones en los cruces y el tiempo transcurrido con el historial activado. El controlador conserva las celdas visitadas y la ruta de regreso en ambas ejecuciones. - Elimina la pista de estrategia de DIRECTIVE. Borra la línea que indica preferir las ramas sin explorar a las celdas visitadas y vuelve a ejecutar con el mismo perfil y laberinto. Compara el orden de las ramas, las decisiones en los cruces y el tiempo transcurrido. El controlador sigue descartando las ramas visitadas; repite las ejecuciones para comprobar si las diferencias persisten.
- Compara perfiles de modelo. Empieza con
model:"direct"y luego comparamodel:"reasoning"ymodel:"omni"en el mismo laberinto. Examina el modelo, el presupuesto de tokens, la temperatura y los ajustes de razonamiento de cada solicitud. Estos perfiles cambian varios ajustes; compara el orden de las ramas y la latencia sin atribuir todas las diferencias únicamente a la identidad del modelo.
Pruébalo · compara el historial de conversación
Este chat comienza con el historial de conversación activado. Dile tu nombre y luego pregúntale cómo te llamas. Desactiva el control de memoria y vuelve a preguntar. Cada llamada a chat() recibe los mensajes que prepara la interfaz; con la memoria desactivada, se omiten los turnos anteriores. Compara las respuestas y examina cómo el código construye la solicitud.