Inicio / Inteligencia Artificial / AI Engineering Pro / Agentes de IA: Arquitectura

Agentes de IA: Arquitectura

Patrones ReAct, Plan-Execute, LATS, function calling y guardrails.

Avanzado
🔒 Solo lectura
📖

Estás en modo lectura

Puedes leer toda la lección, pero para marcar progreso, hacer ejercicios y ganar XP necesitas una cuenta Pro.

Desbloquear por $9/mes

Agentes de IA: Arquitectura y Patrones de Diseño

¿Qué es un Agente de IA?

Un agente de IA es un sistema que usa un LLM como "cerebro" para tomar decisiones, ejecutar acciones y adaptarse en función de los resultados. A diferencia de una cadena lineal (prompt → respuesta), un agente puede:

  • Razonar sobre qué hacer a continuación
  • Usar herramientas (APIs, bases de datos, código)
  • Iterar hasta completar la tarea
  • Autocorregirse cuando algo falla
                    ┌────────────────┐
                    │     AGENTE     │
                    │    (LLM +      │
                    │    Razonamiento)│
                    └───────┬────────┘
                            │
                    ┌───────┼───────┐
                    ▼       ▼       ▼
               [Tool 1] [Tool 2] [Tool 3]
               (Search)  (API)   (Code)
                    │       │       │
                    └───────┼───────┘
                            ▼
                    Observar resultados
                            │
                    ┌───────┴───────┐
                    │ ¿Tarea        │
                    │ completa?     │
                    └───────┬───────┘
                       No   │   Sí
                       ▼    │    ▼
                    Iterar  │  Respuesta
                       │    │    final
                       └────┘

Patrones de Razonamiento

ReAct (Reasoning + Acting)

El patrón más usado. El agente alterna entre razonar y actuar.

Pregunta: ¿Cuál es la población de la capital de Francia?

Pensamiento: Necesito saber la capital de Francia.
Acción: search("capital de Francia")
Observación: La capital de Francia es París.

Pensamiento: Ahora necesito la población de París.
Acción: search("población París 2025")
Observación: París tiene ~2.1 millones de habitantes (12M área metropolitana).

Pensamiento: Ya tengo toda la información necesaria.
Respuesta: La población de París es ~2.1M (ciudad) / ~12M (área metro).

Plan-and-Execute

Primero planifica todos los pasos, luego los ejecuta.

Plan:
  1. Buscar documentación de la API de pagos
  2. Identificar endpoints de webhook
  3. Generar código de integración
  4. Escribir tests

Ejecución:
  Paso 1: search_docs("payment API webhooks") → [resultados]
  Paso 2: extract_endpoints(resultados) → [POST /webhooks, ...]
  Paso 3: generate_code(endpoints) → código Python
  Paso 4: generate_tests(código) → tests pytest

LATS (Language Agent Tree Search)

Explora múltiples caminos de solución en paralelo y elige el mejor.

                    Query
                   /  |  \
                 /    |    \
              Path1 Path2  Path3
              /       |       \
           Tool A   Tool B   Tool A
           Score:8  Score:6  Score:9  ← Evaluar
              |                  |
           Expandir          Expandir  ← Seguir mejores paths

Function Calling / Tool Use

El mecanismo que permite a los LLMs invocar funciones externas.

from openai import OpenAI

client = OpenAI()

# Definir herramientas
tools = [
    {
        "type": "function",
        "function": {
            "name": "search_knowledge_base",
            "description": "Busca información en la base de conocimiento interna",
            "parameters": {
                "type": "object",
                "properties": {
                    "query": {
                        "type": "string",
                        "description": "La consulta de búsqueda"
                    },
                    "filters": {
                        "type": "object",
                        "properties": {
                            "category": {"type": "string"},
                            "date_from": {"type": "string", "format": "date"},
                        }
                    }
                },
                "required": ["query"]
            }
        }
    },
    {
        "type": "function",
        "function": {
            "name": "execute_sql",
            "description": "Ejecuta una consulta SQL de solo lectura",
            "parameters": {
                "type": "object",
                "properties": {
                    "query": {
                        "type": "string",
                        "description": "Consulta SQL SELECT"
                    }
                },
                "required": ["query"]
            }
        }
    },
]

