La factura que dio origen a esto fueron 312 $ por una sola tarde. Un desarrollador, una sesión de Octomind, un modelo haciéndolo todo: leer archivos, ejecutar greps, resumir diffs, decidir cuándo comprimir el contexto y hacer el razonamiento difícil de verdad. Todo sobre un modelo de frontera, porque es lo que eliges cuando quieres que el agente sea bueno.

Entonces OpenRouter empezó a devolver 429 en mitad de una refactorización, y vi cómo el agente se quedaba bloqueado por un límite de tasa haciendo algo que un modelo diez veces más barato habría hecho a la perfección. Ese fue el momento en que encajó lo evidente: la mayoría de lo que hace un agente no es difícil. Listar archivos no es difícil. Refinar una tarea vaga para dejarla más clara no es difícil. Decidir si una sesión es lo bastante grande como para comprimirla no es difícil. Leer un volcado de investigación y extraer los tres archivos relevantes no es difícil.

No necesitas tu mejor modelo para nada de eso. Lo necesitas quizá para el diez por ciento de las llamadas — la revisión, la decisión de diseño peliaguda, el diff que toca la autenticación. El otro noventa por ciento es trabajo pesado, y el trabajo pesado es justo donde brillan los modelos baratos y locales.

Esta es la historia de repartir un único agente de Octomind entre muchos modelos, anclada en las claves de configuración reales que trae. Al final tendrás un montaje multimodelo que funciona, una chuleta para elegir modelo y una respuesta clara a la pregunta que importa: qué pones dónde.


Una cadena, cualquier backend

Octomind habla con cada proveedor a través de una sola librería — octolib, sobre la que escribí antes. Lo que octolib te da, lo que hace posible todo esto, es que cada modelo se nombra igual: una cadena provider:model.

model = "anthropic:claude-sonnet-5"
model = "openai:gpt-5.5"
model = "deepseek:deepseek-chat"
model = "openrouter:google/gemini-3.5-flash"
model = "ollama:glm-5"

El mismo campo, la misma forma, en cualquier lugar donde se configure un modelo. Octolib analiza el prefijo, enruta al backend correcto y normaliza la respuesta — uso de tokens, coste, salida estructurada — para que al resto de Octomind le dé igual qué proveedor respondió.

Los prefijos de proveedor que octolib reconoce, a fecha de la versión actual, son:

openrouter  openai      anthropic   google      amazon
cloudflare  deepseek    cerebras    groq        together
fireworks   nvidia      minimax     moonshot    zai
byteplus    featherless octohub     ollama      local

Veinte proveedores de red, más un meta-proveedor especial cli para agentes locales basados en CLI (más sobre esto abajo). moonshot y kimi son alias del mismo proveedor. Los proveedores nuevos aterrizan en octolib y quedan disponibles en Octomind automáticamente — sin necesidad de una nueva versión de Octomind.

Por cierto, las claves de API son solo de entorno. No puedes ponerlas en el archivo de configuración; eso se eliminó por seguridad. Haces export OPENROUTER_API_KEY=... (o dejas un .env en el directorio de trabajo), y octomind config --show te dice qué claves detectó y de dónde salieron. Una clave de OpenRouter te da casi todo el catálogo a través de un único prefijo; las claves de proveedores concretos te dan el resto.


Dónde se elige un modelo

Antes de repartir el trabajo entre modelos, hay que saber los cuatro lugares donde se puede fijar un modelo, y cuál gana cuando aplica más de uno. Octomind resuelve el modelo efectivo en este orden, de mayor a menor prioridad:

CLI --model  >  role.model  >  config.model

Más una cuarta junta para los agentes de tap: una entrada [taps] sobreescribe config.model para una etiqueta de agente de tap concreta.

  • config.model — el valor por defecto raíz. En una configuración recién generada es un Claude de clase Sonnet enrutado por OpenRouter — hoy pondrías openrouter:anthropic/claude-sonnet-5. Todo recae en esto cuando no se ha fijado nada más específico.
  • role.model — una sobreescritura por rol. Esta es la palanca principal. Cada rol puede nombrar su propio modelo, y el modelo de un rol se respeta directamente por encima del valor raíz.
  • Sobreescritura [taps] — para los agentes de tap (los agentes category:variant que instalas desde un registro), puedes fijar un modelo por etiqueta sin tocar el manifiesto del agente:
[taps]
"developer:general" = "anthropic:claude-sonnet-5"
"octomind:assistant" = "openai:gpt-5.5"
  • CLI --model — gana sobre todo lo demás para una ejecución: octomind run -m anthropic:claude-sonnet-5. Y en mitad de la sesión puedes intercambiar en vivo con /model deepseek:deepseek-chat, o ajustar el esfuerzo de razonamiento con /effort high.

