\n\n\n\n Estoy construyendo agentes de IA: Mi viaje más allá de la ingeniería de prompts - AgntAI Estoy construyendo agentes de IA: Mi viaje más allá de la ingeniería de prompts - AgntAI \n

Estoy construyendo agentes de IA: Mi viaje más allá de la ingeniería de prompts

📖 15 min read2,859 wordsUpdated Mar 26, 2026

Hola a todos, Alex aquí desde agntai.net. Es 25 de marzo de 2026, y últimamente he estado lidiando con algo bastante fundamental: cómo realmente *construimos* estos agentes de IA. No solo las partes brillantes de LLM, sino toda la estructura desordenada que les permite hacer algo útil en el mundo real. Afortunadamente, hemos superado la fase de “la ingeniería de prompts es todo lo que necesitas”, y ahora se trata de ensamblar sistemas confiables y extensibles.

Hoy, quiero hablar sobre la arquitectura de agentes, específicamente sobre cómo podemos pasar de la ejecución de tareas simples y lineales a algo más resiliente y capaz de manejar situaciones inesperadas. Mi enfoque va a ser una arquitectura modular y reflexiva: esencialmente, construir agentes que puedan observar su propio proceso, entender qué salió mal (o bien) y adaptarse. Esto no es solo teoría; he visto de primera mano cómo un poco de autoconciencia puede ahorrar un montón de dolores de cabeza.

El Problema con los Agentes Lineales: Mi Debacle del Proyecto de Fin de Semana

Empecemos con una historia. Hace unas semanas, intentaba automatizar una tarea de análisis de datos bastante sencilla para un proyecto secundario. Quería que un agente obtuviera algunos datos financieros, ejecutara un conjunto específico de pruebas estadísticas y luego resumiera los hallazgos en un informe markdown. ¿Mi pensamiento inicial? Una cadena simple:

  • Recuperar datos de la API.
  • Limpiar datos.
  • Ejecutar pruebas estadísticas (usando una biblioteca predefinida).
  • Generar informe.

Uní todo esto con LangChain, usando una llamada a GPT-4 para cada paso y me sentí bastante satisfecho. Luego presioné “ejecutar”.

¿El primer problema? El límite de tasa de la API. Mi agente seguía intentando alcanzarlo, fallando, y luego pasaba al siguiente paso con un conjunto de datos vacío. Sin manejo de errores, sin lógica de reintento, solo un educado “no pude obtener los datos, pero aquí tienes un informe encantador sobre nada”.

¿El segundo problema? El paso de limpieza de datos. A veces la API devolvía nombres de columna ligeramente diferentes. Mis funciones de prueba estadística esperaban `close_price`, pero obtuvieron `closing_price`. Mi agente simplemente arrojó un rastreo de Python y se detuvo. Nuevamente, sin recuperación elegante, sin intento de entender por qué falló la función.

Esta experiencia, aunque frustrante, realmente subrayó un punto: los diseños de agentes simples y lineales, donde cada paso sigue ciegamente al anterior, son frágiles. Asumen un mundo perfecto donde las API siempre funcionan, los datos siempre son prístinos y las funciones nunca fallan. El mundo real no es así. Necesitamos agentes que puedan hacer más que solo ejecutar una secuencia; necesitan observar, reflexionar y adaptarse.

Presentando la Arquitectura de Agentes Reflexivos: El Enfoque del “Monólogo Interno”

La idea principal detrás de una arquitectura de agente reflexiva es darle al agente un mecanismo para observar sus propias acciones y resultados, y luego usar esa observación para informar decisiones futuras. Piénsalo como un “monólogo interno” donde el agente se pregunta: “¿Qué acaba de pasar? ¿Fue bueno? ¿Qué debería hacer a continuación dado lo que he aprendido?”

No se trata solo de agregar bloques de try-except. Se trata de hacer que el proceso de toma de decisiones del agente sea dinámico e informado por su propia historia de ejecución. Así es como generalmente lo desgloso:

