Renderz Studio
Academia
Proyectos
Servicios
Arsenal
Repo
Herramientas
Skills
El Oráculo
Guía Gratis
← El Arsenal
AutomatizaciónExperto45 min

Agentes Autónomos con Claude

Arquitectura completa · 7 agentes · cron jobs · el sistema que trabaja mientras dormís

AgentesCronAutomatización
✓ Guía gratuita · Acceso completo

Mapa rápido · salta al paso que te interese

Arquitectura de Agentes

Cómo estructurar un sistema multi-agente

Los 7 Agentes

Cada agente con código completo

Cron Jobs + Vercel

Scheduling que funciona

01

Arquitectura de Agentes: cómo estructurar el sistema

Un sistema de agentes tiene 3 capas: el scheduler que dispara, el orchestrator que coordina, y los agentes que ejecutan. Cada agente es independiente y puede fallar sin tumbar el sistema.

CapaResponsabilidadTech Stack
SchedulerDispara agentes en horariosVercel Cron / GitHub Actions
OrchestratorCoordina y maneja erroresNext.js API Routes
AgentsEjecutan tareas específicasClaude API + Tools
StoragePersiste estado y outputsSupabase
NotificationsAlerta cuando algo fallaResend / Slack
Estructura de archivos
/app/api/cron/
├── oracle/route.ts      # Dispara ORACLE diario
├── vera/route.ts        # Dispara VERA semanal
├── repo/route.ts        # Dispara REPO diario
└── signal/route.ts      # Dispara SIGNAL lunes

/lib/agents/
├── base.ts              # Clase base AgentRunner
├── oracle.ts            # Lógica de ORACLE
├── vera.ts              # Lógica de VERA
├── repo.ts              # Lógica de REPO
└── types.ts             # Tipos compartidos

/lib/tools/
├── web-scraper.ts       # Tool de scraping
├── email-sender.ts      # Tool de emails
├── db-writer.ts         # Tool de DB
└── index.ts             # Registry de tools
Clase base AgentRunner
// lib/agents/base.ts
import Anthropic from '@anthropic-ai/sdk'
import { createClient } from '@supabase/supabase-js'

export interface AgentConfig {
  name: string
  systemPrompt: string
  tools: Anthropic.Tool[]
  maxTokens?: number
  model?: string
}

export interface AgentResult {
  success: boolean
  output: string
  tokensUsed: number
  duration: number
  error?: string
}

export class AgentRunner {
  private client: Anthropic
  private supabase: ReturnType<typeof createClient>
  private config: AgentConfig

  constructor(config: AgentConfig) {
    this.config = config
    this.client = new Anthropic()
    this.supabase = createClient(
      process.env.SUPABASE_URL!,
      process.env.SUPABASE_SERVICE_KEY!
    )
  }

  async run(userMessage: string): Promise<AgentResult> {
    const startTime = Date.now()
    let tokensUsed = 0

    try {
      // Loop de agente: sigue hasta que no haya más tool calls
      let messages: Anthropic.MessageParam[] = [
        { role: 'user', content: userMessage }
      ]

      while (true) {
        const response = await this.client.messages.create({
          model: this.config.model || 'claude-sonnet-4-20250514',
          max_tokens: this.config.maxTokens || 4096,
          system: this.config.systemPrompt,
          tools: this.config.tools,
          messages,
        })

        tokensUsed += response.usage.input_tokens + response.usage.output_tokens

        // Si no hay tool calls, terminamos
        if (response.stop_reason === 'end_turn') {
          const textContent = response.content.find(c => c.type === 'text')
          return {
            success: true,
            output: textContent?.text || '',
            tokensUsed,
            duration: Date.now() - startTime,
          }
        }

        // Procesar tool calls
        const toolCalls = response.content.filter(c => c.type === 'tool_use')
        const toolResults: Anthropic.MessageParam = {
          role: 'user',
          content: await Promise.all(
            toolCalls.map(async (tc) => ({
              type: 'tool_result' as const,
              tool_use_id: tc.id,
              content: await this.executeTool(tc.name, tc.input),
            }))
          ),
        }

        messages.push({ role: 'assistant', content: response.content })
        messages.push(toolResults)
      }
    } catch (error) {
      return {
        success: false,
        output: '',
        tokensUsed,
        duration: Date.now() - startTime,
        error: error instanceof Error ? error.message : 'Unknown error',
      }
    }
  }

  private async executeTool(name: string, input: unknown): Promise<string> {
    // Implementar cada tool aquí
    const tools: Record<string, (input: unknown) => Promise<string>> = {
      web_search: async (i) => this.webSearch(i as { query: string }),
      save_to_db: async (i) => this.saveToDb(i as { table: string; data: unknown }),
      send_email: async (i) => this.sendEmail(i as { to: string; subject: string; body: string }),
    }

    const tool = tools[name]
    if (!tool) throw new Error(`Tool not found: ${name}`)
    return tool(input)
  }

  private async webSearch(input: { query: string }): Promise<string> {
    // Implementar búsqueda web
    return JSON.stringify({ results: [] })
  }

