Módulo 3: Medir costo y tokens por run
El pricing de `claude-sonnet-5`
Descripción
Con estimate_tokens ya construida, falta la segunda pieza para calcular dinero: el precio. Esta lección fija, de una vez y para el resto de esta guía, la constante de pricing de claude-sonnet-5 — un número que no se vuelve a investigar ni a recalcular en ningún módulo posterior. Cada lección que necesite calcular un costo, desde la lección 05 en adelante, va a citar esta constante sin volver a justificarla.
El pricing real de un modelo de lenguaje no es un solo número — es, como mínimo, dos: uno para los tokens de entrada, otro para los de salida, y esta lección confirma, con aritmética ejecutada, la asimetría entre ambos que la lección 02 ya adelantó.
Conexión con el módulo
Esta lección agrega las dos constantes que completan la segunda pieza de observability/cost_calculator.py: INPUT_PRICE_CENTS_PER_MILLION_TOKENS y OUTPUT_PRICE_CENTS_PER_MILLION_TOKENS. La lección 05 las combina con estimate_tokens (lección 03) en estimate_cost_cents, la función central del módulo.
La constante: precio de lista, citado, fijo para toda la guía
Pricing de
claude-sonnet-5(precio de lista, verificado en la documentación oficial de Claude): $3.00 por cada millón de tokens de entrada, $15.00 por cada millón de tokens de salida.Existe un precio promocional de lanzamiento —$2.00/$10.00 por millón de tokens— vigente hasta el 31 de agosto de 2026. Esta guía fija su constante en el precio de lista ($3.00/$15.00), no en el promocional, por una razón simple: el precio de lista es el número que sigue siendo cierto después de que la promoción termine, y esta guía va a seguir publicada después de esa fecha. Cada cálculo de esta guía usa el precio de lista; el promocional se menciona, aquí, una sola vez, como una nota honesta — nunca como el número operativo.
En centavos, para que la aritmética de esta guía se mantenga siempre en int —el mismo estilo que ya usaste para cada precio de Reservo—:
INPUT_PRICE_CENTS_PER_MILLION_TOKENS = 300 # $3.00 / 1M tokens -- claude-sonnet-5, precio de lista
OUTPUT_PRICE_CENTS_PER_MILLION_TOKENS = 1500 # $15.00 / 1M tokens -- claude-sonnet-5, precio de lista
300 y 1500 son centavos por un millón de tokens — no por un token individual. Esta escala importa: dividir directamente 300 / 1_000_000 daría una fracción de centavo por token, imposible de representar como int sin perder toda precisión. La lección 05 muestra cómo se multiplica primero y se divide después, exactamente en ese orden, para que la aritmética entera nunca colapse a 0 antes de tiempo.
Confirmando la asimetría: el token de salida cuesta cinco veces más
La lección 02 lo adelantó como concepto; aquí se confirma con números reales. Compara el costo de la misma cantidad de tokens, según sean de entrada o de salida:
def estimate_cost_cents(input_tokens, output_tokens):
return (
input_tokens * INPUT_PRICE_CENTS_PER_MILLION_TOKENS
+ output_tokens * OUTPUT_PRICE_CENTS_PER_MILLION_TOKENS
) // 1_000_000
for n in (1_000, 10_000, 100_000, 1_000_000):
costo_si_es_entrada = estimate_cost_cents(n, 0)
costo_si_es_salida = estimate_cost_cents(0, n)
print(f"{n:>9} tokens -> como entrada: {costo_si_es_entrada:>5} centavos como salida: {costo_si_es_salida:>5} centavos")
Qué esperar:
1000 tokens -> como entrada: 0 centavos como salida: 1 centavos
10000 tokens -> como entrada: 3 centavos como salida: 15 centavos
100000 tokens -> como entrada: 30 centavos como salida: 150 centavos
1000000 tokens -> como entrada: 300 centavos como salida: 1500 centavos
En cada fila, el costo como salida es exactamente cinco veces el costo como entrada —15 contra 3, 150 contra 30, 1500 contra 300—, la misma proporción que hay entre $15.00 y $3.00. La primera fila —1.000 tokens— muestra algo más: como entrada, 1.000 tokens cuestan 0 centavos (la división entera vuelve a redondear hacia abajo, exactamente como en la lección 03), pero como salida ya cuestan 1 centavo — la asimetría es tan real que, para cantidades pequeñas de tokens, puede ser la diferencia entre "no cuesta nada, según esta aritmética" y "ya cuesta algo medible".
Por qué importa esta asimetría para el diseño de un agente
Esta no es una curiosidad de facturación — tiene una consecuencia práctica directa para cualquiera que diseñe un agente como Reservo. Un agente que lee mucho contexto —un historial largo, resultados de tools extensos— pero responde con brevedad paga, proporcionalmente, mucho menos que un agente que genera respuestas largas y verbosas, o que pide tools con argumentos complejos repetidamente. El costo de salida de claude-sonnet-5 pesa cinco veces más por token que el de entrada — así que, en igualdad de cantidad de tokens, la salida es la que domina la factura.
Esta observación no es una instrucción para optimizar nada —eso, con precisión, es tema de cost-optimization-caching-guide, no de esta guía—. Es, simplemente, la razón de fondo por la que la lección 05 va a mostrar output_tokens como una columna que vale la pena mirar con atención en cada CostReport: no porque sea más "interesante" que input_tokens, sino porque, token por token, cuesta más.
Por qué existe esta asimetría: una razón computacional, no arbitraria
Vale la pena entender de dónde sale la diferencia, no solo memorizar que existe. La lección 02 ya explicó que un modelo de lenguaje genera su respuesta de forma autoregresiva: un token a la vez, y cada token nuevo requiere una pasada completa del modelo sobre todo el contexto acumulado hasta ese punto. Procesar el texto de entrada —la pregunta, el historial, los tool_result— es, en cambio, un trabajo que el modelo puede hacer en paralelo, de una sola vez, sobre todo el texto que ya tiene por delante. Generar cien tokens de salida implica, aproximadamente, cien pasadas secuenciales del modelo; leer cien tokens de entrada implica, aproximadamente, una sola pasada sobre los cien a la vez. Esa diferencia de trabajo computacional real —secuencial contra paralelo— es la razón de fondo detrás de que casi todo proveedor de modelos de lenguaje, no solo Claude, cobre más por el token de salida que por el de entrada. La proporción exacta (5x para claude-sonnet-5) es específica de este modelo y esta fecha; la dirección de la asimetría —salida más cara que entrada— es estructural.
El error de usar un precio "promedio": cuantificado
Alguien que quisiera simplificar la fórmula podría sentirse tentado a usar un solo precio "promedio" —por ejemplo, (300 + 1500) / 2 = 900 centavos por millón, aplicado a la suma de tokens de entrada y salida—, en vez de mantener las dos constantes por separado. Esta lección cierra confirmando, con números reales, por qué esa simplificación produce un resultado incorrecto, y qué tan incorrecto puede llegar a ser según el perfil del run.
def blended_cost_cents(input_tokens, output_tokens):
"""La forma INCORRECTA: un solo precio promedio, aplicado al total de
tokens sin distinguir dirección. Existe aquí solo para medir el error
que produce -- nunca se usa en el resto de esta guía."""
blended_price = (INPUT_PRICE_CENTS_PER_MILLION_TOKENS + OUTPUT_PRICE_CENTS_PER_MILLION_TOKENS) // 2
return ((input_tokens + output_tokens) * blended_price) // 1_000_000
n = 100_000
# Perfil 1: parecido al run de Ana (lección 05) -- entrada domina levemente.
correcto_ana = estimate_cost_cents(64 * n, 56 * n)
incorrecto_ana = blended_cost_cents(64 * n, 56 * n)
# Perfil 2: un agente verboso -- responde mucho más de lo que lee.
correcto_verboso = estimate_cost_cents(30 * n, 150 * n)
incorrecto_verboso = blended_cost_cents(30 * n, 150 * n)
for label, correcto, incorrecto in [
("perfil tipo Ana (30 in / 56 out aprox.)", correcto_ana, incorrecto_ana),
("perfil verboso (30 in / 150 out)", correcto_verboso, incorrecto_verboso),
]:
print(f"{label}")
print(f" correcto (precios separados) : {correcto:>6} centavos = ${correcto / 100:.2f}")
print(f" incorrecto (precio promedio) : {incorrecto:>6} centavos = ${incorrecto / 100:.2f}")
print(f" error : {incorrecto - correcto:>6} centavos = ${(incorrecto - correcto) / 100:.2f}")
print()
Qué esperar:
perfil tipo Ana (30 in / 56 out aprox.)
correcto (precios separados) : 10320 centavos = $103.20
incorrecto (precio promedio) : 10800 centavos = $108.00
error : 480 centavos = $4.80
perfil verboso (30 in / 150 out)
correcto (precios separados) : 23400 centavos = $234.00
incorrecto (precio promedio) : 16200 centavos = $162.00
error : -7200 centavos = $-72.00
Dos perfiles, dos errores de signo opuesto. En el primer caso —parecido al run de Ana, con entrada y salida relativamente equilibradas—, el precio promedio sobrestima el costo real en casi cinco dólares por cada 100.000 runs. En el segundo caso —un agente que genera mucho más de lo que lee, un patrón realista para un agente que redacta respuestas largas—, el precio promedio subestima el costo real en setenta y dos dólares: el precio promedio no sabe que ese run gastó, proporcionalmente, mucho más en el token que cuesta cinco veces más caro. Ningún precio único —promedio o no— puede reemplazar a las dos constantes separadas sin introducir un error que cambia de dirección según el perfil del run. Esta es la razón definitiva por la que estimate_cost_cents, en toda esta guía, recibe siempre input_tokens y output_tokens como dos argumentos distintos, nunca como un solo total.
Errores comunes
-
Usar el precio promocional ($2.00/$10.00) como la constante operativa. Esta guía lo menciona una sola vez, como nota honesta — el precio de lista ($3.00/$15.00) es el que se usa en cada cálculo, desde esta lección hasta el cierre del Módulo 8, sin excepción.
-
Dividir
300(o1500) directamente entre un número de tokens pequeño, esperando un resultado con sentido.300 tokens_de_entrada / 1_000_000da una fracción diminuta de centavo — la fórmula real (lección 05) multiplica primero por la cantidad de tokens y divide al final, para que la aritmética entera no pierda toda la información antes de tiempo. -
Olvidar que el precio está expresado por millón, no por token.
INPUT_PRICE_CENTS_PER_MILLION_TOKENS = 300no significa "300 centavos por token" — significa 300 centavos por cada millón de tokens. Confundir la escala es el error más fácil de cometer al leer estas constantes por primera vez. -
Asumir que la asimetría 5x es una regla general de todos los modelos de lenguaje. Es la proporción específica de
claude-sonnet-5, citada de la documentación oficial de Claude en la fecha en que se fijó esta constante. Otros modelos, y el mismoclaude-sonnet-5en el futuro, pueden tener una proporción distinta — por eso esta guía cita la fuente y la fecha, en vez de presentar el número como una verdad universal. -
Recalcular o "verificar de nuevo" el pricing en una lección posterior. El
DISEÑOde esta guía es explícito: esta constante se fija una sola vez, aquí, y las lecciones y módulos que siguen la reusan citándola, sin volver a buscarla ni a cuestionarla.
Ejercicios
Ejercicio 1: Calcula el costo de 500.000 tokens de salida (Fácil)
Sin ejecutar nada primero: usando la fórmula de esta lección, ¿cuántos centavos cuestan 500.000 tokens de salida? Confirma con código.
Ver solución
500_000 * 1500 // 1_000_000 = 750_000_000 // 1_000_000 = 750 centavos.
print(estimate_cost_cents(0, 500_000))
Salida esperada:
750
Explicación: 750 centavos son $7.50 — exactamente la mitad de lo que costarían 1.000.000 de tokens de salida ($15.00), porque 500.000 es exactamente la mitad de un millón. La aritmética entera no introduce ningún error de redondeo en este caso porque 500_000 * 1500 = 750_000_000 es divisible exactamente entre 1_000_000.
Ejercicio 2: Encuentra el punto donde la entrada y la salida cuestan lo mismo en dólares (Medio)
¿Cuántos tokens de entrada hacen falta para costar lo mismo que 200.000 tokens de salida? Calcula primero el costo de 200.000 tokens de salida, y después encuentra —con código, probando valores— la cantidad de tokens de entrada que produce el mismo costo en centavos.
Ver solución
costo_salida = estimate_cost_cents(0, 200_000)
print("costo de 200.000 tokens de salida:", costo_salida, "centavos")
# Como la salida cuesta 5x más por token, hacen falta 5x más tokens de entrada.
tokens_entrada_necesarios = 200_000 * 5
print("tokens de entrada necesarios :", tokens_entrada_necesarios)
print("costo de esos tokens de entrada :", estimate_cost_cents(tokens_entrada_necesarios, 0), "centavos")
Salida esperada:
costo de 200.000 tokens de salida: 300 centavos
tokens de entrada necesarios : 1000000
costo de esos tokens de entrada : 300 centavos
Explicación: hacen falta exactamente cinco veces más tokens de entrada (1.000.000 contra 200.000) para igualar el costo de la salida — la consecuencia numérica directa de la asimetría 5x confirmada en el ejemplo trabajado. Esto ilustra, con un caso concreto, por qué "cantidad de tokens" y "costo" no son intercambiables sin saber si son de entrada o de salida.
Ejercicio 3: Compara el costo real contra el promocional, y cuantifica el ahorro (Difícil)
Usando el precio promocional mencionado en esta lección ($2.00/$10.00 por millón de tokens, en centavos: 200/1000), escribe una versión alternativa de estimate_cost_cents que use esas constantes. Calcula el costo de un run con 10.000 tokens de entrada y 5.000 de salida con ambos precios (lista y promocional), y calcula el porcentaje de ahorro que representaría el promocional.
Ver solución
PROMO_INPUT_PRICE_CENTS_PER_MILLION_TOKENS = 200
PROMO_OUTPUT_PRICE_CENTS_PER_MILLION_TOKENS = 1000
def estimate_cost_cents_promo(input_tokens, output_tokens):
return (
input_tokens * PROMO_INPUT_PRICE_CENTS_PER_MILLION_TOKENS
+ output_tokens * PROMO_OUTPUT_PRICE_CENTS_PER_MILLION_TOKENS
) // 1_000_000
costo_lista = estimate_cost_cents(10_000, 5_000)
costo_promo = estimate_cost_cents_promo(10_000, 5_000)
ahorro_pct = (1 - costo_promo / costo_lista) * 100 if costo_lista else 0
print("costo con precio de lista :", costo_lista, "centavos")
print("costo con precio promocional :", costo_promo, "centavos")
print(f"ahorro del promocional : {ahorro_pct:.1f}%")
Salida esperada:
costo con precio de lista : 10 centavos
costo con precio promocional : 7 centavos
ahorro del promocional : 30.0%
Explicación: el promocional ahorraría un 30% sobre este run específico —consistente con que ambos precios (entrada y salida) del promocional son, aproximadamente, dos tercios de los de lista—. Este ejercicio existe solo para confirmar la magnitud de la diferencia; el DISEÑO de esta guía es explícito en que la constante operativa, la que se usa en cada lección desde aquí en adelante, sigue siendo el precio de lista — el promocional nunca reemplaza a estimate_cost_cents en el resto de esta guía.
Resumen y siguiente paso
- Fijamos la constante de pricing de
claude-sonnet-5: $3.00/1M tokens de entrada, $15.00/1M tokens de salida, precio de lista — citada de la documentación oficial de Claude, con la nota honesta sobre el precio promocional vigente hasta el 31 de agosto de 2026. - Confirmamos, ejecutado, la asimetría 5x entre el costo de un token de salida y uno de entrada, en cuatro órdenes de magnitud distintos (
1.000a1.000.000tokens). - Explicamos la consecuencia práctica de esa asimetría: un agente que responde de forma verbosa paga más, token por token, que uno que lee mucho contexto pero responde con brevedad — sin que esto sea, todavía, una instrucción para optimizar nada.
- Esta constante se fija una sola vez; el resto de esta guía la cita sin volver a investigarla ni a recalcularla.
Siguiente lección: 05 — Costo por run, en centavos. Con estimate_tokens (lección 03) y el pricing fijo (esta lección) ya listos, los combinamos en estimate_cost_cents y cost_for_run, ejecutadas sobre un run real de Reservo, con desglose de costo por cada tool call.
Recursos adicionales
- Anthropic — Pricing — La fuente oficial del precio de lista de
claude-sonnet-5que esta lección fija como constante. - Anthropic — Models overview — Comparación de precios entre modelos de la familia Claude, útil para entender dónde se ubica
claude-sonnet-5. - Python — operadores aritméticos — Multiplicación y división entera, la base de
estimate_cost_cents. - Anthropic — Building effective agents — Sobre por qué el diseño de un agente —qué tan verboso responde, cuánto contexto necesita leer— tiene consecuencias directas de costo.
- Python 3.14 — What's New — La versión con la que se ejecutó cada línea de código de esta lección.