Inicio / Inteligencia Artificial / AI-First Full Stack: Construye Apps con IA / Agentes de IA en Producción

Agentes de IA en Producción

Patrón ReAct, loops de agentes, memoria, planificación, orquestación multi-agente y LangGraph.

Intermedio Funciones
🔒 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 en Producción

Un agente de IA es un sistema que usa un LLM para razonar, planificar y ejecutar acciones de forma autónoma hasta completar una tarea. A diferencia del function calling simple, los agentes mantienen un loop de razonamiento-acción que puede durar múltiples pasos.


Patrón ReAct: Reason + Act

Pregunta del usuario
        │
        ▼
┌─ LOOP ──────────────────────┐
│                              │
│  1. REASON (pensar)          │
│     ¿Qué necesito hacer?     │
│                              │
│  2. ACT (actuar)             │
│     Ejecutar una herramienta │
│                              │
│  3. OBSERVE (observar)       │
│     Analizar el resultado    │
│                              │
│  4. ¿Tengo la respuesta?     │
│     SÍ → Responder           │
│     NO → Volver a 1          │
│                              │
└──────────────────────────────┘

Implementación del loop ReAct

interface AgentMessage {
  role: 'system' | 'user' | 'assistant' | 'tool';
  content: string;
  tool_call_id?: string;
}

class Agent {
  private tools: Tool[];
  private maxIterations: number;

  constructor(tools: Tool[], maxIterations = 10) {
    this.tools = tools;
    this.maxIterations = maxIterations;
  }

  async run(task: string): Promise<string> {
    const messages: AgentMessage[] = [
      { role: 'system', content: this.buildSystemPrompt() },
      { role: 'user', content: task },
    ];

    for (let i = 0; i < this.maxIterations; i++) {
      console.log(`\n--- Iteración ${i + 1} ---`);

      const response = await openai.chat.completions.create({
        model: 'gpt-4o',
        messages,
        tools: this.tools.map(t => t.definition),
        tool_choice: 'auto',
      });

      const choice = response.choices[0];

      // Si el agente decide responder directamente
      if (choice.finish_reason === 'stop') {
        console.log('✅ Agente completó la tarea');
        return choice.message.content!;
      }

      // Ejecutar herramientas
      if (choice.message.tool_calls) {
        messages.push(choice.message);

        for (const call of choice.message.tool_calls) {
          const tool = this.tools.find(t => t.name === call.function.name);
          if (!tool) {
            messages.push({
              role: 'tool',
              tool_call_id: call.id,
              content: `Error: tool "${call.function.name}" not found`,
            });
            continue;
          }

          console.log(`🔧 ${call.function.name}(${call.function.arguments})`);

          try {
            const result = await tool.execute(JSON.parse(call.function.arguments));
            console.log(`   → ${JSON.stringify(result).slice(0, 200)}`);
            messages.push({
              role: 'tool',
              tool_call_id: call.id,
              content: JSON.stringify(result),
            });
          } catch (error) {
            messages.push({
              role: 'tool',
              tool_call_id: call.id,
              content: `Error: ${(error as Error).message}`,
            });
          }
        }
      }
    }

    return 'El agente alcanzó el límite de iteraciones sin completar la tarea.';
  }

  private buildSystemPrompt(): string {
    return `Eres un agente de IA capaz de completar tareas complejas.

INSTRUCCIONES:
- Analiza la tarea paso a paso
- Usa las herramientas disponibles para obtener información y ejecutar acciones
- Si una herramienta falla, intenta otra estrategia
- Cuando tengas toda la información necesaria, genera tu respuesta final
- Sé preciso y verifica tus resultados`;
  }
}

Memoria del Agente

Memoria a corto plazo (conversación)

class AgentMemory {
  private shortTerm: Message[] = [];
  private summaries: string[] = [];
  private maxMessages = 20;

  add(message: Message) {
    this.shortTerm.push(message);

    // Cuando hay demasiados mensajes, resumir los antiguos
    if (this.shortTerm.length > this.maxMessages) {
      this.summarizeOldMessages();
    }
  }

  private async summarizeOldMessages() {
    const oldMessages = this.shortTerm.splice(0, 10);
    const summary = await openai.chat.completions.create({
      model: 'gpt-4o-mini',
      messages: [
        {
          role: 'system',
          content: 'Resumen conciso de esta conversación en 3-5 puntos clave:',
        },
        ...oldMessages,
      ],
      max_tokens: 200,
    });

    this.summaries.push(summary.choices[0].message.content!);
  }

  getContext(): string {
    let context = '';
    if (this.summaries.length > 0) {
      context += `RESUMEN PREVIO:\n${this.summaries.join('\n')}\n\n`;
    }
    return context;
  }
}

Memoria a largo plazo (vector store)

class LongTermMemory {
  async store(content: string, metadata: Record<string, any>) {
    const embedding = await getEmbedding(content);
    await vectorDB.insert({
      content,
      embedding,
      metadata: { ...metadata, timestamp: Date.now() },
    });
  }

  async recall(query: string, limit = 5): Promise<string[]> {
    const results = await vectorDB.search(
      await getEmbedding(query),
      limit
    );
    return results.map(r => r.content);
  }
}

Agente con herramientas prácticas

