effidevFlutter · Edge de Cloudflare · Optimización de costes en la nube
Español

Cloudflare Agents SDK: Agentes IA con Estado en el Edge

Construcción de agentes IA con estado usando Cloudflare Agents SDK

Cualquiera puede llamar a un LLM a través de una API para recibir una respuesta. El verdadero desafío viene después. Si desea crear un “agente de producción con estado (stateful)” que recuerde conversaciones anteriores, invoque herramientas externas, espere la aprobación humana a mitad del proceso antes de reanudar la ejecución e inicie tareas de forma autónoma según una programación cron, debe integrar manualmente la gestión de estado, el almacenamiento persistente, las comunicaciones en tiempo real y los flujos de trabajo de larga duración. Administrar Redis + PostgreSQL + un servidor WebSocket + colas + trabajos cron por separado hace que la infraestructura sea más compleja que el propio agente.

El Agents SDK, presentado por Cloudflare durante la Agents Week de 2026, resuelve este problema sobre una sola capa de Durable Objects. Cada instancia de agente es un Durable Object que persiste su estado en SQLite integrado, se comunica en tiempo real con el frontend mediante WebSockets y gestiona la ejecución autónoma a través de alarmas y expresiones cron. Sin necesidad de infraestructura adicional, un único comando wrangler deploy realiza el despliegue en más de 300 PoPs en todo el mundo.

Este artículo aborda desde la arquitectura del Agents SDK, la implementación de la clase Agent, RPC con seguridad de tipos utilizando el decorador @callable(), la integración con los hooks de React useAgent/useAgentChat, patrones de aprobación Human-in-the-Loop, hasta los límites y costos a considerar en producción, todo a un nivel listo para su implementación operativa real.

Resumen clave

  • Los agentes del Agents SDK ejecutan sobre Durable Objects, ofreciendo hasta 1 GB de SQLite integrado por instancia, 30 segundos de tiempo de CPU (reiniciados por petición) y tiempo de espera de reloj ilimitado.
  • Al heredar de la clase Agent y exponer métodos con el decorador @callable(), el frontend puede invocar inmediatamente un RPC con seguridad de tipos basado en WebSockets mediante el hook useAgent.
  • El patrón Human-in-the-Loop permite controlar llamadas a herramientas con la marca needsApproval o esperar desde días hasta meses mediante waitForApproval() de Cloudflare Workflows.
  • Los agentes pueden iniciar tareas de forma autónoma mediante programaciones cron y alarmas, sin quedar limitados al patrón petición-respuesta.
  • La facturación se basa en las tarifas de Durable Objects del plan Workers Paid, permitiendo operar decenas de millones de instancias de agentes concurrentes por cuenta.

Arquitectura del Agents SDK: Por qué Durable Objects

La mayoría de los enfoques tradicionales para implementar agentes IA serverless utilizan una combinación de “funciones sin estado + almacenamiento externo”. Llaman al LLM desde Lambda o Cloud Functions, guardan el historial de conversación en Redis o DynamoDB, mantienen el estado de larga duración en Step Functions y gestionan las comunicaciones en tiempo real mediante un servidor WebSocket independiente. Es necesario combinar entre 4 y 5 servicios para un solo agente, y el código de integración para mantener la coherencia entre ellos termina siendo más extenso que la propia lógica del agente.

El Agents SDK condensa esta combinación en un único Durable Object. De acuerdo con la documentación oficial de arquitectura de Cloudflare, la estructura de una instancia de agente es la siguiente:

Rol Lo que ofrece Durable Objects Servicio equivalente en arquitectura tradicional
Cómputo Isolate monohilo, 30 s de CPU por petición Lambda / Cloud Run
Estado persistente SQLite integrado (hasta 1 GB por instancia) DynamoDB / Redis
Comunicación en tiempo real WebSocket nativo (con soporte de Hibernation) Servidor Pusher / Socket.IO
Programación API de alarmas + expresiones cron CloudWatch Events / servidor cron
Enrutamiento global ID único global para acceder a la misma instancia desde cualquier lugar Route 53 + equilibrador de carga
Tolerancia a fallos Migración automática, reinicio en otro PoP en caso de fallo Implementación manual

