Guía Completa de la API Z-Image-Base: Aplicación Práctica de CFG y Negative Prompt
Tutorial completo de la API Z-Image-Base: ajuste del parámetro CFG, uso de negative_prompt, guía de imágenes de referencia, control de intensidad. Incluye ejemplos de código en Python/cURL.
Hola, soy Dora. Es sorprendente cómo una pequeña molestia me llevó a la Z-Image-Base API. Tenía un lote de imágenes de referencia, algo de copy que necesitaba una apariencia consistente, y no suficiente tiempo para supervisar prompts manualmente. Seguía viendo a la gente ajustar configuraciones a mano y publicar resultados puntuales. Está bien para demos. Mi trabajo necesitaba algo que pudiera ejecutar dos veces por semana sin sorpresas. Así que, durante varias sesiones entre enero y febrero de 2026, conecté Z-Image-Base, presté atención a los puntos donde me resistía, y tomé notas sobre lo que realmente lo hacía sentir confiable.
Esto no es un recorrido por todos los parámetros. Son las partes que seguí tocando, más pequeños ajustes que redujeron el esfuerzo mental. Si estás rodeado de herramientas de IA y simplemente quieres una que se comporte bien, esto puede ayudarte.
Configuración Básica de la API
Obtener la Clave API de WaveSpeed
Me registré y obtuve una clave API desde el panel de WaveSpeed. Nada sorprendente. Una pequeña nota: los permisos de la clave estaban delimitados por proyecto. Útil en flujos de trabajo compartidos, pero significa que querrás nombrar los proyectos con claridad desde el principio. Creé un proyecto exclusivamente para experimentos de imágenes para que los registros y las cuotas no se mezclaran con producción.
Si rotas claves (yo lo hago, mensualmente), Z-Image-Base lo manejó limpiamente. Cambié el secreto en mis variables de entorno, ejecuté el script de nuevo y no vi ningún estado de autenticación persistente. Así es como debería funcionar, pero aun así sentí algo de alivio cuando funcionó al primer intento.
Estructura de la URL del Endpoint
La base lucía como una configuración REST estándar con un selector de modelo:
- Base:
https://api.wavespeed.ai - Ruta versionada:
/v1/images - Selector de modelo:
model: "Z-Image-Base"
En la práctica, envié solicitudes POST a /v1/images/generations para ejecuciones solo con prompt, y a /v1/images/edits cuando pasaba una imagen de referencia. Prefiero rutas claras sobre cadenas de consulta cargadas, y esto coincidió con mi forma de pensar. Si tu enrutamiento difiere, el nombre del modelo sigue siendo importante: Z-Image-Base parecía un poco más conservador que los modelos más llamativos, lo cual me gustó.
Configuración del Encabezado de Autenticación
Nada complicado aquí, pero la ortografía exacta importa:
Authorization: Bearer YOUR_WAVESPEED_API_KEYContent-Type: application/jsonpara solicitudes solo con promptContent-Type: multipart/form-dataal subir una imagen
Guardo las claves en .env y las cargo en tiempo de ejecución. Es aburrido, y evita commits accidentales. También: si estás usando scripts desde CI, establece la clave como un secreto enmascarado y evita registrar solicitudes completas. Es obvio, pero vale la pena decirlo. Una línea de registro perdida puede perseguirte. Según las mejores prácticas de seguridad de WaveSpeed, las claves API deben almacenarse en variables de entorno, nunca exponerse en código frontend, y rotarse regularmente.
Explicación Detallada de los Parámetros Principales
prompt - Método de Escritura de Prompts Directos
No complicé demasiado el estilo del prompt. Con Z-Image-Base, los prompts directos simples funcionaron mejor que la prosa elaborada. Escribí la intención primero, las restricciones después:
- “Foto de producto estilo editorial de una taza de cerámica sobre una mesa de lino, suave luz matutina.”
- Luego los detalles: “Aspecto de 35mm, gradación de color neutral, sin texto, fondo despejado.”
Mantuve los verbos fuera a menos que necesitara movimiento. El modelo era estable cuando me mantenía concreto: materiales, luz, sensación de lente, tipo de fondo. Se desviaba cuando agregaba vibes. Si escribía “minimalismo acogedor”, obtenía caos de velas. Cuando escribía “luz suave, una fuente difusa, sin velas”, cumplía.
negative_prompt - Excluir Elementos No Deseados
Al principio me resistí a los negative prompts, pero se convirtieron en mi red de seguridad. Mantuve una base corta que reutilizaba:
- “no text, no watermark, no extra hands, no extra limbs, no logo, no signature, no border”
Agregar esto redujo el tiempo de limpieza. No solucionó todos los casos extremos (los anillos todavía se cuelan en las tazas a veces), pero bajó la tasa de rareza lo suficiente como para dejar de volver a renderizar en lotes pequeños. Cuando necesitaba ángulos de producto estrictos, añadí “no dramatic perspective, no tilt” y obtuve tomas más niveladas.
guidance_scale (CFG) - Controlar el Grado de Cumplimiento del Prompt
Este importó más de lo que esperaba. Mis notas:
- 5–6: relajado, un poco más de textura e improvisación
- 7–8: confiable: lo que usé para la mayoría de las ejecuciones
- 9+: cumplimiento literal, pero a veces iluminación frágil y color más plano
Cuando tenía una buena imagen de referencia, bajé el CFG a 6–7 y obtuve mejor microcontraste. Sin referencia, 7.5 era mi mediana. Según la documentación técnica de Z-Image, el modelo admite Classifier-Free Guidance (CFG) completo, proporcionando precisión para ingeniería de prompts compleja. Por encima de 9 era como pedirle a un amigo cuidadoso que fuera aún más cuidadoso: no estaba mal, simplemente un poco sin vida.
image + strength - Guía de Imagen de Referencia
Este par hizo el trabajo pesado. Adjunté un JPG de referencia único y ajusté strength para controlar cuánto seguía el modelo:
- 0.25–0.35: toque ligero: conserva la paleta y el ambiente
- 0.45–0.6: adherencia sólida: la composición se mantiene cercana
- 0.7+: casi copia: útil para variaciones con pequeños cambios de estilo
No esperaba que 0.5 fuera el punto óptimo, pero lo fue. Suficiente estructura para mantener el diseño, suficiente libertad para ajustes de iluminación. Con valores más altos se volvía obstinado: si la fuente tenía una sombra en el lugar equivocado, el modelo se aferraba a ella. Empecé a guiar el prompt con “shadow on camera-left” y bajé la fuerza en su lugar. Menos reintentos de esa manera.
Una nota práctica: redimensioné las entradas de referencia a 1024 en el lado largo antes de subirlas. Las dimensiones consistentes me dieron recortes y velocidades más predecibles. También ahorró algo de ancho de banda a lo largo de muchas iteraciones.
Implementación de Código
Prueba Rápida con cURL
Cuando conecto un nuevo endpoint, comienzo con cURL solo para ver la forma de la respuesta y los códigos de error.
curl -X POST \
https://api.wavespeed.ai/v1/images/generations \
-H "Authorization: Bearer $WAVESPEED_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"model": "Z-Image-Base",
"prompt": "Editorial-style product photo of a ceramic mug on a linen table, soft morning light. 35mm look, neutral color grading, no text, uncluttered background.",
"negative_prompt": "no text, no watermark, no extra hands, no extra limbs, no logo, no signature, no border",
"guidance_scale": 7.5,
"size": "1024x1024"
}'
Obtuve de vuelta un payload JSON con un array de imágenes (base64 o URLs, según las opciones). Si prefieres URLs directas, establece un objetivo de salida o una bandera de almacenamiento si la API lo admite. Me quedé con base64 en las pruebas y decodifiqué localmente.
Ejemplo Completo en Python
Esto es cercano a lo que ejecuté en un trabajo por lotes un martes por la mañana. Es simple, con suficiente estructura para reintentos.
import os
import base64
import requests
API_KEY = os.getenv("WAVESPEED_API_KEY")
BASE_URL = "https://api.wavespeed.ai/v1"
headers = {
"Authorization": f"Bearer {API_KEY}",
}
def generate_image(prompt, negative_prompt, guidance_scale=7.5, size="1024x1024"):
url = f"{BASE_URL}/images/generations"
payload = {
"model": "Z-Image-Base",
"prompt": prompt,
"negative_prompt": negative_prompt,
"guidance_scale": guidance_scale,
"size": size,
}
response = requests.post(
url,
headers={**headers, "Content-Type": "application/json"},
json=payload,
timeout=60
)
response.raise_for_status()
data = response.json()
b64_string = data["data"][0]["b64_json"]
return base64.b64decode(b64_string)
if __name__ == "__main__":
prompt = (
"Editorial-style product photo of a ceramic mug on a linen table, soft morning light. "
"35mm look, neutral color grading, no text, uncluttered background."
)
negative_prompt = (
"no text, no watermark, no extra hands, no extra limbs, "
"no logo, no signature, no border"
)
try:
image_bytes = generate_image(prompt, negative_prompt)
with open("output.png", "wb") as f:
f.write(image_bytes)
print("Saved output.png")
except requests.HTTPError as e:
print("HTTP error:", e.response.text if e.response else str(e))
except Exception as e:
print("Error:", str(e))
Agregué un timeout de 60 segundos después de que un trabajo se quedara bloqueado por Wi‑Fi inestable. El bloque de excepciones es directo, pero en producción mapeo los códigos de estado (429, 503) a retroceso exponencial.
Ejemplo en JavaScript/Node.js
Para Node, usé fetch con un pequeño helper. Misma idea: mantener la autenticación simple, mostrar los errores con claridad.
import fs from 'node:fs/promises';
import fetch from 'node-fetch';
const API_KEY = process.env.WAVESPEED_API_KEY;
const BASE_URL = 'https://api.wavespeed.ai/v1';
async function generateImage({
prompt,
negativePrompt,
guidanceScale = 7.5,
size = '1024x1024',
}) {
const response = await fetch(`${BASE_URL}/images/generations`, {
method: 'POST',
headers: {
'Authorization': `Bearer ${API_KEY}`,
'Content-Type': 'application/json',
},
body: JSON.stringify({
model: 'Z-Image-Base',
prompt,
negative_prompt: negativePrompt,
guidance_scale: guidanceScale,
size,
}),
});
if (!response.ok) {
const errorText = await response.text();
throw new Error(`HTTP ${response.status}: ${errorText}`);
}
const json = await response.json();
const base64String = json.data[0].b64_json;
return Buffer.from(base64String, 'base64');
}
(async () => {
try {
const prompt =
'Editorial-style product photo of a ceramic mug on a linen table, soft morning light. ' +
'35mm look, neutral color grading, no text, uncluttered background.';
const negativePrompt =
'no text, no watermark, no extra hands, no extra limbs, ' +
'no logo, no signature, no border';
const imageBuffer = await generateImage({ prompt, negativePrompt });
await fs.writeFile('node-output.png', imageBuffer);
console.log('Saved node-output.png');
} catch (err) {
console.error('Error:', err.message);
}
})();
Una vez que esto funcionó, dejé de pensar en la fontanería, que es el objetivo. La Z-Image-Base API no se interpuso en el camino.
Modo Asíncrono vs Modo Síncrono
Probé ambos modos. El síncrono estuvo bien para imágenes individuales o verificaciones rápidas. La latencia se situó en los pocos segundos en promedio para salidas de 1024 cuadrados. Cuando ponía en cola 8–12 renders, cambié a asíncrono para que mi script no se bloqueara en cada uno.
El patrón asíncrono era predecible: enviar un trabajo, obtener un id, sondear un endpoint de estado, luego obtener el resultado cuando state: "succeeded". Establecí un intervalo de sondeo de 2–3 segundos y un techo de 2 minutos. En redes inestables, el modo asíncrono me salvó de los timeouts porque podía reanudar el sondeo sin reenviar el trabajo. Pequeño detalle, gran diferencia con Wi‑Fi de viaje.
Si tu flujo de trabajo es interactivo (ajustar, ver, ajustar), el síncrono es más cómodo. Si es por lotes o programado, el asíncrono mantiene el pipeline más fluido y falla de forma más elegante.
Manejo de Errores
Dos patrones me ayudaron a mantener los errores aburridos.
- Límites de tasa (429): Usé retroceso exponencial con jitter. Comenzar en ~500ms, tope en ~20s, y detener después de 5–6 intentos. Con trabajos asíncronos, simplemente reintentaba la llamada de estado en lugar de volver a encolar el render a menos que la API dijera que el trabajo faltaba.
- Errores de validación (400/422): Estos solían provenir de tipos de contenido no coincidentes o tamaños no admitidos. Cuando veía un 422 en ediciones de imágenes, casi siempre era porque el nombre del campo en form-data estaba mal (
imagevsreference_image). Agregué una pequeña verificación de esquema antes de las solicitudes para evitar esto.
Una nota más: registré model, guidance_scale, size y un hash del prompt. Cuando algo extraño se escapaba, podía reproducirlo exactamente. Esa es la diferencia entre encogerse de hombros y solucionar el problema.
¿Falla Z-Image-Base menos que otros modelos? Difícil de decir. Lo que noté fue que cuando fallaba, los mensajes eran lo suficientemente específicos como para no perder tiempo adivinando. Eso es buena ergonomía.