Así que la estrategia es sencilla: elige un valor por defecto razonable en config.model, luego sobreescribe por rol donde un trabajo concreto merezca un modelo distinto. La mayor parte del ahorro viene de la capa de roles.


Roles: la unidad para elegir modelo

Un rol en Octomind es un paquete de comportamiento con nombre: un prompt de sistema, una temperatura, un conjunto de servidores MCP y permisos de herramientas — y, opcionalmente, un modelo. Cada sesión corre con un rol. El rol decide qué puede hacer el agente y qué modelo lo hace.

La configuración que viene de fábrica ya practica lo que predica este post. Define cuatro roles simples, y tres de ellos corren deliberadamente sobre modelos más baratos que el principal — aquí con las cadenas de modelo actualizadas a la generación actual:

# Refinamiento ligero de consultas — aclarar una tarea vaga. Sin herramientas.
[[roles]]
name = "task_refiner"
model = "openrouter:openai/gpt-5.4-mini"
# ...

# Reconocimiento — reunir contexto, leer archivos, reportar hallazgos.
[[roles]]
name = "task_researcher"
model = "openrouter:google/gemini-3.5-flash"
# ...

# Compresión del historial de sesión — resumir y reducir.
[[roles]]
name = "reduce"
model = "openrouter:openai/gpt-5-mini"
# ...

Lee esas elecciones de modelo como una declaración de diseño. Refinar una petición vaga es trabajo para un modelo pequeño y rápido (gpt-5.4-mini). La investigación que lee muchos archivos quiere una ventana de contexto grande y barata (gemini-3.5-flash). Comprimir el historial es una tarea de resumen estructurado que un modelo de razonamiento pequeño resuelve bien (gpt-5-mini). Ninguno de estos necesita un modelo de frontera, y la configuración por defecto no malgasta uno en ellos.

Tus propios roles los defines igual. Todos los campos salvo model son obligatorios — system, welcome, temperature, top_p y top_k tienen que estar presentes o la configuración no se parseará:

# Contexto barato y amplio para barrer el código
[[roles]]
name = "researcher"
model = "openrouter:google/gemini-3.5-flash"
temperature = 0.3
top_p = 0.7
top_k = 20
system = "You gather context and report findings. You do not modify files."
welcome = ""
[roles.mcp]
server_refs = ["filesystem"]
allowed_tools = ["view"]

# Precisión donde cuenta — la revisión y las decisiones difíciles
[[roles]]
name = "reviewer"
model = "anthropic:claude-opus-4-8"
temperature = 0.2
top_p = 0.7
top_k = 20
system = "You review changes for correctness, security, and edge cases."
welcome = "Reviewer ready."
[roles.mcp]
server_refs = ["filesystem"]
allowed_tools = ["view", "ast_grep"]

Ahora octomind run researcher barre el repo sobre un modelo barato de gran contexto, y octomind run reviewer saca el modelo caro solo para el trabajo que se lo gana. Cambia entre ellos en mitad de la sesión con /role reviewer. El mismo agente, la misma sesión, dos modelos — elegidos por tarea.


Capas (layers): encadenar modelos en una sola pasada

Los roles te dejan elegir a ti un modelo por sesión. Las capas dejan que el sistema encadene modelos automáticamente dentro de un mismo flujo.

Una capa es una etapa invocable por ACP que referencia un rol mediante su campo command. El rol lleva el modelo, el prompt de sistema y las herramientas; la capa dice cómo entra y sale la conversación de esa etapa. Los campos son pocos y todos los campos de modo son obligatorios:

[[layers]]
name = "analysis"
description = "Detailed analysis of code, systems, or requirements"
command = "octomind acp analysis"   # spawns the `analysis` role over ACP
input_mode = "last"                 # last | all | summary
output_mode = "append"              # none | append | replace | last | restart
output_role = "assistant"

Como la capa apunta a un rol y el rol lleva el modelo, cada capa de una cadena puede correr sobre un modelo distinto. Un modelo barato reúne contexto, pasa su salida a la siguiente etapa, un modelo más potente razona sobre ella. La misma estructura LayerConfig respalda los [[commands]] — capas que disparas de forma interactiva con /run <name> — así que el comando reduce de fábrica es en sí una capa que corre el rol barato reduce para comprimir el historial bajo demanda.

El modelo mental: los roles responden "qué modelo para esta sesión", las capas responden "qué modelo para esta etapa". Juntos te dejan enrutar una sola petición a través de una tubería barato-luego-caro sin escribir código de orquestación — todo es TOML.

