JamJet

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ónQué midePeso predeterminado
capability_fitCobertura de habilidades + coincidencia de modo de razonamiento1.0
cost_fitClase de costo del agente (bajo=1.0, medio=0.7, alto=0.4)1.0
latency_fitClase de latencia del agente (mismo mapeo)1.0
trust_compatibilityCoincidencia de dominio de confianza (1.0 si coincide, 0.5 en caso contrario)1.0
historical_performanceTasa 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:

  1. Los principales candidatos (máx. 3) se formatean en un prompt estructurado
  2. El LLM devuelve JSON: {"selected_uri": "...", "reasoning": "..."}
  3. La decisión incluye method="llm_tiebreaker" y uso de tokens para seguimiento de costos
  4. 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.

On this page