Capítulo 2: Construye una línea base de costes útil

Vincula cada llamada al modelo, cada cargo de herramienta y cada reintento a la funcionalidad y la tarea que los causaron.

Publicada el

Leer hasta 7 min completo

Visión general#

Pongamos que un mismo modelo se encarga de la clasificación de soporte, la extracción de documentos y un agente de investigación interno. El panel del proveedor muestra que el modelo costó 2.600 $ el mes pasado, pero probablemente no qué funcionalidad lo gastó ni por qué.

Cada funcionalidad puede tener un problema distinto: prompts sobredimensionados en una, búsquedas de pago repetidas en otra, reintentos en la tercera. Antes de cambiar de modelo, atribuye el gasto a la operación responsable.

Práctica#

Asigna a cada operación un task_id y adjúntalo a cada evento del modelo, cada invocación de herramienta y cada reintento. Guarda el resultado final de la tarea por separado de los resultados de cada petición individual.

Un registro de evento mínimo necesita task_id, operation, event_type, provider, model, los recuentos de tokens de entrada, de salida y en caché cuando estén disponibles, el coste estimado o facturado, el número de intento y la latencia. Añade una marca de tiempo y la versión de la tabla de precios usada para calcular el coste. Para el análisis de costes suelen bastar los metadatos, así que no guardes prompts sensibles solo para construir un panel.

El informe de abajo cuenta tareas aceptadas, así que define aceptada antes de contar. En extracción, una tarea podría tener que pasar tres comprobaciones: la respuesta cumple el esquema (forma), las fechas, las monedas y los totales cumplen las reglas de negocio (coherencia) y los valores coinciden con el documento de origen (exactitud). Cada operación necesita su propia definición, porque una respuesta de soporte o la ejecución de un agente tienen éxito de maneras distintas. Registra cada tarea como accepted, rejected, incomplete o pending_review, para que el trabajo fallido y el inacabado se queden en los datos con su coste.

Cada evento lleva el ID de su tarea. Agrupa los eventos por tarea, une cada tarea con su resultado y divide el coste de toda la cohorte entre las tareas aceptadas.

A partir de ahí, genera un informe breve:

OperaciónCoste mensualTareas aceptadasCoste por tarea aceptada
Extracción1.200 $40.0000,030 $
Soporte600 $30.0000,020 $
Agente de investigación800 $2.0000,400 $

Datos ilustrativos. El agente de investigación tiene el coste unitario más alto; la extracción tiene la factura absoluta más grande. Cuál optimizar depende del valor de la tarea, del trabajo innecesario y del ahorro factible.

En lugar de preguntarte qué modelo es caro, busca la operación que más paga en reintentos, la que reenvía una y otra vez contexto que no cambia, la que llama a más herramientas externas o la que muestra más distancia entre las ejecuciones normales y las costosas.

Lo que pagas se calcula a partir de los registros del proveedor, así que trátalos como la fuente de verdad. Obtén el uso y el coste de las API de uso y costes del proveedor o de las exportaciones de facturación, concílialos cada mes con los totales de tus eventos e investiga cualquier diferencia. La atribución es más fácil cuando el gasto se separa en origen: usa API keys distintas o etiquetas de metadatos por funcionalidad, equipo o entorno, para que el tráfico de pruebas no acabe en la factura de una funcionalidad de producción. Si ya usas una herramienta de observabilidad de LLM, o emites trazas que siguen las convenciones semánticas GenAI de OpenTelemetry (todavía en desarrollo), envía allí el mismo task_id en lugar de construir un segundo pipeline.

Después, asigna responsables a las cifras. Fija presupuestos y alertas por equipo. Usa showback, donde cada equipo ve su propio gasto, o chargeback, donde ese gasto se factura a su centro de coste. Mantén una previsión mensual sencilla por operación: el volumen esperado multiplicado por el coste actual por tarea aceptada. Cuando el gasto real se desvíe de ella, comprueba si ha cambiado el volumen o el coste unitario.

Ledgerline. La tabla de arriba es el primer informe de Ledgerline. Añadir un task_id a cada llamada, búsqueda y reintento llevó dos días. El resultado sorprendió al equipo: el agente de investigación produce menos del 3 % de las tareas aceptadas (2.000 de 72.000) pero el 31 % de la factura (800 $ de 2.600 $). La mayoría de los capítulos a partir de aquí cambian una de estas tres líneas.

En profundidad#

Una tabla de eventos sencilla en PostgreSQL puede sostener este análisis:

sql
CREATE TABLE ai_cost_events (
  task_id TEXT NOT NULL,
  operation TEXT NOT NULL,
  event_type TEXT NOT NULL,
  model TEXT,
  input_tokens BIGINT DEFAULT 0,
  output_tokens BIGINT DEFAULT 0,
  cached_tokens BIGINT DEFAULT 0,
  cost_usd NUMERIC(18, 8) NOT NULL,
  attempt INTEGER DEFAULT 1,
  created_at TIMESTAMPTZ NOT NULL DEFAULT now()
);