Nota: una entrada [[layers]] necesita un rol coincidente en [[roles]]. El modelo vive en el rol, nunca en la capa. Si te ves queriendo fijar un modelo en una capa, lo que buscas es el rol.


La compresión tiene su propio modelo — y debe ser barato

Hay una elección de modelo más que es fácil pasar por alto y que se amortiza de inmediato. Octomind comprime las sesiones largas automáticamente, y la llamada de decisión-más-resumen que impulsa la compresión corre sobre su propio modelo configurado, separado del principal:

[compression.decision]
model = "openai:gpt-5-mini"   # barato por diseño
max_tokens = 16000
temperature = 0.3

El valor por defecto de fábrica es openai:gpt-5-mini por algo: esta llamada se dispara una y otra vez a lo largo de una sesión larga, y no quieres un modelo de frontera decidiendo si comprimir. anthropic:claude-haiku-4-5 es una buena alternativa si ya estás en Anthropic. La idea es la misma que en todo este post — un trabajo rutinario y estructural recibe un modelo rutinario y barato, y el ahorro se acumula porque corre a menudo.

El motor de compresión es a su vez consciente del coste: antes de comprimir, calcula el beneficio neto usando precios por modelo obtenidos del proveedor, y se salta la compresión cuando costaría más de lo que ahorra. Para un modelo de sesión gratuito o de precio cero — un modelo local de Ollama, por ejemplo — siempre comprime, porque el coste es irrelevante y solo te importa mantener el contexto manejable. Lo cual enlaza bien con lo siguiente.


Modelos locales para el trabajo masivo

No toda llamada necesita salir de tu máquina. Octomind habla con modelos locales de dos formas.

Ollama y endpoints compatibles con OpenAI mediante los prefijos ollama: y local::

model = "ollama:glm-5"
model = "local:my-finetune"   # set LOCAL_API_URL to your endpoint

ollama: apunta a tu demonio local de Ollama; local: apunta a cualquier servidor compatible con OpenAI mediante LOCAL_API_URL. Cualquiera de los dos es la misma cadena provider:model que usa el resto de la configuración — ponla en el campo model de un rol y ese rol corre en local.

Agentes CLI locales mediante el meta-proveedor especial cli:, que corre un agente de línea de comandos en tu máquina en vez de llamar a una API de red:

model = "cli:codex/gpt-5.2-codex"

El formato es cli:<backend>/<model>, donde el backend es uno de codex, claude, cursor, gemini o un comando genérico. Como corre a través de una CLI local, no se necesita clave de API — Octomind se salta por completo la validación de credenciales para los modelos cli:. El comportamiento se ajusta con variables de entorno específicas del backend (para el backend codex, CODEX_COMMAND, CODEX_REASONING_EFFORT y compañía).

Dónde se ganan el sueldo los modelos locales: trabajo de alto volumen y bajo riesgo donde la latencia y la privacidad importan más que los últimos puntos de calidad. Resumen masivo, clasificación, investigación de primera pasada, cualquier cosa que ejecutes miles de veces. Pon un modelo local en un rol researcher y la fase de reconocimiento no te cuesta nada por token. Reserva el modelo en la nube para el rol reviewer, donde la diferencia de calidad sí se nota.


OctoHub: enrutamiento y respaldo por debajo

Hasta aquí el enrutamiento es por rol y por capa, decidido en tu configuración de Octomind. Pero hay una capa por debajo — un proxy de verdad — y es donde viven el respaldo (fallback), el balanceo de carga y la contabilidad centralizada.

OctoHub es nuestro proxy de LLM de código abierto. Para Octomind no es más que otro proveedor: fijas un modelo como octohub:my-model, apuntas Octomind al endpoint de OctoHub, y desde el lado de Octomind es una cadena provider:model más. Lo que OctoHub hace detrás de esa cadena es donde se vuelve útil. Su configuración mapea un nombre de modelo corto a una lista de destinos provider:model completamente cualificados, y elige uno al azar por petición:

[models]
# Un alias, varios backends reales — elección aleatoria por petición = balanceo de carga simple
"fast" = ["minimax:minimax-m3", "ollama:minimax-m3"]

Ese único mapeo te da balanceo de carga y una forma suave de conmutación por error: si un backend está limitado por tasa o caído, los demás de la lista absorben el tráfico. OctoHub también hace logging completo de peticiones/respuestas, claves de API multiinquilino (para que cada desarrollador o servicio tenga su propia clave y su uso se rastree por separado) y analíticas de uso agregadas por clave e intervalo temporal. Para un equipo que corre muchos agentes, esa es la diferencia entre "gastamos 4 mil dólares en LLM el mes pasado" y "la tubería de revisión del servicio de autenticación gastó 4 mil dólares el mes pasado, aquí está el desglose por clave".

