Cómo montar un router de modelos por tier con presupuesto duro y proveedor intercambiable

Deja de pegar el ID del modelo en cada agente. Un chokepoint de config, coste por trabajo terminado y un cap que aborta o degrada según toque.

16 min de lectura

En este artículo

Llevas el modelo clavado en el código y eso te va a costar una pasta

La mayoría de stacks con IA tienen el mismo agujero: el ID del modelo está escrito a fuego en tres agentes, dos workers y un script que nadie toca desde marzo. Cambiar de proveedor es un despliegue con miedo. Cambiar de tier “porque este es más barato” es una apuesta a ciegas sobre una tabla de precios.

Eso no es arquitectura. Es un chiringuito con API key.

Un router de modelos por tier hace tres cosas y solo tres: decide qué dificultad merece cada trabajo, resuelve qué modelo y proveedor hay detrás de ese tier leyendo configuración (no código), y aplica presupuesto con dos salidas posibles, cortar en seco o degradar al barato, sin dejar la tarea colgada ni convertir un default del proveedor en una factura sorpresa.

No es magia. Es un chokepoint, una métrica honesta y un contrato claro sobre qué pasa cuando el dinero se acaba.

Qué es un router por tier (y qué no es)

Un router por tier es una capa delgada entre tu lógica de negocio y la llamada al modelo. Tú no le pides “Claude tal” ni “GPT cual”. Le pides un tier, barato, estándar, fuerte, según lo jodido que sea el trabajo. El router traduce tier → proveedor + modelo + parámetros permitidos, cuenta el coste acumulado y, si toca techo, ejecuta la política que hayas definido.

Lo que no es:

  • Un balanceador de carga fancy con dashboards de colores.
  • Un “orquestador multi-agente” con nombre de startup.
  • Un sitio donde metes if provider == ... en cada cliente.

La regla de oro del patrón: nada que deba cambiar un administrador del negocio puede vivir hardcodeado en un agente. IDs de modelo, endpoints, claves de tier, techos de €, de tokens, de turnos o de wallclock: todo eso sale de configuración. Si revertir una migración de modelo no es cambiar una línea (o un valor) en config, la migración no está hecha.

Eso también es la cura real del vendor lock-in de proveedor de IA: no “soportar N APIs a mano”, sino que el negocio pueda cambiar de caballo sin reescribir la cuadra.

La promesa cuando lo montas bien

Cuando el router está en su sitio, pasa esto:

  • Un admin cambia el modelo del tier standard y toda la flota lo usa en el siguiente job. Sin PR de pánico en seis repos.
  • Comparas modelos por € por unidad de trabajo terminado (artículo, conversación, documento extraído), no por el postureo del precio por millón de tokens.
  • En evaluación, pasarte de presupuesto aborta y eso cuenta como resultado del modelo, no como error del harness.
  • En producto, pasarte de presupuesto degrada a un modelo más barato y la tarea termina. El usuario no se come un 500 por tu techo interno.
  • Un preflight te dice antes de lanzar una tanda si la proyección de coste se sale del tope total. Si se sale, no arrancas.

Si no tienes esas cinco cosas, tienes llamadas a un LLM con fe.

Pieza 1, Tiers por dificultad, no por marca

El routing se decide por dificultad del trabajo, no por el logo del proveedor. Esa es la decisión de diseño que aguanta el tiempo.

Ejemplo de mapa mental (los nombres son tuyos; lo sagrado es la idea):

Tier Para qué lo usas Mentalidad
cheap Clasificar, etiquetar, borradores basura, triaje Que sea barato y suficiente
standard El grueso del producto: respuestas, extracciones, edición Mejor relación calidad/€ en tu corpus
strong Casos límite, adjudicación, tareas donde fallar sale caro Medir el techo de calidad

El criterio de despliegue es brutal y simple: mides el techo con el mejor; en producción dejas el más barato que aguante.

Eso implica una tanda real, no un benchmark de cartón. Antes de migrar un tier:

  1. Coges N unidades reales del mismo corpus (mismas conversaciones, mismos documentos, mismo encargo).
  2. Las corres con el modelo actual y con el candidato.
  3. Comparas coste total, tokens consumidos y tasa de reintentos (los reintentos son coste disfrazado).
  4. Solo entonces miras la tabla de precios del proveedor. Sin esa tanda, la migración es fe con Excel.

Un detalle que tumba migraciones “baratas”: los defaults del proveedor nuevo. Razonamiento adaptativo, verbosidad alta, longitud de salida generosa. Un default activado convierte un modelo barato en uno caro sin que el precio por token se mueva un céntimo. Menos tokens no es lo mismo que menos factura; el router tiene que dejar esos knobs explícitos en config o apagarlos a propósito, no heredarlos por despiste.

Pieza 2, Proveedor intercambiable por configuración

