AIFreeAPI Logo

Tokens de razonamiento: cómo evitar contarlos dos veces en Gemini, OpenAI y Claude

A
7 min readGuías de API

Una columna de razonamiento puede ser un desglose de la salida o una cantidad que aún debes sumar. La diferencia depende de la API: estas reglas y ejemplos permiten corregir el cálculo antes de contrastarlo con la factura.

Ilustración de un libro de cuentas con columnas de tokens para OpenAI, Gemini y Claude

En OpenAI y Claude, el total de salida ya incluye los tokens de razonamiento. En Gemini generateContent, hay que sumar candidatesTokenCount y thoughtsTokenCount para obtener la salida de texto facturable. Aplicar una misma suma a las tres API es una forma fácil de inflar el informe de costes.

El error nace de confundir un total con su desglose. Que la respuesta JSON muestre dos números no significa que correspondan a dos conceptos que debas cobrar por separado. Tampoco una respuesta corta implica poco consumo: parte del trabajo del modelo puede no aparecer en el texto que recibe el usuario.

Las reglas siguientes corresponden a las interfaces nativas documentadas a 7 de septiembre de 2026. Sirven para conciliar la salida; el importe completo también necesita entrada, caché, tarifas y otros servicios.

Qué campo usar en cada API

Interfaz y objeto recibidoBase de tokens de salidaDesglose de razonamientoOperación correcta
OpenAI Responses, usageoutput_tokensoutput_tokens_details.reasoning_tokensUsar el total, sin añadir el desglose
OpenAI Chat Completions, usagecompletion_tokenscompletion_tokens_details.reasoning_tokensUsar el total, sin añadir el desglose
Gemini generateContent, usageMetadataDos cantidades separadasthoughtsTokenCountSumar candidatesTokenCount + thoughtsTokenCount
Claude Messages, usageoutput_tokensoutput_tokens_details.thinking_tokens, cuando se informaUsar el total, sin añadir el desglose

En OpenAI, los contadores de salida incluyen todos los tokens generados por el modelo, también el razonamiento. Si restas este último obtienes la parte no clasificada como razonamiento, no necesariamente el número exacto de tokens del texto visible: también puede haber estructuras internas, formato o llamadas a herramientas.

En Gemini, UsageMetadata separa candidatos y pensamientos. totalTokenCount incluye entrada, candidatos y pensamientos: no es un contador exclusivo de salida y no debes volver a sumarle el razonamiento. Además, promptTokenCount incluye el contenido en caché; tampoco conviene sumar automáticamente la caché a ese total de entrada.

En Claude, el detalle de pensamiento está incluido en output_tokens. El campo de detalle permite analizar cuánto razonamiento hubo, pero no añade una segunda partida a la salida. Si un SDK antiguo o un intermediario no lo devuelve, puede seguir existiendo un total de salida válido aunque desconozcas su composición.

La marca del modelo no basta para elegir la fórmula

Un modelo Gemini puede llegar a tu aplicación a través de una API compatible con OpenAI. Esa capa podría haber convertido los dos contadores nativos en un completion_tokens inclusivo. Aplicar después la suma nativa de Gemini duplicaría el razonamiento.

Esta es una consecuencia de los distintos formatos, no una afirmación sobre todos los intermediarios. Registra proveedor, interfaz y versión del adaptador, conserva el objeto original y confirma qué promete cada campo. Tampoco traslades sin comprobar esta regla de generateContent a Gemini Interactions, Live u otras interfaces.

Tres cuentas que muestran dónde aparece el error

Para comparar operaciones utilizaremos una tarifa ficticia de 5 USD por millón de tokens de salida, idéntica en los tres ejemplos. No es un precio anunciado por los proveedores ni permite comparar qué modelo resulta más barato. Solo aísla el efecto de elegir mal el contador.

