---
title: "Construir sistemas multi-agente con LLMs"
description: "Una guía práctica para elegir un patrón de orquestación, definir contratos de agentes y mantener la observabilidad de los sistemas multi-agente cuando fallan las tareas."
date: "2026-02-07T00:00:00.000Z"
author: "Carlos Garavito"
tags: ["ai", "agents", "llm", "architecture"]
canonical_url: "https://cgaravito.dev/es/blog/building-multi-agent-systems"
last_updated: "2026-02-07T00:00:00.000Z"
locale: "es"
---

Un sistema multi-agente añade coordinación, estado y más modos de fallo. Lo uso cuando el trabajo tiene límites más claros que los que puede definir el prompt de un solo agente, por ejemplo, planificación, implementación, revisión y pruebas en un flujo de trabajo de software.

Cada agente necesita un system prompt específico, un conjunto limitado de herramientas y un contrato explícito de entrada y salida. La arquitectura depende de cómo se mueve el trabajo entre esos agentes.

## Usa un orquestador cuando el recorrido pueda cambiar

Un orquestador se encarga del plan, selecciona un agente especializado para cada paso y mantiene el contexto compartido. Este enfoque encaja con tareas en las que un resultado puede cambiar lo que debe ocurrir después.

Este esquema simplificado deja fuera del ejemplo la conexión de `planAgent` y `context` compartido.

```typescript
interface Agent {
  name: string;
  systemPrompt: string;
  tools: Tool[];
  execute(input: string): Promise<AgentResult>;
}

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

  async run(task: string): Promise<string> {
    const plan = await this.planAgent.execute(task);

    for (const step of plan.steps) {
      const agent = this.agents.get(step.agentName);
      const result = await agent.execute(step.input);
      this.context.addResult(step.id, result);
    }

    return this.synthesize();
  }
}
```

El coordinador también es el lugar donde registrar qué agente se ejecutó, qué entrada recibió y qué resultado se incorporó al contexto compartido. Sin ese registro, es difícil diagnosticar una respuesta final incorrecta.

## Usa un pipeline cuando el orden sea fijo

Un pipeline es más sencillo cuando cada tarea sigue la misma secuencia y cada salida se convierte en la siguiente entrada.

```typescript
const pipeline = createPipeline([
  researchAgent,
  analysisAgent,
  writingAgent,
  reviewAgent,
]);

const result = await pipeline.execute(initialInput);
```

El principal modo de fallo es la propagación. Un resultado de investigación deficiente llega al análisis, la redacción y la revisión, a menos que alguna etapa valide su entrada. Prefiero un esquema concreto y una comprobación de aceptación en cada límite a un prompt más extenso que pida al siguiente agente recuperar lo que reciba.

## Usa un debate para desacuerdos acotados

El patrón de debate proporciona el mismo tema a varios agentes y transporta sus respuestas durante un número fijo de rondas.

```typescript
async function debate(
  topic: string,
  agents: Agent[],
  rounds: number,
): Promise<string> {
  let context = topic;

  for (let i = 0; i < rounds; i++) {
    for (const agent of agents) {
      const response = await agent.execute(context);
      context += `\n\n${agent.name}: ${response}`;
    }
  }

  return synthesizeDebate(context);
}
```

Puede ser útil cuando las distintas perspectivas forman parte de la tarea, pero cada ronda añade tokens y contexto repetido. Un número fijo de rondas y una regla de síntesis definida evitan que la discusión se convierta en un bucle costoso.

## Haz que los mensajes se puedan inspeccionar

Los agentes siguen necesitando un protocolo compartido aunque la orquestación sea sencilla. Un bus de mensajes puede hacer explícitos el emisor, el destinatario, el tipo de mensaje y los metadatos.

```typescript
interface AgentMessage {
  from: string;
  to: string;
  type: "request" | "response" | "broadcast";
  content: string;
  metadata: Record<string, unknown>;
}

class MessageBus {
  private subscribers = new Map<string, (msg: AgentMessage) => void>();

  send(message: AgentMessage): void {
    const handler = this.subscribers.get(message.to);
    handler?.(message);
  }

  subscribe(agentId: string, handler: (msg: AgentMessage) => void): void {
    this.subscribers.set(agentId, handler);
  }
}
```

El contrato de mensajes proporciona una unidad estable para el registro y los reintentos. Quiero que cada interacción se pueda rastrear, que los fallos sean visibles y que los reintentos o fallbacks ocurran en un límite conocido.

Empieza con dos agentes y un patrón de coordinación. Añade otro agente cuando se encargue de una tarea, unas herramientas y un resultado distintos que puedas evaluar. El sistema útil es el más pequeño cuyos traspasos sigan siendo claros cuando un agente devuelve una respuesta incorrecta o no devuelve ninguna.
