Volver al blog

Optimización de costosGuía

Controla el gasto de la API por proyecto y recibe alertas de presupuesto en Python

Un breve script de Python convierte tu registro de uso en un informe de coste por proyecto y avisa al 50, 75, 95 y 100 % de un presupuesto mensual.

Por CheapTokens TeamPublicado el 6 min de lectura

Terminal con un informe de gasto por proyecto y una advertencia de presupuesto
En esta página
  1. Qué ha lanzado Anthropic y qué puedes copiar
  2. El registro: una línea por petición
  3. El script: coste por proyecto y alertas por umbral
  4. Ejecútalo y lee el resultado
  5. Cómo se ve un mes con modelos baratos
  6. Dónde falla esto

Añade una línea JSON a un archivo después de cada llamada a la API, etiquétala con el nombre de un proyecto y deja que un script de Python de 30 líneas convierta ese archivo en un informe de coste por proyecto y en una advertencia al 50, 75, 95 y 100 % de tu presupuesto mensual. Es la misma vista que Anthropic acaba de dar a los equipos de Claude Enterprise, construida a partir de tu propio registro.

Digamos que un saldo alimenta un agente, un script de redacción de borradores para el blog y un pequeño bot de soporte. Llega el fin de mes, el saldo es más bajo de lo que esperabas y nada te dice cuál de los tres ha sido. Ese es el hueco que esto cierra.

Qué ha lanzado Anthropic y qué puedes copiar#

El anuncio de Anthropic (28 de octubre de 2026) cubre informes inteligentes, encuestas dentro de la aplicación y presupuestos de grupo mancomunados, disponibles de forma general solo en los planes Claude Enterprise (fuente). Aquí importan dos partes. Un informe agrupa el trabajo de un equipo en flujos de trabajo y muestra el gasto de cada uno. Un presupuesto mancomunado es una única cifra mensual compartida, y los administradores de facturación reciben un correo al 50 %, 75 %, 95 % y 100 % de ella. Anthropic añade que los informes sirven para planificar la inversión, no para juzgar a personas concretas.

No necesitas un plan enterprise para la misma forma. Un flujo de trabajo no es más que una etiqueta que eliges, y los cuatro umbrales son una lista en el código. Agrupa por proyecto, no por persona, por la razón que da Anthropic.

Verificación rápida

Tu saldo de prepago ya detiene las peticiones al llegar a cero. ¿Por qué añadir advertencias al 50 % y al 75 %?

Mostrar respuesta

Respuesta: Porque cero es demasiado tarde: quieres darte cuenta de un bucle descontrolado mientras aún queda dinero para investigarlo

El saldo es una parada en seco, no una alarma. Los umbrales tempranos convierten una sorpresa al 100 % en una pregunta el noveno día.

El registro: una línea por petición#

Cada respuesta de chat completion lleva un objeto usage con prompt_tokens y completion_tokens. Eso es todo lo que necesita el informe, más una etiqueta de proyecto que añades tú. Este wrapper envía la petición y añade una línea a un archivo mensual (el nombre del archivo cambia cada mes, así que un mes nuevo empieza desde cero):

python
import json, os, time
from openai import OpenAI

client = OpenAI(base_url="https://api.cheaptokens.dev/v1",
                api_key=os.environ["CHEAPTOKENS_API_KEY"])

def ask(project, model, messages):
    r = client.chat.completions.create(model=model, messages=messages)
    with open(time.strftime("usage-%Y-%m.jsonl"), "a") as f:
        f.write(json.dumps({"project": project, "model": model,
                            "prompt_tokens": r.usage.prompt_tokens,
                            "completion_tokens": r.usage.completion_tokens}) + "\n")
    return r

ask("support-bot", "zai-org/GLM-5.3-Flash",
    [{"role": "user", "content": "Where is my order?"}])

Usa el id de modelo completo de la documentación de CheapTokens (deepseek-ai/DeepSeek-V4-Flash-0731, zai-org/GLM-5.3-Flash); la API no acepta los nombres cortos de las tablas de precios. La clave viene de una variable de entorno, nunca del archivo.

Flujo desde cada petición hasta el registro de uso, el informe por proyecto y las alertas
Cómo una petición se convierte en una línea del registro, luego en un informe y en una alerta

El script: coste por proyecto y alertas por umbral#

Guarda esto como report.py. Los precios son marcadores de posición: copia los actuales de la tabla de precios (aquí ambos modelos comparten un precio de ejemplo solo para que la aritmética sea legible).

python
import json, os, sys, time
from collections import defaultdict

LOG = time.strftime("usage-%Y-%m.jsonl")
BUDGET = float(os.environ.get("BUDGET_USD", "10"))  # example, substitute your own
STATE = LOG + ".alert"
LEVELS = [50, 75, 95, 100]
PRICES = {  # USD per 1M tokens (input, output): example, substitute current prices
    "deepseek-ai/DeepSeek-V4-Flash-0731": (1.0, 2.0),
    "zai-org/GLM-5.3-Flash": (1.0, 2.0),
}

spend = defaultdict(float)
with open(LOG) as f:
    for line in f:
        r = json.loads(line)
        p_in, p_out = PRICES[r["model"]]
        spend[r["project"]] += (r["prompt_tokens"] * p_in
                                + r["completion_tokens"] * p_out) / 1_000_000

total = sum(spend.values())
if total == 0:
    sys.exit("log is empty")

for name, usd in sorted(spend.items(), key=lambda kv: -kv[1]):
    print(f"{name:<8} ${usd:6.2f} {usd / total:5.0%}")