Todo ID de modelo vive en un solo chokepoint. Un archivo, un almacén de config, un secreto versionado: da igual el soporte, importa que sea uno.

La forma mental del mapa (ilustrativa, no dogma de framework):

tiers:
  cheap:
    provider: provider_a
    model: modelo-pequeno-x
    max_output_tokens: 512
  standard:
    provider: provider_b
    model: modelo-medio-y
    max_output_tokens: 2048
  strong:
    provider: provider_b
    model: modelo-grande-z
    max_output_tokens: 4096

budget:
  max_cost_eur: 0.15
  max_tokens: 50000
  max_turns: 20
  max_wallclock_seconds: 120

fallback:
  on_budget: cheap
  on_provider_error: cheap

Lo que el código del agente ve:

result = router.complete(tier="standard", messages=... work_id="doc-441")

Lo que el agente no ve: el nombre del modelo, la URL del proveedor, ni el if de turno.

Parámetros no portables: fuera del cliente común

temperature y compañía no se “condicionan” con un if provider. Se retiran del cliente común o se traducen en el adaptador del proveedor. Si un knob no existe igual en todos lados, no contamina la interfaz que usan los agentes. El router expone lo portable; el adaptador limpia el resto.

Criterio de “migración hecha”

Una migración de modelo está cerrada cuando la reversión también es una línea de config. Si para volver atrás hay que cazar strings en el repo, no migraste: esparciste deuda.

Pieza 3, La métrica: € por trabajo terminado

Aquí es donde se cae el 90 % del discourse de “este modelo es más barato”.

La unidad de comparación es € por unidad de trabajo terminado, medida sobre el mismo corpus real: por conversación, por artículo generado, por documento extraído, por ticket resuelto. No €/millón de tokens en abstracto.

Por qué el precio por token miente:

  • Un modelo “barato” que se enrolla o que obliga a reintentar te sale más caro por trabajo cerrado.
  • Un modelo “caro” que acierta a la primera puede bajar el €/unidad aunque el €/token asuste.
  • Los defaults (razonamiento, verbosidad, max output) mueven el coste total sin tocar tu tarifa negociada.

Cómo se mide sin inventar religión:

  1. Defines la unidad de trabajo con criterio de “terminado” (no “respondió algo”).
  2. Fijas el corpus de calibración (muestras reales, no prompts de juguete).
  3. Corres la misma tanda en los contendientes con el mismo presupuesto de diseño (mismos caps, mismas reglas de reintento).
  4. Anotas coste real, tokens, turnos, reintentos y tasa de éxito bajo tu rúbrica.
  5. El ganador del tier es el que minimiza €/unidad cumpliendo el listón de calidad. No el que gana un leaderboard ajeno.

Esto encaja con montar evaluación con datos propios en lugar de fiarte de un número de marketing. El router no sustituye la evaluación: la hace accionable, porque el veredicto se traduce en qué modelo queda en cada tier.

Pieza 4, Cap de presupuesto duro (y por qué a veces aborta y a veces no)

El presupuesto no es un alarmita al final del mes. Es parte del diseño de la corrida.

Caps típicos por run o por trabajo (los cuatro se complementan):

  • Coste máximo en €
  • Tokens máximos
  • Turnos máximos
  • Wallclock (tiempo real de reloj)

Cuando se toca cualquiera, hay que saber qué significa el corte. Aquí no hay una única verdad universal: hay dos contextos, y en cada uno la decisión correcta es la contraria.

En evaluación / laboratorio: abortar es el resultado

En un laboratorio de benchmarks (incluido el hobby sin ingresos), el control de gasto se eleva a invariante: ningún gasto se dispara en silencio.

Al tocar el cap, el run se corta y se marca budget_exceeded.

El corte es un RESULTADO, no un error. “El modelo no lo resolvió dentro de presupuesto” es un dato publicable y honesto sobre el modelo, no un fallo del harness a reintentar hasta que cuele.

Igual que “no distinguible” es un veredicto legítimo en un test, “no cupo en el presupuesto” también lo es. Reintentar hasta que pase es falsear el experimento.

Historia real de diseño: un contendiente cerró una tanda con casi el doble de turnos y del orden de ~6× el coste del otro, y el harness lo reportó como hallazgo sobre ese modelo, no como “se cayó la infra”. El cap duro protegió la cartera y, de paso, sacó una señal de calidad/coste que una tabla de precios no te da.

En producto conversacional: degradar y seguir

En producto, un techo absoluto que devuelve error al usuario suele ser peor UX de la que “compensa”. La spec puede decir “bloqueo al 100 % del presupuesto”; la decisión operativa sensata en muchos casos es otra:

  • Al superar el presupuesto del trabajo, el tier caro baja al modelo barato configurado en fallback.
  • Se sigue sirviendo la tarea.
  • La “excepción de presupuesto” como hard fail deja de existir en ese flujo; queda la alerta de coste para quien paga la factura.

