Blog Houssan Ali Hijazi
IA · Python · Android
← Voltar ao blog
Inteligência Artificial, Python

Como reduzir o custo de categorizar milhares de produtos treinando um modelo local

Categorização Híbrida de Produtos: Sklearn local + IA como fallback

Como reduzimos o custo de categorizar milhares de produtos treinando um modelo local que resolve parte dos casos a custo zero antes de chamar uma LLM.

O problema

O catálogo do Lojas Paraguai recebe milhares de produtos novos vindos do crawler, e cada um precisa de categoria e marca para aparecer corretamente no site. Categorizar à mão é inviável, e a primeira solução automatizada, enviar todos os produtos para uma LLM, funcionava, mas com dois custos altos:

  • Tempo: alguns segundos por batch via API (Ollama/Google/OpenAI).
  • Dinheiro: cada batch de produtos era uma chamada de API paga, mesmo para casos óbvios como "Samsung Galaxy A50" → Smartphones / Samsung.

A maioria dos produtos é trivial de classificar. Pagar uma LLM para resolver o óbvio não fazia sentido.

A solução

Uma estratégia híbrida em duas fases, implementada no comando categorize_products_hybrid:

  1. Fase 1, Sklearn (local, custo zero, mais rápido) Um classificador treinado com os próprios dados do banco prediz categoria e marca a partir do nome do produto. Se a confiança for ≥ ao threshold (padrão 0.75), o resultado é aceito direto.

  2. Fase 2, LLM (fallback, tem custo, mais lento) Só os produtos em que o modelo local ficou inseguro vão para a IA (via LiteLLM, padrão gemini-2.5-flash-lite), que retorna nomes de categoria/marca resolvidos contra o banco por um mapa de aliases. Esse custo de api é cortado com a possibilidade do uso de modelos locais.

A fração que o modelo local resolve sozinho depende do mix de produtos: em itens comuns é alta, na cauda longa (nomes ruins, produtos raros, marcas obscuras) a confiança cai e a LLM assume. Cada produto que o Sklearn resolve é tempo e custo de API economizados.

Comparativo por batch de 50 produtos (mesma carga nas duas colunas):

Métrica Sklearn (local) LLM (se tudo fosse IA)
Tempo/batch (50) <50ms alguns segundos
Custo API/batch 0 ~0.005 USD
Acurácia cat ~94% · marca ~90% ~95–98% (estimado)

Como resolvemos

1. Treinamos um modelo para rodar localmente

O comando train_category_brand_model treina dois classificadores independentes, um para categoria (~1000 classes) e outro para marca (~200), salvos como pickles separados.

O pipeline é TF-IDF + SGDClassifier, gera os modelos como pickle:

crawler/data/models/categoria_classifier.pkl
crawler/data/models/marca_classifier.pkl
lnp train_category_brand_model

Esse é o ponto-chave: o modelo roda 100% local, sem API, sem rede, sem custo por predição. Carregado uma vez, classifica milhares de produtos por segundo. E como é treinado com os dados do próprio banco, retorna IDs diretos de categoria e marca, sem necessidade de resolução de nomes.

2. Orquestramos as duas fases com threshold de confiança

O processor_hybrid.py decide por produto: aceita a predição do Sklearn se a confiança passa do threshold, senão acumula em lotes para a LLM. O threshold é o botão de ajuste entre custo e qualidade:

Threshold Efeito
0.50 Aceita mais predições locais → menos IA, mais barato, menor precisão
0.75 (padrão) Equilíbrio entre custo e qualidade
0.95 Só aceita predições muito confiantes → mais IA, mais caro, maior precisão

Quanto cada threshold resolve localmente depende do mix de produtos do lote, não é um percentual fixo.

Resultados

Saída real de uma execução sobre o backlog de produtos não categorizados:

📊 Resumo Categorização
  Modo               HÍBRIDO
  Total processado   164
  Sklearn            80 (49%)
  IA                 84 (51%)
  Cat adicionada     98
  Marca adicionada   84
  Sem categoria      66
  Cat novas          34
  Erros              1

Medindo 4 execuções seguidas (764 produtos do backlog), o modelo local resolveu ~36% a custo zero e o restante foi para a LLM, uma economia de custo de ~1,5× neste cenário.

⚠️ Importante: esse teste consome o backlog acumulado de casos difíceis (a cauda longa que sobrou sem categoria), o pior cenário para o modelo local. A fração resolvida cai a cada execução (49% → 37% → 27% → 32%) conforme os fáceis são esgotados. Em produção contínua, com produtos comuns chegando do crawler e retreino frequente, a fração local tende a ser maior, mas isso depende do mix real de cada dia.

Lições

  • Nem todo problema de classificação precisa de LLM. Um TF-IDF + classificador linear treinado nos próprios dados resolve boa parte dos casos em menos de 1ms e a custo zero, quanto mais comum o produto, maior a fatia que ele cobre.
  • A LLM brilha como fallback, não como primeira linha: ela cuida dos casos ambíguos, genéricos ou novos que o modelo local nunca viu.
  • Modelo local melhora com o tempo: cada produto categorizado (por IA ou revisão) vira dado de treino para o próximo train_category_brand_model, reduzindo progressivamente a dependência da LLM.