Enriquecimos 28,840 Registros con IA: Lecciones del Procesamiento de Datos Masivos
Enriquecimiento de Contenido de IA a Escala: Procesando 28,840 Registros de Productos
El trimestre pasado, asumimos un proyecto que sonaba simple sobre el papel: enriquecer 28.840 registros de productos con descripciones, categorías y metadatos generados por IA. El cliente tenía un enorme catálogo de comercio electrónico migrando a un CMS headless, y cada registro necesitaba mejor contenido. Lo que siguió fue una lección magistral en todo lo que puede salir mal -- y bien -- cuando arrojas decenas de miles de registros contra una API de IA.
Esto no es una guía teórica. Voy a guiarte a través de la arquitectura actual que construimos, los costos exactos que pagamos, los modos de falla que encontramos, y los patrones que nos salvaron. Si estás considerando enriquecimiento de contenido en lote con IA para tu propio proyecto, esto debería ahorrarte algunas semanas de descubrimiento doloroso.
Tabla de Contenidos
- Por Qué Elegimos Enriquecimiento con IA Sobre Trabajo Manual
- La Arquitectura: Cómo Construimos el Pipeline
- Elegir la API de Claude para Procesamiento en Lote
- Ingeniería de Prompts a Escala
- Límites de Velocidad, Reintentos, y el Arte de No Ser Baneado
- Control de Calidad: La Realidad del Humano en el Bucle
- Desglose Real de Costos
- Lo Que Hicimos Mal
- Lo Que Haríamos Diferente la Próxima Vez
- Preguntas Frecuentes
Por Qué Elegimos Enriquecimiento con IA Sobre Trabajo Manual
Las matemáticas eran brutalmente simples. Nuestro cliente tenía 28.840 registros de productos -- cada uno necesitaba una descripción reescrita (150-300 palabras), tres etiquetas de categoría amigables para SEO, una meta descripción, y atributos estructurados extraídos de texto no estructurado. Con una estimación conservadora de 8 minutos por registro para un redactor humano, son 3.845 horas de trabajo. A $35/hora, estamos viendo $134.575 y aproximadamente 6 meses de tiempo transcurrido con un equipo pequeño.
Completamos el enriquecimiento con IA en 11 días por menos de $3.200 en costos de API, más aproximadamente 80 horas de tiempo de ingeniería y QA. Incluso factorizando nuestras horas de desarrollo, el costo total fue aproximadamente una décima parte del enfoque manual.
Pero aquí está lo que nadie te dice: la parte difícil no es llamar a la API. Es todo lo que la rodea. Limpieza de datos, ajuste de prompts, validación de calidad, manejo de errores, y los casos extremos inevitables que te hacen cuestionarte tus decisiones profesionales.
La Arquitectura: Cómo Construimos el Pipeline
Construimos el pipeline de enriquecimiento como una aplicación Node.js, lo que tenía sentido dado la experiencia de nuestro equipo en desarrollo de Next.js y TypeScript. Aquí está la arquitectura de alto nivel:
CSV Fuente → Parser → Cola por Lotes → API de Claude → Validador de Respuesta → Almacén de Salida → Dashboard QA
La Capa de Datos
Usamos SQLite como nuestra base de datos de procesamiento local. Suena poco sexy, ¿verdad? Pero para procesamiento por lotes como este, es perfecto. Sin servidor que gestionar, las transacciones son rápidas, y puedes consultar tus resultados fácilmente. Cada registro obtuvo una columna de estado rastreando su viaje:
interface EnrichmentRecord {
id: string;
original_title: string;
original_description: string;
raw_attributes: string;
status: 'pending' | 'processing' | 'completed' | 'failed' | 'needs_review';
enriched_description: string | null;
enriched_categories: string[] | null;
enriched_meta: string | null;
structured_attributes: Record<string, string> | null;
attempts: number;
last_error: string | null;
token_usage: number;
created_at: string;
updated_at: string;
}
El Sistema de Cola
Implementamos una cola de trabajo simple usando BullMQ respaldada por Redis. Cada trabajo representaba un enriquecimiento de un solo registro. Lo configuramos con:
- Concurrencia: 5 workers paralelos (más sobre por qué este número después)
- Máximo de reintentos: 3 por registro
- Backoff: Exponencial, comenzando en 30 segundos
- Tiempo de espera del trabajo: 60 segundos
const enrichmentQueue = new Queue('enrichment', {
connection: redisConnection,
defaultJobOptions: {
attempts: 3,
backoff: {
type: 'exponential',
delay: 30000,
},
timeout: 60000,
removeOnComplete: false, // Mantener para auditoría
},
});
El Worker de Procesamiento
Cada worker tomaba un registro, construía el prompt, llamaba a la API de Claude, validaba la estructura de la respuesta, y escribía los resultados de vuelta. Si la respuesta no coincidía con nuestro esquema JSON esperado, iba a un bucket needs_review en lugar de corromper silenciosamente nuestro conjunto de datos.
Elegir la API de Claude para Procesamiento en Lote
Evaluamos tres opciones antes de decidir por Claude (específicamente Claude 3.5 Sonnet, y posteriormente Claude 3.5 Haiku para tareas más simples):
| Característica | Claude 3.5 Sonnet | GPT-4o | Gemini 1.5 Pro |
|---|---|---|---|
| Costo de entrada (por 1M tokens) | $3.00 | $2.50 | $1.25 |
| Costo de salida (por 1M tokens) | $15.00 | $10.00 | $5.00 |
| Límites de velocidad (RPM, Nivel 2) | 1.000 | 500 | 360 |
| Confiabilidad del modo JSON | Excelente | Bueno | Inconsistente |
| Calidad de salida estructurada | La mejor de su clase | Muy bueno | Bueno |
| Descuento de API por Lotes | 50% | 50% | N/A |
Precios a partir de Q1 2025. Verifica los precios actuales -- estos cambian frecuentemente.
Nos decantamos por Claude por algunas razones. Primero, su seguimiento de instrucciones para salida estructurada fue notablemente mejor que las alternativas durante nuestra ejecución de prueba de 500 registros. Cuando estás procesando casi 29K registros, incluso una mejora del 2% en el cumplimiento de formato te ahorra cientos de correcciones manuales. Segundo, la API por Lotes de Anthropic ofrecía un descuento del 50% para trabajo no sensible al tiempo, lo que hizo que la economía fuera aún más favorable.
Honestamente, GPT-4o habría estado bien también. Las diferencias a esta escala son más sobre límites de velocidad y precios que sobre calidad bruta. Pero la consistencia de Claude con salida JSON fue el factor decisivo.
Por Qué Usamos Tanto Sonnet Como Haiku
Aquí está un truco que nos ahorró aproximadamente el 40% en costos de API: no usamos el mismo modelo para todo. Las descripciones de productos necesitaban la calidad de Sonnet. ¿Pero clasificación de categorías y extracción de atributos? Haiku se manejó bien con una fracción del costo.
Dividimos el enriquecimiento en dos pasadas:
- Pasada 1 (Haiku): Clasificación de categorías, extracción de atributos, metadatos básicos -- $0.25/1M entrada, $1.25/1M salida
- Pasada 2 (Sonnet): Reescritura de descripciones, meta descripciones, contenido SEO -- $3.00/1M entrada, $15.00/1M salida
Ingeniería de Prompts a Escala
Aquí es donde la mayoría de tutoriales te fallan. Te muestran un solo prompt y lo llaman un día. Cuando estás ejecutando 28.840 registros a través de la misma plantilla de prompt, los pequeños defectos se amplifican en problemas masivos.
La Plantilla de Prompt
Después de aproximadamente 15 iteraciones (sí, las rastreamos en git), aquí está la estructura aproximada que funcionó:
const buildPrompt = (record: SourceRecord): string => `
Estás enriqueciendo datos de productos para un catálogo de comercio electrónico. Genera lo siguiente para el producto a continuación:
1. Una descripción de producto (150-300 palabras, segunda persona, enfocada en beneficios)
2. Exactamente 3 etiquetas de categoría de esta lista permitida: ${CATEGORY_LIST}
3. Una meta descripción (120-155 caracteres)
4. Atributos estructurados como pares clave-valor
Reglas:
- NO inventes características no presentes en los datos fuente
- Si la información es ambigua, usa la bandera "uncertain"
- Coincide con el tono de la marca: profesional pero accesible
- La descripción debe ser única -- no repitas el título textualmente en la primera oración
Responde ÚNICAMENTE con JSON válido coincidiendo con este esquema:
${JSON_SCHEMA}
Datos del producto fuente:
Título: ${record.title}
Descripción existente: ${record.description}
Atributos sin procesar: ${record.attributes}
Precio: ${record.price}
Marca: ${record.brand}
`;
Lecciones sobre Prompts a Escala
Sé absurdamente específico sobre el formato de salida. Incluimos el esquema JSON completo en cada solicitud. Sí, añade tokens. No, no lo saltes. La única vez que intentamos confiar únicamente en instrucciones del sistema, nuestro cumplimiento de formato cayó de 97% a 81%.
Restringe el vocabulario de salida. Para etiquetas de categoría, proporcionamos una lista permitida explícita. La categorización de extremo abierto produjo 847 categorías únicas en nuestro lote de prueba. ¿La versión restringida? Exactamente las 42 que queríamos.
Añade guardrails contra alucinaciones. Los productos ocasionalmente brotarían características que no tenían. Añadir "NO inventes características no presentes en los datos fuente" redujo atributos alucinados por aproximadamente 70%. Añadir la bandera uncertain capturó la mayoría de los casos restantes.
La temperatura importa más de lo que crees. Nos establecimos en 0.3. Más bajo que eso y las descripciones se volverían repetitivas en productos similares. Más alto y comenzaríamos a obtener escritura creativa que no coincidía con la voz de la marca.
Límites de Velocidad, Reintentos, y el Arte de No Ser Baneado
Esta sección debería realmente llamarse "la parte que tomó más tiempo de ingeniería." Los límites de velocidad de Anthropic están bien documentados pero se comportan diferente bajo carga sostenida de lo que esperarías de leer la documentación.
Nuestra Estrategia de Límite de Velocidad
En Nivel 2 (que obtienes después de gastar $40+), Claude te da 1.000 solicitudes por minuto y 80.000 tokens por minuto. Suena generoso hasta que te das cuenta de que nuestra solicitud promedio era aproximadamente 1.200 tokens de entrada y 800 tokens de salida. Eso significaba que nuestro límite práctico era aproximadamente 40 solicitudes concurrentes antes de golpear los límites de tokens.
Ejecutamos 5 workers concurrentes, cada uno procesando un registro a la vez, con un retraso de 200ms entre solicitudes. Esto nos dio aproximadamente 15-20 solicitudes por minuto -- muy por debajo del límite de RPM y cómodamente dentro de los presupuestos de tokens.
const rateLimiter = new Bottleneck({
maxConcurrent: 5,
minTime: 200, // ms entre solicitudes
reservoir: 900, // solicitudes por minuto (dejando buffer)
reservoirRefreshAmount: 900,
reservoirRefreshInterval: 60 * 1000,
});
¿Por qué tan conservador? Porque golpear límites de velocidad causa fallas en cascada. Una respuesta 429 dispara un reintento, que añade a la cola, que aumenta la presión de concurrencia. Aprendimos esto de la manera difícil durante la hora 3 de nuestra primera ejecución real, cuando configuraciones agresivas causaron una tormenta de reintentos que efectivamente estancó el pipeline por 45 minutos.
La Alternativa de API por Lotes
A mitad del proyecto, cambiamos parcialmente a la API por Lotes de Anthropic. En lugar de hacer solicitudes individuales, subes un archivo JSONL de solicitudes y obtienes resultados de vuelta en 24 horas. El compromiso: reducción del costo del 50%, pero pierdes retroalimentación en tiempo real.
Usamos la API por Lotes para la Pasada 1 (clasificación de Haiku) y API en tiempo real para la Pasada 2 (descripciones de Sonnet). Este enfoque híbrido fue el punto óptimo para nosotros -- retroalimentación rápida en el trabajo creativo caro, economía de lote en la clasificación de productos básicos.
Control de Calidad: La Realidad del Humano en el Bucle
Cualquiera que te diga que el enriquecimiento con IA está completamente automatizado está mintiendo o no lo ha hecho a escala. Construimos un proceso de QA que atrapó problemas temprano y previno basura llegara a producción.
Validación Automatizada
Cada respuesta de API se sometió a validación antes de ser aceptada:
const validateEnrichment = (result: EnrichmentResult): ValidationOutcome => {
const issues: string[] = [];
// Verificaciones de longitud
if (result.description.length < 400 || result.description.length > 2000) {
issues.push('description_length');
}
// Validación de categoría
const invalidCats = result.categories.filter(c => !ALLOWED_CATEGORIES.includes(c));
if (invalidCats.length > 0) issues.push('invalid_categories');
// Longitud de meta descripción
if (result.meta.length > 160) issues.push('meta_too_long');
// Señales de alucinación
const hallucination_phrases = ['I think', 'probably', 'might be', 'as an AI'];
if (hallucination_phrases.some(p => result.description.includes(p))) {
issues.push('possible_hallucination');
}
// Detección de duplicados (coincidencia difusa contra registros ya procesados)
if (isDuplicateDescription(result.description)) {
issues.push('duplicate_content');
}
return {
valid: issues.length === 0,
issues,
needsReview: issues.length > 0 && issues.length < 3,
rejected: issues.length >= 3,
};
};
Muestreo de Revisión Manual
Muestreamos el 5% de todos los registros procesados (aproximadamente 1.440) para revisión manual. Nuestro equipo de QA puntuó cada uno en precisión, voz de marca, e integridad. Aquí están los números de nuestra revisión actual:
| Métrica | Puntuación |
|---|---|
| Precisión fáctica | 94.2% |
| Coincidencia de voz de marca | 87.6% |
| Cumplimiento de formato | 97.1% |
| Precisión de categoría | 91.8% |
| Registros necesitando revisión | 8.3% |
| Registros completamente rechazados | 1.9% |
Ese 8.3% que necesita revisión es un contexto importante. Significa aproximadamente 2.400 registros necesitaban edición humana. Aún mucho menos que escribir manualmente todos los 28.840 -- pero no es cero. Presupuesta para ello.
Desglose Real de Costos
Tiempo de transparencia. Aquí está lo que realmente gastamos:
| Categoría de Costo | Cantidad |
|---|---|
| Claude 3.5 Haiku (Pasada 1 - API por Lotes) | $312 |
| Claude 3.5 Sonnet (Pasada 2 - Tiempo Real) | $2.147 |
| Solicitudes fallidas/reintentos (~6% de sobrecarga) | $189 |
| Alojamiento de Redis (2 semanas) | $15 |
| Tiempo de ingeniería (80 hrs × $150) | $12.000 |
| Tiempo de revisión QA (40 hrs × $45) | $1.800 |
| Total | $16.463 |
| Solo costos de API | $2.648 |
Compara eso con la estimación de $134.575 para trabajo completamente manual. Incluso incluyendo todo el tiempo de ingeniería y QA, estamos en aproximadamente el 12% del costo manual. Y el pipeline es reutilizable -- la próxima vez que ejecutemos un proyecto similar, el costo de ingeniería cae a casi cero.
El costo de API por registro resultó ser aproximadamente $0.092. Menos de una moneda de diez centavos por registro para enriquecimiento con IA. Ese es el número que hace que los ejecutivos se sienten en sus sillas.
Lo Que Hicimos Mal
Subestimar la Limpieza de Datos
Pasamos 3 días solo limpiando los datos fuente antes de enviarlos a Claude. Los registros tenían entidades HTML, basura Unicode, descripciones truncadas, y campos en las columnas incorrectas. Basura dentro, basura fuera no es solo un cliché -- es la ley fundamental del procesamiento de IA en lote.
No Usar la API por Lotes desde el Primer Día
Gastamos aproximadamente $400 extra en costos de API ejecutando la Pasada 1 a través de la API en tiempo real antes de descubrir que la API por Lotes habría sido la mitad del precio. Lee la documentación completa antes de comenzar. Todo de ella.
Detección de Duplicados Insuficiente
Nuestra detección de duplicados inicial era demasiado ingenua -- simple coincidencia de string. Claude generaría descripciones que eran estructuralmente idénticas pero usaban palabras ligeramente diferentes para productos similares. Tuvimos que implementar verificación de similitud semántica (usando embeddings) para capturar estos, lo que añadió un día de trabajo.
Fallos en el Análisis JSON
Aproximadamente el 2.4% de las respuestas vinieron de vuelta con JSON malformado. A veces una coma final, a veces una comilla sin escapar en una descripción de producto. Deberíamos haber implementado un analizador JSON más tolerante desde el principio en lugar de tratar estos como fallos duros.
// Lo que deberíamos haber hecho desde el primer día
const parseResponse = (raw: string): EnrichmentResult | null => {
try {
return JSON.parse(raw);
} catch {
// Intenta extraer JSON de bloques de código markdown
const jsonMatch = raw.match(/```json?\n?([\s\S]*?)\n?```/);
if (jsonMatch) {
try { return JSON.parse(jsonMatch[1]); } catch { /* continuar */ }
}
// Intenta librería jsonrepair como último recurso
try { return JSON.parse(jsonrepair(raw)); } catch { return null; }
}
};
Lo Que Haríamos Diferente la Próxima Vez
Comienza con un piloto de 1.000 registros antes de comprometerte con la ejecución completa. Hicimos 500 y no fue suficiente para superficie todos los casos extremos.
Usa salidas estructuradas desde el principio. Anthropic ahora soporta uso de herramientas con esquemas definidos, lo que elimina la mayoría de problemas de análisis JSON. Migramos a esto a mitad de camino y desearíamos haber comenzado allí.
Construye el dashboard de QA primero. Lo construimos reactivamente después de que aparecieron problemas. Tenerlo desde el primer día habría atrapado problemas en los primeros 100 registros en lugar de los primeros 2.000.
Invierte en mejores embeddings para dedup. Usaríamos un modelo de embedding dedicado (como
text-embedding-3-small) desde el principio para detección de duplicados semánticos.Considera enrutamiento de modelo híbrido. Algunos registros son simples (camisetas con atributos básicos) y algunos son complejos (electrónica con docenas de especificaciones). Enrutar registros simples a Haiku y complejos a Sonnet -- incluso para descripciones -- habría ahorrado otro 20-30% en costos de API.
Si estás planificando un proyecto similar y quieres saltarte las partes dolorosas, hemos construido pipelines reutilizables para este tipo de trabajo como parte de nuestra práctica de desarrollo de CMS headless. Encantado de compartir más detalles específicos.
Preguntas Frecuentes
¿Cuánto tiempo toma enriquecer 28.000+ registros con IA? Nuestro tiempo de procesamiento actual fue aproximadamente 11 días, incluyendo desarrollo del pipeline, pruebas, procesamiento, y revisión QA. El procesamiento de API mismo (envío de solicitudes y obtención de respuestas) tomó aproximadamente 48 horas de ejecución continua. Si usas exclusivamente la API por Lotes, espera 24-48 horas para procesamiento más 3-5 días para ingeniería y QA.
¿Cuál es el costo por registro para enriquecimiento de contenido con IA? Usando Claude 3.5 Sonnet y Haiku en combinación, nuestro costo de API fue aproximadamente $0.092 por registro para generar una descripción de producto, categorías, meta descripción, y atributos estructurados. Tu resultado variará según longitudes de entrada/salida y qué modelo elijas. El procesamiento de API por Lotes reduce esto aproximadamente por la mitad.
¿Es Claude o GPT-4 mejor para enriquecimiento de datos en lote? Ambos funcionan bien. Elegimos Claude 3.5 Sonnet porque de su cumplimiento de formato JSON superior durante nuestras pruebas (97.1% vs ~94% para GPT-4o). Sin embargo, GPT-4o es ligeramente más barato para tokens de salida. Si tu enriquecimiento es principalmente clasificación en lugar de generación de contenido, la diferencia es negligible. Prueba ambos con 500 registros antes de comprometerte.
¿Cómo manejas límites de velocidad al hacer miles de llamadas a API? Usa una librería de limitador de velocidad como Bottleneck, establece concurrencia conservadora (5-10 solicitudes paralelas), implementa backoff exponencial para reintentos, y deja un buffer del 10-15% por debajo de los límites de velocidad publicados. Para trabajo no sensible al tiempo, la API por Lotes de Anthropic evita preocupaciones de límites de velocidad por completo y cuesta 50% menos.
¿Qué porcentaje de registros enriquecidos con IA necesitan revisión humana? En nuestro proyecto, 8.3% de registros necesitaban alguna forma de edición humana y 1.9% fueron completamente rechazados y reescritos manualmente. Tus números dependerán de la calidad de datos, ingeniería de prompts, y umbrales aceptables de calidad. Presupuesta para intervención humana del 5-15% como una línea base realista.
¿Puede el enriquecimiento en lote con IA manejar múltiples idiomas? Sí, pero la calidad varía significativamente según el idioma. Claude y GPT-4 manejan bien los principales idiomas europeos, pero la precisión cae para idiomas menos comunes. Recomendamos ejecutar plantillas de prompt separadas por idioma y tener hablantes nativos en tu muestra de QA. Espera que el porcentaje de revisión humana se duplique aproximadamente para contenido que no sea inglés.
¿Cómo previene alucinaciones de IA en datos de productos? Tres capas: instrucciones de prompt explícitamente prohibiendo características inventadas, una bandera "uncertain" para datos ambiguos, y validación automatizada comparando atributos enriquecidos contra datos fuente. También usamos puntuación de similitud semántica para marcar descripciones que divergían demasiado de la información original del producto. Esto redujo atributos alucinados por aproximadamente 70%.
¿Vale la pena construir un pipeline personalizado o debería usar una herramienta existente? Para menos de 1.000 registros, herramientas como Clay, Bardeen, o incluso un Google Sheets bien estructurado + setup de Apps Script pueden funcionar. Más allá de eso, un pipeline personalizado se paga a sí mismo rápidamente. El control sobre lógica de reintentos, validación de calidad, y optimización de costos que proporciona una solución personalizada es esencial a escala. Nuestro pipeline fue aproximadamente 2.000 líneas de TypeScript -- no trivial, pero tampoco un proyecto masivo. Verifica nuestra página de precios si te gustaría que construyamos uno para tu caso de uso.