Enriquecemos 28.840 Registros com IA: Lições de Processamento em Massa
Enriquecimento de 28.840 registros de produtos com IA: Arquitetura, custos e lições aprendidas
No trimestre passado, assumimos um projeto que parecia simples no papel: enriquecer 28.840 registros de produtos com descrições geradas por IA, categorias e metadados. O cliente tinha um catálogo de e-commerce massivo migrando para um CMS headless, e cada registro precisava de melhor conteúdo. O que se seguiu foi uma aula magistral sobre tudo que pode dar errado -- e certo -- quando você joga dezenas de milhares de registros em uma API de IA.
Isto não é um guia teórico. Vou te guiar através da arquitetura real que construímos, dos custos exatos que pagamos, dos modos de falha que encontramos, e dos padrões que nos salvaram. Se você está considerando enriquecimento de conteúdo em massa com IA para seu próprio projeto, isto deve economizar algumas semanas de descoberta dolorosa.
Índice
- Por que escolhemos enriquecimento com IA sobre trabalho manual
- A arquitetura: como construímos o pipeline
- Escolhendo Claude API para processamento em massa
- Engenharia de prompt em escala
- Limites de taxa, tentativas e a arte de não ser bloqueado
- Controle de qualidade: a realidade do humano no loop
- Breakdown de custos reais
- O que fizemos errado
- O que faríamos diferente da próxima vez
- Perguntas frequentes
Por que escolhemos enriquecimento com IA sobre trabalho manual
A matemática era brutalmente simples. Nosso cliente tinha 28.840 registros de produtos -- cada um precisava de uma descrição reescrita (150-300 palavras), três tags de categoria amigáveis para SEO, uma meta descrição e atributos estruturados extraídos de texto não estruturado. Com uma estimativa conservadora de 8 minutos por registro para um redator copywriter humano, isso dá 3.845 horas de trabalho. A $35/hora, você está olhando para $134.575 e aproximadamente 6 meses de tempo com uma pequena equipe.
Completamos o enriquecimento com IA em 11 dias por menos de $3.200 em custos de API, mais cerca de 80 horas de tempo de engenharia e QA. Até mesmo fatorando nossas horas de desenvolvimento, o custo total foi aproximadamente um décimo da abordagem manual.
Mas aqui está a coisa que ninguém te diz: a parte difícil não é chamar a API. É tudo ao redor dela. Limpeza de dados, ajuste de prompt, validação de qualidade, tratamento de erros e os casos extremos inevitáveis que te fazem questionar suas escolhas de carreira.
A arquitetura: como construímos o pipeline
Construímos o pipeline de enriquecimento como uma aplicação Node.js, o que fazia sentido dado a expertise do nosso time em desenvolvimento Next.js e TypeScript. Aqui está a arquitetura de alto nível:
CSV de origem → Parser → Fila em lote → Claude API → Validador de resposta → Armazenamento de saída → Dashboard de QA
A camada de dados
Usamos SQLite como nosso banco de dados de processamento local. Soa sem graça, certo? Mas para processamento em lote como este, é perfeito. Nenhum servidor para gerenciar, transações são rápidas e você pode facilmente consultar seus resultados. Cada registro recebeu uma coluna de status rastreando sua jornada:
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;
}
O sistema de fila
Implementamos uma fila de trabalho simples usando BullMQ apoiada por Redis. Cada trabalho representava um único enriquecimento de registro. Configuramos com:
- Concorrência: 5 workers paralelos (mais sobre por que esse número depois)
- Máximo de tentativas: 3 por registro
- Backoff: Exponencial, começando em 30 segundos
- Timeout do trabalho: 60 segundos
const enrichmentQueue = new Queue('enrichment', {
connection: redisConnection,
defaultJobOptions: {
attempts: 3,
backoff: {
type: 'exponential',
delay: 30000,
},
timeout: 60000,
removeOnComplete: false, // Manter para auditoria
},
});
O worker de processamento
Cada worker puxava um registro, construía o prompt, chamava a API de Claude, validava a estrutura da resposta e escrevia os resultados de volta. Se a resposta não correspondesse ao nosso schema JSON esperado, era enviada para um bucket needs_review em vez de corromper silenciosamente nosso dataset.
Escolhendo Claude API para processamento em massa
Avaliamos três opções antes de nos estabelecermos em Claude (especificamente Claude 3.5 Sonnet, e depois Claude 3.5 Haiku para tarefas mais simples):
| Feature | Claude 3.5 Sonnet | GPT-4o | Gemini 1.5 Pro |
|---|---|---|---|
| Custo de entrada (por 1M de tokens) | $3.00 | $2.50 | $1.25 |
| Custo de saída (por 1M de tokens) | $15.00 | $10.00 | $5.00 |
| Limites de taxa (RPM, Tier 2) | 1.000 | 500 | 360 |
| Confiabilidade do modo JSON | Excelente | Bom | Inconsistente |
| Qualidade de saída estruturada | Melhor da classe | Muito bom | Bom |
| Desconto de API em lote | 50% | 50% | N/A |
Preços como de Q1 2025. Verifique os preços atuais -- estes mudam frequentemente.
Escolhemos Claude por algumas razões. Primeiro, seu acompanhamento de instruções para saída estruturada foi notavelmente melhor do que as alternativas durante nossa execução de teste de 500 registros. Quando você está processando quase 29K registros, até uma melhoria de 2% em conformidade de formato economiza centenas de correções manuais. Segundo, a Batch API de Anthropic oferecia um desconto de 50% para trabalho não sensível ao tempo, o que tornou a economia ainda mais favorável.
Honestamente, GPT-4o teria sido bom também. As diferenças nesta escala são mais sobre limites de taxa e preços do que qualidade bruta. Mas a consistência de Claude com saída JSON foi o fator decisivo.
Por que usamos Sonnet e Haiku
Aqui está um truque que economizou cerca de 40% em custos de API: não usamos o mesmo modelo para tudo. Descrições de produtos precisavam da qualidade do Sonnet. Mas classificação de categoria e extração de atributos? Haiku se saía bem apenas com uma fração do custo.
Dividimos o enriquecimento em dois passes:
- Pass 1 (Haiku): Classificação de categoria, extração de atributos, metadados básicos -- $0.25/1M entrada, $1.25/1M saída
- Pass 2 (Sonnet): Reescrita de descrição, meta descrições, conteúdo SEO -- $3.00/1M entrada, $15.00/1M saída
Engenharia de prompt em escala
Isto é onde a maioria dos tutoriais te falha. Eles mostram um único prompt e chamam de pronto. Quando você está rodando 28.840 registros através do mesmo template de prompt, pequenos defeitos são amplificados em problemas massivos.
O template de prompt
Após cerca de 15 iterações (sim, rastreamos elas em git), aqui está a estrutura aproximada que funcionou:
const buildPrompt = (record: SourceRecord): string => `
Você está enriquecendo dados de produto para um catálogo de e-commerce. Gere o seguinte para o produto abaixo:
1. Uma descrição de produto (150-300 palavras, segunda pessoa, focada em benefícios)
2. Exatamente 3 tags de categoria desta lista permitida: ${CATEGORY_LIST}
3. Uma meta descrição (120-155 caracteres)
4. Atributos estruturados como pares chave-valor
Regras:
- NÃO invente recursos não presentes nos dados de origem
- Se a informação for ambígua, use a flag "uncertain"
- Corresponda ao tom da marca: profissional mas acessível
- A descrição deve ser única -- não repita o título textualmente na primeira sentença
Responda APENAS com JSON válido correspondendo a este schema:
${JSON_SCHEMA}
Dados de produto de origem:
Título: ${record.title}
Descrição existente: ${record.description}
Atributos brutos: ${record.attributes}
Preço: ${record.price}
Marca: ${record.brand}
`;
Lições sobre prompts em escala
Seja absurdamente específico sobre formato de saída. Incluímos o schema JSON completo em cada request. Sim, adiciona tokens. Não, não pule isso. A única vez que tentamos confiar apenas em instruções do sistema, nossa conformidade de formato caiu de 97% para 81%.
Restrinja o vocabulário de saída. Para tags de categoria, fornecemos uma lista permitida explícita. Categorização aberta produzia 847 categorias únicas no lote de teste. A versão restrita? Exatamente as 42 que queríamos.
Adicione proteções contra alucinação. Produtos ocasionalmente brotariam recursos que não tinham. Adicionar "NÃO invente recursos não presentes nos dados de origem" reduziu atributos alucinados em cerca de 70%. Adicionar a flag uncertain capturou a maioria dos casos restantes.
Temperatura importa mais do que você pensa. Nos estabelecemos em 0.3. Menor do que isso e descrições ficavam repetitivas entre produtos similares. Maior e começávamos a conseguir escrita criativa que não correspondia à voz da marca.
Limites de taxa, tentativas e a arte de não ser bloqueado
Esta seção deveria ser chamada "a parte que levou a maior parte do tempo de engenharia." Os limites de taxa de Anthropic são bem documentados mas se comportam diferentemente sob carga sustentada do que você esperaria lendo a documentação.
Nossa estratégia de limite de taxa
No Tier 2 (que você consegue depois de gastar $40+), Claude te dá 1.000 requests por minuto e 80.000 tokens por minuto. Soa generoso até você perceber que nosso request médio era cerca de 1.200 tokens de entrada e 800 tokens de saída. Isso significava que nosso limite prático era cerca de 40 requests concorrentes antes de bater limites de token.
Rodamos 5 workers concorrentes, cada um processando um registro de cada vez, com um atraso de 200ms entre requests. Isto nos dava aproximadamente 15-20 requests por minuto -- bem abaixo do limite de RPM e confortavelmente dentro dos orçamentos de token.
const rateLimiter = new Bottleneck({
maxConcurrent: 5,
minTime: 200, // ms entre requests
reservoir: 900, // requests por minuto (deixando buffer)
reservoirRefreshAmount: 900,
reservoirRefreshInterval: 60 * 1000,
});
Por que tão conservador? Porque bater limites de taxa causa falhas em cascata. Uma resposta 429 dispara uma tentativa, que adiciona à fila, que aumenta pressão de concorrência. Aprendemos isso da forma difícil durante a hora 3 de nossa primeira execução real, quando configurações agressivas causaram uma tempestade de tentativas que efetivamente travou o pipeline por 45 minutos.
A alternativa de Batch API
No meio do projeto, mudamos parcialmente para a Batch API de Anthropic. Em vez de fazer requests individuais, você envia um arquivo JSONL de requests e consegue resultados de volta em 24 horas. O tradeoff: redução de custo de 50%, mas você perde feedback em tempo real.
Usamos a Batch API para o Pass 1 (classificação Haiku) e API em tempo real para o Pass 2 (descrições Sonnet). Esta abordagem híbrida foi o ponto doce para nós -- feedback rápido sobre o trabalho criativo caro, economia em lote no trabalho de classificação mercadoria.
Controle de qualidade: a realidade do humano no loop
Qualquer um que te diga que enriquecimento com IA é totalmente automatizado está mentindo ou não fez em escala. Construímos um processo de QA que capturou problemas cedo e preveniu lixo de chegar à produção.
Validação automatizada
Toda resposta de API passou por validação antes de ser aceita:
const validateEnrichment = (result: EnrichmentResult): ValidationOutcome => {
const issues: string[] = [];
// Verificações de comprimento
if (result.description.length < 400 || result.description.length > 2000) {
issues.push('description_length');
}
// Validação de categoria
const invalidCats = result.categories.filter(c => !ALLOWED_CATEGORIES.includes(c));
if (invalidCats.length > 0) issues.push('invalid_categories');
// Comprimento de meta descrição
if (result.meta.length > 160) issues.push('meta_too_long');
// Sinais de alucinação
const hallucination_phrases = ['I think', 'probably', 'might be', 'as an AI'];
if (hallucination_phrases.some(p => result.description.includes(p))) {
issues.push('possible_hallucination');
}
// Detecção de duplicação (correspondência difusa contra registros já processados)
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,
};
};
Amostragem de revisão manual
Amostramos 5% de todos os registros processados (cerca de 1.440) para revisão manual. Nosso time de QA pontuou cada um em precisão, voz de marca e completude. Aqui estão os números de nossa revisão real:
| Métrica | Pontuação |
|---|---|
| Precisão factual | 94.2% |
| Correspondência de voz de marca | 87.6% |
| Conformidade de formato | 97.1% |
| Precisão de categoria | 91.8% |
| Registros precisando revisão | 8.3% |
| Registros completamente rejeitados | 1.9% |
Esse 8.3% precisando revisão é importante contexto. Significa que cerca de 2.400 registros precisaram de edição humana. Ainda muito menos do que escrever manualmente todos 28.840 -- mas não é zero. Faça orçamento para isto.
Breakdown de custos reais
Tempo de transparência. Aqui está o que realmente gastamos:
| Categoria de custo | Quantia |
|---|---|
| Claude 3.5 Haiku (Pass 1 - Batch API) | $312 |
| Claude 3.5 Sonnet (Pass 2 - Tempo real) | $2.147 |
| Requests falhados/tentativas (~6% de sobrecarga) | $189 |
| Hospedagem Redis (2 semanas) | $15 |
| Tempo de engenharia (80 hrs × $150) | $12.000 |
| Tempo de revisão de QA (40 hrs × $45) | $1.800 |
| Total | $16.463 |
| Apenas custos de API | $2.648 |
Compare isso com a estimativa de $134.575 para trabalho totalmente manual. Até mesmo incluindo todo o tempo de engenharia e QA, estamos em cerca de 12% do custo manual. E o pipeline é reutilizável -- da próxima vez que rodamos um projeto similar, o custo de engenharia cai para praticamente zero.
O custo de API por registro funcionou a cerca de $0.092. Menos de dez centavos por registro para enriquecimento com IA. Esse é o número que faz executivos se endireitar nas cadeiras.
O que fizemos errado
Subestimar limpeza de dados
Gastamos 3 dias apenas limpando os dados de origem antes de enviar para Claude. Registros tinham entidades HTML, lixo Unicode, descrições truncadas e campos nas colunas erradas. Lixo entra, lixo sai não é apenas um cliché -- é a lei fundamental do processamento em massa com IA.
Não usar a Batch API desde o primeiro dia
Queimamos cerca de $400 extra em custos de API rodando Pass 1 através da API em tempo real antes de descobrir que a Batch API teria sido metade do preço. Leia a documentação completa antes de começar. Tudo.
Detecção insuficiente de duplicação
Nossa detecção de duplicação inicial era muito ingênua -- correspondência de string simples. Claude geraria descrições que eram estruturalmente idênticas mas usavam palavras um pouco diferentes para produtos similares. Tivemos que implementar verificação de similaridade semântica (usando embeddings) para capturar estas, que adicionou um dia de trabalho.
Falhas de parsing JSON
Cerca de 2.4% das respostas vieram de volta com JSON malformado. Às vezes uma vírgula à direita, às vezes uma citação não escapada em uma descrição de produto. Devíamos ter implementado um parser JSON mais indulgente desde o início em vez de tratar estes como falhas duras.
// O que devíamos ter feito desde o primeiro dia
const parseResponse = (raw: string): EnrichmentResult | null => {
try {
return JSON.parse(raw);
} catch {
// Tente extrair JSON de blocos de código markdown
const jsonMatch = raw.match(/```json?\n?([\s\S]*?)\n?```/);
if (jsonMatch) {
try { return JSON.parse(jsonMatch[1]); } catch { /* cair através */ }
}
// Tente biblioteca jsonrepair como último recurso
try { return JSON.parse(jsonrepair(raw)); } catch { return null; }
}
};
O que faríamos diferente da próxima vez
Comece com um piloto de 1.000 registros antes de se comprometer com a execução completa. Fizemos 500 e não foi suficiente para surfar todos os casos extremos.
Use saídas estruturadas desde o início. Anthropic agora suporta uso de ferramenta com schemas definidos, que elimina a maioria dos problemas de parsing JSON. Migramos para isto no meio do caminho e desejávamos ter começado aí.
Construa o dashboard de QA primeiro. Construímos reativamente após problemas aparecerem. Tê-lo desde o primeiro dia teria capturado problemas nos primeiros 100 registros em vez dos primeiros 2.000.
Invista em melhores embeddings para dedup. Usaríamos um modelo de embedding dedicado (como
text-embedding-3-small) desde o início para detecção de duplicação semântica.Considere roteamento de modelo híbrido. Alguns registros são simples (camisetas com atributos básicos) e alguns são complexos (eletrônicos com dezenas de especificações). Rotear registros simples para Haiku e complexos para Sonnet -- até mesmo para descrições -- teria economizado outro 20-30% em custos de API.
Se você está planejando um projeto similar e quer pular as partes dolorosas, construímos pipelines reutilizáveis para este tipo de trabalho como parte de nossa prática de desenvolvimento CMS headless. Feliz em compartilhar mais especificidades.
Perguntas frequentes
Quanto tempo leva para enriquecer 28.000+ registros com IA? Nosso tempo de processamento real foi cerca de 11 dias, incluindo desenvolvimento de pipeline, testes, processamento e revisão de QA. O processamento de API em si (enviar requests e receber respostas) levou aproximadamente 48 horas de execução contínua. Se você estiver usando exclusivamente a Batch API, espere 24-48 horas para processamento mais 3-5 dias para engenharia e QA.
Qual é o custo por registro para enriquecimento de conteúdo com IA? Usando Claude 3.5 Sonnet e Haiku em combinação, nosso custo de API foi aproximadamente $0.092 por registro para gerar uma descrição de produto, categorias, meta descrição e atributos estruturados. Seus resultados variarão baseado em comprimentos de entrada/saída e qual modelo você escolhe. O processamento de Batch API corta isto aproximadamente na metade.
Claude ou GPT-4 é melhor para enriquecimento de dados em massa? Ambos funcionam bem. Escolhemos Claude 3.5 Sonnet por causa de sua conformidade de formato JSON superior durante nossos testes (97.1% vs ~94% para GPT-4o). Porém, GPT-4o é um pouco mais barato para tokens de saída. Se seu enriquecimento é primariamente classificação em vez de geração de conteúdo, a diferença é negligenciável. Teste ambos com 500 registros antes de se comprometer.
Como você gerencia limites de taxa ao fazer milhares de chamadas de API? Use uma biblioteca de rate limiter como Bottleneck, defina concorrência conservadora (5-10 requests paralelos), implemente backoff exponencial para tentativas e deixe um buffer de 10-15% abaixo dos limites de taxa publicados. Para trabalho não sensível ao tempo, a Batch API de Anthropic evita problemas de limite de taxa inteiramente e custa 50% menos.
Qual porcentagem de registros enriquecidos com IA precisa de revisão humana? Em nosso projeto, 8.3% de registros precisavam de alguma forma de edição humana e 1.9% foram completamente rejeitados e reescritos manualmente. Seus números dependerão de qualidade de dados, engenharia de prompt e limites aceitáveis de qualidade. Faça orçamento para 5-15% de intervenção humana como baseline realista.
A enriquecimento em massa com IA pode lidar com múltiplos idiomas? Sim, mas a qualidade varia significativamente por idioma. Claude e GPT-4 lidam bem com idiomas europeus principais, mas a precisão cai para idiomas menos comuns. Recomendamos rodar templates de prompt separados por idioma e ter falantes nativos em sua amostra de QA. Espere que a porcentagem de revisão humana aproximadamente dobre para conteúdo não-inglês.
Como você previne alucinações de IA em dados de produto? Três camadas: instruções de prompt explicitamente proibindo recursos inventados, uma flag "uncertain" para dados ambíguos e validação automatizada comparando atributos enriquecidos contra dados de origem. Também usamos scoring de similaridade semântica para marcar descrições que divergiram muito da informação de produto original. Isto reduziu atributos alucinados por aproximadamente 70%.
Vale a pena construir um pipeline customizado ou devo usar uma ferramenta existente? Para menos de 1.000 registros, ferramentas como Clay, Bardeen ou até mesmo um setup bem-estruturado de Google Sheets + Apps Script podem funcionar. Além disso, um pipeline customizado se paga rapidamente. O controle sobre lógica de tentativa, validação de qualidade e otimização de custo que uma solução customizada fornece é essencial em escala. Nosso pipeline foi aproximadamente 2.000 linhas de TypeScript -- não trivial, mas não um projeto massivo tampouco. Verifique nossa página de preços se você gostaria que nós construíssemos um para seu caso de uso.