Los Componentes Básicos de un Agente Reflexivo

  1. Módulo de Percepción: Así es como el agente “ve” el mundo y sus propias acciones. Recoge observaciones de su entorno (respuestas de API, cambios en el sistema de archivos, input del usuario) y, crucialmente, de las salidas de sus propias herramientas y mensajes de error.
  2. Módulo de Acción: Aquí es donde el agente realiza tareas usando sus herramientas disponibles (funciones, APIs, otros modelos). Esto es lo que la mayoría de la gente piensa cuando construye agentes.
  3. Módulo de Memoria: Almacena observaciones, acciones y reflexiones pasadas. Esto no es solo contexto a corto plazo; para la reflexión, a menudo necesitamos memoria a largo plazo de estrategias exitosas y fallidas.
  4. Módulo de Reflexión: Este es el cerebro del proceso reflexivo. Después de una acción, este módulo toma las observaciones y recuerdos, y evalúa críticamente el resultado. Hace preguntas como:
    • ¿La última acción tuvo éxito?
    • Si no, ¿por qué falló?
    • ¿Qué podría haberse hecho de manera diferente?
    • ¿Cuál debería ser la *siguiente* acción, dado este nuevo entendimiento?
    • ¿Debería modificar mi plan?
  5. Módulo de Planificación/Gestión de Objetivos: Aunque a menudo se entrelaza con la reflexión, este módulo se encarga de desglosar objetivos a alto nivel en pasos accionables y actualizar el plan basado en reflexiones.

La clave aquí es el bucle de retroalimentación: Acción -> Percepción -> Reflexión -> (potencialmente) Actualización del Plan -> Nueva Acción. No es una calle de una sola dirección; es un ciclo continuo.

Un Ejemplo Práctico: Agente de Pipeline de Datos Autoreparable

Volvamos a mi proyecto de datos financieros. ¿Cómo manejaría un agente reflexivo esos problemas? En lugar de una cadena ciega, introduciríamos la reflexión en momentos críticos.

Paso 1: Definir Herramientas

Nuestro agente necesita herramientas para interactuar con el mundo. Estas son simplemente funciones de Python envueltas de manera que el LLM pueda llamarlas.


def get_financial_data(symbol: str, start_date: str, end_date: str) -> dict:
 """
 Recupera datos financieros históricos para un símbolo de acción dado.
 Lanza una excepción para errores de API o límites de tasa.
 """
 # Simular llamada a API con posibles errores
 import random
 if random.random() < 0.1: # Simular 10% de falla en la API/límite de tasa
 raise ConnectionError("La llamada a la API falló: Límite de tasa excedido o servicio no disponible.")
 if symbol == "FAILCO":
 raise ValueError("Símbolo inválido proporcionado.")
 return {"symbol": symbol, "data": [{"date": "2023-01-01", "close_price": 100.0}]}

def clean_data(raw_data: dict) -> dict:
 """
 Limpia y estandariza los datos financieros.
 Intenta normalizar variaciones comunes en los nombres de las columnas.
 """
 data = raw_data.get("data", [])
 if not data:
 raise ValueError("No hay datos para limpiar.")
 
 # Simular variación en el nombre de la columna y intento de corrección
 if "closing_price" in data[0]:
 for item in data:
 item["close_price"] = item.pop("closing_price")
 
 # Validación básica
 for item in data:
 if "close_price" not in item:
 raise ValueError(f"Falta 'close_price' en el ítem: {item}")
 
 return {"symbol": raw_data["symbol"], "cleaned_data": data}

def run_statistical_tests(cleaned_data: dict) -> dict:
 """
 Ejecuta pruebas estadísticas predefinidas sobre datos financieros limpios.
 """
 if not cleaned_data.get("cleaned_data"):
 raise ValueError("No hay datos limpios para analizar.")
 
 # Simular algún análisis estadístico
 avg_price = sum(item["close_price"] for item in cleaned_data["cleaned_data"]) / len(cleaned_data["cleaned_data"])
 return {"analysis_results": f"Precio de cierre promedio: {avg_price:.2f}"}

def generate_report(analysis_results: dict) -> str:
 """
 Genera un informe markdown a partir de los resultados del análisis.
 """
 return f"# Informe de Análisis Financiero\n\n{analysis_results.get('analysis_results', 'No se realizó ningún análisis.')}"

tools = [get_financial_data, clean_data, run_statistical_tests, generate_report]

Estas herramientas son bastante estándar. La magia ocurre en cómo el agente las utiliza y reflexiona sobre sus resultados.

Paso 2: El Ciclo del Agente Reflexivo

Aquí es donde introducimos los pasos de observación y reflexión. Estoy simplificando las llamadas al LLM aquí por brevedad, pero imagina un aviso del sistema que guía al LLM para actuar como el “Módulo de Reflexión”.


from typing import List, Dict, Any
import time

