Enrutado
Clasifica cada entrada y envíala al flujo especializado que le toca, con su propio prompt, herramientas y modelo, para no optimizar todo con un único prompt.
- Coste
- 1 de 3
- Latencia
- 2 de 3
- Cuándo usarlo
- Cuando las entradas caen en categorías claras que se atienden mejor por separado y la clasificación es fiable.
- Cuándo no
- Si las categorías se solapan mucho o un único prompt ya trata bien todos los casos.
El enrutado añade un paso de clasificación delante de todo lo demás: una llamada decide de qué tipo es la entrada y tu código la manda al flujo preparado para ese tipo. Así cada flujo tiene un prompt corto y específico, y mejorar uno no estropea los otros. Es el segundo workflow de Building effective agents (Anthropic, 2024).
Qué es
Sin enrutado, un único prompt intenta atender devoluciones, dudas técnicas y quejas a la vez. Cada regla que añades para un caso puede empeorar otro. Con enrutado, separas responsabilidades: el clasificador solo clasifica y cada ruta solo resuelve su tipo de caso.
flowchart LR E[Entrada] --> C[LLM clasificador] C -- devolucion --> A[Flujo devoluciones] C -- tecnica --> B[Flujo técnico] C -- general --> D[Flujo general] C -- dudosa --> H[Humano]
La clasificación puede hacerla un LLM o un modelo clásico entrenado con tus datos. El artículo admite las dos opciones. El LLM gana cuando no tienes datos etiquetados o las categorías cambian a menudo.
Cuándo usarlo
- Hay categorías distintas que se tratan mejor por separado, y puedes clasificar con precisión.
- Quieres mandar lo fácil a un modelo pequeño y rápido y lo difícil a uno más capaz. El artículo lo cita como uso típico para ajustar coste y velocidad; tienes el método en Elegir modelo por tarea.
- Cada categoría necesita herramientas o permisos diferentes. El flujo de facturación puede consultar pagos; el general, no. Es una forma sencilla de aplicar mínimo privilegio.
Cuándo no
- Las categorías no están claras ni para un humano. Si dos personas etiquetarían distinto el mismo caso, el clasificador también dudará.
- Solo hay una o dos variantes que un prompt bien escrito resuelve con un ejemplo de cada una.
- El coste de un error de ruta es alto y no tienes salida para los casos dudosos. Añade siempre una categoría “dudosa” que vaya a un humano o a un flujo general seguro.
Ejemplo concreto
Una tienda online recibe correos de clientes. El clasificador devuelve devolucion, incidencia_tecnica, consulta_general o dudosa, más una frase de motivo. Las devoluciones pasan a un flujo con acceso a pedidos y a la política de devoluciones. Las incidencias técnicas, a otro con la base de conocimiento del producto. Las consultas generales las responde un modelo rápido. Las dudosas van a la cola de un agente humano. La receta paso a paso está en Clasificar y enrutar tickets de soporte.
Esqueleto de código
El clasificador usa salida estructurada con un enum, así la ruta siempre es uno de los valores válidos.
import json
import anthropic
MODEL = "claude-sonnet-5-5"
client = anthropic.Anthropic()
RUTAS = ["devolucion", "incidencia_tecnica", "consulta_general", "dudosa"]
ESQUEMA = {
"type": "object",
"properties": {
"ruta": {"type": "string", "enum": RUTAS},
"motivo": {"type": "string"},
},
"required": ["ruta", "motivo"],
"additionalProperties": False,
}
def clasificar(mensaje: str) -> dict:
resp = client.messages.create(
model=MODEL, max_tokens=256,
system=("Clasifica el mensaje del cliente. Usa 'dudosa' si encaja en más de una ruta "
"o en ninguna. Ejemplos:\n- 'Quiero devolver las zapatillas' → devolucion\n"
"- 'La app se cierra al pagar' → incidencia_tecnica"),
messages=[{"role": "user", "content": f"<mensaje>\n{mensaje}\n</mensaje>"}],
output_config={"format": {"type": "json_schema", "schema": ESQUEMA}},
)
texto = next(b.text for b in resp.content if b.type == "text")
return json.loads(texto)
def atender(mensaje: str) -> str:
decision = clasificar(mensaje)
manejadores = {
"devolucion": flujo_devoluciones, # con herramientas de pedidos
"incidencia_tecnica": flujo_tecnico, # con la base de conocimiento
"consulta_general": flujo_general, # candidato a un modelo más rápido
"dudosa": enviar_a_humano,
}
registrar(mensaje, decision) # para medir la precisión del router
return manejadores[decision["ruta"]](mensaje)Cada flujo_* puede ser una llamada aumentada, un encadenado o incluso un agente. El router no necesita saberlo.
Coste y latencia
El clasificador es una llamada corta con poca salida, así que su coste es bajo. A cambio añade una espera en serie antes de cada respuesta. Hay dos formas de compensarla: usar un modelo rápido para clasificar y aprovechar que las rutas sencillas pueden ir a modelos más baratos. Si el prompt del clasificador lleva muchos ejemplos, cachéalo con prompt caching.
Patrones relacionados
- Encadenado de prompts: cada ruta suele ser una cadena de pasos.
- Paralelización: varios clasificadores que votan cuando la ruta es delicada.
- Orquestador y trabajadores: cuando la entrada no se clasifica sino que se descompone en varias subtareas.
- Agente de soporte con aprobación humana: un sistema de soporte que combina enrutado y agente.