Agrega primero los eventos por tarea y después únelos a una tabla de resultados de tareas. Así, una operación con ocho llamadas no cuenta como ocho tareas. Registra de forma explícita los costes fijos excluidos y los eventos incompletos, para que una factura incompleta nunca se presente como coste total.

Si la mezcla de tareas cambia de un mes a otro, el coste unitario medio puede moverse sin que cambie la eficiencia del modelo. Compara cosas comparables, o desglosa la métrica por tipo de tarea y complejidad.

Define la aceptación antes de comparar costes de modelos#

La palabra aceptada necesita un significado operativo. Si no, el denominador se convierte en una cuestión de opinión, y la implementación más barata a menudo parecerá ganar porque descarta los casos difíciles.

Las tres comprobaciones de extracción necesitan herramientas distintas. Un validador de esquema se ocupa de la forma, y el código de la aplicación puede ocuparse de parte de la coherencia. La exactitud puede necesitar una comparación con el documento de origen o una revisión, porque una respuesta puede pasar las dos primeras comprobaciones y seguir siendo incorrecta.

En un asistente de documentación, una respuesta aceptada podría tener que responder a la pregunta, citar una fuente vigente y autorizada y evitar afirmaciones sin respaldo. En un agente de programación, la aceptación podría exigir que el cambio pedido esté presente, que no haya modificaciones ajenas y que se cumplan las condiciones de aceptación definidas. Una tarea de clasificación puede tener una etiqueta de referencia determinista; una tarea de investigación abierta puede necesitar una revisión graduada y estados explícitos de sin resolver.

Indica cuáles de los cuatro estados de tarea entran en tu denominador. En un informe mensual, define la cohorte y el corte: ¿tareas creadas este mes o tareas completadas este mes? Si mezclas las dos, el coste y las tasas de aceptación pueden no cuadrar solo porque algunas ejecuciones cruzan el cambio de mes.

Informa de la tasa de aceptación junto al coste por tarea aceptada. Cualquiera de las dos cifras por sí sola puede inducir a error:

OperaciónIniciadasAceptadasTasa de aceptaciónCoste atribuibleCoste / aceptada
Extracción de facturas10.0009.60096 %300 $0,03125 $
Síntesis de investigación1.00085085 %425 $0,50 $

Escenario ilustrativo. Las dos operaciones producen tipos de resultado distintos, así que sus costes unitarios no se pueden clasificar directamente uno frente al otro.

Un cálculo que une los eventos con los resultados#

Esta consulta de PostgreSQL hace explícito el denominador. Toma como cohorte las tareas iniciadas en el mes, de modo que el trabajo rechazado, incompleto y aún pendiente mantiene su coste en el numerador en lugar de desaparecer del informe. Supone una fila por tarea con su estado actual, y que la tabla de eventos incluye todos los costes variables directamente atribuibles. La capacidad fija compartida y la revisión humana necesitan sus propias asignaciones antes de que esto se convierta en un informe de TCO completo.

sql
WITH task_cost AS (
  SELECT task_id, SUM(cost_usd) AS cost_usd
  FROM ai_cost_events
  GROUP BY task_id
), cohort AS (
  SELECT t.task_id, t.operation, t.status,
         COALESCE(c.cost_usd, 0) AS cost_usd
  FROM ai_tasks AS t
  LEFT JOIN task_cost AS c USING (task_id)
  WHERE t.created_at >= DATE '2026-10-01'
    AND t.created_at < DATE '2026-11-01'
)
SELECT operation,
       COUNT(*) AS started_tasks,
       COUNT(*) FILTER (WHERE status = 'accepted') AS accepted_tasks,
       COUNT(*) FILTER (WHERE status = 'pending_review') AS pending_tasks,
       SUM(cost_usd) AS variable_cost_usd,
       SUM(cost_usd) / NULLIF(
         COUNT(*) FILTER (WHERE status = 'accepted'), 0
       ) AS cost_per_accepted_task
FROM cohort
GROUP BY operation;

La consulta requiere una tabla ai_tasks con task_id, operation, created_at y status (accepted, rejected, incomplete o pending_review). Trata el mes como provisional mientras pending_tasks siga siendo significativo: cada tarea pendiente que acaba aceptada reduce el coste por tarea aceptada. En la contabilidad real, distingue los eventos de uso con coste cero o desconocido de los eventos confirmados como gratuitos. Concilia las sumas con las facturas, porque los cálculos de precios pueden pasar por alto descuentos por tokens en caché, cargos de herramientas o registros de uso que llegan con retraso.

Documenta la definición de aceptación y las exclusiones contables junto al informe, para que otro ingeniero pueda reproducir las cifras.

Las definiciones de las tablas y la consulta mensual también están en un archivo SQL que puedes descargar, con la tabla de tareas añadida.

Referencias: API de uso y costes de OpenAI, API de uso y costes de Anthropic, Spans de cliente GenAI de OpenTelemetry.