Introducción a los Sistemas Multiagente
En los ecosistemas actuales de Inteligencia Artificial, depender de un único agente para resolver problemas complejos suele resultar insuficiente. Un escenario habitual requiere que un sistema no solo genere contenido creativo, sino que también lo evalúe bajo criterios comerciales y lo refine. Los sistemas multiagente (Multi-Agent Systems) resuelven esta limitación mediante la división del trabajo.
Semantic Kernel ofrece una infraestructura robusta para orquestar estos flujos, permitiendo a los desarrolladores diseñar redes de agentes que colaboran, debaten y se enrutan de manera autónoma para cumplir objetivos específicos.
Mecanismos Fundamentales del Enrutamiento
La arquitectura subyacente en Semantic Kernel opera mediante un modelo de máquina de estados que gestiona el ciclo de vida de la conversación:
- Evaluación de entrada: Verifica si el sistema necesita solicitar más contexto al usuario.
- Control de finalización: Determina si se han alcanzado los criterios de éxito para detener el ciclo.
- Selección de turno: Decide qué agente es el más adecuado para intervenir a continuación.
- Filtrado de salida: Procesa el historial completo para devolver únicamente el resultado final consolidado.
Caso Práctico: Equipo de Copywriting Publicitario
Para demostrar esta arquitectura, implementaremos un entorno con dos roles especializados: un redactor enfocado en la creatividad y un editor encargado de aprobar la calidad del texto.
Configuración de los Agentes y el Orquestador
using Microsoft.SemanticKernel;
using Microsoft.SemanticKernel.Agents;
using Microsoft.SemanticKernel.Agents.Orchestration;
using Microsoft.SemanticKernel.Agents.Orchestration.GroupChat;
using Microsoft.SemanticKernel.Agents.Runtime.InProcess;
using Microsoft.SemanticKernel.ChatCompletion;
// Inicialización del agente generador
var creativeWriter = new ChatCompletionAgent(
name: "RedactorCreativo",
description: "Experto en redacción publicitaria con un tono persuasivo",
instructions: """
Actúas como un redactor con amplia trayectoria. Tu estilo es impactante y conciso.
Tu objetivo es formular la mejor propuesta de eslogan.
Entrega únicamente una opción por respuesta.
Concéntrate exclusivamente en la meta asignada y evita las trivialidades.
Incorpora las críticas para pulir tus ideas.
""");
// Inicialización del agente evaluador
var qualityEditor = new ChatCompletionAgent(
name: "EditorDeCalidad",
description: "Director creativo enfocado en la viabilidad comercial",
instructions: """
Eres el director creativo. Evalúa si el eslogan propuesto es apto para su lanzamiento.
Si cumple con los estándares, responde exactamente: "Aprobado".
En caso contrario, ofrece retroalimentación constructiva sobre cómo mejorarlo, sin redactar ejemplos directos.
""");
// Lógica de control para el flujo de trabajo
public class CampaignDirector : RoundRobinGroupChatManager
{
private readonly string _writerId;
private readonly string _editorId;
public CampaignDirector(string writerId, string editorId)
{
_writerId = writerId;
_editorId = editorId;
}
// Extracción del resultado final tras la validación
public override ValueTask<groupchatmanagerresult>> FilterResults(
ChatHistory history, CancellationToken cancellationToken = default)
{
var approvedCopy = history.Last(msg => msg.AuthorName == _writerId);
return ValueTask.FromResult(
new GroupChatManagerResult<string>($"{approvedCopy}")
{
Reason = "Eslogan validado por el director"
});
}
// Criterio de parada basado en la aprobación del editor
public override async ValueTask<groupchatmanagerresult>> ShouldTerminate(
ChatHistory history, CancellationToken cancellationToken = default)
{
var defaultCheck = await base.ShouldTerminate(history, cancellationToken);
if (!defaultCheck.Value)
{
var latestMsg = history.LastOrDefault();
if (latestMsg != null &&
latestMsg.AuthorName == _editorId &&
$"{latestMsg}".Contains("Aprobado", StringComparison.OrdinalIgnoreCase))
{
return new GroupChatManagerResult<bool>(true)
{
Reason = "Validación completada con éxito"
};
}
}
return defaultCheck;
}
}
</bool></groupchatmanagerresult></string></groupchatmanagerresult>
Ejecución del Flujo Colaborativo
// Configuración del motor de orquestación
var groupChat = new GroupChatOrchestration(
new CampaignDirector(creativeWriter.Name!, qualityEditor.Name!)
{
MaximumInvocationCount = 8 // Límite preventivo de interacciones
},
creativeWriter,
qualityEditor);
// Despliegue del entorno local
var executionRuntime = new InProcessRuntime();
await executionRuntime.StartAsync();
// Disparo del proceso multiagente
string initialPrompt = "Diseña un eslogan para un vehículo eléctrico urbano que destaque por su bajo costo y agilidad";
var executionResult = await groupChat.InvokeAsync(initialPrompt, executionRuntime);
// Recuperación del producto final
string finalSlogan = await executionResult.GetValueAsync(TimeSpan.FromSeconds(45));
Console.WriteLine($"Eslogan definitivo: {finalSlogan}");
Comparativa de Estrategias de Enrutamiento
| Estrategia de Enrutamiento | Escenario Ideal | Ventajas | Desventajas |
|---|---|---|---|
| Circular (Round-Robin) | Tareas secuenciales simples | Fácil de implementar, equitativo | Carece de adaptabilidad contextual |
| Basado en Contenido | Clasificación de consultas | Dirige la petición al especialista adecuado | Requiere análisis previo del texto |
| Basado en Estado | Flujos de trabajo estrictos | Control total del proceso de negocio | Alta complejidad en el manejo de estados |
| Impulsado por IA | Toma de decisiones dinámica | Flexibilidad y comprensión del contexto | Mayor consumo de tokens y latencia |
Personalización Avanzada del Enrutamiento
Delegación Dinámica mediante LLM
En lugar de reglas fijas, es posible utilizar un modelo de lenguaje para analizar la conversación y seleccionar al próximo participante.
public class DynamicRoutingManager : GroupChatManager
{
private readonly IChatCompletionService _llmService;
public DynamicRoutingManager(IChatCompletionService llmService)
{
_llmService = llmService;
}
public override async ValueTask<groupchatmanagerresult>> SelectNextAgent(
ChatHistory history, GroupChatTeam team, CancellationToken cancellationToken = default)
{
var routingPrompt = $"""
Analiza el historial de la conversación y las capacidades del equipo para determinar quién debe intervenir a continuación:
Historial:
{string.Join("\n", history.Select(m => $"{m.AuthorName}: {m.Content}"))}
Equipo disponible:
{string.Join("\n", team.Select(a => $"{a.Key}: {a.Value.Description}"))}
Responde únicamente con el nombre exacto del agente seleccionado.
""";
var decision = await _llmService.GetChatMessageContentAsync(
routingPrompt, new ChatHistory(), cancellationToken: cancellationToken);
return new GroupChatManagerResult<string>(decision.Content)
{
Reason = "Selección dinámica mediante modelo de lenguaje"
};
}
}
</string></groupchatmanagerresult>
Criterios Complejos de Terminación
Un sistema robusto debe contemplar múltiples condiciones para evitar bloqueos o bucles infinitos.
public override async ValueTask<groupchatmanagerresult>> ShouldTerminate(
ChatHistory history, CancellationToken cancellationToken = default)
{
// Evaluación por límite estricto de turnos
if (this.InvocationCount >= this.MaximumInvocationCount)
{
return new GroupChatManagerResult<bool>(true)
{
Reason = "Límite máximo de turnos alcanzado"
};
}
// Verificación de acuerdo mutuo entre participantes
if (CheckConsensus(history))
{
return new GroupChatManagerResult<bool>(true)
{
Reason = "Consenso logrado entre los agentes"
};
}
// Prevención de ciclos repetitivos
if (DetectLoop(history))
{
return new GroupChatManagerResult<bool>(true)
{
Reason = "Bucle de repetición detectado"
};
}
return new GroupChatManagerResult<bool>(false)
{
Reason = "Proceso en curso"
};
}
</bool></bool></bool></bool></groupchatmanagerresult>
Optimización de Recursos y Telemetría
| Estrategia | Implementación | Impacto |
|---|---|---|
| Truncamiento de contexto | Conservar exclusivamente las últimas N interacciones | Optimiza la memoria sin perder el hilo conductor |
| Caché de decisiones | Almacenar rutas de enrutamiento recurrentes | Acelera drásticamente el tiempo de respuesta |
| Gestión de conexiones | Reutilizar instancias de clientes hacia los proveedores LLM | Minimiza la sobrecarga de red y latencia |
Registro de Eventos en Tiempo Real
// Trazabilidad de mensajes estándar
groupChat.ResponseCallback = (message) =>
{
Console.WriteLine($"[Traza] {message.AuthorName}: {message.Content}");
};
// Captura de respuestas transmitidas en streaming
groupChat.StreamingResponseCallback = async (stream) =>
{
await foreach (var token in stream)
{
Console.Write(token);
}
};
Casos de Uso en Producción
Automatización de Atención al Cliente
Un agente de triaje clasifica la consulta inicial, un agente técnico busca documentación en una base de conocimientos vectorial, y un agente de empatía reformula la respuesta para asegurar un tono adecuado antes de envirala al usuario.
Pipeline de Creación de Contenido Editorial
- Generador de ideas: Propone estructuras y ángulos narrativos.
- Desarrollador de texto: Expande los conceptos en párrafos completos.
- Editor de estilo: Ajusta el vocabulario al manual de marca.
- Auditor de cumplimiento: Revisa la ausencia de sesgos o información incorrecta.
- Formateador: Convierte el texto final a Markdown o HTML para publicación.
Resolución de Desafíos Comunes
1. Cuellos de botella en la colaboración
Solución: Definir límites estrictos de responsabilidad para cada agente, configurar tiempos de espera agresivos y almacenar en caché las inferencias intermedias para evitar reprocesamientos.
2. Errores en la asignación de tareas
Solución: Enriquecer el prompt de enrutamiento con metadatos contextuales, implementar bucles de retroalimentación donde los agentes puedan rechazar tareas mal asignadas, y mantener un canal de intervención humana (Human-in-the-loop) para casos ambiguos.
3. Limitaciones de escalabilidad
Solución: Transicionar de un entorno en memoria a una arquitectura de microservicios, habilitar el descubrimiento dinámico de agentes mediante un registro centralizado y utilizar brokers de mensajes como RabbitMQ o Kafka para la comunicación asíncrona.