{
  "title": "Corrigindo a busca no comércio B2B na era da IA",
  "excerpt": "Auditei 775.000 registros de produtos que alimentam a busca de quatro distribuidores B2B. Os gigantes do consumo já publicaram como corrigir catálogos como esses com LLMs, mas a distribuição comercial não adotou o manual. Aqui está ele, adaptado para HVAC, encanamento e elétrica, com custos reais.",
  "content_html": "<p>A busca no comércio B2B tem um segredo sujo: o algoritmo de ranqueamento raramente é o problema.</p>\n<p>Quando os resultados são ruins, as equipes buscam as alavancas divertidas. Boosts, sinônimos, embeddings, rerankers e, recentemente, compreensão de consultas por LLM. Eu mesmo puxei todas essas alavancas. Na semana passada, fiz a coisa sem glamour: despejei todos os registros de produtos de quatro índices de busca de produção - 775.051 registros em quatro distribuidores B2B de HVAC, encanamento, suprimentos industriais e fixadores - e auditei os próprios dados. Usei doze agentes de IA rodando em paralelo, cada um atribuído a uma dimensão: cobertura, qualidade do texto, números de peça, marcas, preços, especificações, categorias, mídia, duplicatas.</p>\n<p>O que voltou seria banal para quem já trabalhou no catálogo de um distribuidor e chocante para quem não trabalhou. Mas a parte que me marcou é esta: a correção já está publicada. Amazon, DoorDash e Instacart passaram dois anos escrevendo, em blogs públicos de engenharia, exatamente como usam LLMs para limpar, rotular e enriquecer catálogos bagunçados em escala. A distribuição comercial em grande parte não notou. O que é estranho, porque seus catálogos são mais bagunçados, suas consultas valem mais (um empreiteiro pedindo um condensador de US$ 4.000, não um almoço de US$ 12), e o tamanho dos catálogos torna a economia mais fácil.</p>\n<p>Então este post é esse manual, adaptado para distribuição comercial: os problemas de dados que quebram a busca B2B, como encontrá-los com um agente de codificação ainda hoje, como corrigi-los com LLMs, incluindo categorização UNSPSC, e quanto tudo isso custa. Spoiler sobre o último: menos do que você imagina por duas ordens de magnitude.</p>\n<h2>O manual já existe, só não na nossa indústria</h2>\n<p>Algumas coisas que as empresas de marketplace publicaram:</p>\n<ul>\n<li>A DoorDash usa LLMs com geração aumentada por recuperação para <a href=\"https://careersatdoordash.com/blog/how-doordash-leverages-llms-for-better-search-retrieval/\">construir seu grafo de conhecimento de produtos e melhorar a recuperação de busca</a>: extração automatizada de marcas, extração de atributos e vinculação de entidades em milhões de itens fornecidos por comerciantes.</li>\n<li>A Amazon construiu o <a href=\"https://www.amazon.science/blog/building-commonsense-knowledge-graphs-to-aid-product-recommendation\">COSMO</a>, um grafo de conhecimento gerado por LLM que conecta o que os clientes querem dizer (\"sapatos para mulheres grávidas\") ao que os produtos são (\"sapatos antiderrapantes\"). Eles relatam até 60% de melhoria no desempenho de recomendações em testes offline.</li>\n<li>A Instacart colocou LLMs na pilha de busca para <a href=\"https://tech.instacart.com/supercharging-discovery-in-search-with-llms-556c585d4720\">gerar conteúdo de descoberta</a> e está <a href=\"https://www.instacart.com/company/tech-innovation/building-the-intent-engine-how-instacart-is-revamping-query-understanding-with-llms\">reconstruindo a compreensão de consultas em torno deles</a> - com a geração pesada feita offline em lotes, precisamente para manter o custo baixo.</li>\n</ul>\n<p>O fio condutor é fácil de perder: as vitórias dos LLMs são do lado do catálogo e offline. Essas empresas enriquecem os dados antes de uma única consulta chegar. Os sistemas de descoberta se dividem em um lado offline que constrói artefatos (o catálogo, os índices, os embeddings) e um lado online que recupera e ranqueia sobre eles, e quase todo o valor publicado dos LLMs fica offline. A camada de ranqueamento só pode ser tão boa quanto o que recebe.</p>\n<p>Agora imagine um catálogo típico de distribuidor de HVAC ou encanamento ao lado disso. Ele é montado a partir de exportações de ERP, planilhas de fornecedores, feeds de grupos de compra e um parser CSV que alguém escreveu há uma década. Os \"títulos\" dos produtos são abreviações de fatura escritas para separadores de armazém. E o tráfego de busca que o atinge é tão denso em intenção quanto o tráfego de busca pode ser: metade são números de peça exatos, o resto é jargão comercial como \"3/4 cxc 90 ell\". Sinceramente, não consigo pensar em um ambiente melhor para este manual. As consultas são valiosas, os dados são corrigíveis e, com algumas centenas de milhares de SKUs, uma passada completa de LLM pelo catálogo custa centenas de dólares. Não milhões. Centenas.</p>\n<p>Aqui está a forma da auditoria, porque você vai querer reproduzi-la:</p>\n<pre><code class=\"language-mermaid\">flowchart TD\n    D[\"Raw catalog dump<br/>(JSONL, one record per line)\"] --&gt; C1[\"Per-catalog coverage agents<br/>null rates, distributions, dead fields\"]\n    D --&gt; C2[\"Dimension agents<br/>text · part numbers · brands · pricing<br/>specs · categories · media · duplicates\"]\n    C1 --&gt; S[\"Synthesis: findings ranked by<br/>severity, with example records\"]\n    C2 --&gt; S\n    S --&gt; F[\"Fix pipeline: rules + LLM enrichment<br/>+ UNSPSC classification + ingest gates\"]\n</code></pre>\n<p>Uma nota sobre o formato antes dos prompts. Tudo abaixo funciona em um dump genérico: um objeto JSON por linha, cada um com um <code>id</code> único e os campos do registro. Elasticsearch, OpenSearch, Solr, Algolia, Typesense, um PIM, uma exportação simples de banco de dados - não importa. Toda plataforma pode produzir essa forma, e todo prompt aqui roda contra ela.</p>\n<h2>Categoria 1: Falhas silenciosas no pipeline</h2>\n<p>A pior coisa que encontrei não foram dados ruins escritos por alguém. Foram dados que o pipeline destruiu no caminho, sem avisar ninguém.</p>\n<p>Esses catálogos constroem seu texto de busca primário no momento da ingestão, usando um regex scriptado que extrai dimensões e unidades dos títulos dos produtos. Em títulos longos, o regex estoura o limite de complexidade do mecanismo, o processador falha e o registro é indexado mesmo assim - com um campo de erro que ninguém lê e nenhum campo de busca primário.</p>\n<p><img src=\"/assets/images/b2b-search-silent-failures.png\" alt=\"Documents indexed with no primary search field, by distributor\" /></p>\n<p>Em toda a frota, 52.570 registros estavam no índice, invisíveis ao caminho principal de consulta. No pior catálogo, isso é um produto em sete. Nenhum painel detectou porque nada falhou. O pipeline retornou sucesso o dia todo, todos os dias, por meses.</p>\n<p>Mais duas descobertas da mesma família. O espelho desatualizado: um campo contém a verdade (um mapa de direitos por conta), e um segundo campo achatado o espelha para filtragem. Em um catálogo, o espelho havia divergido em 19,85% dos registros - 31.000 produtos ativos incorretamente ocultos da busca filtrada por conta. E o catálogo congelado: um índice não era atualizado há dez semanas enquanto seus irmãos eram atualizados diariamente. O tempo de atividade era monitorado. A atualização não era.</p>\n<p>As correções são chatas e é esse o ponto. Alerte sobre a cobertura de campos derivados (campo derivado vazio enquanto sua fonte não está). Não mantenha duas representações de um fato; derive o campo filtrável no momento da escrita. Monitore a atualização dos dados por catálogo como você monitora o tempo de atividade.</p>\n<p>Aqui está o prompt para encontrar tudo isso no seu próprio catálogo (Claude Code ou <code>codex exec</code>; mecânica no final):</p>\n<pre><code>Here is a dump of my product catalog as JSONL files in ./dump/ - one JSON\nrecord per line, each with a unique \"id\" and the product fields. My field/\nschema definition (if any) is in schema.json.\n\nWrite streaming Python (don't load it all in memory) to find silent pipeline\nfailures:\n1. Records carrying any error/exception field a pipeline stamped on them.\n2. For every DERIVED field (concatenations, *_search, *_normalized variants):\n   records where the derived field is empty but its obvious source field\n   is not.\n3. Pairs of fields that look like mirrors of each other (one nested/rich,\n   one flat/filterable): quantify how often they disagree.\n4. The distribution of updated/indexed timestamps: is any slice of the\n   catalog frozen while the rest refreshes?\n\nReport each finding with counts, % of catalog, 5 example ids, and whether the\naffected records are active/visible. Rank by severity.\n</code></pre>\n<h2>Categoria 2: Placeholders e sentinelas, ou: dados que mentem</h2>\n<p>Verificações de nulo são a ferramenta de qualidade de dados que todos já têm. Placeholders as derrotam, porque um placeholder é preenchido. Só não é verdadeiro.</p>\n<p>Meu exemplo favorito: em um catálogo de 313 mil SKUs, o campo de marca tinha 741 valores distintos e 99,99% de preenchimento. Parece saudável. O valor principal, em 88,8% de todos os registros, era \"Approved Vendor\". Um placeholder de ERP. A marca real mais popular cobria 0,3% do catálogo. Então, cada faceta de marca, boost de marca e reescrita consciente de marca estava efetivamente morta para nove décimos do catálogo, enquanto a interface de facetas oferecia alegremente \"Approved Vendor\" como o filtro de marca nº 1.</p>\n<p>Quando você começa a procurar, isso está em todo lugar:</p>\n<ul>\n<li>Um sentinela de \"sem preço\" de <code>99999999.000000</code> em 55% de um catálogo. O preço mediano desse índice era de noventa e nove milhões de dólares.</li>\n<li>Nomes de produtos literalmente <code>\"unknown\"</code> em 64 registros, que então ranqueiam para a consulta \"unknown\".</li>\n<li>Um booleano <code>true</code> escrito em um campo de descrição de texto em 1.516 produtos ativos. O mecanismo o coagiu para a string \"true\", o que tornou esses produtos encontráveis ao buscar \"true\".</li>\n<li>227 UPCs armazenados como <code>\"6.71E+11\"</code> - notação científica do Excel, com 51 produtos não relacionados compartilhando esse único \"identificador\" - além de 15.121 UPCs sem o zero inicial. O Excel ataca novamente.</li>\n<li>Um catálogo de fixadores cujo campo de marca continha nomes de linhas de produtos (\"C6L Lockbolts\", \"Tool Parts\") enquanto a marca real estava um campo ao lado.</li>\n</ul>\n<p>A lição que tirei desta categoria: audite as distribuições de valores top-N por campo, não as taxas de nulos. Um campo 100% preenchido pode ser 88% lixo, e nenhuma verificação de nulo vai te dizer isso. Em seguida, coloque os sentinelas na lista de bloqueio na ingestão, mapeie-os para nulos reais com flags explícitas <code>has_price</code> / <code>has_real_image</code>, faça asserção de tipo na fronteira e valide identificadores estruturalmente. Trate qualquer coisa que já passou por uma planilha como suspeita.</p>\n<pre><code>Same JSONL dump. For every field in my catalog, compute the top-20 value\ndistribution (full pass, streaming).\n\nFlag: (a) any single value covering &gt;10% of records - placeholder/sentinel\ncandidates like \"Approved Vendor\", \"unknown\", 99999999, 0.0; (b) values whose\ntype differs from the field's dominant type (booleans in text fields, floats\namong strings); (c) identifier fields (UPC/EAN/GTIN/part numbers): validate\nchecksum and length, flag scientific notation, stripped leading zeros,\nembedded whitespace/unicode, and identifiers shared by multiple records;\n(d) category-like or product-line values sitting in brand fields.\n\nFor each flag: count, % of catalog, 5 verbatim examples with ids, and a\none-line proposed ingest rule that would have rejected it.\n</code></pre>\n<h2>Categoria 3: Conteúdo empobrecido</h2>\n<p>Catálogos de distribuidores são escritos por ERPs, não por merchandisers. O texto é abreviação de fatura: <code>PROPRESS 2-1/2X1 CXC RED CPLG</code>, <code>HC HX 18X8 W</code>. Em um catálogo, um terço dos nomes de produtos tinha menos de 60% de palavras de dicionário. Em outro, os campos brutos de nome e descrição eram 100% nulos - o texto só existia dentro de blobs de busca derivados, então tudo que lia os campos brutos (títulos de resultados, entradas de embeddings, prompts de avaliação de relevância) estava lendo nada e ninguém sabia.</p>\n<p><img src=\"/assets/images/b2b-search-field-coverage.png\" alt=\"Field coverage across four production B2B indices\" /></p>\n<p>Esse heatmap é meu artefato favorito da auditoria. Cada um desses campos existe em todos os esquemas. Os números são quanto de cada um realmente contém dados. A linha que me pega é a de descrições de ML: a camada de enriquecimento que os esquemas prometiam em cada registro foi preenchida em dezoito documentos de 775.051. Dezoito. Cada ramo \"use enriquecimento se presente\" no pipeline de pontuação era um no-op silencioso. Esquema é uma aspiração; apenas cobertura é um fato.</p>\n<p>Esta categoria é onde o manual publicado se aplica mais diretamente - extração de atributos da DoorDash, geração offline da Instacart - e a seção de custos abaixo precifica isso. Mas quatro regras importam em um negócio de números de peça, aprendidas em parte com o que a tentativa anterior de enriquecimento errou:</p>\n<ul>\n<li>Expanda, não substitua. Gere o título legível pelo cliente junto com a string de fatura bruta e indexe ambos. A consulta do técnico de balcão e a do proprietário devem ambas acertar.</li>\n<li>Nunca verbalize códigos. Aqueles dezoito registros pioneiros? O gerador havia soletrado números de modelo em palavras: \"RGF cento e oitenta\". Nenhum empreiteiro digitará isso. Códigos permanecem verbatim; expansões são adições, não substituições.</li>\n<li>Extraia estrutura enquanto estiver lá. O mesmo passe que reescreve um título pode emitir <code>{size, material, connection_type}</code> para facetas.</li>\n<li>Jargão comercial é um problema de sinônimos, não de reescrita. <code>CXC</code>, <code>ELL</code>, <code>CPLG</code>, \"t-stat\" pertencem à expansão de sinônimos em nível de analisador, corrigida uma vez. Não pague para reescrevê-los em meio milhão de registros.</li>\n</ul>\n<pre><code>Same dump. Assess text quality of the customer-facing fields (name, short/long\ndescription) with a full streaming pass:\n\n1. Effective-title coverage: % of ACTIVE records with a non-empty display name.\n2. Readability: % ALL-CAPS names; % with under 60% dictionary-word tokens\n   (abbreviation salad); names under 10 chars; digits-only descriptions.\n3. Junk: HTML/CMS markup, encoding artifacts, embedded operational notes\n   (*** NOT A PHYSICAL ITEM ***), CSV column spillover.\n4. Duplication: identical short/long descriptions; boilerplate shared by 20+\n   SKUs; exact-length clusters (254/255/500 chars) indicating upstream\n   VARCHAR caps.\n5. Enrichment reality check: for every ML/enriched/embedding field the schema\n   promises, its actual coverage.\n\nNumbers, 5 verbatim examples each, severity, and which issues need an LLM\nenrichment pass vs. a pipeline fix vs. a synonym-layer fix.\n</code></pre>\n<h2>Categoria 4: Números de peça são sagrados</h2>\n<p>Metade do tráfego de busca B2B é alguém digitando um número de peça. Correspondência exata é todo o jogo lá, e ela falha de maneiras silenciosas.</p>\n<p>Em um catálogo, o número de peça indexado era um SKU numérico interno em 99,99% dos registros. O número do fabricante - o que está impresso na caixa - existia apenas dentro de descrições de texto livre. 183.000 produtos inacessíveis pelo número que um cliente realmente digitaria.</p>\n<p>Outro catálogo tinha um sistema de expansão de variantes: remover os traços, colapsar os segmentos, indexar as variantes para que a busca tolerante por PN funcione. Boa ideia. Mas o gerador era combinatório (até 80 variantes por produto), e em 11.826 registros uma variante gerada de um produto era exatamente igual ao número de peça canônico de um produto diferente. Fixadores são o caso brutal, porque a pontuação codifica dimensões físicas: <code>702-1-5/32</code> é uma peça de 1-5/32 polegadas e <code>702-15/32</code> é uma peça de 15/32 polegadas, e ambos normalizam para <code>7021532</code>. Um cliente digita um número de peça exato e recebe um cara ou coroa entre a peça certa e sua prima dimensional.</p>\n<p>Também nesta categoria: referências cruzadas de concorrentes (\"Eu tenho o número Ferguson, qual é o seu?\") armazenadas como blobs não divididos separados por pipe, como <code>19MU82|Fastenal 0269214|Ferguson M48222407</code>, em campos configurados como não pesquisáveis, então um movimento central de venda B2B simplesmente não funciona. E bifurcações de espaços em branco - o mesmo número de peça indexado três vezes (simples, com NBSP, com espaço final) - além de gêmeos mojibake de UTF-8 duplamente decodificado.</p>\n<p>O princípio que corrige a maior parte disso: o exato deve vencer o difuso estruturalmente, não probabilisticamente. Uma cláusula exata que preserva pontuação pontuada estritamente acima de qualquer camada normalizada, nunca uma correspondência plana onde uma variante pode empatar com um acerto canônico. Verifique as variantes geradas contra o espaço de PN canônico antes de indexar e descarte colisões. Normalize Unicode antes de derivar IDs de registro. Divida os blobs de referência cruzada em arrays; isso é uma única linha de código de ingestão que desbloqueia uma classe inteira de consultas.</p>\n<pre><code>Same dump. My users search by part number; audit exact-match integrity:\n\n1. Which PN-ish fields exist (part_number, mpn, alt/competitor/customer PNs,\n   UPC), their coverage, and which are configured unsearchable while holding\n   real data.\n2. Records whose only searchable PN token is an internal SKU (real\n   manufacturer PN appears only inside description text - show the pattern).\n3. If there's a PN-variant/keyword expansion field: find every generated\n   variant that equals a DIFFERENT record's canonical PN (normalize:\n   lowercase, strip punctuation). Show colliding pairs - especially\n   fraction-bearing fastener sizes.\n4. PNs differing only by whitespace/invisible chars/case from another\n   record's PN (duplicate identity forks).\n5. Multi-value cross-reference fields stored as delimited blobs instead of\n   arrays.\n\nCounts, examples, and for each issue the ingest rule or query-builder change\nthat fixes it.\n</code></pre>\n<p>Algumas coisas que não se encaixaram acima, mas merecem uma frase: um gerador de sinônimos que transformava qualquer número em termos de bitola de fio, então <code>REF#259286</code> virou \"259286 awg\" e uma rosca de parafuso <code>#8-32</code> virou \"fio de bitola 8\" (milhares de registros agora correspondem a consultas elétricas com as quais não têm nada a ver); flags internas de uma plataforma de e-commerce indexadas como especificações de produto pesquisáveis, 2,1 milhões de pares chave-valor inúteis; e 18 campos de esquema preenchidos em zero registros em qualquer lugar. Geradores de expansão precisam de portões de contexto. Esquema morto é uma promessa falsa sobre a qual alguém eventualmente construirá.</p>\n<h2>A camada ausente: UNSPSC e produtos que não sabem o que são</h2>\n<p>Há um quinto problema que merece sua própria seção, porque é onde a distribuição comercial fica mais atrás dos marketplaces: categorização.</p>\n<p>Na minha auditoria, os campos de categoria estavam ausentes em 83% de um catálogo. As chaves de atributo não tinham taxonomia alguma - 7.068 chaves de especificação distintas em um catálogo de 156 mil registros, 64% delas usadas em menos de dez produtos, com deriva como <code>horse_power</code> vs <code>horsepower</code> dividindo o mesmo atributo entre facetas. E o detalhe em que sempre volto: dois dos quatro catálogos tinham campos UNSPSC em seus esquemas, mapeados e prontos, preenchidos em exatamente zero registros. Alguém sabia que a categorização importava, construiu o espaço e nunca o preencheu. Aposto dinheiro no porquê: classificar 300 mil SKUs em uma taxonomia manualmente é um ano de trabalho da equipe de catálogo, então ficou no roadmap para sempre.</p>\n<p>Se você está fora do B2B, UNSPSC é o Código Padrão de Produtos e Serviços da ONU, a taxonomia que os sistemas de compras falam. Esta é a parte que a busca do consumidor não tem: os sistemas de compra dos seus clientes exigem isso. Catálogos punchout, plataformas de e-procurement e ferramentas de análise de gastos são construídos em torno dos códigos UNSPSC. Um distribuidor cujo catálogo carrega códigos limpos pode se conectar ao sistema de compras de um empreiteiro ou hospital. Um sem eles é uma lista de preços em PDF com uma caixa de busca. Internamente, também é o que alimenta facetas de categoria, ranqueamento com escopo de categoria (\"um número que é interpretado como bitola de fio só deve impulsionar fio\"), deduplicação entre catálogos e os portões de contexto para cada gerador de expansão da Categoria 4.</p>\n<p>E agora é um trabalho em lote. Este é o mesmo formato de problema que a DoorDash descreve resolver com LLMs - rotulagem de alto volume contra um vocabulário controlado - e a abordagem transfere diretamente:</p>\n<ul>\n<li>Classifique hierarquicamente, não plano. UNSPSC tem quatro níveis (segmento, família, classe, commodity). Faça o modelo escolher a família entre ~450 opções, depois a classe dentro dessa família. Duas escolhas pequenas e restritas vencem uma escolha de 50.000 vias, e você pode alimentar a fatia relevante da taxonomia no contexto da mesma forma que a DoorDash restringe a vinculação de entidades ao seu vocabulário.</li>\n<li>Pare no nível de classe primeiro. Códigos de classe já desbloqueiam facetas e integração de compras; a precisão em nível de commodity pode vir depois, onde valer a pena.</li>\n<li>Roteie por confiança. Um modelo pequeno pega os casos claros, registros de baixa confiança escalam para um modelo maior, e desacordos persistentes vão para uma fila humana que também serve como seu conjunto de avaliação.</li>\n</ul>\n<p>O custo é quase embaraçoso de digitar. Classificação é uma tarefa de saída curta: cerca de 300 tokens de entrada por registro e 30 de saída. No Claude Haiku 4.5 com preço da API em lote, isso é cerca de 17 centavos por mil SKUs. Minha frota inteira de 775 mil registros seria classificada por cerca de US$ 130. A coisa que ficou no roadmap por anos porque era um ano de trabalho manual custa menos do que o almoço da equipe onde você discutiria isso.</p>\n<pre><code>You classify B2B distributor products into UNSPSC. Attached: the UNSPSC\nfamily list (level 2, ~450 entries) as reference data.\n\nFor each product record (title, description, brand, part number, any existing\ncategory text), output JSON:\n- unspsc_family: the 4-digit family code - choose ONLY from the attached list\n- family_confidence: high | low\n- rationale: one short phrase (e.g. \"copper press fitting -&gt; pipe fittings\")\n\nRules: judge from the product's function, not its brand. Trade shorthand:\nCXC/FPT/MPT are pipe connections, ELL is elbow, CPLG is coupling, a bare\nfraction+material is usually a fitting size. If the record is not a physical\nproduct (freight lines, upcharges, \"*** NOT A PHYSICAL ITEM ***\"), output\nNOT_A_PRODUCT. Use low confidence liberally - low-confidence records get a\nsecond pass with the class-level list.\n</code></pre>\n<h2>O manual de limpeza, com a conta real</h2>\n<p>O pipeline de correção tem três camadas mais o trabalho de classificação. O truque é gastar na camada certa, porque você quase nunca precisa de uma chamada de LLM por registro.</p>\n<pre><code class=\"language-mermaid\">flowchart LR\n    A[\"Tier 0 - Rules<br/>deterministic code<br/>~$0\"] --&gt; B[\"Tier 1 - LLM on unique values<br/>brands · spec keys · units<br/>tens of dollars\"]\n    B --&gt; C[\"Tier 2 - LLM per record<br/>titles · attributes · UNSPSC<br/>hundreds of dollars\"]\n    C --&gt; G[\"Ingest gates<br/>every fix becomes a validator\"]\n</code></pre>\n<p><strong>Camada 0 é código determinístico e é basicamente grátis.</strong> Remova HTML e decodifique entidades. Transforme sentinelas em nulos reais com flags explícitas. Repare UPCs (preencha à esquerda, rejeite notação científica, valide o dígito verificador). Normalize IDs Unicode. Divida as referências cruzadas separadas por pipe. Descarte variantes de PN que colidem com o número canônico de outro produto. Exclua esquema morto. Um agente escreve esses scripts em uma sessão, e essa camada corrigiu cerca de metade de tudo que minha auditoria encontrou. Faça isso antes de qualquer enriquecimento, ou você pagará a um modelo para reescrever lindamente títulos de produtos que seu pipeline descartou silenciosamente.</p>\n<p><strong>Camada 1 roda o LLM sobre valores únicos, não registros.</strong> Este é o truque que torna problemas de vocabulário baratos: meu pior catálogo tinha 313 mil registros, mas apenas 741 strings de marca distintas. A normalização de marca é um trabalho sobre 741 strings - agrupe as variantes de maiúsculas, mapeie sub-marcas para as matrizes, sinalize os placeholders - não 313 mil chamadas. Mesma jogada para chaves de especificação e sufixos de unidade. Cada trabalho de vocabulário custa dígitos únicos de dólares e sua saída é uma tabela de aliases estática que sua ingestão aplica para sempre, deterministicamente. Chame a camada inteira de US$ 20-50 para uma frota, principalmente gastos em passes de revisão.</p>\n<pre><code>Attached: the full distinct-value distribution of my brand and manufacturer\nfields (value, record_count). Produce a normalization table:\n\ncanonical_brand, parent_manufacturer, [raw variants], confidence\n\nRules: cluster case/punctuation/whitespace variants; map sub-brands to parent\nmanufacturers as a separate column (don't merge); mark placeholder values as\nNULL_SENTINEL; mark product lines or categories misfiled as brands as\nNOT_A_BRAND. Flag uncertain clusters rather than guessing. Output CSV, then\nwrite a script that applies it at ingest and logs unmatched new values.\n</code></pre>\n<p><strong>Camada 2 é o passe por registro</strong>: um título legível pelo cliente, expansões de busca, atributos estruturados e um número de peça do fabricante recuperado para cada produto. Por SKU é pequeno - cerca de 400 tokens de entrada (o registro, mais instruções compartilhadas que o cache de prompt torna quase grátis) e 250 de saída. Duas alavancas antes mesmo de escolher um modelo: enriqueça o que está ativo (no meu pior catálogo, apenas 14% dos registros estavam ativos, um corte de 86% logo ali) e use uma API em lote onde o provedor tiver uma, já que o enriquecimento não tem requisito de latência e tanto a Anthropic quanto a OpenAI dão 50% de desconto para lote.</p>\n<p>Eu precifiquei o mesmo trabalho em tudo que você plausivelmente usaria em 2026 - Claude, <a href=\"https://openai.com/index/advancing-the-price-performance-frontier-with-gpt-5-6/\">os três níveis do GPT-5.6</a> (Sol, Terra, Luna), Kimi K3, GLM-5.2, Qwen3.5 e <a href=\"https://deepseek.ai/pricing\">DeepSeek V4</a>. Mesma carga de trabalho, taxas publicadas pelos provedores, desconto em lote aplicado onde existe:</p>\n<p><img src=\"/assets/images/b2b-search-enrichment-cost-by-model.png\" alt=\"Cost to enrich 775K SKUs across models\" /></p>\n<p>Tive que verificar esses números duas vezes porque pareciam errados. A versão de pior caso deste projeto - um modelo de fronteira, cada SKU, sem filtragem alguma - chega a cerca de US$ 3.800. O piso é menos de cem dólares: o DeepSeek V4-Flash enriqueceria a frota inteira pelo preço de uma furadeira decente. A versão que você realmente rodaria mistura camadas: um modelo econômico (Haiku, Luna, Qwen Flash, DeepSeek) para a maioria mecânica, um modelo intermediário (Sonnet, Terra, GLM-5.2) para a cauda de salada de abreviações que o pequeno sinaliza como baixa confiança, e um modelo de fronteira verificando uma amostra de 1-2% como portão de qualidade. Isso chega a algumas centenas de dólares para os SKUs ativos, independentemente de quais fornecedores você escolher.</p>\n<p>Duas ressalvas que o gráfico não mostra. Modelos baratos só são baratos se sua saída sobreviver à sua avaliação - rode a comparação de 200 amostras antes de se comprometer, porque um modelo econômico que estraga 5% dos números de peça custa mais do que o modelo de fronteira que não estraga. E seu catálogo é dado competitivo: preços, referências cruzadas e números de peça de clientes estão nesses registros, então verifique os termos de retenção de dados e treinamento de cada provedor antes de enviar 775 mil registros para o endpoint mais barato da lista. Para muitos distribuidores, essa verificação sozinha inclui ou exclui alguns fornecedores, e as opções de peso aberto (DeepSeek, GLM, Qwen, Kimi) têm a propriedade extra de que você pode hospedá-las você mesmo se os dados não puderem sair de forma alguma.</p>\n<p>Adicione o passe UNSPSC de ~US$ 130 (que escala da mesma forma entre modelos - na camada econômica cai para trocados) e o trabalho de vocabulário, e toda a transformação do catálogo fica entre algumas centenas e alguns milhares de dólares, contra um trabalho que costumava ser o ano de uma equipe de merchandising. É a mesma economia de lote offline que a Instacart descreve, só que na escala de catálogo comercial, onde os números ficam pequenos o suficiente para colocar em um cartão de crédito.</p>\n<p>Como fica em um registro real da minha auditoria:</p>\n<pre><code>IN:  part_number: 1678619\n     short_desc:  PROPRESS 2-1/2X1 CXC RED CPLG 20685\n     brand:       (placeholder)\n\nOUT: display_title:      2-1/2\" x 1\" ProPress Copper Reducing Coupling\n     search_expansions:  [\"copper press fitting\", \"reducing coupling\",\n                          \"press x press coupling\"]\n     attributes:         {size_1: {value: 2.5, unit: in},\n                          size_2: {value: 1, unit: in},\n                          material: copper, connection: press}\n     extracted_mpn:      \"20685\"\n     unspsc_family:      4017 (pipe fittings)\n     confidence:         high\n</code></pre>\n<p>Olhe a linha <code>extracted_mpn</code>. O mesmo passe recupera números de peça do fabricante que estavam enterrados no texto da descrição - em um dos meus catálogos, isso são 183 mil produtos se tornando encontráveis pelo número impresso na caixa. Isso sozinho paga o trabalho em lote.</p>\n<pre><code>You enrich B2B distributor product records for search. For each input record\n(raw ERP name, descriptions, brand, part number, category) produce JSON:\n\n- display_title: customer-readable, &lt;=80 chars, Title Case. Expand trade\n  abbreviations (CXC -&gt; copper x copper connection, ELL -&gt; elbow, CPLG -&gt;\n  coupling, RED -&gt; reducing). Keep every part number, model code, and\n  dimension VERBATIM as typed - never spell codes out in words.\n- search_expansions: 2-5 phrases a customer might type that don't appear in\n  the raw text (plain-English product type, common trade names). Never invent\n  specs absent from the source.\n- attributes: {name: {value, unit}} extracted ONLY from the source text.\n- extracted_mpn: manufacturer part number if present in the description text\n  (usually the token after the brand) and absent from the PN fields, else null.\n- confidence: high | low. Use low whenever you had to guess; a low answer\n  routed to review beats a confident hallucination.\n</code></pre>\n<p>Duas notas de produção: coloque as instruções compartilhadas em um prefixo de prompt em cache (o cache corta o lado de entrada em até 90% além do desconto em lote) e use saídas estruturadas com um esquema JSON para nunca pagar imposto de falha de análise.</p>\n<p><strong>A última camada é a que as pessoas pulam, e é a que se acumula.</strong> A auditoria vale uma limpeza. Os validadores que ela gera valem cada feed futuro. Termine a sessão de correção com:</p>\n<pre><code>Turn every issue we just fixed into an automated check that fails the ingest\npipeline loudly: derived-field coverage assertions, sentinel blocklists, type\nassertions on text fields, identifier checksum validation, PN-variant\ncollision checks, id hygiene rules, UNSPSC coverage tracking, and a data-\nfreshness alarm per catalog. Emit them as tests CI runs against a sample of\nevery new feed.\n</code></pre>\n<p>Pule isso e as mesmas exportações de ERP regenerarão o mesmo lixo em um trimestre, e você pagará pela limpeza duas vezes. Sei disso porque dois dos bugs que minha auditoria encontrou claramente já haviam sido corrigidos antes e voltaram.</p>\n<h2>Executando os prompts</h2>\n<p>Um passo de configuração: despeje seu catálogo em JSONL, um objeto JSON por linha com um <code>id</code> único e os campos do registro. Qualquer que seja sua plataforma - Elasticsearch, OpenSearch, Solr, Algolia, Typesense, um PIM, o banco de dados por trás de tudo - basta pedir ao agente para escrever o exportador:</p>\n<pre><code>Write a script that exports every product record from my catalog [describe:\nsearch index name / database table / PIM export] to ./dump/records-{n}.jsonl\nin 50k-record chunks - one JSON object per line with a unique \"id\" plus all\nfields - and my field/schema definition (if the platform has one) to\nschema.json. Verify the exported count matches the source count.\n</code></pre>\n<p>Com Claude Code, coloque qualquer prompt de categoria em uma sessão nesse diretório. Ele escreve e executa a análise sozinho, passes completos sem desculpas de amostragem, e volta com recibos em nível de registro. Quando você diz \"agora corrija\", a mesma sessão produz o validador de ingestão, o script de backfill e o trabalho de enriquecimento em lote. Rode as categorias como sessões paralelas ou subagentes; foi assim que rodei as minhas, e toda a auditoria levou cerca de doze minutos de tempo real. Com Codex, <code>codex exec</code> lida com os passes de análise somente leitura usando os mesmos prompts; mantenha as correções do lado de escrita em uma sessão que você revise.</p>\n<p>Três regras que aprendi da maneira difícil:</p>\n<ol>\n<li>Exija passes completos e recibos. \"Analise estes dados\" convida a amostragem e vibes. Peça contagens exatas e cinco IDs de exemplo por descoberta, e cada afirmação se torna verificável.</li>\n<li>Regras antes do enriquecimento. Corrija a verdade antes de adicionar prosa, ou você vai alucinar marcas para os 88% dos registros rotulados como \"Approved Vendor\".</li>\n<li>Amostre, avalie, depois lote. Nunca dispare um lote de 775 mil registros a partir de um prompt não validado. 200 amostras, um passe de pontuação, depois escale. O harness de avaliação custa uma sessão de agente e reduz o risco de todo o gasto.</li>\n</ol>\n<h2>Os ofícios merecem busca de nível marketplace</h2>\n<p>Amazon, DoorDash e Instacart não publicaram seu trabalho de LLM de catálogo como caridade. Eles publicaram porque as técnicas são gerais e o fosso é a execução. E as técnicas transferem para a distribuição comercial melhor do que quase qualquer outro lugar que eu consiga pensar: os catálogos são pequenos o suficiente para que um passe completo seja barato, os dados são ruins o suficiente para que o espaço de melhoria seja enorme, as consultas carregam dinheiro real, e o mundo de compras já roda em uma taxonomia que um trabalho em lote agora pode preencher por cerca de US$ 130.</p>\n<p>Das dezenas de problemas que minha auditoria revelou em quatro catálogos de distribuidores, nenhum era visível da camada de ranqueamento. Todos o degradavam. A cadeia de suprimentos que alimenta esses índices - as exportações de ERP, as planilhas de fornecedores, os antigos parsers CSV - é exatamente o que o manual publicado corrige. Os distribuidores que o executarem terão busca de nível marketplace em catálogos onde seus concorrentes ainda não conseguem encontrar uma serpentina de condensador.</p>\n<p>A pergunta \"há algo errado com meus dados?\" costumava custar duas semanas do tempo de alguém, e é por isso que ninguém a fazia. Agora custa um prompt. Faça-a.</p>",
  "source_hash": "sha256:729970b39c1b22c143ba55272659d6cc431b0f8889282089a4ea4eaa71f75000",
  "model": "~deepseek/deepseek-v4-flash-latest",
  "generated_at": "2026-08-06T08:45:03.066588+00:00"
}