El reparto de tareas es limpio:

  • octolib es la librería que sabe cómo hablar con cada proveedor — forma de la petición, parseo de la respuesta, tablas de coste.
  • OctoHub es el proxy que se sienta delante de los proveedores y decide a cuál llega una petición, la registra y la mide por clave.
  • Octomind es el agente que decide, por rol y por capa, qué cadena de modelo enviar en primer lugar.

Puedes correr Octomind sin proxy alguno y enrutar puramente a través de roles y OpenRouter. Añades OctoHub cuando quieres control centralizado: un único lugar para rotar claves, reequilibrar tráfico y ver adónde se fue el dinero.


La chuleta para elegir modelo

Aquí está dónde pondría yo cada clase de modelo. Trata los nombres concretos como ejemplos actuales, no como mandamientos — el modelo correcto este trimestre no será el correcto el siguiente, pero la forma de la decisión se mantiene.

Trabajo en el agente Clase de modelo Ejemplo concreto Por qué
Revisión final, decisiones de diseño difíciles, diffs cerca de autenticación Frontera anthropic:claude-opus-4-8 La calidad vale el precio en el 10% que importa
Bucle principal de desarrollo Potente, con caché anthropic:claude-sonnet-5 Buen código + caché de prompt mantienen el coste a raya
Investigación / barridos de contexto Gran contexto, barato openrouter:google/gemini-3.5-flash Lee muchos archivos, no necesita ser brillante
Refinamiento de tareas Pequeño, rápido openrouter:openai/gpt-5.4-mini Aclarar una petición vaga — trabajo trivial
Decisión de compresión Pequeño, barato openai:gpt-5-mini Se dispara constantemente; nunca uses un modelo de frontera aquí
Reducción de sesión / resúmenes Razonamiento pequeño openrouter:openai/gpt-5-mini Resumen estructurado, corre a menudo
Masivo / alto volumen / privado Local ollama:glm-5, cli:codex/gpt-5.2-codex Latencia + privacidad + coste cero por token
Respaldo en la nube económico Nativo barato deepseek:deepseek-chat El menor coste cuando aún necesitas una API de verdad

La regla bajo la tabla: gasta en las llamadas en proporción a cuánto cambia el resultado la calidad de la salida. La revisión pilla el bug o no — gasta ahí. El listado de archivos vuelve igual desde cualquier modelo — no gastes.


Una configuración multimodelo completa

Juntándolo todo, aquí tienes una configuración que reparte el trabajo entre cuatro modelos — un valor por defecto barato, un revisor potente, un investigador local y una decisión de compresión barata — más topes de gasto duros para que un bucle desbocado no te dé un susto:

# Valor por defecto barato y capaz, enrutado por una única clave de OpenRouter
model = "openrouter:anthropic/claude-sonnet-5"

# Topes duros — se aplican, no son meros consejos
max_request_spending_threshold = 0.50   # USD por petición, detiene la ejecución
max_session_spending_threshold = 5.00   # USD por sesión, pregunta/detiene

# La compresión corre sobre un modelo barato, separado del principal
[compression.decision]
model = "openai:gpt-5-mini"
max_tokens = 16000
temperature = 0.3

# Modelo local para la fase de reconocimiento de alto volumen
[[roles]]
name = "researcher"
model = "ollama:glm-5"
temperature = 0.3
top_p = 0.7
top_k = 20
system = "You gather context and report findings. You do not modify files."
welcome = ""
[roles.mcp]
server_refs = ["filesystem"]
allowed_tools = ["view"]

# Modelo de frontera para el trabajo que se lo gana
[[roles]]
name = "reviewer"
model = "anthropic:claude-opus-4-8"
temperature = 0.2
top_p = 0.7
top_k = 20
system = "You review changes for correctness, security, and edge cases."
welcome = "Reviewer ready."
[roles.mcp]
server_refs = ["filesystem"]
allowed_tools = ["view", "ast_grep"]

Valídala antes de confiar en ella:

octomind config --validate
octomind config --show     # confirms which provider keys were detected

Luego corre la ruta barata por defecto y llama a la cara solo cuando lo decidas:

octomind run researcher              # local model, free per token
octomind run reviewer                # frontier model, on purpose
octomind run -m deepseek:deepseek-chat   # one-off override for a session