# El LLM decide cuándo y qué herramienta usar
response = client.chat.completions.create(
    model="gpt-4o",
    messages=[{"role": "user", "content": "¿Cuántas ventas hubo ayer?"}],
    tools=tools,
    # tool_choice controla si el LLM puede usar herramientas:
    #   "auto" = el LLM decide si usar tools o responder directamente (recomendado)
    #   "none" = nunca usar tools (fuerza respuesta de texto)
    #   "required" = DEBE usar al menos una tool
    #   {"type": "function", "function": {"name": "..."}} = fuerza una tool específica
    tool_choice="auto",
)

# Loop de tool calls: el LLM NO ejecuta las tools — solo las "solicita".
# Nosotros ejecutamos la función y enviamos el resultado de vuelta al LLM
# para que genere la respuesta final (o solicite otra tool).
if response.choices[0].message.tool_calls:
    for tool_call in response.choices[0].message.tool_calls:
        function_name = tool_call.function.name
        arguments = json.loads(tool_call.function.arguments)
        
        # Ejecutar la herramienta (nosotros, no el LLM)
        result = execute_tool(function_name, arguments)
        
        # Enviar resultado al LLM para que genere la respuesta final
        # role: "tool" indica que este mensaje es el resultado de una tool call
        # tool_call_id vincula este resultado con la solicitud específica del LLM
        messages.append({"role": "tool", "tool_call_id": tool_call.id, "content": result})

Diseño de Herramientas para Agentes

Principios de Diseño

  1. Descripción clara — El LLM elige la herramienta basándose en la descripción
  2. Parámetros mínimos — Menos parámetros = menos errores
  3. Idempotencia — Las herramientas deben ser seguras de re-ejecutar
  4. Errores descriptivos — Mensajes que el agente pueda usar para corregir
  5. Timeout y rate limiting — Prevenir loops infinitos
# MAL: Descripción vaga, parámetros confusos
{"name": "do_stuff", "description": "Does stuff", ...}

# BIEN: Descripción precisa, parámetros claros
{
    "name": "search_customer_orders",
    "description": "Busca pedidos de un cliente por email o ID. "
                   "Retorna los últimos 10 pedidos con estado, fecha y monto. "
                   "Usar cuando el usuario pregunte sobre pedidos, entregas o compras.",
    "parameters": {
        "type": "object",
        "properties": {
            "customer_email": {"type": "string", "description": "Email del cliente"},
            "status": {"type": "string", "enum": ["pending", "shipped", "delivered"]},
        },
        "required": ["customer_email"]
    }
}

Manejo de Estado y Memoria

class AgentState:
    """Estado persistente del agente durante una conversación."""

    def __init__(self):
        self.messages: list = []
        self.tool_results: dict = {}
        self.iteration_count: int = 0
        self.max_iterations: int = 10

    def add_message(self, role: str, content: str):
        self.messages.append({"role": role, "content": content})

    def should_stop(self) -> bool:
        """Condiciones de parada para evitar loops infinitos."""
        if self.iteration_count >= self.max_iterations:
            return True
        return False

Guardrails para Agentes

class AgentGuardrails:
    BLOCKED_ACTIONS = ["DROP", "DELETE", "TRUNCATE", "ALTER"]

    @staticmethod
    def validate_sql(query: str) -> bool:
        """Solo permite SELECT queries."""
        normalized = query.strip().upper()
        if not normalized.startswith("SELECT"):
            return False
        for blocked in AgentGuardrails.BLOCKED_ACTIONS:
            if blocked in normalized:
                return False
        return True

    @staticmethod
    def validate_api_call(url: str, method: str) -> bool:
        """Solo permite llamadas a dominios aprobados."""
        from urllib.parse import urlparse
        allowed_domains = ["api.internal.com", "data.company.com"]
        parsed = urlparse(url)
        return parsed.hostname in allowed_domains

    @staticmethod
    def check_budget(cost_so_far: float, max_budget: float = 1.0) -> bool:
        """Detiene el agente si supera el presupuesto."""
        return cost_so_far < max_budget

