Token overhead per archetype< a docstring paragraph tokens 218 436 654 872 api_backend 412 cli_tool 287 ml_pipeline 759 docs_writer 198 library 345 data_etl 612 ui_component 256 positioning_doc 178 avg = 374 overhead about 374 tokens avg — paid once per generation

What it actually costs to embed quality contracts at every stage

1 de junio de 2026·Implementations

"Surface the contract at every stage" suena caro. La primera reacción que tuve cuando refactorizamos para hacerlo fue exactamente esa: vamos a triplicar tokens, esto se va a poner inviable. Después medimos. El overhead promedio fue ~374 tokens por respuesta, con un máximo de 759 en el arquetipo más pesado. Menos que un párrafo de docstring decente.

Lo escribo porque la intuición me había mentido durante semanas, y creo que es una intuición común: si haces explícito lo que antes era implícito, parece que estás duplicando trabajo. A veces sí. A veces — como acá — el costo es bounded, comprimible, y mucho más bajo que el rework que evita. Pero la única forma de saberlo es medir, no opinar.

El cambio que disparó la medición

Antes, el contrato de calidad sólo aparecía en validate(), al final del pipeline. El modelo generaba skeleton, contracts_and_wiring y logic ciego respecto a contra qué iba a ser evaluado. La validación llegaba, fallaba en dimensiones que el modelo nunca consideró, y había que regenerar. El loop era frustrante: el modelo no era malo, simplemente no sabía qué le íbamos a pedir.

La hipótesis fue: si el modelo conoce el rúbrico desde el primer stage, va a optimizar hacia él en cada paso. Va a tomar decisiones tempranas — qué interfaces declarar, dónde poner los logs, qué tipos elegir — que ya estén alineadas con lo que vamos a evaluar al final. Eso requiere meter el contrato en skeleton(), en contracts_and_wiring(), en logic(). Tres lugares más donde antes no estaba.

Mi intuición inmediata fue "esto va a triplicar tokens y va a hacer que el costo se dispare". La intuición de cualquier persona que mira el cambio en abstracto es la misma. Y es razonable: estás repitiendo la rúbrica completa cuatro veces en vez de una. Aritmética simple dice que el costo se multiplica.

Lo que la aritmética simple no captura es la naturaleza de los tokens del rúbrico. No son prosa expandida — son una estructura compacta con dimensiones, pesos y criterios. Esa fue la primera sorpresa cuando vi los números.

Lo que medimos

El número está documentado en paper §4: ~374 tokens promedio de overhead por respuesta. El máximo, 759 tokens, ocurre en el arquetipo con más criterios de self_challenge cargados. La medición fue sobre 10 arquetipos built-in en la versión previa a la refactorización a 8, ejecutando el pipeline completo sobre prompts representativos de cada arquetipo.

374 tokens es menos que un párrafo de docstring decente. Para poner escala: el contrato cabe holgado dentro del overhead típico que cualquier prompt serio carga en system instructions. No es un costo invisible — es un costo plano, predecible, medido. Si lo conviertes a dólares con precios actuales de inferencia, está en el orden de fracciones de centavo por respuesta generada.

La otra cosa que la medición mostró es que la distribución es bastante estable. No hay arquetipos que se disparen a miles de tokens. El peor caso es ~2x el promedio, no 10x. Eso es lo que vuelve la decisión defendible: el upper bound está acotado, lo que significa que puedes planificar capacity y budget sin escenarios catastróficos.

La estabilidad también dice algo sobre el diseño del rúbrico. Si el peor arquetipo costara 10x más que el promedio, significaría que la rúbrica de ese arquetipo está sobrecargada — probablemente con criterios que se podrían factorizar. El hecho de que la dispersión sea baja es señal de que las rúbricas están bien dimensionadas entre sí.

Por qué el costo es bounded

Tres razones, en orden de importancia. La primera: el rúbrico es declarativo y comprimible. No es prosa explicando el contrato — es una estructura corta, con dimensiones, pesos y criterios listados en formato denso. El modelo lo lee como referencia, no como contexto narrativo. La densidad informacional por token es alta.

La segunda: el contrato se envía una vez por stage, no por iteración interna del modelo. Si el stage logic() hace razonamiento multi-paso internamente — y los modelos modernos suelen hacerlo cuando el problema lo amerita — el contrato no se duplica en cada paso de pensamiento. Está en el prompt de entrada y ahí queda. El costo escala linealmente con el número de stages, no con la profundidad del razonamiento dentro de cada stage.