class ReflectiveAgent:
 def __init__(self, llm, tools: List[Any]):
 self.llm = llm # Este sería tu cliente LLM (e.g., OpenAI, Anthropic)
 self.tools = {tool.__name__: tool for tool in tools}
 self.memory: List[Dict[str, Any]] = [] # Almacena el historial de acciones, observaciones, reflexiones
 self.current_plan: List[str] = ["get_financial_data", "clean_data", "run_statistical_tests", "generate_report"]
 self.current_step_index = 0
 self.max_retries = 3

 def _call_llm(self, prompt: str) -> str:
 # En un sistema real, esto llamaría a tu LLM
 # Para este ejemplo, simularemos una respuesta simple del LLM basada en palabras clave
 print(f"LLM Prompt: {prompt}\n---")
 if "Error" in prompt or "failed" in prompt:
 if "API call failed" in prompt:
 return "Reflexión: La llamada al tool anterior falló debido a un error de API. Debo intentar de nuevo la herramienta 'get_financial_data'. Este es un problema transitorio. Esperaré un poco antes de volver a intentarlo."
 elif "Missing 'close_price'" in prompt or "No data to clean" in prompt:
 return "Reflexión: La herramienta 'clean_data' falló debido a un formato de datos inesperado o datos faltantes. Necesito reevaluar los datos originales o ajustar mi estrategia de limpieza. Quizás la herramienta 'get_financial_data' no proporcionó buenos datos. Debo intentar llamar de nuevo a 'get_financial_data' para ver si la estructura de los datos cambió, o podría necesitar pedir aclaraciones al usuario si tuviera una herramienta de interacción con el usuario."
 elif "Invalid symbol" in prompt:
 return "Reflexión: La herramienta 'get_financial_data' falló debido a un símbolo inválido. Este es un error de entrada fundamental. Debo informar al usuario o detenerme."
 else:
 return "Reflexión: Ocurrió un error inesperado. Necesito reevaluar la última acción y tratar de entender la causa raíz. Mi plan actual podría ser defectuoso."
 elif "succeeded" in prompt and "next step" in prompt:
 return "Reflexión: La última acción tuvo éxito. Debo proceder al siguiente paso en mi plan."
 else:
 return "Reflexión: Actualmente estoy reflexionando sobre la tarea. ¿Cuál es el estado actual y cuál debería ser mi próxima acción basada en el plan?"


 def run(self, symbol: str):
 context = {"symbol": symbol, "raw_data": None, "cleaned_data": None, "analysis_results": None}

 while self.current_step_index < len(self.current_plan):
 current_tool_name = self.current_plan[self.current_step_index]
 tool_func = self.tools.get(current_tool_name)

 if not tool_func:
 print(f"Error: Herramienta '{current_tool_name}' no encontrada. Deteniendo.")
 break

 print(f"\n--- Intentando ejecutar: {current_tool_name} ---")
 
 observation = {"status": "started", "tool": current_tool_name}
 retries = 0

 while retries <= self.max_retries:
 try:
 if current_tool_name == "get_financial_data":
 result = tool_func(symbol=symbol, start_date="2023-01-01", end_date="2023-12-31")
 context["raw_data"] = result
 elif current_tool_name == "clean_data":
 result = tool_func(context["raw_data"])
 context["cleaned_data"] = result
 elif current_tool_name == "run_statistical_tests":
 result = tool_func(context["cleaned_data"])
 context["analysis_results"] = result
 elif current_tool_name == "generate_report":
 result = tool_func(context["analysis_results"])
 print(result) # Salida del informe final
 context["final_report"] = result
 
 observation["status"] = "succeeded"
 observation["output"] = result
 break # Acción exitosa, salir del bucle de reintentos
 except Exception as e:
 observation["status"] = "failed"
 observation["error"] = str(e)
 print(f"La herramienta '{current_tool_name}' falló: {e}")
 retries += 1
 if retries <= self.max_retries:
 print(f"Reintentando '{current_tool_name}' (Intento {retries}/{self.max_retries})...")
 time.sleep(1) # Simular retroceso
 else:
 print(f"Se alcanzaron los reintentos máximos para '{current_tool_name}'.")
 break # Se alcanzaron los reintentos máximos, salir del bucle de reintentos

 self.memory.append({"action": observation})

 # --- Paso de Reflexión ---
 reflection_prompt = f"""
 Contexto Actual: {context}
 Última Acción: {observation}
 Objetivo: Completar el análisis de datos financieros e informar.

 Reflexiona sobre el resultado de la última acción.
 - ¿Tuvo éxito?
 - Si no, ¿cuál fue el error?
 - ¿Cuál debería ser el siguiente paso? ¿Debería intentarlo de nuevo, cambiar de estrategia o detenerme?
 - Si ocurrió un error que indica un mal ingreso, ¿qué debería hacer?
 """
 reflection = self._call_llm(reflection_prompt)
 print(f"Reflexión: {reflection}")
 self.memory.append({"reflection": reflection})

 # Basado en la reflexión, decide el próximo curso de acción
 if observation["status"] == "failed":
 if "API call failed" in observation["error"] and retries <= self.max_retries:
 # La lógica de reintentos ya está manejada por el bucle interno,
 # pero la reflexión confirma la estrategia. Si quisiéramos ajustar
 # el recuento de reintentos o la estrategia basada en el LLM, lo haríamos aquí.
 print("La reflexión sugiere reintentar, lo cual ya se intentó.")
 # Si todos los reintentos fallaron, necesitamos una nueva estrategia o detenernos.
 if retries > self.max_retries:
 print("La reflexión indica que todos los reintentos fallaron por un error transitorio. Deteniendo o escalando.")
 break
 # Si los reintentos aún están en curso, el 'break' del bucle interno no se activó,
 # por lo que realmente deberíamos quedarnos en el mismo paso para la próxima iteración del bucle externo,
 # continuando efectivamente el reintento, o, si queremos que la reflexión guíe,
 # el LLM necesitaría emitir una nueva acción. Para simplicidad,
 # si se alcanzaron los reintentos máximos y fallaron, nos detenemos.
 if retries > self.max_retries:
 print("Todos los reintentos por error transitorio fallaron. Deteniéndose.")
 break

 elif "Invalid symbol" in observation["error"]:
 print("La reflexión indica un error crítico de entrada. No se puede proceder. Informando al usuario.")
 # En un agente real, esto activaría una herramienta de interacción con el usuario.
 break
 elif "No data to clean" in observation["error"] or "Missing 'close_price'" in observation["error"]:
 print("La reflexión indica un problema de calidad de datos. Reevaluando el paso anterior o deteniéndose.")
 # Aquí, una reflexión más avanzada podría sugerir volver a 'get_financial_data'
 # o incluso alterar los parámetros de la herramienta 'clean_data'.
 # Por ahora, nos detendremos si es un problema persistente de datos después de los reintentos.
 if retries > self.max_retries:
 print("Problema persistente de limpieza de datos. Deteniéndose.")
 break
 # Si el error fue sobre datos faltantes, implica que get_financial_data falló en silencio o proporcionó malos datos.
 # Un agente más astuto podría reflexionar y decidir volver a llamar a get_financial_data antes de volver a intentar clean_data.
 # Para este ejemplo, simplemente nos detendremos si los reintentos no lo solucionaron.
 print("La reflexión sugiere un problema de datos. Deteniéndose por ahora.")
 break # Detenerse por problemas de datos no resueltos después de los reintentos

 else:
 print("Falla no controlada después de la reflexión. Deteniéndose.")
 break # Errores no controlados

 self.current_step_index += 1 # Pasar al siguiente paso si el actual tuvo éxito o fue manejado.

 print("\n--- Ejecución del Agente Terminada ---")
 return context