EjemploDatos disponiblesSalida correctaCálculo que fallaCoste correcto de salida
OpenAI, cifras de su documentaciónSalida: 1.186; razonamiento: 1.0241.1861.186 + 1.024 = 2.2100,005930 USD
Gemini, caso sintéticoCandidatos: 162; pensamientos: 1.0241.186Usar solo 1620,005930 USD
Claude, cifras de su documentaciónSalida: 348; pensamiento: 312348348 + 312 = 6600,001740 USD

El primer ejemplo figura en la guía de razonamiento de OpenAI; el tercero, en la explicación de costes de Claude. Los importes son cálculos ilustrativos con la tarifa ficticia anterior, no resultados de peticiones realizadas para este artículo.

En OpenAI, la suma incorrecta produciría 0,011050 USD: una diferencia de 0,005120 USD por esa petición. Repetir exactamente el error en 100.000 peticiones iguales añadiría 512 USD al informe local. Eso no demuestra que el proveedor haya cobrado 512 USD de más: demuestra que el cálculo local está inflado.

En Gemini ocurre también el error contrario. Si solo contabilizas los 162 tokens de candidatos, estimarías 0,000810 USD y omitirías 0,005120 USD de razonamiento. La regla correcta evita tanto sobreestimar como infravalorar el consumo.

La operación monetaria, una vez identificada la salida, es:

text
coste_de_salida = tokens_de_salida × tarifa_por_millón / 1.000.000

Esta fórmula presupone que todos esos tokens pertenecen a la categoría cubierta por la tarifa. Para audio, imágenes, herramientas u otras partidas, consulta el desglose aplicable en vez de asignar un precio único a todo usage.

Diagrama de un total con su desglose y de dos cantidades separadas en OpenAI y Gemini
Diagrama de un total con su desglose y de dos cantidades separadas en OpenAI y Gemini

Normalizar una vez y mantener lo desconocido como desconocido

Conviene que una única función traduzca el objeto nativo a un total común. Las pantallas, exportaciones y agregaciones posteriores utilizarán ese total, sin volver a sumar los detalles.

El siguiente ejemplo en Python recibe el objeto usage o usageMetadata, no la respuesta completa. Devuelve el total de salida o None si faltan datos necesarios. En los totales inclusivos, la ausencia del detalle no impide usar el total; en Gemini, sin uno de los dos sumandos no lo calcula. No sustituye un sistema de facturación ni interpreta formatos de intermediarios.

python
def tokens_de_salida(api, usage): def contador(obj, campo): valor = obj.get(campo) if valor is None: return None if type(valor) is not int or valor < 0: raise ValueError(f"Contador inválido: {campo}") return valor if api == "gemini.generateContent": candidatos = contador(usage, "candidatesTokenCount") pensamientos = contador(usage, "thoughtsTokenCount") if candidatos is None or pensamientos is None: return None return candidatos + pensamientos campos = { "openai.responses": ("output_tokens", "output_tokens_details", "reasoning_tokens"), "openai.chat.completions": ("completion_tokens", "completion_tokens_details", "reasoning_tokens"), "claude.messages": ("output_tokens", "output_tokens_details", "thinking_tokens"), } if api not in campos: raise ValueError("Interfaz no admitida") campo_total, campo_detalle, campo_pensamiento = campos[api] total = contador(usage, campo_total) detalle = usage.get(campo_detalle) if detalle is None: detalle = {} if not isinstance(detalle, dict): raise ValueError("Desglose inválido") pensamiento = contador(detalle, campo_pensamiento) if total is not None and pensamiento is not None and pensamiento > total: raise ValueError("El desglose supera el total") return total

Los casos sintéticos de comprobación incluyen las cuatro interfaces, un cero explícito, totales ausentes, desglose ausente y contadores negativos, fraccionarios o incompatibles con el total. La función se ejecutó localmente con esos casos, sin llamar a las API de pago.

Un None debe conservarse como consumo pendiente o desconocido; no lo conviertas en cero al calcular el coste. Un cero explícito sí es una cantidad conocida. Si tu interfaz documenta una omisión equivalente a cero en una situación concreta, incorpora esa regla únicamente en su adaptador y conserva su procedencia.

Streaming y reintentos: no todos los duplicados son iguales

