No me fío del modelo
Uso un modelo de lenguaje para escribir anuncios de producto a partir de una imagen: título, trece etiquetas, descripción y texto alternativo. Escribe bien. Aun así, trato todo lo que devuelve como trataría el campo de un formulario que llega de internet: como una entrada que hay que comprobar antes de usarla.
Esto es lo que hay alrededor del modelo. La mayor parte no es inteligencia artificial.
1. Los límites son datos, no frases en una instrucción
Etsy admite títulos de 140 caracteres como máximo y trece etiquetas de hasta 20 caracteres, sin repetir. Lo fácil es escribir eso en la instrucción y confiar.
En vez de eso, los límites viven en un bloque de datos al principio de un documento:
verified_date: "2026-07-11"
title:
max_chars: 140
forbidden_chars: ["$", "^", "`", ".", "°"]
max_allcaps_words: 3
tags:
count: 13
max_chars_per_tag: 20
allow_duplicates: false
alt_text:
max_chars: 250
Ese bloque es la única fuente de verdad. El código no tiene ningún número escrito a mano: lo lee en cada petición. El mismo bloque se le pasa al modelo y al validador, así que los dos trabajan con las mismas cifras. Si el límite cambia, se edita un fichero y no hay que tocar nada más.
2. Los límites caducan
Las normas de una plataforma cambian sin avisar, y lo que el modelo recuerda de ellas es la fuente menos fiable de todas.
Por eso el bloque lleva verified_date. Pasados 30 días, la aplicación avisa de que están caducados. Hay una acción para volver a verificarlos: el modelo busca en las fuentes oficiales y propone los cambios como un diff sobre el bloque. Nunca se aplica solo; lo confirmo yo.
En el documento, cada límite lleva su fuente y la fecha en que se leyó. Lo que no pude confirmar está marcado como sin verificar.
3. El servidor valida, y distingue errores de avisos
El modelo responde en JSON. El servidor lo analiza y lo pasa por un validador que no tiene nada de inteligente: cuenta caracteres y compara.
Hay dos niveles:
- Errores: lo que la plataforma rechazaría. Título demasiado largo, un carácter prohibido, que no sean exactamente trece etiquetas, una etiqueta de más de 20 caracteres, etiquetas repetidas, HTML en la descripción.
- Avisos: mis propias reglas de estilo. Que el título no esté entre 80 y 120 caracteres, que aparezca una frase que no quiero, que el texto alternativo parezca una lista de palabras clave. No bloquean; se muestran.
La diferencia importa. Un error significa que el resultado no se puede usar. Un aviso significa que quiero mirarlo.
El validador tiene 20 pruebas propias. Es la parte del sistema que tiene que ser exacta, así que es la que está probada.
4. Un solo reintento, con el error concreto
Si la validación falla, el servidor vuelve a preguntar una vez. No le dice «inténtalo de nuevo»: le manda su respuesta anterior y la lista exacta de fallos.
for attempt in (1, 2):
raw = await ask_model(prompt)
listing = parse(raw)
result = validate(listing, limits)
if result["ok"]:
break
if attempt == 1:
prompt = base_prompt + previous(raw) + what_to_fix(result["errors"])
¿Por qué solo uno? Porque si el modelo falla dos veces con el error delante, un tercer intento es tirar una moneda, y la causa suele estar en otra parte: reglas que se contradicen. El mensaje que veo en ese caso me manda a revisar el fichero de reglas, no a pulsar otra vez.
Tras el segundo fallo el resultado se devuelve igualmente, con los campos inválidos marcados en rojo. No se oculta ni se arregla en silencio. Decido yo.
5. Lo que tiene que ser idéntico no lo escribe el modelo
Todas las descripciones llevan un bloque de cinco líneas con las características del papel y la impresión. Tiene que ser igual en todos los anuncios, letra por letra.
Pedirle a un modelo que copie un texto literal funciona casi siempre. Ese casi es el problema.
Así que el modelo no lo copia: escribe un marcador, [[PRACTICAL_BLOCK]], y el servidor lo sustituye por el texto real. El bloque sale idéntico byte a byte porque lo pone el código. La regla general: al modelo se le pide que señale dónde va algo, no que lo reproduzca.
6. Una regla que detiene la generación
Antes de escribir nada, el modelo evalúa si la imagen es o parece una reproducción de una obra con derechos vigentes: un personaje, una marca, un artista vivo. Si lo parece, devuelve el motivo y ahí se acaba. No se genera texto, no hay reintento y la tarjeta aparece en rojo.
Es la única regla que va antes que el resto, porque es la única cuyo fallo no se arregla editando un título: en un marketplace, una reclamación de propiedad intelectual puede cerrar la tienda.
Tiene un límite evidente: ese juicio también es una salida del modelo, y puede equivocarse. Por eso la regla es conservadora (basta con que lo parezca) y yo veo la imagen igualmente. Reduce el riesgo; no lo elimina.
7. Lo pequeño
- Los ficheros de impresión pesan más de 100 MB. Al modelo le llega un JPEG reducido.
- La única herramienta que puede usar es leer ese fichero. Nada más.
- Cada petición tiene un tiempo máximo. Si lo agota, veo un mensaje claro, nunca una traza de error.
- La cola procesa los anuncios de uno en uno, y de cada uno se guardan los tokens consumidos.
8. Lo que no compruebo
El validador comprueba la forma, no la verdad. No sabe si la descripción cuenta lo que hay en la imagen, ni si el título es el que un comprador teclearía. Eso lo leo yo.
Por eso lo que sale del sistema es un borrador con marcas verdes y rojas, no un anuncio publicado. Publicar es un paso manual.
9. El patrón
Sirve para cualquier trabajo en el que la salida de un modelo acabe en un sitio con reglas:
- Escribe las restricciones como datos, con fecha y fuente.
- Dale los mismos datos al modelo y al validador.
- Valida en código todo lo que se pueda contar.
- Reintenta una vez, con el error exacto.
- Si vuelve a fallar, que se vea.
- Lo que tenga que ser exacto, que lo haga el código.