Justificación en una frase: el degradado es baratísimo comparado con cortar al usuario. El router no improvisa el modelo de backup: lo lee de config (fallback.on_budget), igual que el resto.

Misma pieza, dos políticas

Contexto Al tocar cap Qué se registra Por qué
Evaluación Abortar budget_exceeded (resultado) Equidad y honestidad del benchmark
Producto Degradar a cheap Alerta de coste + tier efectivo No matar la UX por un techo interno

Si mezclas las dos políticas sin decirlo, tus números de lab mienten o tu producto pega tiros al aire. El router debe saber en qué modo corre.

Pieza 5, Preflight: el dinero habla antes del arranque

Un cap por run no basta si lanzas una batería entera que en proyección ya se pasa del tope del mes.

El patrón de preflight:

  1. Hay un tope total por benchmark o por lote (suma de modelos × intentos × €/unidad medido).
  2. Se estima el coste antes de lanzar, con los €/conversación (o €/unidad) sacados de tandas de calibración previas.
  3. Si la proyección supera el tope, no se arranca.
  4. El lanzamiento real exige dry-run + OK explícito de quien pone el dinero.

En la práctica de laboratorio eso se ha usado para tandas del orden de 1.680 conversaciones proyectadas en torno a ~24 € antes de correr, y para duelos largos con el cap por modelo repartido por fases, de modo que una fase golosa no se coma el margen de las siguientes.

El presupuesto se sella como parte del diseño experimental: idéntico para todos los contendientes (equidad), visible en el pre-registro, y el coste real queda grabado en el report. Sin preflight, el cap por run solo te salva del incendio local; el preflight te salva del incendio del lote.

Pieza 6, Fallback al barato sin dejar tareas a medias

El fallback no es “reintenta y reza”. Es una política explícita con destino explícito.

Casos que debe cubrir el router:

  • Presupuesto agotado en modo producto → bajar a tier/modelo barato y terminar.
  • Error de proveedor (timeout, 5xx, rate limit duro) → mismo destino o cola de reintento acotada; nunca un bucle infinito contra el caro.
  • Modelo no disponible tras un cambio de catálogo → fallar en el chokepoint al resolver config, no a mitad del agente con un stacktrace críptico.

Reglas para que el fallback no sea peor que el fallo:

  • El modelo de backup está en config, calibrado, y ya pasó por la métrica de €/trabajo en su tier.
  • El tier efectivo usado se registra en el resultado (auditoría y post-mortem). Si degradaste, el log lo dice.
  • Los reintentos cuentan contra el mismo presupuesto. Un retry feliz que ignora el contador es un agujero con forma de while.
  • En evaluación, el fallback de presupuesto no maquilla el resultado: o abortas con budget_exceeded, o si permites degradar en un test concreto lo etiquetas para no mezclar peras con naranjas en el report.

Cómo se ensambla el flujo (paso a paso operativo)

Esto es el orden mental, y de implementación, que evita el chiringuito:

  1. Define unidades de trabajo y tiers de dificultad. Qué es “terminado” en tu producto. Qué trabajos son cheap, standard o strong. Sin esto, el router es un diccionario tonto.
  2. Levanta el chokepoint de configuración. Un solo sitio con mapa tier → provider/model/params y bloque de budget/fallback. Los agentes solo conocen el nombre del tier.
  3. Implementa adaptadores de proveedor detrás del router. Traducción de mensajes, auth, errores y knobs no portables. El cliente común se queda limpio.
  4. Instrumenta coste real por trabajo. Acumula € y tokens por work_id / run. Sin contador, el cap es decorativo.
  5. Calibra €/unidad con N trabajos reales. Misma tanda, varios modelos, defaults revisados a mano. Guarda esos €/unidad para el preflight.
  6. Elige política de cap según contexto. Lab: abortar como resultado publicable. Producto: degradar a barato + alerta. No las mezcles en silencio.
  7. Añade preflight a todo lote caro. Proyección vs tope total → dry-run → OK humano del dueño del dinero.
  8. Criterio de aceptación del sistema. Cambiar de modelo en un tier = cambio de config. Revertir = lo mismo. Un job de producto no muere solo por techo de € si hay fallback. Un run de eval que se pasa de presupuesto no se reintenta “hasta que salga bonito”.

Errores comunes (donde la caga todo el mundo)

Hardcodear el modelo “solo en este agente, es temporal”. Temporal es eterno. El chokepoint existe para que el admin del negocio no dependa de un developer con contexto arqueológico.

Migrar por precio de catálogo sin tanda en corpus propio. Estás comparando menús, no digestiones. Sin N unidades reales, no tienes dato: tienes hope-driven development.