La clave reside en la asignación 1:1: “Instancia de agente = Instancia de Durable Object”. Cuando el agente invoca this.setState(), los cambios se escriben inmediatamente en SQLite integrado y se transmiten automáticamente a todos los clientes WebSocket conectados. Mientras el agente espera la respuesta del LLM, el Durable Object puede esperar de forma ilimitada en tiempo de reloj (sin consumir tiempo de CPU), lo que permite procesar flujos de trabajo de larga duración dentro del propio agente sin necesidad de colas externas ni Step Functions.

La ventaja práctica de este diseño es la eliminación de la complejidad de despliegue. Con un único wrangler deploy, el código del agente, el almacenamiento de estado, los endpoints WebSocket y el programador se despliegan simultáneamente en la red global de Cloudflare. No se requiere aprovisionar bases de datos independientes, escalar servidores WebSocket ni configurar trabajos cron.

Implementación de la clase Agent: Gestión de estado y RPC @callable

La estructura básica de un agente comienza al heredar de la clase Agent. Creemos un proyecto basado en la plantilla agents-starter en GitHub y examinemos su estructura central.

# Creación del proyecto (plantilla actualizada a 2026-08)
npm create cloudflare@latest -- --template cloudflare/agents-starter my-agent
cd my-agent

A continuación se muestra un ejemplo de implementación en el lado del servidor para un agente que procesa tickets de soporte al cliente. Este código resuelve el patrón de persistencia de estado + RPC con seguridad de tipos + invocación de herramientas dentro de una sola clase.

// src/server.ts
import { Agent, callable } from "agents";
import { AIChatAgent } from "@cloudflare/ai-chat";

// Definición del tipo de estado del agente
export interface TicketState {
  ticketId: string | null;
  status: "idle" | "investigating" | "waiting-approval" | "resolved";
  history: Array<{ role: string; content: string; timestamp: number }>;
  metadata: Record<string, string>;
}

export class SupportAgent extends AIChatAgent<Env, TicketState> {
  // Estado inicial: se guarda automáticamente en SQLite al crear el Durable Object
  initialState: TicketState = {
    ticketId: null,
    status: "idle",
    history: [],
    metadata: {},
  };

  // Los métodos expuestos con @callable() pueden invocarse desde el frontend como agent.stub.assignTicket()
  @callable()
  async assignTicket(ticketId: string, priority: string): Promise<string> {
    // setState() escribe inmediatamente en SQLite y transmite el estado a todos los clientes conectados
    this.setState({
      ...this.state,
      ticketId,
      status: "investigating",
      metadata: { ...this.state.metadata, priority },
    });

    // Análisis del ticket con Workers AI (inferencia en el edge)
    const analysis = await this.env.AI.run("@cf/meta/llama-3.3-70b-instruct-fp8-fast", {
      messages: [
        { role: "system", content: "Analiza el ticket de soporte al cliente y sugiere una solución." },
        { role: "user", content: `Ticket ${ticketId}, prioridad: ${priority}` },
      ],
    });

    return analysis.response ?? "Análisis completado";
  }

  @callable()
  async getStatus(): Promise<TicketState> {
    return this.state;
  }

  // Programación cron: verifica tickets no resueltos cada hora
  async onCronTrigger(cron: string): Promise<void> {
    if (this.state.status === "investigating") {
      const elapsed = Date.now() - (this.state.history.at(-1)?.timestamp ?? 0);
      if (elapsed > 3600_000) {
        // Sin resolver durante más de 1 hora → notificación de escalado
        await this.escalate();
      }
    }
  }

  private async escalate(): Promise<void> {
    this.setState({ ...this.state, metadata: { ...this.state.metadata, escalated: "true" } });
    // Lógica para enviar notificaciones mediante webhooks de Slack, correo electrónico, etc.
  }
}

Nota importante: el decorador @callable() está diseñado exclusivamente para RPC basado en WebSockets. Para invocar métodos del agente dentro del mismo Worker o desde otro Durable Object, utilice el RPC estándar de Durable Objects (this.env.AGENT.get(id)). Usar @callable() para llamadas internas añade sobrecarga innecesaria de WebSockets.

Tampoco olvide la vinculación del agente como Durable Object en la configuración de wrangler.jsonc.