  private async saveToDb(input: { table: string; data: unknown }): Promise<string> {
    const { error } = await this.supabase.from(input.table).insert(input.data)
    if (error) throw error
    return 'Saved successfully'
  }

  private async sendEmail(input: { to: string; subject: string; body: string }): Promise<string> {
    // Implementar envío de email
    return 'Email sent'
  }
}
02

Los 7 Agentes: código completo de cada uno

Cada agente tiene un rol específico. Ninguno se superpone con otro. Juntos cubren las operaciones de un negocio digital.

Curador de noticias de IA. Busca, filtra, reescribe, y publica artículos diarios.

CampoValor
Schedule08:00 UTC diario
Duración2-5 minutos
Output3 artículos en news_articles
Tokens/run~15,000
lib/agents/oracle.ts
import { AgentRunner } from './base'

const ORACLE_SYSTEM = `Sos ORACLE, el editor de inteligencia de Renderz Studio.

Tu trabajo:
1. Buscar las 10 noticias más relevantes de IA de las últimas 24h
2. Filtrar las 3 más importantes para nuestra audiencia
3. Reescribir cada una en español, con tu análisis
4. Guardarlas en la base de datos

Audiencia: developers y emprendedores hispanohablantes que quieren usar IA en sus negocios.

<rules>
- NO cubrir gossip o drama de la industria
- SÍ cubrir: nuevos modelos, herramientas, técnicas, casos de uso
- Cada artículo: 200-300 palabras
- Tono: directo, técnico pero accesible
- Incluir un "Por qué importa" en cada artículo
</rules>`

const ORACLE_TOOLS = [
  {
    name: 'web_search',
    description: 'Busca noticias en la web',
    input_schema: {
      type: 'object',
      properties: {
        query: { type: 'string', description: 'Query de búsqueda' },
      },
      required: ['query'],
    },
  },
  {
    name: 'save_article',
    description: 'Guarda un artículo en la DB',
    input_schema: {
      type: 'object',
      properties: {
        title: { type: 'string' },
        content: { type: 'string' },
        source_url: { type: 'string' },
        category: { type: 'string', enum: ['modelos', 'herramientas', 'tecnicas', 'negocio'] },
      },
      required: ['title', 'content', 'category'],
    },
  },
]

export async function runOracle() {
  const agent = new AgentRunner({
    name: 'ORACLE',
    systemPrompt: ORACLE_SYSTEM,
    tools: ORACLE_TOOLS,
    maxTokens: 8192,
  })

  return agent.run('Ejecuta tu rutina diaria: busca, filtra, y publica las noticias de hoy.')
}
03

Cron Jobs en Vercel

Vercel Cron Jobs disparan tus agentes en horarios. Free tier: 2 jobs. Pro: ilimitados.

vercel.json
{
  "crons": [
    {
      "path": "/api/cron/oracle",
      "schedule": "0 8 * * *"
    },
    {
      "path": "/api/cron/vera",
      "schedule": "0 9 * * 5"
    },
    {
      "path": "/api/cron/repo",
      "schedule": "0 10 * * *"
    },
    {
      "path": "/api/cron/signal",
      "schedule": "0 10 * * 1"
    }
  ]
}
app/api/cron/oracle/route.ts
import { NextRequest } from 'next/server'
import { runOracle } from '@/lib/agents/oracle'

export async function GET(req: NextRequest) {
  // Verificar auth
  const authHeader = req.headers.get('authorization')
  if (authHeader !== `Bearer ${process.env.CRON_SECRET}`) {
    return Response.json({ error: 'Unauthorized' }, { status: 401 })
  }

  try {
    const result = await runOracle()

    // Log para debugging
    console.log(`ORACLE completed: ${result.success ? 'SUCCESS' : 'FAILED'}`)
    console.log(`Tokens: ${result.tokensUsed}, Duration: ${result.duration}ms`)

    if (!result.success) {
      // Notificar error
      await fetch(process.env.SLACK_WEBHOOK!, {
        method: 'POST',
        body: JSON.stringify({
          text: `🔴 ORACLE failed: ${result.error}`,
        }),
      })
    }

    return Response.json(result)
  } catch (error) {
    return Response.json({
      success: false,
      error: error instanceof Error ? error.message : 'Unknown error',
    }, { status: 500 })
  }
}

⚠ Advertencia

CRON_SECRET es obligatorio. Vercel envía el header Authorization: Bearer CRON_SECRET. Sin validarlo, cualquiera puede disparar tus agentes.

Tip Pro

Pro tip: Usa un solo cron job que lea de una tabla agent_schedules en Supabase. Así puedes cambiar schedules sin redeploy.

"Un agente bien configurado genera más valor dormido que vos despierto. El primer agente que automatices te va a parecer magia. El séptimo va a ser tu nuevo normal."

— El Arsenal, Renderz Studio

Guías relacionadas

System Prompts de Producción

Los prompts que usan los agentes

Pipeline de Contenido

Automatizá la creación de contenido

¿Quieres el sistema completo?

500+ páginas, 25 capítulos, código de producción, acceso a todas las guías del Arsenal.

Curso Completo · €29

PayPal · Acceso inmediato

¿Hablamos?