Nodo Coordinador
Enrutamiento dinámico de agentes con puntuación estructurada y desempate opcional mediante LLM.
Nodo Coordinador
El Coordinador descubre agentes en tiempo de ejecución, los evalúa en múltiples dimensiones y enruta hacia el más adecuado. Cuando las puntuaciones están próximas, un desempate opcional mediante LLM toma la decisión final.
Tres Fases
1. Descubrimiento
Filtra el registro de agentes por habilidades requeridas y dominio de confianza. Los agentes que carecen de habilidades necesarias o están en el dominio de confianza incorrecto son rechazados con una razón.
graph.add_coordinator("route",
task="Enrutar ticket de soporte al mejor agente",
required_skills=["support", "billing"],
trust_domain="internal",
)2. Puntuación
Cada candidato es evaluado en cinco dimensiones:
| Dimensión | Qué mide | Peso predeterminado |
|---|---|---|
capability_fit | Cobertura de habilidades + coincidencia de modo de razonamiento | 1.0 |
cost_fit | Clase de costo del agente (bajo=1.0, medio=0.7, alto=0.4) | 1.0 |
latency_fit | Clase de latencia del agente (mismo mapeo) | 1.0 |
trust_compatibility | Coincidencia de dominio de confianza (1.0 si coincide, 0.5 en caso contrario) | 1.0 |
historical_performance | Tasa de éxito histórica (predeterminado 0.5) | 1.0 |
Una puntuación compuesta ponderada determina el ranking. Anula los pesos para priorizar lo que importa:
graph.add_coordinator("route",
task="Enrutar solicitud sensible a latencia",
required_skills=["inference"],
weights={"latency_fit": 3.0, "cost_fit": 0.5},
)3. Decisión
Si la ventaja del candidato principal es clara (diferencia > umbral), gana mediante puntuación estructurada. Si las puntuaciones están próximas, el desempate por LLM toma el control.
Desempate por LLM
Cuando la diferencia entre los candidatos principales está dentro del umbral, el coordinador invoca un LLM con el contexto de la tarea y resúmenes de Agent Card para hacer la selección final.
graph.add_coordinator("route",
task="Enrutar tarea de investigación compleja",
required_skills=["research"],
tiebreaker={"model": "claude-sonnet-4-6", "threshold": 0.1},
)Cómo funciona:
- Los principales candidatos (máx. 3) se formatean en un prompt estructurado
- El LLM devuelve JSON:
{"selected_uri": "...", "reasoning": "..."} - La decisión incluye
method="llm_tiebreaker"y uso de tokens para seguimiento de costos - Si falla la llamada al LLM, recurre a selección estructurada con
method="tiebreaker_failed"
El desempate usa clientes SDK asíncronos (AsyncAnthropic, AsyncOpenAI) — intenta primero con Anthropic, recurre a OpenAI.
Modos de Razonamiento
Las Agent Cards pueden declarar capacidades de razonamiento:
AgentCandidate(
uri="jamjet://org/planner",
agent_card={"name": "Planning Agent"},
skills=["task-decomposition"],
reasoning_modes=["plan-and-execute", "react"],
cost_class="medium",
latency_class="medium",
)Cuando el contexto del coordinador incluye preferred_reasoning_modes, los agentes coincidentes reciben un incremento en la puntuación de capacidad (hasta +0.2):
context = {"preferred_reasoning_modes": ["plan-and-execute"]}Si no se establece ninguna preferencia, los modos de razonamiento no afectan la puntuación.
Estrategias Personalizadas
La estrategia predeterminada maneja la mayoría de los casos, pero puedes implementar la tuya propia heredando de CoordinatorStrategy:
from jamjet.coordinator.strategy import CoordinatorStrategy, Decision
class MyStrategy(CoordinatorStrategy):
async def discover(self, task, required_skills, preferred_skills, trust_domain, context):
# Lógica de descubrimiento personalizada
...
async def score(self, task, candidates, weights, context):
# Lógica de puntuación personalizada
...
async def decide(self, task, top_candidates, threshold, tiebreaker_model, context):
# Lógica de decisión personalizada
...Regístrala con el servidor de estrategias:
from jamjet.coordinator.server import StrategyServer
server = StrategyServer()
server.register("my-strategy", MyStrategy())
server.run()Salida de Decisión
El coordinador devuelve una Decision con total transparencia:
Decision(
selected_uri="jamjet://org/agent-a",
method="llm_tiebreaker", # o "structured", "tiebreaker_failed"
reasoning="Mejor coincidencia para tareas de descomposición de investigación",
confidence=0.82,
rejected=[{"uri": "jamjet://org/agent-b", "reason": "not selected by tiebreaker"}],
tiebreaker_tokens={"input": 150, "output": 30},
)Cada decisión de enrutamiento se registra en el log de eventos para observabilidad y reproducción.
Ejemplo
Consulta el ejemplo coordinator-routing para una configuración completa funcional con múltiples agentes y puntuación.