La tercera, y la más importante a largo plazo: el modelo ahorra trabajo de regeneración, que es donde el costo real se acumula. Cuando un stage falla la validación al final, no se regenera el último 20% — se regenera todo, porque las decisiones tempranas pueden ser las que estén mal. Pagar 374 tokens upfront para evitar regenerar 10.000 tokens cuando algo se rompe es el trade obvio. La intuición de "esto va a costar más" omite el costo del rework, que es el costo dominante en cualquier pipeline de generación serio.

Cómo lo trackeamos en runtime

La medición no fue manual. La librería tiene Tracer / Trace / Span propios, con ledger de tokens y costo. Cada stage abre un span, registra input y output tokens, suma al trace, y al final el tracer reporta. Es el mismo patrón que usa cualquier APM serio — pero aplicado al consumo de inferencia, no a latencia de operaciones HTTP.

La decisión de no usar OpenTelemetry directamente fue intencional. OTel está optimizado para spans de microsegundos en sistemas distribuidos. Para tracear stages de generación que duran segundos y producen tokens contables como recurso económico, una estructura más liviana y más específica funciona mejor. La interoperabilidad con OTel se puede agregar como exporter si alguien la necesita.

El tracer se integra con un budget por benchmark. --budget 5.0 corta antes de que el gasto explote, y eso es útil cuando estás iterando sobre 100 prompts y un bug en el orquestador te puede dejar una cuenta inesperada. Es la versión de un breaker, aplicada al gasto. Para quien viene de operar APIs externas con consumo variable, el patrón es familiar; lo nuevo es aplicarlo al gasto en inferencia.

Cada stage imprime su entrada y salida en tokens cuando corres el benchmark con verbose. Eso te permite ver dónde se acumula el costo. Casi siempre es logic() — porque ahí está la implementación real. skeleton() y contracts_and_wiring() son baratos comparados, lo que también significa que cortar temprano cuando uno de esos falla es muy efectivo: te ahorras el stage caro.

Tracer / Trace / Spanbudget enforcement at the boundary Tracer (root) budget=$5.00 cost ledger --budget cutoff Trace (per request) req_1 req_2 req_3 Span (per stage) skeleton contracts logic validate --budget 5.0 triggers automatic cutoff

Lo que todavía no medimos

No medimos point-in-time la mejora de calidad con vs sin el contrato surface-at-every-stage. Sé que mejoró cualitativamente porque vi menos regeneraciones, vi outputs que pegaban mejor con la rúbrica desde el primer intento, vi menos casos de "está casi bien pero le falta logging". Pero el protocolo riguroso para reportar esa mejora — con baselines, con métricas consistentes, con varianza controlada — está descrito en paper §5, no en el primer paper. Es la diferencia entre saber que algo funciona y poder defenderlo con números frente a alguien escéptico.

Tampoco tengo ROI duro del overhead vs el rework que evita. Hay señal cualitativa fuerte — menos failures aguas abajo, menos regeneraciones completas, menos turns de iteración por output aceptable — pero no hay un número limpio que diga "por cada token de overhead te ahorras X tokens de rework". Calcular ese ratio requiere comparar dos pipelines en paralelo durante un período largo, y la economía del esfuerzo todavía no justifica esa medición específica. Es trabajo pendiente.

Y no sé todavía cómo se comporta con modelos locales chicos. El contrato puede ser demasiado pesado en un modelo de 7B parámetros, no porque cueste mucho — el costo es despreciable cuando corres localmente — sino porque puede saturar el contexto efectivo del modelo y degradar la calidad de la generación. Está en curso medirlo. La hipótesis preliminar es que los modelos chicos necesitan rúbricas más compactas, no el mismo rúbrico recortado.

Transferable Principle

El overhead de governance es medible. No es especulación, no es "siento que cuesta más" — es una métrica que entra en un dashboard al lado de latencia y error rate. Una vez que está medida, deja de ser tema de discusión y empieza a ser dato de decisión.

Si no estás midiendo el costo de tus quality contracts, no puedes decidir cuánto contrato querer. Vas a oscilar entre "esto cuesta mucho, lo saco" y "esto sirve, lo dejo" sin datos para apoyar ninguna de las dos posiciones. Esa oscilación es cara — más cara que el overhead que estás tratando de evitar.

La pregunta correcta no es "¿cuánto cuesta el overhead?" — es "¿cuánto rework previene?". El segundo número casi siempre justifica al primero, pero sólo lo sabes si los mediste a ambos. Y hasta que no los mides a ambos, cualquier discusión sobre si vale la pena es opinión disfrazada de análisis.

Pregunta para comentarios: ¿están midiendo el costo de governance de IA en tokens? ¿O todavía es un "feeling"?

#AI #GenAI #Engineering #CodeQuality #Architecture

Escríbenos por WhatsApp