// wrangler.jsonc
{
  "name": "support-agent",
  "main": "src/index.ts",
  "compatibility_date": "2026-07-28",
  "durable_objects": {
    "bindings": [
      {
        "name": "SUPPORT_AGENT",
        "class_name": "SupportAgent"
      }
    ]
  },
  "migrations": [
    { "tag": "v1", "new_sqlite_classes": ["SupportAgent"] }
  ],
  "ai": { "binding": "AI" }
}

Integración con el frontend de React: Hooks useAgent y useAgentChat

El Agents SDK proporciona hooks específicos para React para gestionar la conexión entre el frontend y el agente de forma declarativa. La guía oficial de integración con React define funciones claramente diferenciadas para cada uno de los tres hooks:

Hook Paquete Propósito
useAgent agents/react Conexión general con el agente. Sincronización de estado + llamadas RPC
useAgentChat @cloudflare/ai-chat/react Especializado en chat. Persistencia de mensajes, streaming y ejecución automática de herramientas
useVoiceAgent @cloudflare/voice STT/TTS de voz. Procesamiento de voz en tiempo real sobre el mismo WebSocket

A continuación se presenta un ejemplo de un componente de React que se conecta al SupportAgent creado anteriormente mediante useAgent. Este código resuelve el patrón de gestión de conexiones WebSocket + sincronización automática de estado + llamadas RPC con seguridad de tipos de manera declarativa.

// src/client.tsx
import { useAgent } from "agents/react";
import { useState, useCallback } from "react";
import type { SupportAgent, TicketState } from "./server";

function SupportDashboard() {
  const [ticket, setTicket] = useState<TicketState | null>(null);
  const [ticketId, setTicketId] = useState("");

  // useAgent gestiona automáticamente la conexión WebSocket y
  // dispara automáticamente onStateUpdate cuando el agente llama a setState()
  const agent = useAgent<SupportAgent, TicketState>({
    agent: "SupportAgent",
    onStateUpdate: (state) => setTicket(state),
    onError: (error) => console.error("Agent connection error:", error),
  });

  const handleAssign = useCallback(async () => {
    if (!agent.stub || !ticketId) return;
    // Llamada RPC con seguridad de tipos: solo los métodos @callable() están expuestos en stub
    const result = await agent.stub.assignTicket(ticketId, "high");
    console.log("Resultado del análisis:", result);
  }, [agent.stub, ticketId]);

  return (
    <div>
      <input
        value={ticketId}
        onChange={(e) => setTicketId(e.target.value)}
        placeholder="Ingrese ID del ticket"
      />
      <button onClick={handleAssign} disabled={!agent.connected}>
        Asignar ticket
      </button>
      {ticket && (
        <div>
          <p>Estado: {ticket.status}</p>
          <p>Prioridad: {ticket.metadata.priority ?? "No especificada"}</p>
        </div>
      )}
    </div>
  );
}

useAgentChat es un hook aún más especializado que gestiona internamente la persistencia del historial de mensajes en SQLite, el procesamiento de respuestas en streaming del LLM y la inclusión automática de los resultados de llamadas a herramientas. Al crear interfaces de usuario de chat, el uso de useAgentChat en lugar de useAgent reduce las líneas de código a menos de la mitad.

Human-in-the-Loop: Gating de aprobación de herramientas y patrones de larga espera

Uno de los aspectos más complejos en agentes IA de producción es “obtener la confirmación humana antes de que el agente ejecute acciones de alto riesgo”. El Agents SDK admite esta funcionalidad en tres niveles:

Patrón 1: Gating de herramientas con needsApproval. Al establecer needsApproval: true en la definición de una herramienta, el agente detiene su ejecución cuando intenta invocarla y pasa al estado approval-requested. Cuando el frontend envía una aprobación o rechazo, el agente reanuda la ejecución o se detiene.

// Ejemplo de definición de herramienta: aplicación de gate de aprobación a una herramienta de reembolso
const tools = [
  {
    name: "process_refund",
    description: "Procesa un reembolso al cliente",
    parameters: {
      type: "object",
      properties: {
        amount: { type: "number", description: "Monto a reembolsar (USD)" },
        reason: { type: "string", description: "Motivo del reembolso" },
      },
      required: ["amount", "reason"],
    },
    // Esta marca es la clave: cuando el agente intenta llamar a esta herramienta, la ejecución se pausa
    needsApproval: true,
  },
];

