Markr (5): cuánto cuesta corregir una redacción con IA
En la entrada anterior dejé Markr desplegado y llamando a la API de Anthropic. Ahora cada corrección se paga, y antes de pensar en precios había que responder a dos preguntas: ¿qué modelo hace falta? y ¿cuánto cuesta de verdad una corrección?
Esta entrada es la historia de cómo el coste por corrección bajó de 0,178 $ a 0,032 $ (y a 0,016 $ en lote) sin cambiar de proveedor. La clave fue medir en lugar de suponer.
La primera estimación estaba mal
Mi primera pregunta fue si Sonnet era suficiente, porque las pruebas se habían hecho con Opus. La primera respuesta fue una estimación: unos 0,10 € por corrección con Opus y unos 0,05 € con Sonnet.
En lugar de fiarnos, lanzamos la evaluación con los siete textos de prueba (de A1 a C2) con los dos modelos, registrando los tokens reales de cada llamada:
| Opus 5.5 | Sonnet 5.5 | |
|---|---|---|
| Entradas del MCER encontradas | 96 % | 100 % |
| Errores detectados | 97 % | 92 % |
| Errores inventados | 0 | 2 |
| Tiempo por corrección | ~55 s | ~35 s |
| Coste medio (50-300 palabras) | 0,16 € | 0,07 € |
La estimación era optimista: el coste real era casi el doble. Sonnet resultaba suficiente, con un pequeño coste en minuciosidad (se le escaparon dos errores de colocación en el texto B2). Y con Opus no salía ningún precio razonable.
Con siete textos anotados por Claude esto es una señal, no una prueba. Pero una señal medida vale más que una estimación de memoria.
¿Dónde se va el dinero?
Al mirar los tokens de una corrección típica de 300 palabras con Sonnet en una sola llamada apareció la sorpresa:
| Tokens | Coste | |
|---|---|---|
| Entrada: instrucciones + texto + bloque MCER | ~30.300 | 0,061 $ |
| Salida: errores, acepciones, estructuras | ~5.600 | 0,056 $ |
| Total | 0,116 $ |
De esos 30.300 tokens de entrada, unos 28.000 eran el bloque de acepciones del MCER: todas las definiciones candidatas de cada palabra del texto, para que el modelo eligiera cuál usa el alumno. El texto del alumno ocupaba unos 400.
Es decir, estábamos pagando al modelo caro por leer un diccionario.
Tres optimizaciones
1. Enviar menos diccionario
El bloque se recortó un 58 % sin perder información útil:
- Agrupar las palabras repetidas: si however aparece cuatro veces, sus acepciones se envían una vez con los cuatro identificadores de ocurrencia.
- Reunir los usos básicos en una sola opción
basic, que no se muestra al alumno. - Quitar lo que nunca se mostraría, como modismos que no pueden cambiar el nivel visible.
2. Repartir el trabajo entre dos modelos
La pregunta lógica fue: "¿eso no implicaría varias ejecuciones? ¿Cómo va a ser más barato?". El coste no depende del número de llamadas, sino de cuántos tokens procesa cada modelo y a qué precio. Así que la corrección se dividió en dos tareas:
- Acepciones, con Haiku 5.5. Lee el bloque grande del MCER y elige la acepción de cada palabra ambigua. Es una tarea sencilla (elegir entre unas pocas definiciones) y Haiku cuesta 0,10 $ por millón de tokens de entrada frente a los 2 $ de Sonnet. Si no hay nada ambiguo, no se llama.
- Revisión, con Sonnet 5.5. Recibe solo el texto y las acepciones ya resueltas, unas pocas líneas, y devuelve errores, estructuras, coherencia y valoración.
Antes: Sonnet lee 30.000 tokens de diccionario → 0,061 $ solo de entrada
Ahora: Haiku lee el diccionario (recortado) → ~0,003 $
Sonnet lee ~2.500 tokens → la entrada casi desaparece
El riesgo estaba en que Haiku decide la acepción y, con ella, el nivel oficial de cada palabra. Por eso las elecciones se validan: solo se aceptan identificadores que estaban entre los candidatos de esa ocurrencia. En la primera evaluación Haiku eligió una vez una acepción que no correspondía, y el sistema la descartó. Para eso está.
Las instrucciones de cada tarea van en el system prompt con caché, y cada tarea se define una sola vez y se puede ejecutar de tres formas: por la API al momento, por lotes o con Claude Code en local.
3. Corrección en lote, a mitad de precio
La Message Batches API de Anthropic cobra la mitad a cambio de no responder al momento: normalmente en menos de una hora, como mucho en 24. Encaja perfectamente con un profesor que sube treinta redacciones el domingo y las necesita el lunes.
Así que, al subir dos o más archivos, el usuario elige: "Ahora" o "En lote (−50 %)", con un aviso claro de que tardará más.
Por dentro, cada corrección en lote es una pequeña máquina de estados que el worker avanza cada dos minutos:
"" → se envía a un lote de acepciones (Haiku) → "senses"
"senses" → lote terminado: se guardan las elecciones → "review_pending"
"review_pending" → se envía a un lote de revisión (Sonnet) → "review"
"review" → lote terminado: se monta el resultado → corregida
Entre fases solo se guardan las elecciones de acepción; el análisis de spaCy se recalcula del texto, que es barato y determinista. Un cerrojo de PostgreSQL (pg_try_advisory_lock) impide que dos ejecuciones se pisen. Si un lote falla o caduca, la corrección queda como error, no consume créditos y se puede reintentar al momento.
El resultado
| Configuración | Entradas MCER | Errores detectados | Errores inventados | Coste medio |
|---|---|---|---|---|
| Opus, una llamada | 96 % | 97 % | 0 | 0,178 $ |
| Sonnet, una llamada | 100 % | 92 % | 2 | 0,081 $ |
| Haiku + Sonnet (por defecto) | 96 % | 86 % | 3 | 0,032 $ |
| Haiku + Opus | 96 % | 92 % | 0 | 0,079 $ |
Con Haiku + Sonnet una corrección pasa a costar 0,032 $ al momento y 0,016 $ en lote: cinco veces menos que la primera versión con Opus y menos de la mitad que Sonnet solo.
Hay que decirlo claro: detecta algo menos, un 86 % de los errores frente al 92 %. Son dos errores sobre 37, y con siete textos no puedo saber si es una diferencia real o ruido entre ejecuciones. Lo sabré cuando tenga redacciones corregidas por profesores.
Mientras tanto, Haiku + Opus cuesta lo mismo que Sonnet solo y no se inventa ningún error: es un buen candidato para un plan premium en el futuro. Cambiar de uno a otro es una variable de entorno (MARKR_MODEL), sin tocar código.
Medir cada corrección
La última pieza fue que cada corrección guarde su consumo real: tokens de entrada, de salida y de caché, modelo, si fue en lote y coste en dólares. Con los precios de cada modelo en un solo sitio:
# Precios por millón de tokens (USD): entrada, salida, lectura de caché.
# La escritura en caché cuesta 1,25 veces la entrada; los lotes, la mitad de todo.
PRICES = {
"claude-haiku-5-5": (0.10, 0.50, 0.01),
"claude-sonnet-5-5": (2.00, 10.00, 0.20),
"claude-opus-5-5": (4.00, 20.00, 0.20),
}
Esto no es solo curiosidad. Es lo que permite fijar precios con datos, detectar si un cambio de prompt dispara el coste y revisar los márgenes si Anthropic cambia sus tarifas.
Con un coste por corrección medido y estable, ya se podía diseñar cómo cobrar. Eso, en la próxima entrada.