Observa lo que cuesta de verdad con /info para el resumen de la sesión y /report para el desglose por petición. La primera vez que corras una tarea real así y veas que la fase de investigación no cuesta nada mientras la revisión cuesta unos céntimos, el reparto deja de ser teórico.


Qué cambió tras el reparto

La tarde de 312 $ ya no ocurre, y no porque usemos menos el agente. El tráfico de investigación y refinamiento se movió a modelos baratos y locales, la decisión de compresión dejó de ir sobre un modelo de frontera, y el modelo caro ahora solo aparece para la revisión y las decisiones genuinamente difíciles. La cuota del modelo de frontera sobre el total de llamadas bajó a aproximadamente ese diez por ciento que siempre debió ser.

Los bloqueos por límite de tasa también desaparecieron, lo cual no me esperaba. Repartir el tráfico entre proveedores — algunos por OpenRouter, otros directos, otros locales, otros tras el mapeo de elección aleatoria de OctoHub — significa que ningún 429 de un solo proveedor detiene la sesión entera. El agente que antes se congelaba ante el límite de tasa de un upstream ahora simplemente lo rodea.

Nada de esto requirió un framework, una librería de enrutamiento ni código de orquestación. Son cadenas provider:model en TOML, unos cuantos roles extra y un modelo de compresión barato. La parte difícil no fue el cableado — octolib y Octomind ya lo tenían todo. La parte difícil fue el cambio de mentalidad: deja de pagar precios de frontera por trabajo pesado, y pon tu mejor modelo solo donde la calidad de la salida cambia de verdad lo que pasa después.

Si también estás envolviendo herramientas específicas del proyecto para estos agentes, el patrón de MCP personalizados en tu repo compone limpiamente con roles multimodelo — herramientas estrechas y modelos del tamaño justo tiran en la misma dirección.


Preguntas frecuentes

¿Necesito OpenRouter, o puedo usar proveedores directamente?

Cualquiera de los dos. Una sola OPENROUTER_API_KEY te da casi todo el catálogo a través del prefijo openrouter:, que es el arranque más fácil. O fija claves individuales (ANTHROPIC_API_KEY, DEEPSEEK_API_KEY, …) y usa los prefijos nativos. Puedes mezclar ambos en una configuración — distintos roles pueden golpear proveedores completamente distintos.

¿Cómo cambio de modelo sin editar la configuración?

Por ejecución: octomind run -m anthropic:claude-sonnet-5. En mitad de la sesión: /model deepseek:deepseek-chat. El flag de la CLI gana sobre los modelos de rol y de configuración; el comando de barra intercambia la sesión en vivo y la guarda.

¿Dónde se decide exactamente un modelo?

El orden de resolución es CLI --model > role.model > config.model, con una sobreescritura [taps] que encaja en el nivel config.model para los agentes de tap. Fija un config.model por defecto razonable, luego sobreescribe por rol para los trabajos que merecen un modelo distinto.

¿Pueden distintos pasos de una tarea usar modelos distintos?

Sí — para eso están las capas. Una capa referencia un rol, el rol lleva el modelo, así que una cadena de capas corre una cadena de modelos. El modelo barato reúne contexto, el modelo potente razona sobre ello, todo en un mismo flujo.

¿Romperán los modelos locales el seguimiento de coste?

No. Un modelo gratuito o de precio cero se maneja explícitamente: el seguimiento de coste reporta cero, y el motor de compresión siempre comprime para esos modelos (ya que el control de coste deja de aplicar) para mantener el contexto manejable.

¿Qué añade OctoHub que los roles no?

Los roles enrutan en tu configuración; OctoHub enruta en el proxy. Mapea un alias a varios backends reales con balanceo de carga aleatorio, registra cada petición, emite claves de API por clave para seguimiento de uso multiinquilino y agrega analíticas. Lo quieres cuando un equipo necesita un único lugar para reequilibrar tráfico y rendir cuentas del gasto.


La idea nunca fue "usa un modelo más barato". Es "usa el modelo correcto para cada llamada, y deja que el enrutamiento sea configuración, no código". Octomind te da las juntas — valor por defecto raíz, por rol, por capa, por ejecución, más un proxy por debajo — y una sola cadena provider:model las une todas.

Gasta tu mejor modelo donde la respuesta importa de verdad. Deja que todo lo demás corra barato.

— Don


Octomind es de código abierto bajo Apache-2.0, y también lo son octolib y OctoHub. El enrutamiento multimodelo es configuración, no un plugin — si falta un proveedor que necesitas, aterriza en octolib y aparece en Octomind automáticamente. Abre un issue si algo de aquí no se sostiene.