Módulo 8: Proyecto Integrador — 50-80% Cost Reduction
Entrega del Módulo 8: Cost-Reduced AI System
Descripción del proyecto
Este es el proyecto final de la guía. Integra todo lo que aprendiste en 8 módulos: cost anatomy, tracking, prompt optimization, Redis caching (exact + semantic), model selection, y quality validation en un sistema cohesivo con un benchmark documentado.
El entregable no es solo código funcional — es un portfolio piece. Incluye un reporte de benchmark que dice, con números reales y metodología reproducible: "Reduje costos de AI en X% con calidad equivalente validada." Eso es diferenciador en una entrevista o en tu perfil profesional.
Este proyecto integra todos los mini-proyectos de módulos anteriores:
Cost Breakdown Calculator (M1) ──┐
Cost Dashboard (M2) ─────────────┤
Prompt Optimization Pipeline (M3)┤
Redis Caching Layer (M4) ────────┼──→ Cost-Reduced AI System
Response Cache (M5) ─────────────┤ + Benchmark Report
Semantic Cache (M6) ─────────────┤ + Quality Validation
Cost-Optimized Router (M7) ──────┘
Al completar este proyecto, tendrás un sistema que tú construiste, entiendes por completo, y puedes explicar en detalle — cada capa, cada decisión, cada número.
Recap del módulo
En este módulo (cápsulas 02-07) construiste:
- Arquitectura del pipeline (02): orden de capas, por qué cache primero
- Implementación (03):
OptimizedPipelinecon 8 capas - Benchmark methodology (04):
BenchmarkRunner, workload, baseline - Ejecución y reporte (05):
BenchmarkReportcon desglose por componente - Quality validation (06):
QualityValidatorconfirma calidad equivalente - Production considerations (07): TTL, métricas, alertas, graceful degradation
El proyecto integra todo esto en una estructura limpia y ejecutable.
Objetivo del proyecto
Construir un Cost-Reduced AI System completo con benchmark documentado que demuestre 50-80% de reducción de costos sin degradación de calidad.
Al completar este proyecto:
- Tendrás un pipeline funcional que procesa queries a través de todas las capas de optimización
- Un benchmark formal que compara baseline vs optimizado con 1,000 queries
- Un reporte portfolio-worthy con desglose por componente, distribución, y quality validation
- Documentación clara de cómo funciona y cómo reproducir los resultados
Especificaciones técnicas
Stack tecnológico
- Lenguaje: Python 3.10+
- APIs: OpenAI (GPT-4o, GPT-4o-mini, GPT-3.5-turbo, text-embedding-3-small)
- Cache: Redis (via Docker)
- Dependencias: openai, tiktoken, redis, numpy, python-dotenv
Setup inicial
mkdir cost-reduced-ai-system
cd cost-reduced-ai-system
python -m venv venv
source venv/bin/activate # Mac/Linux
# venv\Scripts\activate # Windows
pip install openai tiktoken redis numpy python-dotenv
Docker para Redis
docker run -d --name redis-stack \
-p 6379:6379 \
-p 8001:8001 \
redis/redis-stack:latest
# Verificar
docker ps | grep redis-stack
Estructura del proyecto
cost-reduced-ai-system/
├── .env # OPENAI_API_KEY
├── requirements.txt # Dependencias con versiones
├── README.md # Documentación del proyecto
│
├── pipeline/
│ ├── __init__.py
│ ├── normalizer.py # QueryNormalizer
│ ├── exact_cache.py # ExactCache con TTL
│ ├── semantic_cache.py # SemanticCache con embeddings
│ ├── classifier.py # ComplexityClassifier
│ ├── router.py # ModelRouter + ModelConfig
│ ├── prompt_optimizer.py # PromptOptimizer
│ └── pipeline.py # OptimizedPipeline (orquestador)
│
├── benchmark/
│ ├── __init__.py
│ ├── workload.py # WorkloadGenerator
│ ├── runner.py # BenchmarkRunner
│ ├── report.py # BenchmarkReport
│ └── quality.py # QualityValidator
│
├── main.py # Script principal
└── benchmark_report.md # Output del benchmark
Funcionalidades obligatorias
1. Pipeline integrado
Archivo: pipeline/pipeline.py
El OptimizedPipeline recibe una query y la pasa por 8 capas en orden:
normalize → exact_cache → semantic_cache → classify →
select_model → optimize_prompt → llm_call → cache_store
Qué debe hacer:
- Normalizar la query (lowercase, strip whitespace, eliminar puntuación)
- Verificar exact cache con SHA-256 de la query normalizada
- Verificar semantic cache con embeddings y cosine similarity (threshold 0.85)
- Clasificar complejidad (TRIVIAL, SIMPLE, MEDIUM, COMPLEX) con heurísticas
- Seleccionar modelo según complejidad (GPT-4o-mini, GPT-3.5, GPT-4o)
- Optimizar prompt (reducir tokens innecesarios)
- Llamar al LLM seleccionado (o simular para benchmark sin API key)
- Almacenar respuesta en exact y semantic cache
- Retornar
PipelineResultcon query, response, source, model, cost, savings
2. Benchmark runner
Archivo: benchmark/runner.py
El BenchmarkRunner ejecuta dos runs:
baseline = runner.run_baseline(queries) # todo GPT-4o, sin cache
optimized = runner.run_optimized(queries) # pipeline completo
comparison = runner.compare(baseline, optimized)
Qué debe hacer:
- Generar workload de 1,000 queries con distribución realista
- Ejecutar baseline (cálculo teórico: todo GPT-4o)
- Ejecutar optimizado (queries pasan por el pipeline)
- Comparar costos y producir métricas
3. Benchmark report
Archivo: benchmark/report.py
El BenchmarkReport genera dos formatos:
Qué debe hacer:
- Generar reporte de texto plano para terminal
- Generar reporte Markdown para portfolio
- Incluir: configuración, resultados, desglose por componente, distribución por fuente, distribución por modelo, proyección mensual/anual, quality validation, conclusiones
4. Quality validation
Archivo: benchmark/quality.py
El QualityValidator compara respuestas optimizadas vs baseline:
Qué debe hacer:
- Comparar length ratio (respuesta optimizada vs baseline)
- Comparar keyword overlap (conceptos cubiertos)
- Reportar pass rate por fuente (exact cache, semantic, LLM)
- Pass rate objetivo: >90%
5. Production-ready features
Qué debe incluir:
- TTL configurado en el cache (default 1 hora)
- Graceful degradation si Redis no está disponible
- Métricas básicas: hit rate, avg cost, total savings
- Seed para reproducibilidad del benchmark
6. README documentado
Qué debe incluir:
- Qué es el proyecto y qué problema resuelve
- Setup instructions (paso a paso)
- Cómo ejecutar el benchmark
- Resultados del benchmark (copy-paste del reporte)
- Arquitectura del pipeline (diagram)
- Cómo funciona cada componente (1-2 líneas cada uno)
- Cómo reproducir los resultados
Validaciones y manejo de errores
Validaciones obligatorias
- Query no vacía antes de procesarla
- Redis connection check antes de operaciones de cache
- API key presente en
.envantes de llamar a OpenAI - Workload size > 0 antes de ejecutar benchmark
- Resultados no vacíos antes de generar reporte
Manejo de errores
class PipelineError(Exception):
"""Error del pipeline con contexto."""
def __init__(self, layer: str, message: str, query: str = ""):
self.layer = layer
self.query = query[:50]
super().__init__(f"[{layer}] {message} (query: '{self.query}')")
# Errores que DEBEN manejarse:
# Redis no disponible → fallback a LLM directo
try:
cached = self.cache.get(key)
except redis.ConnectionError:
cached = None # skip cache, no crash
# OpenAI API error → retry con backoff o error graceful
try:
response = client.chat.completions.create(...)
except openai.RateLimitError:
time.sleep(5)
response = client.chat.completions.create(...) # retry una vez
# Query inválida → skip con warning
if not query or not query.strip():
return PipelineResult(query="", response="", source="error",
model_used=None, cost=0, savings=0)
Criterios de éxito
Tu proyecto está completo cuando:
- ✅ El pipeline procesa 1,000 queries sin errores
- ✅ El benchmark muestra 50-80% de reducción de costos
- ✅ El desglose muestra la contribución de cada técnica
- ✅ El quality validation tiene pass rate >90%
- ✅ El reporte Markdown es legible y presentable
- ✅ El README tiene setup instructions que un tercero puede seguir
- ✅ El código corre con
python main.pysin configuración adicional (excepto.env)
Rúbrica de evaluación (100 puntos)
Funcionalidad (50 puntos)
- (10 pts) Pipeline procesa queries a través de todas las capas
- (10 pts) Benchmark ejecuta baseline vs optimizado correctamente
- (10 pts) Reporte incluye desglose por componente y distribución
- (10 pts) Quality validation con pass rate documentado
- (5 pts) Cache con TTL funcional
- (5 pts) Graceful degradation si Redis no disponible
Código (30 puntos)
- (10 pts) Código organizado en módulos (pipeline/, benchmark/)
- (5 pts) Type hints consistentes en funciones públicas
- (5 pts) Comentarios en puntos clave (no redundantes)
- (5 pts) Sin imports innecesarios ni código muerto
- (5 pts) Dataclasses para structured data (PipelineResult, BenchmarkResult)
Documentación (20 puntos)
- (8 pts) README con setup, uso, y resultados del benchmark
- (7 pts) Reporte Markdown portfolio-worthy con todas las secciones
- (5 pts) requirements.txt con versiones
Extra credit (hasta +15 puntos)
- (+5 pts) Benchmark con confidence interval (múltiples seeds)
- (+5 pts) Reporte JSON exportable para dashboards
- (+5 pts) Gráficos ASCII en el reporte de terminal
Ejemplo de implementación mínima
Este es el esqueleto de main.py — la implementación mínima que pasa los criterios:
"""Cost-Reduced AI System — Main entry point."""
import random
import time
from dotenv import load_dotenv
from pipeline.pipeline import OptimizedPipeline
from benchmark.workload import WorkloadGenerator
from benchmark.runner import BenchmarkRunner
from benchmark.report import BenchmarkReport
from benchmark.quality import QualityValidator
def main():
load_dotenv()
random.seed(42)
print("=" * 60)
print("COST-REDUCED AI SYSTEM — BENCHMARK")
print("=" * 60)
# 1. Generar workload
print("\n[1/5] Generating workload...")
generator = WorkloadGenerator()
queries = generator.generate(1000)
print(f" Generated {len(queries)} queries")
print(f" Unique queries: {len(set(queries))}")
# 2. Crear pipeline
print("\n[2/5] Initializing pipeline...")
pipeline = OptimizedPipeline()
print(" Pipeline ready (8 layers)")
# 3. Ejecutar benchmark
print("\n[3/5] Running benchmark...")
runner = BenchmarkRunner(pipeline)
start = time.time()
baseline = runner.run_baseline(queries)
optimized = runner.run_optimized(queries)
elapsed = time.time() - start
comparison = runner.compare(baseline, optimized)
print(f" Benchmark completed in {elapsed:.1f}s")
print(f" Baseline: ${baseline.total_cost:.4f}")
print(f" Optimized: ${optimized.total_cost:.4f}")
print(f" Savings: {comparison['savings_pct']:.1f}%")
# 4. Quality validation
print("\n[4/5] Running quality validation...")
validator = QualityValidator()
unique_sample = list(set(queries))[:50]
for query in unique_sample:
matching = [r for r in pipeline.results
if r.query.startswith(query[:40])]
if matching:
result = matching[0]
baseline_resp = f"[GPT-4o] Full response for: {query}"
validator.check(
query=query,
baseline_response=baseline_resp,
optimized_response=result.response,
source=result.source,
model_used=result.model_used
)
quality_summary = validator.summary()
print(f" Checks: {quality_summary['total_checks']}")
print(f" Pass rate: {quality_summary['pass_rate']}")
# 5. Generar reporte
print("\n[5/5] Generating reports...")
report = BenchmarkReport(
pipeline=pipeline,
baseline=baseline,
optimized=optimized,
comparison=comparison,
quality=quality_summary
)
# Reporte terminal
print("\n" + report.generate_text())
# Reporte Markdown
md_filename = "benchmark_report.md"
report.save_markdown(md_filename)
print(f"\n Markdown report saved to: {md_filename}")
print("\n" + "=" * 60)
print("BENCHMARK COMPLETE")
print("=" * 60)
if __name__ == "__main__":
main()
Este ejemplo:
- ✅ Muestra la estructura esperada del main.py
- ✅ Usa todas las clases del proyecto
- ✅ Tiene output progresivo (1/5, 2/5...)
- ❌ NO incluye las implementaciones de cada clase (eso lo construiste en M8/02-07)
Ejemplo de benchmark_report.md (output)
Tu reporte generado debe verse similar a esto:
# Cost Optimization Benchmark Report
**Date:** 2026-03-13
**System:** OptimizedPipeline v1.0
**Seed:** 42
## Results Summary
| Metric | Baseline | Optimized |
|--------|----------|-----------|
| Total cost | $4.2500 | $0.7650 |
| Avg cost/query | $0.004250 | $0.000765 |
| **Savings** | - | **82.0%** |
## Component Breakdown
| Component | Contribution |
|-----------|-------------|
| Exact cache | ~45% of savings |
| Semantic cache | ~20% of savings |
| Model routing | ~30% of savings |
| Prompt optimization | ~5% of savings |
## Response Distribution
| Source | Count | Percentage |
|--------|-------|-----------|
| Exact cache | 430 | 43.0% |
| Semantic cache | 220 | 22.0% |
| LLM | 350 | 35.0% |
## Quality Validation
| Metric | Value |
|--------|-------|
| Sample size | 50 |
| Pass rate | 95.3% |
| Exact cache | 100% |
| Semantic cache | 87.5% |
| LLM | 94.1% |
## Monthly Projection (3,500 queries/day)
| Period | Baseline | Optimized | Savings |
|--------|----------|-----------|---------|
| Monthly | $446.25 | $80.33 | $365.93 |
| Annual | $5,355.00 | $963.90 | $4,391.10 |
## Conclusion
System achieves **82% cost reduction** with 95.3% quality
validation pass rate. Primary savings from exact cache (43%)
and semantic cache (22%) preventing 65% of LLM calls.
Remaining calls are routed to cheaper models (75% to
GPT-4o-mini) with prompt optimization providing marginal
additional savings.
Errores comunes
Error 1: ModuleNotFoundError: No module named 'pipeline'
Causa: Python no encuentra el package pipeline/ porque falta __init__.py.
Solución:
touch pipeline/__init__.py benchmark/__init__.py
Error 2: Redis ConnectionError al iniciar
Causa: Docker no está corriendo o el container se detuvo. Solución:
docker start redis-stack
# o si no existe:
docker run -d --name redis-stack -p 6379:6379 redis/redis-stack:latest
Error 3: El benchmark muestra 0% savings
Causa: El cache no acumula entries entre queries. Probablemente estás creando un nuevo pipeline para cada query.
Solución: Usa un SOLO instance de OptimizedPipeline para todo el run de run_optimized.
Error 4: openai.AuthenticationError — API key inválida
Causa: .env no tiene la API key o está mal formateada.
Solución:
# Verificar que .env existe y tiene el formato correcto:
cat .env
# OPENAI_API_KEY=sk-proj-...
# En Python:
from dotenv import load_dotenv
import os
load_dotenv()
print(os.getenv("OPENAI_API_KEY")[:10]) # debe mostrar "sk-proj-..."
Error 5: El reporte Markdown tiene tablas rotas
Causa: Valores con longitud variable rompen el alineamiento de las columnas.
Solución: Usa f-strings con formato fijo: f"${value:<10.4f}". O formatea el valor antes de insertarlo en la tabla.
Error 6: Quality validation tiene 0 checks
Causa: pipeline.results está vacío porque el pipeline no guarda resultados.
Solución: Asegúrate de que OptimizedPipeline.process() agrega cada PipelineResult a self.results:
def process(self, query: str) -> PipelineResult:
# ... lógica ...
self.results.append(result)
return result
Error 7: El seed no funciona — resultados diferentes cada vez
Causa: random.seed(42) se llama después de generar queries, o hay otros puntos de aleatoriedad no controlados.
Solución: Llama random.seed(42) ANTES de cualquier operación aleatoria. Si usas numpy, también: numpy.random.seed(42).
Error 8: El quality validator siempre pasa al 100%
Causa: Las respuestas simuladas comparten texto con las del pipeline porque ambas incluyen la query en el output. Solución: Esto es esperado en el benchmark simulado. El quality validator demuestra el mecanismo. Con llamadas LLM reales, los resultados serían más realistas.
Tests de validación
Antes de considerar tu proyecto terminado, ejecuta estos tests:
# test_project.py
"""Tests de validación para el Cost-Reduced AI System."""
import random
def test_pipeline_processes_queries():
"""Verifica que el pipeline puede procesar queries sin errores."""
from pipeline.pipeline import OptimizedPipeline
pipeline = OptimizedPipeline()
test_queries = [
"Hola",
"¿Qué es Python?",
"Explica cómo funciona un hash table",
"Analiza los trade-offs de microservicios vs monolito paso a paso",
]
for query in test_queries:
result = pipeline.process(query)
assert result.response, f"Empty response for: {query}"
assert result.source in ("exact_cache", "semantic_cache", "llm"), \
f"Unknown source: {result.source}"
assert result.cost >= 0, f"Negative cost for: {query}"
print("✅ Pipeline processes queries correctly")
def test_cache_hits():
"""Verifica que queries repetidas son cache hits."""
from pipeline.pipeline import OptimizedPipeline
pipeline = OptimizedPipeline()
# Primera vez: debería ser LLM call
r1 = pipeline.process("¿Qué es Python?")
assert r1.source == "llm", f"First call should be LLM, got {r1.source}"
# Segunda vez: debería ser exact cache hit
r2 = pipeline.process("¿Qué es Python?")
assert r2.source == "exact_cache", \
f"Repeated query should be exact_cache, got {r2.source}"
assert r2.cost == 0, "Cache hit should cost $0"
print("✅ Cache hits work correctly")
def test_routing_distribution():
"""Verifica que el routing distribuye a diferentes modelos."""
from pipeline.pipeline import OptimizedPipeline
pipeline = OptimizedPipeline()
queries = [
"Hola", # trivial
"¿Qué es Python?", # simple
"Explica TCP/IP en detalle", # medium
"Analiza la complejidad algorítmica de quicksort paso a paso", # complex
]
models_used = set()
for query in queries:
result = pipeline.process(query)
if result.model_used:
models_used.add(result.model_used)
assert len(models_used) >= 2, \
f"Expected multiple models, got: {models_used}"
print(f"✅ Routing distributes to {len(models_used)} models: {models_used}")
def test_benchmark_runs():
"""Verifica que el benchmark completo ejecuta sin errores."""
from pipeline.pipeline import OptimizedPipeline
from benchmark.workload import WorkloadGenerator
from benchmark.runner import BenchmarkRunner
random.seed(42)
pipeline = OptimizedPipeline()
generator = WorkloadGenerator()
queries = generator.generate(100) # muestra pequeña para test
runner = BenchmarkRunner(pipeline)
baseline = runner.run_baseline(queries)
optimized = runner.run_optimized(queries)
comparison = runner.compare(baseline, optimized)
assert comparison["savings_pct"] > 0, "Should have some savings"
assert comparison["savings_pct"] < 100, "Can't save 100%"
print(f"✅ Benchmark runs: {comparison['savings_pct']:.1f}% savings")
def test_report_generates():
"""Verifica que el reporte se genera sin errores."""
from pipeline.pipeline import OptimizedPipeline
from benchmark.workload import WorkloadGenerator
from benchmark.runner import BenchmarkRunner
from benchmark.report import BenchmarkReport
random.seed(42)
pipeline = OptimizedPipeline()
generator = WorkloadGenerator()
queries = generator.generate(50)
runner = BenchmarkRunner(pipeline)
baseline = runner.run_baseline(queries)
optimized = runner.run_optimized(queries)
comparison = runner.compare(baseline, optimized)
report = BenchmarkReport(
pipeline=pipeline,
baseline=baseline,
optimized=optimized,
comparison=comparison,
quality={"pass_rate": "95%", "total_checks": 20, "passed": 19, "failed": 1}
)
text = report.generate_text()
assert len(text) > 100, "Report too short"
assert "savings" in text.lower() or "ahorro" in text.lower(), \
"Report should mention savings"
print("✅ Report generates correctly")
if __name__ == "__main__":
test_pipeline_processes_queries()
test_cache_hits()
test_routing_distribution()
test_benchmark_runs()
test_report_generates()
print("\n🎯 All project tests passed!")
Ejecuta los tests con:
python test_project.py
Todos deben pasar antes de generar tu benchmark final con python main.py.
Ejemplo de README.md
Tu README debe incluir al menos estas secciones:
# Cost-Reduced AI System
Sistema que reduce costos de AI en 50-80% mediante semantic caching,
model selection, y prompt optimization. Incluye benchmark formal con
calidad validada.
## Architecture
[Pipeline diagram ASCII]
## Quick Start
1. Clone and setup:
```bash
git clone [repo-url]
cd cost-reduced-ai-system
python -m venv venv && source venv/bin/activate
pip install -r requirements.txt
-
Start Redis:
docker run -d --name redis-stack -p 6379:6379 redis/redis-stack:latest -
Configure API key:
echo "OPENAI_API_KEY=sk-proj-..." > .env -
Run benchmark:
python main.py
Benchmark Results
[Paste your benchmark_report.md results here]
How It Works
- Exact Cache: SHA-256 hash match → instant response ($0)
- Semantic Cache: Embedding similarity > 0.85 → cached response
- Model Router: Classifies query complexity → cheapest capable model
- Prompt Optimizer: Reduces tokens 15-25% without quality loss
Reproducing Results
# Same seed (42) produces identical results
python main.py
---
## Recursos para el proyecto
1. [OpenAI Python SDK](https://github.com/openai/openai-python) - API reference para llamadas LLM
2. [Redis Python client](https://redis-py.readthedocs.io/en/stable/) - Documentación de redis-py
3. [Python dataclasses](https://docs.python.org/3/library/dataclasses.html) - Para PipelineResult, BenchmarkResult
4. [python-dotenv](https://pypi.org/project/python-dotenv/) - Manejo de variables de entorno
5. [tiktoken](https://github.com/openai/tiktoken) - Token counting para cost calculation
6. [Docker Redis Stack](https://hub.docker.com/r/redis/redis-stack) - Setup de Redis con RediSearch
---
## Checklist de completitud final
Antes de considerar tu proyecto terminado, verifica cada punto:
**Código:**
- [ ] `python main.py` ejecuta sin errores
- [ ] Pipeline tiene las 8 capas en orden correcto
- [ ] Cache funciona (queries repetidas son hits)
- [ ] Routing distribuye a múltiples modelos
- [ ] Quality validator genera pass rate
**Reporte:**
- [ ] `benchmark_report.md` generado con todas las secciones
- [ ] Desglose por componente incluido
- [ ] Proyección mensual/anual incluida
- [ ] Quality validation incluida
**Documentación:**
- [ ] README.md con setup instructions
- [ ] requirements.txt con versiones
- [ ] Resultados del benchmark en el README
**Tests:**
- [ ] `python test_project.py` pasa (si lo creaste)
---
## Conexión: ¿Qué sigue después de esta guía?
Esta guía te dio las herramientas para reducir costos de AI en 50-80%. Pero hay más:
**Siguientes pasos recomendados:**
- **Testing formal** — unit tests para cada componente del pipeline
- **Deployment** — containerizar el sistema con Docker Compose
- **Monitoring real** — Prometheus + Grafana para métricas en producción
- **Fine-tuning** — entrenar modelos más pequeños para tu dominio específico (reduce costos aún más)
- **Semantic cache con embeddings reales** — la versión word-overlap de esta guía es simplificada. Con text-embedding-3-small y RediSearch HNSW, el hit rate sube significativamente
**Lo que construiste es real.** No es un tutorial que copiaste — es un sistema que diseñaste, implementaste y mediste. El benchmark con números reales es evidencia. Ponlo en tu portfolio, mencionalo en entrevistas. Poca gente en español puede decir "reduje costos de AI en 70% con un sistema que yo construí."
### Cómo presentar este proyecto
En un README de portfolio o en una entrevista técnica:
1. **El problema:** "Los costos de AI escalan linealmente con el tráfico. Sin optimización, 3,500 queries/día cuestan $446/mes."
2. **La solución:** "Construí un pipeline de 8 capas: normalización → exact cache → semantic cache → complexity classification → model selection → prompt optimization → LLM call → cache store."
3. **El resultado:** "Benchmark de 1,000 queries muestra 70% reducción ($446 → $134/mes) con 95% quality validation pass rate."
4. **Las técnicas:** "Exact cache para queries repetidas, semantic cache con embeddings para variaciones, model routing para elegir el modelo más barato capaz."
5. **La evidencia:** "El benchmark es reproducible: `python main.py` con seed 42 genera los mismos resultados."
Practica estas 5 frases antes de una entrevista. Son tu elevator pitch para el proyecto.
---
**Creado:** Marzo 2026
**Versión:** 1.0