Con un modelo local no pagas euros, pagas vatios.

Con un modelo local no pagas euros, pagas vatios.

Hay una respuesta muy repetida cuando alguien se queja de lo que le cuesta un agente: móntalo en local y deja de pagar.

Es cierto a medias. Dejas de pagar al proveedor. No dejas de pagar.

Cuando el modelo corre en tu máquina, estimate_cost_usd devuelve null, porque efectivamente nadie te está facturando. Pero el coste no ha desaparecido: se ha transformado. Ahora lo pagas en vatios, en calor, en tiempo de tu propia GPU y en la vida útil de un hardware que compraste tú.

Y eso también se puede medir.

Qué se mide y qué no.

Con un modelo local, OxideGate publica cuatro campos por petición:

CampoQué es
energy_whEnergía bruta consumida durante la ventana de la petición
energy_idle_whEl reposo de esa misma ventana, publicado aparte
power_peak_wPico de potencia alcanzado
energy_samplesCuántas muestras sostienen el número

En el panel de terminal aparece como una columna, Wh_net, justo al lado de la de dólares. Medido sobre un modelo de 7.000 millones de parámetros ya caliente: 79,1 mWh por 200 tokens.

Fíjate en un detalle de diseño que dice bastante del proyecto: el reposo se publica al lado, no restado.

La tentación es obvia. Restas el idle de la bruta y das un número limpio de “energía neta de esta petición”. Queda mucho mejor en una tabla. Pero la atribución no es limpia —tu GPU estaba haciendo otras cosas, el reposo no es constante, la ventana no empieza y acaba donde tú crees— y un número ya cocinado fingiría una precisión que no existe.

Así que salen los dos, y resta quien quiera restar, sabiendo lo que está haciendo.

Y la columna no se puede sumar.

Esta es la limitación que más nos costó aceptar, y está fijada en un test para que nadie la rompa por accidente.

El campo dice “lo que gastó la máquina mientras esta petición estuvo abierta”. No dice “lo que costó esta petición”. Y la diferencia importa en cuanto hay concurrencia: dos peticiones solapadas reclaman los mismos vatios. Sumar la columna cuenta esa energía dos veces.

Repartirla entre peticiones solapadas es imposible con los datos que se pueden capturar desde fuera. No es un pendiente: es un no se puede, declarado como tal, con su leyenda en el propio panel.

Podríamos haber inventado un reparto proporcional al tiempo. Habría sido plausible, habría quedado bien y habría sido falso.

El hallazgo: el rendimiento no predice el consumo.

Aquí está el número que hizo que este capítulo mereciera existir.

Comparamos dos modelos locales a través del proxy, mismo prompt y con el número de tokens a generar fijado para igualar la carga:

VelocidadEnergía
Modelo de 3B frente al de 7B1,82× más rápido2,89× más barato

Los dos números no coinciden. Y esa discrepancia es justamente el resultado.

Si hubieras estimado el ahorro de energía a partir de la velocidad —que es lo que hace todo el mundo, porque es lo único que se ve— habrías dicho “ahorra 1,8 veces”. La realidad es 2,89. Te habrías equivocado en un 60%.

El motivo es que son dos factores independientes multiplicándose: el modelo pequeño tarda 1,72× menos y además dibuja 1,68× menos potencia mientras tanto. Menos tiempo por menos vatios.

La conclusión práctica: los tokens por segundo no son un proxy del consumo energético. Si te importa la energía, mídela. No la deduzcas del rendimiento.

Cargar el modelo es medio tiempo y una décima parte de la energía.

El segundo hallazgo salió de una decisión técnica que parecía menor: soportar el dialecto nativo de Ollama, y no solo su endpoint compatible con OpenAI.

El endpoint compatible publica contadores de tokens y tira el reparto interno del tiempo. El dialecto nativo publica tres campos que ese otro pierde: tiempo de carga, tiempo de evaluación del prompt y tiempo de generación.

Con esos tres campos, medimos una petición fría:

  Carga del modelo   ████████████████████████████  54% del tiempo
                     ███                           11% de la energía
                                                   43 W de media

  Generación         ████████████████████████      46% del tiempo
                     █████████████████████████     89% de la energía
                                                   ~189 W de media

Cargar mueve memoria. No calcula. Por eso ocupa más de la mitad del reloj y apenas una décima parte de los vatios.

Y esa distancia entre tiempo y energía es, otra vez, la razón de que una de las dos cifras no sirva para deducir la otra.

Una nota de honestidad: esta medición corrigió una afirmación anterior de este mismo proyecto, que decía que cargar costaba 2,5 veces más. Estaba mal. Se retractó, se documentó la retractación y el número nuevo lleva la medición que lo sostiene. Un proyecto de medición que no retracta sus propios errores no está midiendo, está defendiendo una posición.

El fallo silencioso que casi nos pasa por encima.

Merece la pena contarlo porque es la clase de error que no da la cara.

El escáner que lee las respuestas en streaming exigía el prefijo data: en cada línea, porque es lo que hace el formato de eventos servidor que usan los proveedores remotos.

El dialecto nativo de Ollama no usa ese formato: usa NDJSON, un objeto JSON por línea, sin prefijo.

Contra ese dialecto, el escáner habría publicado cero tokens, en silencio. Sin error, sin aviso, sin nada raro en el panel. Una columna de ceros que parecería un modelo que no responde en lugar de un medidor que no sabe leer.

Es el mismo principio que atraviesa todo el proyecto, esta vez en su versión más incómoda: un cero y un dato ausente no son lo mismo, y confundirlos es peor que no medir, porque un cero se cree.

Cuándo esto te sirve.

Escenarios concretos donde medir energía cambia una decisión:

Cómo se activa.

El muestreo de potencia se enciende solo si detecta nvidia-smi. Se apaga con:

OXIDEGATE_POWER_SAMPLING=off

Y cuando está apagado, energy_wh pasa a null. No a cero.

Para dirigir el tráfico al motor local:

OXIDEGATE_OLLAMA_API_BASE=http://127.0.0.1:11434

Las rutas del dialecto nativo, que son las que publican el reparto de tiempo y la energía, son POST /api/generate y POST /api/chat.

Los límites, dichos antes de que los descubras tú.

Un efecto lateral muy útil.

Y termino con algo que no era el objetivo y resultó ser de lo más práctico del proyecto.

Si puedes medir contra un modelo local, puedes medir el peaje de un harness sin gastar cuota de nadie.

El bloque de instrucciones, los esquemas de herramientas y el listado de skills los inyecta el harness, no el modelo. Medir esa petición contra un modelo pequeño en local mide exactamente lo mismo que medirla contra uno de pago.

Sin cuenta. Sin red. Sin gastar un céntimo. Y reproducible por cualquiera que quiera comprobar los números de los capítulos anteriores en su propia máquina.

Eso convierte un banco de pruebas caro en uno gratuito, y es la diferencia entre “confía en mis números” y “compruébalos tú”.

En el siguiente capítulo dejamos el proxy y pasamos a la primera lente que lee sus datos: cuánto pesa exactamente cada servidor MCP en cada una de tus peticiones.

¿Listo para hacer crecer tu negocio?

Analicemos tu proyecto y definamos la estrategia perfecta para alcanzar tus objetivos

Solicitar consultoría gratuita