Los 5 errores que hacen que tu app de IA gaste el doble de tokens sin que lo notes
Datos y precios verificados al 27 de mayo de 2026 — Fuentes: OpenAI Pricing Page, Anthropic API Docs, DevTk.AI, PECollective LLM Pricing Comparison.
Si llevas meses mirando tu factura de API con cara de no entender qué pasó, bienvenido al club. El consumo excesivo de tokens es uno de los problemas más silenciosos y costosos que tienen hoy los equipos que construyen aplicaciones sobre modelos de lenguaje. No es que los modelos sean caros por naturaleza —GPT-5.4 cuesta $2.50/M de tokens de entrada y $15/M de salida, Claude Sonnet 4.6 va en $3/$15 y Gemini 2.5 Flash en $0.30/$2.50— el problema real es que la mayoría de las apps consumen entre el doble y el triple de lo que deberían, y nadie se entera hasta que llega la factura.
El dato que más duele es este: según equipos que han auditado pipelines de producción en 2026, entre el 40% y el 60% del presupuesto de tokens se desperdicia en ineficiencias de implementación. No en funcionalidad. En desperdicio puro. Un sistema de soporte al cliente que procesa 10,000 conversaciones diarias con un contexto promedio de 2,000 tokens está gastando entre $60 y $300 solo en tokens de entrada —antes de optimizar nada. Y eso con modelos de gama media.
En este artículo vas a ver los cinco errores que hacen que tu app de IA gaste el doble de tokens sin que lo notes, con ejemplos concretos, código real y el impacto en dólares de cada uno. No hay teoría de relleno: esto es lo que está pasando en producción ahora mismo.
Error 1: Enviar el historial completo de conversación en cada turno
Este es el error número uno en aplicaciones de chatbot y asistentes multi-turno. El patrón es siempre el mismo: el desarrollador construye el array de messages concatenando todo el historial desde el turno 1, y lo manda completo en cada llamada. A las 3 o 4 rondas, ya estás enviando 3,000-5,000 tokens de contexto que el modelo ya procesó y cuya información está mayoritariamente obsoleta para la pregunta actual.
Por qué ocurre sin que lo notes
Los SDKs oficiales de OpenAI y Anthropic no tienen ningún límite automático de historial. Si usas el patrón estándar de messages.append(response) sin limpiar, tu contexto crece linealmente con cada turno. En una conversación de 20 rondas con respuestas de ~300 tokens cada una, puedes estar enviando 6,000 tokens adicionales de historial en cada request —tokens que pagas íntegramente como input.
La solución: ventana deslizante con resumen
python# Gestión de historial con ventana deslizante y resumen automático import anthropic client = anthropic.Anthropic() def comprimir_historial(mensajes: list, max_tokens_historial: int = 2000) -> list: """ Comprime el historial cuando supera un umbral de tokens estimados. Regla práctica: 1 token ≈ 4 caracteres en inglés / 3.5 en español. """ # Estimación rápida de tokens por longitud de texto tokens_estimados = sum(len(m["content"]) // 4 for m in mensajes) if tokens_estimados <= max_tokens_historial: return mensajes # No hace falta comprimir todavía # Separar los últimos 4 mensajes (contexto reciente) del historial viejo contexto_reciente = mensajes[-4:] historial_viejo = mensajes[:-4] if not historial_viejo: return contexto_reciente # Construir texto del historial viejo para resumirlo texto_historial = "\n".join( f"{m['role'].upper()}: {m['content']}" for m in historial_viejo ) # Llamar al modelo más barato (Haiku) para generar el resumen # Claude Haiku 4.5 cuesta $1/M input vs $3/M de Sonnet: 3x más barato respuesta_resumen = client.messages.create( model="claude-haiku-4-5-20251001", max_tokens=300, # El resumen no debe ser más largo que esto messages=[{ "role": "user", "content": ( f"Resume en máximo 200 palabras los puntos clave de esta conversación " f"para mantener el contexto esencial:\n\n{texto_historial}" ) }] ) texto_resumen = respuesta_resumen.content[0].text # Reconstruir el historial: resumen como contexto + mensajes recientes historial_comprimido = [ { "role": "user", "content": f"[Resumen de la conversación anterior]: {texto_resumen}" }, { "role": "assistant", "content": "Entendido, continúo con ese contexto en mente." } ] + contexto_reciente return historial_comprimido # Uso en el loop principal del chatbot historial = [] def chat(mensaje_usuario: str) -> str: historial.append({"role": "user", "content": mensaje_usuario}) # Comprimir antes de enviar si el historial creció demasiado historial_enviado = comprimir_historial(historial, max_tokens_historial=1500) respuesta = client.messages.create( model="claude-sonnet-4-6", max_tokens=1024, system="Eres un asistente técnico especializado en arquitectura de software.", messages=historial_enviado ) contenido = respuesta.content[0].text historial.append({"role": "assistant", "content": contenido}) return contenido
Explicación línea por línea:
tokens_estimados: Estimación rápida sin tiktoken —suficiente para decisiones de corte.contexto_reciente = mensajes[-4:]: Conservamos siempre los últimos 4 mensajes para mantener coherencia inmediata.model="claude-haiku-4-5-20251001": El resumen se genera con Haiku ($1/M input) en lugar de Sonnet ($3/M). El costo del resumen es marginal frente al ahorro.max_tokens=300: El resumen tiene un techo duro. Sin esto, el "resumen" puede costar más que el historial original.historial_comprimido: El historial final tiene estructura user/assistant para que los modelos lo acepten correctamente. El ahorro estimado en una conversación de 20 turnos con mensajes de ~400 tokens: entre 40% y 65% de los tokens de entrada.
Error 2: System prompts que crecieron sin control
El segundo error más común es el system prompt inflado. Empieza con 200 tokens. Alguien agrega instrucciones de formato. Otro agrega reglas de negocio. Se suman ejemplos de few-shot. Un mes después tienes 2,000 tokens de sistema que se envían en absolutamente cada request, día y noche, incluso en las llamadas más triviales.
Un system prompt de 1,800 tokens enviado a 10,000 requests por día equivale a 18 millones de tokens de entrada mensuales gastados solo en instrucciones. Con Claude Sonnet 4.6 a $3/M, eso son $54/mes solo en el system prompt. Con GPT-5.5 a $5/M, $90/mes. El número escala brutalmente con el volumen.
La solución: prompt caching para contenido estático
Prompt caching es la optimización de mayor impacto disponible hoy. OpenAI y Anthropic la implementan de forma diferente pero el principio es el mismo: el proveedor cachea el prefijo inmutable del prompt y cobra una tarifa reducida en las lecturas posteriores. Con Anthropic, las lecturas de caché cuestan $0.30/M tokens en lugar de $3/M —una reducción del 90%. OpenAI aplica descuentos automáticos de hasta el 50% en prompts cacheados.
La clave está en la estructura del prompt: el contenido estático primero, el dinámico al final.
python# Estructura de prompt optimizada para caching en Anthropic import anthropic client = anthropic.Anthropic() # System prompt largo que NO cambia entre requests: se cachea SYSTEM_PROMPT_ESTATICO = """ Eres un asistente de soporte técnico para la plataforma X. REGLAS DE COMPORTAMIENTO: 1. Responde siempre en el idioma del usuario. 2. Si no puedes resolver el problema, escala con código ERR-[número]. 3. No menciones competidores. [... 1500 tokens más de instrucciones estáticas ...] """ def responder_ticket(pregunta_usuario: str, contexto_ticket: dict) -> str: """ La parte estática del sistema se cachea automáticamente por Anthropic. Solo la pregunta del usuario y el contexto dinámico pagan tarifa completa. """ respuesta = client.messages.create( model="claude-sonnet-4-6", max_tokens=1024, system=[ { "type": "text", "text": SYSTEM_PROMPT_ESTATICO, # Esta marca indica a Anthropic que este bloque es cacheable "cache_control": {"type": "ephemeral"} } ], messages=[ { "role": "user", # Solo esta parte varía por request —paga tarifa completa "content": ( f"Ticket #{contexto_ticket['id']} " f"(Plan: {contexto_ticket['plan']}): {pregunta_usuario}" ) } ] ) return respuesta.content[0].text
En producción con 10,000 requests/día y un system prompt de 1,800 tokens, el ahorro con caching activado supera los $45/mes solo en ese componente, con Sonnet 4.6.
Error 3: RAG con sobre-recuperación de chunks
Los pipelines de RAG (Retrieval-Augmented Generation) son especialmente propensos al desperdicio silencioso. El patrón más común: el desarrollador configura top_k=8 o top_k=10 porque "más contexto es mejor", y manda al modelo 8 fragmentos de documento en cada consulta, la mayoría irrelevantes.
El problema matemático
Un chunk típico de RAG tiene entre 300 y 500 tokens. Si recuperas 8 chunks por defecto:
- Tokens de contexto por request: 8 × 400 = 3,200 tokens adicionales
- Si el 60% de esos chunks son marginalmente relevantes: estás desperdiciando ~1,920 tokens por request
- Con GPT-5.4 a $2.50/M y 50,000 queries/mes: $240/mes en chunks irrelevantes
La solución: recuperación en dos fases + reranking
En lugar de mandar los top-8 directamente al modelo, usa un reranker ligero para filtrar a los 2-3 chunks más relevantes antes de incluirlos en el prompt. Modelos de cross-encoder como ms-marco-MiniLM-L-6-v2 corren localmente en milisegundos y no consumen tokens de API.
python# RAG con reranking para reducir chunks enviados al modelo from sentence_transformers import CrossEncoder import anthropic # El reranker corre localmente: coste cercano a cero reranker = CrossEncoder("cross-encoder/ms-marco-MiniLM-L-6-v2") client = anthropic.Anthropic() def buscar_con_reranking(query: str, chunks_candidatos: list, top_k_final: int = 2) -> str: """ Fase 1: Recuperación amplia desde el vector store (top_k=8 o 10). Fase 2: Reranking local para quedarse solo con los 2 mejores. Fase 3: Solo los 2 chunks pasan al contexto del LLM. """ if not chunks_candidatos: return "No se encontró información relevante." # Crear pares (query, chunk) para que el reranker puntúe relevancia pares_query_chunk = [[query, chunk["texto"]] for chunk in chunks_candidatos] # El reranker asigna un score de relevancia a cada par: más alto = más relevante scores = reranker.predict(pares_query_chunk) # Ordenar por score descendente y tomar solo los top_k_final mejores chunks_rankeados = sorted( zip(scores, chunks_candidatos), key=lambda x: x[0], reverse=True ) mejores_chunks = [chunk for _, chunk in chunks_rankeados[:top_k_final]] # Construir el contexto solo con los chunks de mayor relevancia contexto = "\n---\n".join(c["texto"] for c in mejores_chunks) respuesta = client.messages.create( model="claude-sonnet-4-6", max_tokens=1024, messages=[{ "role": "user", "content": ( f"Responde la siguiente pregunta basándote SOLO en el contexto dado.\n\n" f"CONTEXTO:\n{contexto}\n\n" f"PREGUNTA: {query}" ) }] ) return respuesta.content[0].text
Con este patrón, pasas de 3,200 tokens de contexto promedio a 800-1,000 tokens, manteniendo o mejorando la calidad de respuesta. El reranker elimina el ruido que el LLM de todas formas ignoraría.
Error 4: Tokens de salida fuera de control
Los tokens de salida son el ítem más caro de tu factura: cuestan entre 4x y 8x más que los de entrada en todos los modelos frontier. GPT-5.5 cobra $5/M input y $30/M output (ratio 6:1). Claude Opus 4.6 va en $5/$25 (ratio 5:1). Aun así, la mayoría de los sistemas no ponen ningún techo real a la longitud de las respuestas.
El error específico: no usar max_tokens como límite de presupuesto
max_tokens no es solo un parámetro de longitud. Es tu límite de gasto por request. Si lo dejas en 4,096 por defecto y tu caso de uso real necesita 300 tokens promedio, estás dejando abierta la puerta a respuestas innecesariamente largas que cuestan 10 veces más de lo necesario.
El segundo error relacionado es no usar instrucciones de formato concreto en el prompt. Un modelo al que le preguntas "¿qué es Docker?" puede responder con 150 tokens o con 1,200 dependiendo de lo vago que sea el prompt. La instrucción explícita "responde en máximo 3 oraciones" puede reducir el output en un 70% sin degradar la utilidad.
La solución: max_tokens ajustado + instrucciones de longitud explícitas
python# Configuración de max_tokens según tipo de tarea PRESUPUESTO_TOKENS = { "clasificacion": 150, # Sí/No, categoría: nunca necesita más "resumen_corto": 300, # Un párrafo "respuesta_chat": 512, # Respuesta conversacional estándar "analisis": 1024, # Análisis técnico detallado "generacion_codigo": 2048 # Solo para snippets medianos } def llamar_con_presupuesto(prompt: str, tipo_tarea: str) -> str: max_tk = PRESUPUESTO_TOKENS.get(tipo_tarea, 512) # Instrucción de longitud explícita dentro del prompt: complementa max_tokens instruccion_longitud = { "clasificacion": "Responde SOLO con la categoría exacta, sin explicación.", "resumen_corto": "Responde en un único párrafo de máximo 3 oraciones.", "respuesta_chat": "Sé conciso. Si puedes responder en 2-3 oraciones, hazlo.", "analisis": "Estructura la respuesta con bullets cuando aplique.", "generacion_codigo": "Incluye solo el código relevante y comentarios esenciales." }.get(tipo_tarea, "") prompt_final = f"{instruccion_longitud}\n\n{prompt}" if instruccion_longitud else prompt respuesta = client.messages.create( model="claude-sonnet-4-6", max_tokens=max_tk, # Techo duro: el modelo no puede gastar más que esto messages=[{"role": "user", "content": prompt_final}] ) return respuesta.content[0].text
Error 5: Usar el mismo modelo para todas las tareas
El quinto error, y quizás el más costoso en volumen, es no diferenciar entre tareas simples y complejas. Muchos sistemas usan Claude Sonnet 4.6 o GPT-5.4 para absolutamente todo, incluidas las tareas triviales de clasificación, extracción de campos o reformateo de texto.
La diferencia de precio es brutal: Claude Haiku 4.5 cuesta $1/M de entrada, mientras que Sonnet 4.6 cuesta $3/M y Opus 4.6 $5/M. Para tareas de clasificación binaria o extracción de entidades —donde Haiku rinde igual que Sonnet— estás pagando 3x o 5x de más.
La solución: enrutamiento inteligente por complejidad
El patrón model routing consiste en clasificar la tarea antes de elegir el modelo. Puedes hacerlo con reglas heurísticas o con un clasificador liviano:
- Haiku 4.5 ($1/$5): clasificación, extracción de campos, resúmenes cortos, validación de formato.
- Sonnet 4.6 ($3/$15): respuestas conversacionales, análisis de texto moderado, generación de código simple.
- Opus 4.6 / GPT-5.5 ($5/$25-30): razonamiento complejo, síntesis de múltiples documentos, generación de código crítico. Un pipeline de producción que procesa 100,000 tareas diarias donde el 60% son clasificaciones puede ahorrar más de $1,200/mes solo cambiando esas llamadas a Haiku.
Conclusión: La optimización de tokens es una disciplina de ingeniería, no un truco puntual
Ninguno de estos cinco errores es obvio a primera vista. Todos se acumulan silenciosamente en producción hasta que la factura mensual no cuadra con el tráfico. La buena noticia es que son completamente solucionables con cambios de arquitectura relativamente simples:
- Gestiona el historial con ventanas deslizantes y resúmenes automáticos.
- Audita y cachea tu system prompt —especialmente si supera los 500 tokens.
- Implementa reranking antes de pasar chunks de RAG al contexto del LLM.
- Trata
max_tokenscomo un presupuesto, no como un parámetro de configuración genérico. - Enruta por complejidad: no uses un modelo frontier para tareas que puede resolver un modelo de bajo costo.
El primer paso es siempre la visibilidad. Si no mides el consumo de tokens por tipo de operación, no sabes dónde está el desperdicio. Instrumenta tu app con logs de
usage.input_tokensyusage.output_tokensdesde hoy, agrúpalos por tipo de tarea, y verás el patrón en días.
¿Por dónde empezar? Activa el prompt caching esta semana —es el cambio con mayor ROI y el de menor riesgo. Si tu system prompt tiene más de 500 tokens y recibes más de 5,000 requests diarios, el ahorro se nota en la próxima factura.
Si este artículo te resultó útil, compártelo con tu equipo de ingeniería. Las decisiones de arquitectura de IA que se toman hoy en desarrollo van a definir los costos operativos del próximo año.
Preguntas frecuentes
Fredo
Ingeniero de Sistemas · Especialista en costos de IA
"Ingeniero de sistemas especializado en arquitectura de costos para APIs de IA. Analiza y compara modelos de lenguaje en producción para ayudar a equipos de desarrollo latinoamericanos a optimizar su infraestructura de IA sin destruir sus márgenes."