Hay tres problemas distintos que pueden acabar mostrando un importe demasiado alto. Cada uno requiere otra corrección.

Un desglose sumado al total. El mismo consumo se cuenta dos veces dentro de una petición. Se corrige eligiendo el contador inclusivo o sumando solo las categorías separadas, según la tabla inicial.

Varios registros de una misma respuesta. Un consumidor puede procesar dos veces un evento final o almacenar cada actualización como si fuera una respuesta completa. Se corrige identificando la petición o respuesta del proveedor y el intento correspondiente, y actualizando su registro de consumo.

En Claude, el consumo de message_delta es acumulativo. Si las actualizaciones indican 40, 90 y 120 tokens de salida, el total final es 120, no 250. Utiliza el último total definitivo o el mensaje final que reconstruye el SDK; los detalles de pensamiento se informan en el evento final correspondiente. Un corte antes de recibir el consumo definitivo puede dejar la conciliación pendiente.

Dos peticiones que realmente se ejecutaron. Un reintento tras un tiempo de espera puede ser otra ejecución con consumo propio. No elimines uno de los registros porque el texto enviado sea idéntico. Distingue la operación de tu aplicación, sus intentos y las respuestas del proveedor. Ante un tiempo de espera sin consumo confirmado, conserva la incertidumbre hasta poder contrastarla.

Para una conciliación práctica, guarda el identificador disponible de la petición o respuesta, un identificador local de intento, el modelo efectivo, el objeto de consumo original, el total normalizado y si ese total es definitivo. El nombre exacto de cada identificador depende de la API. Esta recomendación organiza tus registros; no presupone que todas las plataformas ofrezcan la misma clave de deduplicación.

Esquema de actualizaciones acumulativas, eventos repetidos y nuevos intentos al registrar el consumo
Esquema de actualizaciones acumulativas, eventos repetidos y nuevos intentos al registrar el consumo

Antes de atribuir la diferencia a un cobro incorrecto

Empieza por una petición concreta, no por el total mensual. Contrasta el consumo original con el registro normalizado y comprueba si la diferencia es exactamente el razonamiento añadido otra vez. Después busca eventos repetidos, acumulados sumados y reintentos reales. Solo entonces aplica las tarifas correspondientes al modelo, la fecha, la modalidad de servicio y las categorías de consumo.

El precio de salida puede variar entre modalidades. Por ejemplo, Google publica tarifas Standard y Batch que incluyen pensamiento en la tabla de precios de Gemini. No presupongas que el razonamiento tiene siempre un multiplicador aparte o queda siempre fuera del precio Batch.

Revisa también la entrada y la caché, y separa cargos por herramientas o almacenamiento. La comparativa de costes de las API de Gemini, OpenAI y Claude aborda la elección de proveedor y los escenarios de uso; para conciliar una factura concreta, utiliza las tarifas vigentes de tu modelo y servicio.

¿Puede haber coste si no llega una respuesta visible?

Sí. OpenAI documenta que el límite de salida comprende razonamiento y que una respuesta incompleta puede consumir tokens sin producir texto visible. Contar o tokenizar únicamente el mensaje mostrado al usuario no reconstruye ese consumo. Consulta el estado de la respuesta y sus datos de uso, incluso si el contenido visible está vacío. Guía de razonamiento de OpenAI.

¿Mostrar menos pensamiento en Claude reduce automáticamente la factura?

No. Claude factura el pensamiento generado, aunque la presentación lo resuma u oculte; la generación del resumen no añade un cargo. La longitud del resumen no sustituye al contador de uso. Costes del pensamiento en Claude.

¿Cobrar después esos tokens como entrada sería contarlos dos veces?

No necesariamente. El pensamiento conservado en el contexto puede formar parte de la entrada de una petición posterior, con un comportamiento que depende del modelo de Claude. Son conceptos de uso de peticiones distintas. El error tratado aquí consiste en sumar dos veces la misma parte de la salida de una única petición, no en borrar consumos posteriores legítimos. Funcionamiento del pensamiento en Claude.