print(f"{'total':<8} ${total:6.2f} of ${BUDGET:.2f} ({total / BUDGET:.0%})")

last = int(open(STATE).read()) if os.path.exists(STATE) else 0
crossed = [l for l in LEVELS if total >= BUDGET * l / 100 and l > last]
if crossed:
    print(f"WARNING: budget passed {crossed[-1]}%")
    open(STATE, "w").write(str(crossed[-1]))

Las cuatro últimas líneas son la parte que la gente olvida. Sin el pequeño archivo de estado, el script gritaría "superado el 50 %" en cada ejecución durante el resto del mes. Con él, cada nivel se dispara una sola vez.

Ejecútalo y lee el resultado#

Toma un registro de juguete de cuatro líneas (uno real tiene una línea por petición, es decir, miles):

text
{"project": "agent", "model": "deepseek-ai/DeepSeek-V4-Flash-0731", "prompt_tokens": 2400000, "completion_tokens": 300000}
{"project": "agent", "model": "deepseek-ai/DeepSeek-V4-Flash-0731", "prompt_tokens": 1000000, "completion_tokens": 100000}
{"project": "blog", "model": "zai-org/GLM-5.3-Flash", "prompt_tokens": 800000, "completion_tokens": 400000}
{"project": "bot", "model": "zai-org/GLM-5.3-Flash", "prompt_tokens": 500000, "completion_tokens": 100000}

Con los precios de ejemplo y un presupuesto de 10, python report.py imprime:

text
agent    $  4.20   65%
blog     $  1.60   25%
bot      $  0.70   11%
total    $  6.50 of $10.00 (65%)
WARNING: budget passed 50%

El agente es casi dos tercios de la factura, y la advertencia llegó al 50 %, no al final. Ejecútalo otra vez y la advertencia se queda callada hasta que el total alcanza el 75 %.

Una terminal que muestra el informe por proyecto y la advertencia del 50 %
Salida del informe sobre el registro de juguete: porcentajes por proyecto y la primera advertencia

Para que esto funcione cada mes, necesitas tres pasos:

Paso a paso

Conéctalo en tres pasos

Registra cada llamada

Pasa todas tus llamadas por ask(project, model, messages) y elige una etiqueta de proyecto corta y estable. Cambiar las etiquetas a mitad de mes divide un proyecto en dos filas.

Define precios y presupuesto

Pon los precios actuales de la tabla de precios en PRICES y exporta tu límite: export BUDGET_USD=25.

Ejecútalo con una programación

Basta con una línea de cron cada hora: 0 * * * * cd ~/ai && python3 report.py. Envía la salida a un comando de correo o de chat si quieres que la advertencia te llegue.

Cómo se ve un mes con modelos baratos#

Los números se vuelven útiles cuando son tus números. Supón que el agente del registro de juguete promedia 30.000 tokens de entrada y 2.000 de salida por paso, 20 pasos por tarea y dos tareas al día. Un paso con DeepSeek-V4-Flash cuesta $0.00065; con GLM-5.3-Flash, $0.00068. Un día son 40 pasos, un mes 1.200. Mueve los controles para que coincidan con tu propio agente:

Calculadora de costos

Un día del agente: pasos por tarea multiplicado por tareas al día

Tokens de entrada por solicitud: 30.000 · Tokens de salida por solicitud: 2000 · Solicitudes por día: 40

ModeloPor díaPor mes
GLM-5.3-Flash$0.0272$0.816
DeepSeek-V4-Flash$0.026$0.78
MiniMax-M2.7$0.072$2.16

Y el mes con 1.200 pasos, contando entrada y salida juntas:

Modelo Por solicitud 1200 solicitudes OpenRouter, 1200 solicitudes
GLM-5.3-Flash $0.00068 $0.816 $1.41
DeepSeek-V4-Flash $0.00065 $0.78 $2.86
MiniMax-M2.7 $0.0018 $2.16 $25.92

30.000 tokens de entrada y 2000 tokens de salida por solicitud. Los precios por 1M de tokens son actuales y cambian junto con nuestras tarifas; la columna de OpenRouter muestra precios de referencia para la misma carga de trabajo.

En total, contando entrada y salida juntas, ambos modelos salen más baratos que los precios de referencia de OpenRouter de esa tabla, con un único precio a cualquier hora y sin recargo en horas punta. DeepSeek-V4-Flash también permite hasta 32.768 tokens de salida por respuesta y un contexto de 380K; GLM-5.3-Flash tiene un contexto de 390K. Una vez que el informe muestra qué proyecto es el que pesa, cambiar solo la cadena model de ese proyecto es un cambio de una línea, y un saldo cubre todos los modelos. Para saber cuántos tokens usa realmente una sola petición, consulta cuántos tokens usa una petición a la API; para detener a mitad una ejecución de un agente, consulta seguimiento del coste de tokens de agentes de IA. Los precios y los modelos están en la página de modelos de CheapTokens.

Dónde falla esto#

  • Falta un modelo en PRICES. El script se detiene con un KeyError que nombra el modelo. Añádelo; no uses cero por defecto, o el proyecto parecerá gratis.
  • Llamadas en streaming. El fragmento final lleva el uso solo si lo pides (stream_options={"include_usage": True} en el SDK de OpenAI). Si no, tu registro tendrá huecos.
  • Peticiones fallidas. Registra solo las respuestas que tengan un objeto usage; una petición que dio error no tiene nada que contar.
  • Informes por persona. Mantén la etiqueta como nombre de proyecto o de agente. Un informe sobre personas invita a conclusiones equivocadas.