Ignorar defaults del proveedor nuevo. El modelo barato con razonamiento verboso y max output hinchado es un modelo caro disfrazado. Revisa defaults en cada alta de modelo en el mapa de tiers.

Tratar budget_exceeded como error de infra en evaluación. Si lo reintentas hasta que pase, has dejado de medir el modelo. Has medido tu paciencia.

Cap duro en producto sin degradado. Bloquear al usuario al 100 % del presupuesto interno suele ser peor que servir con el barato y avisar al equipo. Si de verdad quieres hard stop en producto (cumplimiento, riesgo), que sea una política consciente, no el default porque copiaste el lab.

Presupuesto por token suelto sin wallclock ni turnos. Hay modelos y flujos que se ponen creativos con el tiempo y los tool calls. Los cuatro caps existen porque cada uno tapa un modo de fallo distinto.

Fallback al barato que nadie evaluó. Si el backup no pasó por tu métrica de trabajo terminado, el “plan B” es un plan de vergüenza en producción.

Contadores que no ven los reintentos. El coste real incluye lo que tiraste a la basura. Si el router solo suma la llamada “bonita” final, tu €/trabajo es ficción.

Trampa sutil: equidad del presupuesto en el lab

Si vas a comparar modelos, el presupuesto de diseño tiene que ser idéntico para todos los contendientes y estar sellado antes de correr. Si a uno le dejas más turnos “porque el otro ya quedó mal”, no tienes duelo: tienes narrativa.

Reparte caps por fases en tandas largas. Una fase inicial desbocada no debería vaciar el margen de las siguientes. El report debe llevar el coste real al lado del veredicto de calidad; si no, vuelves al culto del accuracy sin factura, el mismo que deja los benchmarks de escaparate en papel mojado cuando llegas a producción.

Seamos justos: hay escenarios donde hardcodear el modelo en el agente no es negligencia sino pragmatismo. Si tienes un solo tier, un solo proveedor y cero previsión de cambio en el horizonte del proyecto, añadir una capa de indirección es sobreingeniería pura. El router brilla cuando hay varios modelos, varios tiers o la factura empieza a doler; antes de eso, un string en una variable de entorno es un chokepoint perfectamente válido. La trampa no es empezar simple, sino no mover el código cuando el contexto ya pide otra cosa.

Qué queda fuera del router (a propósito)

El router no decide la rúbrica de calidad. No sustituye revisión humana donde haga falta. No es tu sistema de memoria ni tu capa de permisos. Es el sitio donde dificultad → modelo y dinero → corte o degradado se resuelven sin esparcir basura por el código.

Si le pides que también “sea el cerebro del agente”, lo vas a convertir en el monstruo que juraste no construir. Delgado, aburrido, configurable: así se porta bien.

Cierre

Montar esto no te hace más listo en Twitter. Te deja cambiar de modelo en una línea, medir lo que de verdad pagas por trabajo cerrado, y elegir con criterio cuándo un techo de presupuesto es un veredicto científico y cuándo es una degradación elegante para no dejar al usuario tirado.

El resto, hardcodear el sabor del mes y mirar el precio por millón de tokens como si fuera la verdad revelada, es exactamente el chiringuito del que estás intentando salir.

Preguntas frecuentes

¿Qué es un router de modelos por tier?

Es una capa que recibe la dificultad del trabajo (tier) y resuelve qué proveedor y qué modelo usar según configuración, no según código pegado en cada agente. Acumula coste, aplica techos de presupuesto y, si toca, aborta o degrada al modelo barato. El agente solo pide un tier; el mapa tier→modelo vive en un chokepoint que puede cambiar un admin.

¿Por qué no basta comparar el precio por millón de tokens?

Porque pagas por trabajo terminado, no por token suelto. Un modelo barato que reintenta o se enrolla puede salir más caro por conversación o por documento que uno con tarifa más alta que acierta a la primera. La comparación seria usa las mismas N unidades reales y mira coste total, tokens, reintentos y calidad bajo tu criterio de “hecho”.

¿El cap de presupuesto debe abortar la tarea o cambiar a un modelo más barato?

Depende del contexto. En evaluación, abortar y marcar budget_exceeded es un resultado publicable sobre el modelo, no un error a reintentar. En producto, suele ser mejor degradar al modelo barato configurado y terminar la tarea, dejando alerta de coste. Misma pieza mecánica; dos políticas distintas y explícitas.

¿Qué tiene que estar en configuración y no en el código del agente?

Todo lo que un administrador del negocio deba poder cambiar sin redesplegar lógica: IDs de modelo, proveedor por tier, techos de €, tokens, turnos y wallclock, y el destino de fallback. Los parámetros no portables entre proveedores no se esparcen con ifs en el cliente común; se aíslan en el adaptador. Si revertir una migración no es una línea de config, aún no hay router de verdad.