// Herramientas para un "Research Agent"
const researchTools: Tool[] = [
  {
    name: 'web_search',
    definition: {
      type: 'function',
      function: {
        name: 'web_search',
        description: 'Busca información en internet',
        parameters: {
          type: 'object',
          properties: {
            query: { type: 'string', description: 'Término de búsqueda' },
          },
          required: ['query'],
        },
      },
    },
    execute: async ({ query }) => {
      const results = await searchAPI.search(query);
      return results.slice(0, 5).map(r => ({
        title: r.title,
        snippet: r.snippet,
        url: r.url,
      }));
    },
  },
  {
    name: 'read_webpage',
    definition: {
      type: 'function',
      function: {
        name: 'read_webpage',
        description: 'Lee el contenido de una página web',
        parameters: {
          type: 'object',
          properties: {
            url: { type: 'string', description: 'URL de la página' },
          },
          required: ['url'],
        },
      },
    },
    execute: async ({ url }) => {
      const response = await fetch(url);
      const html = await response.text();
      return extractText(html).slice(0, 3000);
    },
  },
  {
    name: 'save_note',
    definition: {
      type: 'function',
      function: {
        name: 'save_note',
        description: 'Guarda una nota con información relevante',
        parameters: {
          type: 'object',
          properties: {
            title: { type: 'string' },
            content: { type: 'string' },
          },
          required: ['title', 'content'],
        },
      },
    },
    execute: async ({ title, content }) => {
      await prisma.note.create({ data: { title, content } });
      return { saved: true };
    },
  },
];

// Uso
const researcher = new Agent(researchTools, 15);
const result = await researcher.run(
  'Investiga las últimas novedades de React 19 y crea un resumen con las 5 features más importantes'
);

Orquestación multi-agente

class MultiAgentOrchestrator {
  private agents: Map<string, Agent>;

  constructor() {
    this.agents = new Map([
      ['researcher', new Agent(researchTools)],
      ['coder', new Agent(codeTools)],
      ['reviewer', new Agent(reviewTools)],
    ]);
  }

  async execute(task: string): Promise<string> {
    // Paso 1: Router decide qué agente usar
    const routerResponse = await openai.chat.completions.create({
      model: 'gpt-4o-mini',
      response_format: { type: 'json_object' },
      messages: [{
        role: 'user',
        content: `Dado esta tarea: "${task}"

Decide qué agentes necesitan ejecutarse y en qué orden.
Agentes disponibles: researcher, coder, reviewer.

Responde JSON: { "pipeline": ["agent1", "agent2"], "subtasks": ["subtask1", "subtask2"] }`,
      }],
    });

    const plan = JSON.parse(routerResponse.choices[0].message.content!);
    let context = '';

    // Paso 2: Ejecutar pipeline
    for (let i = 0; i < plan.pipeline.length; i++) {
      const agentName = plan.pipeline[i];
      const subtask = plan.subtasks[i];
      const agent = this.agents.get(agentName)!;

      console.log(`\n🤖 Agente: ${agentName} — Tarea: ${subtask}`);

      const result = await agent.run(
        `${subtask}\n\nContexto previo:\n${context}`
      );

      context += `\n\nResultado de ${agentName}:\n${result}`;
    }

    return context;
  }
}

Guardrails para agentes

class SafeAgent extends Agent {
  private budget: { maxTokens: number; maxCalls: number; maxTime: number };
  private usage = { tokens: 0, calls: 0, startTime: 0 };

  constructor(tools: Tool[], budget = {
    maxTokens: 50_000,
    maxCalls: 20,
    maxTime: 60_000, // 1 minuto
  }) {
    super(tools);
    this.budget = budget;
  }

  async run(task: string): Promise<string> {
    this.usage.startTime = Date.now();

    // Override del loop con checks de budget
    // ...

    return super.run(task);
  }

  private checkBudget(): void {
    if (this.usage.tokens > this.budget.maxTokens) {
      throw new Error(`Token budget exceeded: ${this.usage.tokens}/${this.budget.maxTokens}`);
    }
    if (this.usage.calls > this.budget.maxCalls) {
      throw new Error(`Call budget exceeded: ${this.usage.calls}/${this.budget.maxCalls}`);
    }
    if (Date.now() - this.usage.startTime > this.budget.maxTime) {
      throw new Error(`Time budget exceeded`);
    }
  }
}

Patterns y anti-patterns

Pattern Descripción
ReAct Reason → Act → Observe en loop
Plan and Execute Planificar todos los pasos primero, luego ejecutar
Reflexion El agente evalúa sus propias respuestas y mejora
Human-in-the-loop Pedir confirmación en acciones destructivas
Anti-pattern Problema
Sin límite de iteraciones El agente puede loopear infinitamente
Sin manejo de errores Un fallo en una tool rompe todo
Demasiadas tools El LLM se confunde; máximo 10-15
Sin observabilidad No puedes debuggear qué hizo el agente
🔒

Ejercicio práctico disponible

Loop de agente ReAct

Desbloquear ejercicios
// Loop de agente ReAct
// Desbloquea Pro para acceder a este ejercicio
// y ganar +50 XP al completarlo

function ejemplo() {
    // Tu código aquí...
}

¿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