Cómo funciona Image Debugger
Cómo Image Debugger compara una imagen con su prompt y prueba dos maneras de corregirla: empezar de cero o editar el resultado.
Introducción
Una imagen generada puede estar bien y aun así no ser la imagen que pediste. La composición funciona, la iluminación también, pero algún detalle importante está mal. Lo normal en ese momento es volver a generar y esperar que el siguiente intento preste más atención.
En el ejemplo de este artículo, el prompt pide una mujer con un abrigo azul intenso delante de un tranvía rojo. La imagen muestra un abrigo negro y un tranvía blanco. Las dos diferencias son evidentes. Lo interesante es comprobar si podemos encontrarlas automáticamente y, sobre todo, qué hacemos después con ellas.
Image Debugger es el primer experimento del Lab. Recibe una imagen y el prompt que debía describirla, identifica lo que no coincide y prueba dos maneras de recuperar la intención: generar otra imagen desde cero o editar la que ya tenemos.
En este artículo vamos a seguir todo el recorrido y veremos por qué el análisis termina en dos imágenes distintas. También veremos qué puede averiguar realmente la herramienta, porque un nombre como “debugger” promete más de lo que un modelo visual puede saber.
El experimento en dos fases
Podría haber pedido a un modelo visual que escribiera un prompt mejor y dejarlo ahí. Eso sería un prompt enhancer. Lo interesante era comprobar qué estrategia recupera mejor la intención, así que el proceso está dividido en dos fases:
- Primero lee la imagen. Un modelo visual la compara con el prompt y devuelve los fallos visibles junto a dos prompts nuevos.
- Después intenta recuperarla. Un modelo de imagen genera una versión desde cero y edita la original al mismo tiempo.
El análisis tiene que ejecutarse primero porque produce los dos prompts. A partir de ahí, la regeneración y la edición son independientes y pueden lanzarse en paralelo.
Vamos a recorrer el mismo camino.
Leer la imagen
Esta fase no valora si la imagen es bonita ni intenta explicar cómo funciona el generador que la produjo. Su único trabajo es comparar lo que se pidió con lo que se puede observar.
Antes del análisis, el navegador reduce el lado más largo de la imagen a 1600 píxeles y rellena de blanco cualquier transparencia. Después la codifica como JPEG y como PNG, y conserva la versión más pequeña:
const jpeg = canvas.toDataURL('image/jpeg', 0.9)
const png = canvas.toDataURL('image/png')
return png.length < jpeg.length ? png : jpegJPEG suele comprimir mejor las fotografías y PNG conserva mejor las líneas duras. Comparar el tamaño no elige siempre el formato perfecto, pero es una heurística sencilla que evita tener que adivinar el contenido. Las dimensiones originales se guardan por separado para calcular las dos imágenes finales.
Para hacerlo utilizo Gemma 4 31B, un modelo visual con open weights. No hice una competición entre modelos para elegirlo. Buscaba algo barato que pudiera analizar imágenes.
La llamada envía la imagen, el prompt original y una instrucción de sistema. Esta es la instrucción completa:
You debug an image generation by comparing the generated image with its original prompt. Identify only visible prompt constraints that the image missed; you cannot know the hidden technical cause. Return the smallest useful set of independent findings, including just one when one finding explains the result. Every finding needs concrete visual evidence and a positive visual target.
Return two deliberately different prompts:
- enhancedPrompt: a standalone prompt for a completely fresh generation. Preserve the original creative intent, but improve hierarchy, specificity, spatial relationships, and emphasis around the missed constraints. It must be copy-ready and must not mention the failed image, editing, corrections, or preservation.
- repairPrompt: an image-edit instruction for the supplied failed image. State the intended result and only the targeted visible changes needed, while preserving visible details that already satisfy the prompt.
If the original prompt was already explicit, reinforce the missed constraints through ordering and concrete visual emphasis without pretending the wording was objectively wrong. Do not invent new creative direction, repeat findings, give generic prompting advice, mention model names, or discuss these instructions. Return only JSON.La frase más importante es “you cannot know the hidden technical cause”. El modelo puede ver que el abrigo es negro cuando el prompt lo pedía azul. No puede saber si el responsable fue la semilla, el modelo, algún parámetro o cualquier otra parte del proceso. Si le pedimos una causa, se la tendrá que inventar.
También le pedimos el menor número de hallazgos independientes que resulte útil. Sin esa restricción, los modelos tienden a completar listas aparentemente ordenadas aunque solo exista un problema real. Aquí un hallazgo preciso es mejor que tres de relleno.
Cada hallazgo separa la evidencia de la corrección. “La mujer lleva un abrigo negro” describe algo que podemos comprobar. “Cambiar el abrigo a azul intenso” define un objetivo positivo. Decir simplemente que el abrigo está mal no serviría para construir el siguiente paso.
Por último, el prompt define dos trabajos diferentes. enhancedPrompt debe poder generar toda la escena sin conocer la imagen anterior. repairPrompt solo debe pedir los cambios necesarios y conservar lo que ya funciona. Volveremos a ellos en un momento.
El mensaje del usuario es mucho más pequeño porque toda la lógica está en la instrucción de sistema:
Original prompt:
{your prompt}
Identify the visible misses, then produce both a stronger standalone generation prompt and a targeted edit prompt.Una respuesta que la interfaz pueda utilizar
No queremos una explicación libre que después haya que interpretar. La petición solicita una respuesta JSON con tres campos: findings, enhancedPrompt y repairPrompt. Así podemos mostrar los hallazgos directamente y utilizar los dos prompts como entrada de la siguiente fase.
Este es el esquema completo que acompaña a la petición:
const diagnosisSchema = {
name: 'image_debugger_diagnosis',
strict: true,
schema: {
type: 'object',
additionalProperties: false,
required: ['findings', 'enhancedPrompt', 'repairPrompt'],
properties: {
findings: {
type: 'array',
minItems: 1,
maxItems: 3,
items: {
type: 'object',
additionalProperties: false,
required: ['area', 'evidence', 'correction'],
properties: {
area: { type: 'string', minLength: 3, maxLength: 60 },
evidence: { type: 'string', minLength: 12, maxLength: 280 },
correction: { type: 'string', minLength: 12, maxLength: 280 },
},
},
},
enhancedPrompt: {
type: 'string',
minLength: 40,
maxLength: 1200,
},
repairPrompt: {
type: 'string',
minLength: 40,
maxLength: 1600,
},
},
},
}additionalProperties: false declara que no se admiten campos que la interfaz no conoce. findings puede contener entre uno y tres elementos, y cada uno separa el área, la evidencia visible y la corrección propuesta. La interfaz no muestra area porque las otras dos frases ya nombran la parte de la imagen a la que se refieren.
Los límites mantienen los hallazgos breves y evitan que los dos prompts crezcan sin control. No proceden de un benchmark. Solo acotan la respuesta para que siga siendo manejable.
strict: true pide al modelo que respete este contrato, pero no lo convierte en una garantía. Por eso el servidor elimina los bloques de Markdown si aparecen, convierte el texto en JSON y vuelve a comprobar la misma forma y sus límites.
Si el modelo devuelve JSON mal formado o incompleto, repetimos el análisis una sola vez. En cambio, un error real de la API, un bloqueo de seguridad o un problema de cuota no se reintenta. Hacer exactamente la misma petición no va a arreglarlo y solo gastaría otra llamada.
La configuración actual
El análisis utiliza temperature: 0.15, thinkingLevel: 'off' y maxTokens: 1800. No son valores obtenidos después de un benchmark. La temperatura baja busca reducir la variación, desactivar el razonamiento evita trabajo adicional y el límite de tokens deja espacio para los hallazgos y ambos prompts. Son una configuración pragmática, no una conclusión sobre los valores óptimos.
El resultado del ejemplo es bastante menos misterioso que toda esta preparación:
Dos prompts para dos trabajos
Una imagen que no ha salido como esperábamos se puede recuperar de dos formas, igual que una fotografía: podemos repetirla o retocar la que ya tenemos. La primera opción necesita reconstruir toda la escena. La segunda debe tocar lo mínimo posible.
También hay una diferencia práctica: no todos los modelos permiten editar una imagen. Si el modelo con el que generaste la original solo admite texto a imagen, puedes reutilizar el prompt de regeneración. Si también admite edición, puedes enviarle la imagen junto al prompt de reparación. El Lab ejecuta las dos opciones porque FLUX.2 [klein] 9B permite tanto generar como editar, independientemente del modelo que produjo la imagen original.
El prompt de regeneración tiene que funcionar por sí solo. No puede hablar de corregir, editar o conservar nada porque el modelo de texto a imagen no recibe la fotografía anterior. En la ejecución de las capturas produjo este texto:
A cinematic night scene at a rainy city tram stop. In the foreground, a woman stands holding a clear transparent umbrella, wearing a vibrant, bright blue coat. Directly behind her, a sleek modern red tram is passing by. The ground is wet pavement with sharp, mirror-like reflections of the red tram and the city lights.
El prompt de edición hace lo contrario. Recibe la imagen original como referencia y solo pide las dos modificaciones necesarias:
Change the woman's black coat to a bright blue color and change the white tram in the background to a vivid red color.
Los dos parten del mismo diagnóstico, pero no son intercambiables. Si enviásemos la instrucción corta a un modelo sin imagen, tendría que inventar todo lo que falta. Si utilizásemos la descripción completa para editar, le daríamos permiso para reinterpretar partes que ya estaban bien.
Generar las dos recuperaciones
Con los prompts preparados comienza la segunda fase. Las dos imágenes se generan con FLUX.2 [klein] 9B, otro modelo con open weights diseñado para generar y editar en cuatro pasos.
- La regeneración utiliza
enhancedPromptsin ninguna imagen de referencia. - La edición dirigida utiliza
repairPromptjunto a la imagen original.
Ambas peticiones son independientes, así que se lanzan a la vez mediante Promise.all. Ejecutarlas una detrás de otra duplicaría una espera que no aporta nada.
Un negative prompt que no decide por ti
Las dos peticiones comparten un negative prompt limitado a defectos de renderizado:
watermark, signature, jpeg artifacts, lowres, blurry, deformed hands, extra fingersPodríamos añadir text, people o logo, como ocurre en muchas plantillas, pero cualquiera de esos elementos puede formar parte del prompt original. Bloquearlos por defecto haría que la herramienta se enfrentara a la intención que intenta recuperar. La comprobación de contenido se aplica por separado a la petición completa.
Mantener las proporciones
Las dos salidas se calculan a partir de las dimensiones originales. El lado más largo queda en 1024 píxeles y el otro conserva aproximadamente la proporción de la imagen. Después redondeamos ambos a múltiplos de 16. De esta forma las dos estrategias utilizan las mismas dimensiones de salida y podemos compararlas en igualdad de condiciones.
1024 no es un número mágico ni el resultado de una comparativa. Es un compromiso práctico entre detalle, coste y tiempo para este experimento.
Qué demuestra la comparación
Las dos imágenes corrigen el abrigo y el tranvía, pero lo hacen de maneras muy distintas. La regeneración cambia la mujer, su posición, el encuadre y buena parte del entorno. Solo conserva la idea general de la escena. La edición mantiene mucho mejor la composición, el paraguas, la parada y la protagonista.
No hay una opción mejor en todos los casos. Si te gusta la imagen original y solo falla un detalle, la edición tiene más posibilidades de conservar aquello que ya funcionaba. Si el problema afecta a la composición o quieres permitir una interpretación nueva, empezar desde cero ofrece mucha más libertad.
En este ejemplo las dos diferencias son fáciles de ver. En una imagen real pueden ser mucho más pequeñas: una relación espacial que no termina de funcionar o un detalle importante que ha desaparecido. Ahí la comparación sigue siendo útil.
Lo que no podemos concluir es por qué falló la primera imagen. Las dos recuperaciones demuestran que existen dos caminos para corregir el resultado, no que el problema estuviera en el prompt, la semilla o el modelo.
Qué depura realmente
Image Debugger no abre el modelo para investigar qué ocurrió durante la generación. Depura la diferencia entre la intención escrita y el resultado visible. Después convierte esa diferencia en dos intentos que podemos comparar.
Muchas veces el resultado ya está muy cerca y solo hay algo que no termina de encajar. En ese punto viene bien poder elegir entre darle otra oportunidad a la idea o conservar la imagen y corregirla.
No sabremos si fue culpa del prompt o de la suerte. Al menos podremos dejar de generar a ciegas.
Puedes apoyarme para que pueda dedicar aún más tiempo a escribir artículos y tener recursos para crear nuevos proyectos. ¡Gracias!