# --- Ejecutando el Agente ---
# Reemplaza con tu cliente LLM real
class MockLLM:
 def chat(self, messages):
 return {"choices": [{"message": {"content": "Respuesta de LLM simulada"}}]}

mock_llm = MockLLM()
agent = ReflectiveAgent(mock_llm, tools)

print("\n--- Ejecutando con un símbolo válido ---")
agent.run("AAPL")

print("\n--- Ejecutando con un símbolo que podría fallar en la API ---")
# Reiniciar el estado del agente para una nueva ejecución
agent = ReflectiveAgent(mock_llm, tools)
agent.run("GOOG")

print("\n--- Ejecutando con un símbolo deliberadamente inválido ---")
agent = ReflectiveAgent(mock_llm, tools)
agent.run("FAILCO")

¿Qué está ocurriendo aquí?

  • El `ReflectiveAgent` tiene una `memory` para hacer un seguimiento de su trayectoria.
  • Después de cada ejecución de herramienta, registra la `observación` (éxito, fallo, salida, error).
  • Crucialmente, luego llama a `_call_llm` (simulando nuestro LLM para la reflexión) con un aviso que incluye el contexto actual y el resultado de la `last_action`.
  • La “reflexión” del LLM luego informa el próximo movimiento del agente. Si la API falló, el LLM sugiere reintentar. Si es un símbolo inválido, sugiere detenerse. Si la limpieza de datos falló debido a un formato inesperado, idealmente sugeriría reevaluar los datos o ajustar el enfoque de limpieza (aunque la respuesta de mi LLM simulado es simplificada).
  • El bucle exterior `while` continúa hasta que el plan esté completo o ocurra un error crítico e irrecuperable después de la reflexión.