Nota importante: needsApproval es adecuado para aprobaciones en tiempo real dentro de la sesión. Dado que la conexión WebSocket se interrumpe si el usuario cierra el navegador, no se recomienda para escenarios donde el estado de espera pueda prolongarse durante varias horas.

Patrón 2: waitForApproval() de Cloudflare Workflows. Para casos que requieren esperas prolongadas (por ejemplo, flujos de trabajo donde la aprobación del administrador puede tardar hasta el día siguiente), se utiliza el método waitForApproval() de Cloudflare Workflows. Este método crea un gate persistente sobre el Durable Object. Incluso si la instancia del agente se descarga de la memoria (Hibernation), se reactiva automáticamente al recibir el evento de aprobación para continuar con el flujo de trabajo. Permite esperas desde días hasta meses.

Patrón 3: MCP Elicitation. Cuando el agente se comunica con un servidor Model Context Protocol (MCP), si el servidor MCP requiere información adicional, puede enviar preguntas directamente al usuario mediante configureElicitationHandlers(). Resulta de gran utilidad cuando el agente actúa como cliente MCP orquestando múltiples herramientas externas.

Programación y ejecución autónoma: Cron, alarmas y webhooks

Los chatbots de IA tradicionales solo funcionan cuando el usuario envía un mensaje. Un agente de producción debe ser capaz de iniciar tareas por sí mismo. Los agentes en Agents SDK heredan la API de alarmas de Durable Objects para ofrecer cuatro patrones de ejecución autónoma:

Disparador Método de configuración Escenario adecuado
Programación cron triggers.crons en wrangler.jsonc Tareas periódicas cada hora/día (informes, monitoreo)
Alarma this.ctx.storage.setAlarm(timestamp) Ejecución única en un momento determinado (envíos programados, recordatorios)
Recepción de webhooks Enrutamiento al agente desde el controlador fetch del Worker Respuesta a eventos externos (pago completado en Stripe, fusión de PR en GitHub)
Recepción de correo electrónico Controlador email() Respuestas y clasificación automáticas basadas en correo

La ventaja fundamental de este diseño es que el costo en estado de inactividad es igual a 0. Gracias a la API de Hibernation de Durable Objects, el agente puede descargarse de la memoria manteniendo la conexión WebSocket activa. Al activarse una alarma o una expresión cron, se despierta automáticamente para realizar el trabajo y vuelve a suspenderse. Al no requerir instancias de VM siempre activas, incluso si se despliegan miles de agentes de forma simultánea, solo se facturan los agentes que están ejecutando procesamiento activo.

// Configuración del disparador cron (wrangler.jsonc)
{
  "triggers": {
    "crons": ["0 */6 * * *"]  // Ejecución cada 6 horas
  }
}

Despliegue en producción: Límites, costos y lista de verificación operativa

A continuación se resumen los límites y la estructura de costos que se deben verificar al trasladar el Agents SDK a producción. Los valores corresponden a la página de precios de Cloudflare Workers y a la página de precios de Durable Objects vigentes a agosto de 2026.

Concepto Valor Observaciones
Instancias concurrentes de agentes por cuenta Más de decenas de millones El límite estricto se puede aumentar a petición
Tamaño máximo de estado por instancia 1 GB (SQLite) Almacenamiento Key-Value disponible de forma independiente
Tiempo de CPU por petición 30 s Se reinicia por petición HTTP o mensaje WebSocket
Tiempo de espera en tiempo de reloj Ilimitado La espera de respuesta del LLM no consume CPU
Número de definiciones de agentes ~250.000 En toda la cuenta
Tarifa de Durable Objects (Paid) $0.15 por millón de peticiones + $12.50/mes por GB-segundo El tiempo de reloj no se cobra durante Hibernation
Inferencia Workers AI Según modelo Llama 3.3 70B: $0.27 por 1M de tokens de entrada

