The 5-Stage Architecture
Stage 1: Prompt Engineering
↓
Stage 2: Generation
↓
Stage 3: Post-Processing
↓
Stage 4: Quality Check
↓
Stage 5: Delivery
Every production system — whether it generates product images, marketing videos, or music — follows this architecture. The specific tools change, but the stages don't.
Stage 1: Prompt Engineering
The prompt is not a string — it's a structured input with variables, templates, and style guidance.
# Prompt template with variable substitution
PROMPT_TEMPLATE = """
{subject}, {style}, {lighting}, {quality_modifiers}
""".strip()
# Variables injected per generation
variables = {
"subject": "a red sneaker on a white pedestal",
"style": "professional product photography",
"lighting": "studio lighting, soft shadows",
"quality_modifiers": "8k, ultra detailed, sharp focus"
}
prompt = PROMPT_TEMPLATE.format(**variables)
Key components:
- Templates: reusable prompt structures with variable slots
- Style modifiers: consistent quality tags ("8k, ultra detailed, sharp focus")
- LoRA injection: brand-specific style adapters loaded into the model
- Negative prompts: what to avoid ("blurry, deformed, low quality, watermark")
Stage 2: Generation
The generation stage calls the model API with the engineered prompt and parameters.
generation_params = {
"prompt": prompt,
"negative_prompt": "blurry, deformed, low quality, watermark",
"image_size": {"width": 1024, "height": 1024},
"num_inference_steps": 4, # FLUX Schnell: 4 steps
"guidance_scale": 7.5, # CFG scale
"seed": 42, # Reproducibility
}
Key parameters:
- Steps: 4 (Schnell) to 50 (high quality) — diminishing returns past 30
- Guidance scale: 1-15 — controls prompt adherence vs creative freedom
- Seed: fixed seed = reproducible results; random = variety
- Image size: 1024x1024 (FLUX/SDXL native), 512x512 (SD 1.5)
Stage 3: Post-Processing
Post-processing transforms the raw generation into a production-ready asset.
| Technique | Tool | When to Use |
|---|
| Upscaling | Real-ESRGAN (4x) | Resolution too low for print/web |
| Face restoration | CodeFormer | Portraits with distorted faces |
| Background removal | rembg | Product cutouts, compositing |
| Color correction | PIL/OpenCV | White balance, exposure fixes |
| Inpainting | LaMa/SDXL inpainting | Fix specific regions |
| Watermark removal | LaMa | Remove accidental watermarks |
# Post-processing chain
raw_image = generate(prompt)
upscaled = upscale(raw_image, scale=4)
restored = face_restore(upscaled) if has_faces(upscaled) else upscaled
final = remove_background(restored) if product_shot else restored
Stage 4: Quality Check
Quality check is what separates production systems from demos. You don't ship every generation — you score it and reject bad outputs.
| Metric | What It Measures | Threshold |
|---|
| CLIPScore | Text-image alignment (0-1) | > 0.25 |
| Aesthetic Score | Visual appeal (1-10) | > 5.0 |
| ImageReward | Human preference (-1 to 2) | > 0.0 |
| Artifact detection | Blurring, distortion | < 10% pixels |
# Quality gate
clip_score = compute_clip_score(image, prompt)
aesthetic = compute_aesthetic_score(image)
if clip_score < 0.25 or aesthetic < 5.0:
logger.warning(f"Quality gate FAILED: CLIP={clip_score:.3f}, Aesthetic={aesthetic:.1f}")
# Option 1: Regenerate with different seed
# Option 2: Route to human review
# Option 3: Use generate-N-pick-best (generate 8, pick best)
else:
logger.info(f"Quality gate PASSED: CLIP={clip_score:.3f}, Aesthetic={aesthetic:.1f}")
Your pipeline generates 100 images but 15 have visible artifacts (extra fingers, distorted faces). What's the production approach?
Manual review doesn't scale. Shipping bad outputs damages trust. The production approach is automated quality gates: score each image with CLIPScore and Aesthetic Score, reject outputs below threshold, and for critical outputs use generate-N-pick-best (generate 8 candidates, score them, deliver the best).
Stage 5: Delivery
Delivery is not just "save the file" — it's storage with metadata, format conversion, and CDN distribution.
# Delivery with metadata
metadata = {
"prompt": prompt,
"seed": seed,
"model": "flux-schnell",
"parameters": generation_params,
"quality_scores": {"clip": clip_score, "aesthetic": aesthetic},
"cost_usd": total_cost,
"timestamp": datetime.utcnow().isoformat(),
"pipeline_version": "1.0",
}
# Save to S3 (or local simulating S3)
save_to_storage(image, path=f"outputs/{job_id}.png", metadata=metadata)
# Generate thumbnail
thumbnail = resize(image, size=(256, 256))
save_to_storage(thumbnail, path=f"outputs/{job_id}_thumb.png")
# Convert to WebP for web delivery
webp = convert_format(image, format="webp", quality=85)
save_to_storage(webp, path=f"outputs/{job_id}.webp")
Key delivery components:
- Metadata tagging: prompt, seed, model, scores, cost — for reproducibility and auditing
- Format conversion: WebP/AVIF for web, PNG for lossless, MP4 H.264 for video
- Thumbnail generation: for galleries and previews
- CDN distribution: CloudFront, Cloudflare for low-latency delivery
- C2PA provenance: embed metadata identifying the image as AI-generated