Este es un ejemplo simplificado, pero demuestra el bucle central. Un sistema real tendría un aviso mucho más sofisticado para el `Módulo de Reflexión` y potencialmente un LLM que pueda emitir directamente comandos estructurados como `RETRY_TOOL(tool_name, delay)` o `MODIFY_PLAN(new_step, index)`. Mi función `_call_llm` es un marcador de posición que devuelve respuestas predeterminadas basadas en palabras clave, pero en una configuración de producción, aquí es donde viviría tu cadena LLM real, diseñada para emitir acciones específicas basadas en su reflexión.

Mi Experiencia Construyendo Esto

Cuando comencé a integrar estos bucles reflexivos, la configuración inicial fue un poco más trabajo. Tienes que crear buenos avisos para el paso de reflexión, asegurándote de que el LLM entienda su papel en la evaluación de resultados. También necesitas estructurar tus observaciones de manera clara para que el LLM tenga buena entrada.

Pero el retorno ha sido significativo. Mis agentes pasaron de caer ante el primer signo de problemas a manejar elegantemente errores transitorios de red, adaptándose a cambios menores en el esquema de datos y, a veces, incluso identificando problemas más profundos que no había anticipado. Es como darle a tu agente un poco de sentido común.

Un desafío que enfrenté fue la ingeniería de avisos del módulo de reflexión. No quieres que solo repita el error. Quieres que analice, infiera y proponga. Encontré éxito con avisos que preguntan explícitamente:

  • “Dada la falla observada, ¿cuál es la causa raíz más probable?”
  • “¿Qué acción específica se debería tomar para abordar esto? Considera reintentos, herramientas alternativas o modificación del plan.”
  • “Si este problema es persistente, ¿cómo debería escalar o terminar de manera elegante?”

Además, no subestimes la importancia del `Memory Module`. Para tareas complejas, el agente necesita recordar *por qué* intentó algo y cuáles fueron los resultados a lo largo de múltiples pasos. Las ventanas de contexto a corto plazo no son suficientes para una verdadera reflexión.

Conclusiones Accionables

  1. Diseña para el Fracaso, No Solo para el Éxito: Al planear el flujo de trabajo de tu agente, piensa activamente en lo que podría salir mal en cada paso. Esto te prepara para decidir dónde colocar tus puntos de observación y reflexión.
  2. La Observación Explícita es Clave: Asegúrate de que tus herramientas devuelvan salidas claras y estructuradas y, de manera crítica, propaguen errores de forma efectiva. El Reflection Module solo puede trabajar con lo que “ve.”
  3. Trata la Reflexión como un Ciudadano de Primera Clase: No solo añadas manejo de errores. Integra un módulo de reflexión dedicado (incluso si solo es una llamada específica a un LLM) en el bucle central de tu agente.
  4. Empieza Simple, Itera: No necesitas un sistema de reflexión super complejo desde el primer día. Comienza con una lógica básica de reintento basada en la reflexión del LLM, luego añade gradualmente toma de decisiones más sofisticada para modificar planes o cambiar herramientas.
  5. Indica al Reflection Module Cuidadosamente: Guía a tu LLM para que realice un pensamiento analítico, no solo resumir. Haz preguntas abiertas sobre las causas raíz y las soluciones propuestas.
  6. Considera la Memoria a Largo Plazo: Para agentes que funcionen durante períodos prolongados o manejen tareas complejas de múltiples etapas, un sistema de memoria que almacene más que solo el contexto del turno actual es crucial para una reflexión y aprendizaje efectivos.

Construir agentes que puedan reflexionar sobre su propio desempeño los hace significativamente más útiles y confiables. Nos acerca a sistemas verdaderamente autónomos que pueden operar de manera confiable en entornos impredecibles. Es un poco más trabajo al principio, pero es una inversión que rinde buenos frutos en la confiabilidad del agente y reduce los dolores de cabeza en el mantenimiento. ¡Inténtalo en tu próximo proyecto!

Artículos Relacionados

🕒 Published:

🧬
Written by Jake Chen

Deep tech researcher specializing in LLM architectures, agent reasoning, and autonomous systems. MS in Computer Science.

Learn more →
Browse Topics: AI/ML | Applications | Architecture | Machine Learning | Operations

More AI Agent Resources

ClawgoAi7botBot-1Botclaw
Scroll to Top