Tres puntos de atención durante las operaciones:

  1. Depurar el estado para evitar superar el límite de 1 GB en SQLite. Si el historial de conversación crece indefinidamente, alcanzará el límite máximo. Se recomienda aplicar una estrategia de archivado de historiales antiguos en R2, conservando únicamente las últimas N entradas en SQLite.

  2. Tener en cuenta el límite de 30 segundos de CPU. Las llamadas a LLM en sí no consumen tiempo de CPU al estar en espera await, pero si la lógica de procesamiento de respuestas o parseo es compleja, se pueden superar los 30 segundos de CPU. Desplace el procesamiento pesado a un Worker independiente o procéselo de forma asíncrona mediante Cloudflare Queues.

  3. Aprovechar al máximo la funcionalidad de Hibernation. Incluso manteniendo conexiones WebSocket, el uso de hibernateWebSocket() permite que el agente se descargue de la memoria cuando no hay mensajes activos. De este modo, el cobro por GB-segundo se aplica exclusivamente al tiempo de procesamiento activo, lo que reduce los costos considerablemente. En la guía de WebSocket Hibernation se analiza en detalle el efecto de ahorro de costos de este patrón.

Diferencias con otros frameworks de agentes: Comparación con LangGraph y Mastra

El Agents SDK no es la única opción disponible. Al compararlo con los frameworks de agentes más utilizados en la actualidad, su posicionamiento queda definido con claridad:

Criterio de comparación Cloudflare Agents SDK LangGraph Mastra
Entorno de ejecución Edge de Cloudflare (exclusivo) Cualquier entorno (nube, local) Cualquier entorno (Node.js)
Gestión de estado SQLite integrado en Durable Objects Checkpointer externo (Redis, Postgres) Requiere base de datos externa
Comunicación en tiempo real WebSocket nativo + hooks de React Implementación manual o LangServe Implementación manual
Ejecución de larga duración Hibernation + Workflows AsyncIO + cola externa Requiere cola externa
Despliegue Comando único wrangler deploy Configuración manual en contenedores/serverless Configuración manual en contenedores/serverless
Dependencia de proveedor Alta (exclusivo de Cloudflare) Baja Baja
Puntos fuertes Cero infraestructura, edge global, eficiencia de costos Flujos complejos basados en grafos, flexibilidad API concisa, rápida creación de prototipos

El principal compromiso del Agents SDK radica en que “elimina la complejidad de la infraestructura a cambio de una dependencia total de Cloudflare”. Para los equipos que ya utilizan Cloudflare Workers como su plataforma principal, el Agents SDK ofrece la vía más rápida hacia la producción. Por el contrario, si se requiere una estrategia multicloud o si el grafo de estados del agente exige estructuras DAG o cíclicas complejas, LangGraph resulta más adecuado.

Preguntas frecuentes

¿En qué se diferencian Agents SDK y Workers AI?

Workers AI es una API de inferencia de modelos que actúa como motor para ejecutar modelos como Llama o Whisper en el edge. El Agents SDK es un framework de agentes que proporciona la infraestructura para el “cerebro” del agente, incluyendo gestión de estado, invocación de herramientas, interacción con el usuario y programación. Por lo general, se utilizan juntos, llamando a Workers AI como backend de inferencia desde el Agents SDK.

¿Es posible conectar múltiples usuarios a un solo agente?

Sí. Un Durable Object acepta múltiples conexiones WebSocket simultáneas. Al utilizar el ID del agente de manera similar al ID de una sala de chat, varios usuarios pueden conectarse al mismo agente y compartir su estado en tiempo real. No obstante, debido a la naturaleza monohilo de Durable Objects, existen limitaciones de rendimiento en escenarios con escrituras concurrentes extremadamente elevadas (miles de operaciones por segundo).

¿Se puede añadir el Agents SDK a un proyecto de Workers existente?

Sí. Tras instalar el paquete agents y añadir la vinculación de Durable Objects en wrangler.jsonc, basta con llamar a routeAgentRequest(request, env) dentro del controlador fetch del Worker. Esto permite que el enrutamiento existente y el enrutamiento del agente coexistan, lo que facilita añadir funciones de agente de forma gradual manteniendo los endpoints API existentes.

¿Cómo se realiza el desarrollo local?

Al ejecutar el servidor de desarrollo local mediante wrangler dev, los Durable Objects, SQLite y WebSockets se emulan por completo de forma local. Esto permite probar exactamente la misma superficie de API que en producción, acelerando el ciclo de desarrollo y pruebas sin depender de servicios externos.