Patrones de Error y Recovery

Agente intenta Tool A ──► Error: timeout
         │
         ▼
Retry con backoff (1s, 2s, 4s)
         │
   ┌─────┴─────┐
   ▼           ▼
 Éxito      Max retries
   │           │
   ▼           ▼
 Continuar   Fallback: Tool B alternativa
               │
          ┌────┴────┐
          ▼         ▼
        Éxito    Error final
          │         │
          ▼         ▼
       Continuar  Respuesta parcial
                  + explicación

Resumen

Los agentes de IA son poderosos pero requieren diseño cuidadoso:

  1. Patrón ReAct — Razonamiento + acción iterativa
  2. Function calling — Mecanismo estándar de tool use
  3. Herramientas bien diseñadas — Descripciones claras, parámetros mínimos
  4. Guardrails — Validación de acciones, budgets, rate limits
  5. Recovery patterns — Retries, fallbacks, respuestas parciales

🧠 Preguntas de Repaso

1. En el patrón ReAct (Reasoning + Acting), ¿cuál es el ciclo que sigue un agente para resolver una tarea?

  • A) Input → Output → Validación
  • B) Pensamiento → Acción → Observación, repitiendo hasta completar
  • C) Planificación completa → Ejecución secuencial
  • D) Búsqueda paralela → Selección del mejor resultado

Respuesta: B) — ReAct alterna entre Pensamiento (razonamiento sobre qué hacer), Acción (ejecutar una herramienta) y Observación (interpretar el resultado), repitiendo el ciclo hasta completar la tarea. Es el patrón de agentes más utilizado.

2. Cuando un LLM hace "function calling", ¿quién ejecuta realmente la función/herramienta?

  • A) El LLM ejecuta la función directamente en el servidor
  • B) El LLM solo solicita la ejecución; el desarrollador/sistema ejecuta la función y envía el resultado de vuelta al LLM
  • C) La función se ejecuta automáticamente en el navegador del usuario
  • D) Un servicio externo independiente ejecuta todas las funciones

Respuesta: B) — El LLM NO ejecuta herramientas directamente — solo genera una solicitud estructurada (nombre de función + argumentos). El sistema del desarrollador ejecuta la función y devuelve el resultado al LLM con role: "tool" y el tool_call_id correspondiente.

3. ¿Por qué es importante configurar max_iterations en un agente de IA?

  • A) Para aumentar la calidad de las respuestas
  • B) Para evitar loops infinitos que consumen tokens y presupuesto sin avanzar
  • C) Para mejorar la velocidad de respuesta del modelo
  • D) Para limitar el número de usuarios concurrentes

Respuesta: B) — Sin un límite de iteraciones (ej: max_iterations=10), un agente podría entrar en loops infinitos, consumiendo tokens y presupuesto sin resolver la tarea. Es un guardrail esencial para control de costos y estabilidad.

4. ¿Cuál es la estrategia correcta de recovery cuando una herramienta del agente falla repetidamente?

  • A) Detener el agente inmediatamente sin respuesta
  • B) Retry con backoff exponencial → si falla, fallback a herramienta alternativa → si falla, respuesta parcial con explicación
  • C) Reiniciar el agente desde cero con un prompt diferente
  • D) Ignorar el error y continuar con la siguiente herramienta

Respuesta: B) — La estrategia de recovery sigue una cascada: primero retry con backoff exponencial (1s, 2s, 4s), si se agotan los reintentos se usa una herramienta alternativa (fallback), y si todo falla se da una respuesta parcial explicando qué información falta.

¿Te gustó esta lección?

Con Pro puedes marcar progreso, hacer ejercicios, tomar quizzes, ganar XP y obtener tu constancia.

Ver planes desde $9/mes