{
  "title": "Cómo arreglar la búsqueda en el comercio B2B en la era de la IA",
  "excerpt": "Audité 775 000 registros de productos que alimentan la búsqueda de cuatro distribuidores B2B. Los gigantes del consumo ya han publicado cómo arreglar catálogos como estos con LLMs, pero la distribución comercial no ha recogido el manual. Aquí está, adaptado para HVAC, plomería y electricidad, con costos reales.",
  "content_html": "<p>La búsqueda en el comercio B2B tiene un secreto incómodo: el algoritmo de ranking rara vez es el problema.</p>\n<p>Cuando los resultados son malos, los equipos tiran de las palancas divertidas. Boosts, sinónimos, embeddings, rerankers y, últimamente, la comprensión de consultas con LLM. Yo mismo he tirado de todas esas palancas. La semana pasada hice lo poco glamuroso en su lugar: volqué todos los registros de productos de cuatro índices de búsqueda en producción —775 051 registros de cuatro distribuidores B2B en HVAC, plomería, suministro industrial y fijaciones— y audité los datos en sí. Usé doce agentes de IA ejecutándose en paralelo, cada uno asignado a una dimensión: cobertura, calidad del texto, números de parte, marcas, precios, especificaciones, categorías, medios, duplicados.</p>\n<p>Lo que volvió no sorprendería a nadie que haya trabajado en el catálogo de un distribuidor, y sería impactante para quien no lo haya hecho. Pero lo que se me quedó grabado es esto: la solución ya está publicada. Amazon, DoorDash e Instacart han pasado dos años documentando, en blogs públicos de ingeniería, exactamente cómo usan los LLM para limpiar, etiquetar y enriquecer catálogos desordenados a escala. La distribución comercial, en su mayoría, no se ha dado cuenta. Lo cual es extraño, porque sus catálogos son más desordenados, sus consultas valen más (un contratista ordenando un condensador de $4 000, no un almuerzo de $12) y el tamaño de sus catálogos hace que la economía sea más sencilla.</p>\n<p>Así que esta publicación es ese manual, adaptado para la distribución comercial: los problemas de datos que rompen la búsqueda B2B, cómo encontrarlos esta tarde con un agente de programación, cómo solucionarlos con LLM incluyendo la categorización UNSPSC, y cuánto cuesta todo. Spoiler del último punto: menos de lo que imaginas por dos órdenes de magnitud.</p>\n<h2>El manual ya existe, solo que no en nuestra industria</h2>\n<p>Algunas de las cosas que han publicado las empresas de marketplaces:</p>\n<ul>\n<li>DoorDash usa LLM con generación aumentada por recuperación (RAG) para <a href=\"https://careersatdoordash.com/blog/how-doordash-leverages-llms-for-better-search-retrieval/\">construir su grafo de conocimiento de productos y mejorar la recuperación en búsqueda</a>: extracción automatizada de marcas, extracción de atributos y vinculación de entidades entre millones de artículos proporcionados por comerciantes.</li>\n<li>Amazon construyó <a href=\"https://www.amazon.science/blog/building-commonsense-knowledge-graphs-to-aid-product-recommendation\">COSMO</a>, un grafo de conocimiento generado por LLM que conecta lo que los clientes quieren decir (&quot;zapatos para mujeres embarazadas&quot;) con lo que son los productos (&quot;zapatos antideslizantes&quot;). Reportan hasta un 60 % de mejora en el rendimiento de recomendaciones en pruebas offline.</li>\n<li>Instacart integró LLM en su stack de búsqueda para <a href=\"https://tech.instacart.com/supercharging-discovery-in-search-with-llms-556c585d4720\">generar contenido de descubrimiento</a> y está <a href=\"https://www.instacart.com/company/tech-innovation/building-the-intent-engine-how-instacart-is-revamping-query-understanding-with-llms\">reconstruyendo la comprensión de consultas en torno a ellos</a> —con la generación pesada hecha offline por lotes, precisamente para mantener bajo el costo.</li>\n</ul>\n<p>El hilo conductor es fácil de pasar por alto: las victorias de los LLM están del lado del catálogo y son offline. Estas empresas enriquecen los datos antes de que llegue una sola consulta. Los sistemas de descubrimiento se dividen en un lado offline que construye artefactos (el catálogo, los índices, los embeddings) y un lado online que recupera y ordena sobre ellos, y casi todo el valor publicado de los LLM cae del lado offline. La capa de ranking solo puede ser tan buena como lo que se le alimenta.</p>\n<p>Ahora imagina el catálogo típico de un distribuidor de HVAC o plomería junto a eso. Está cosido a partir de exportaciones de ERP, hojas de cálculo de proveedores, feeds de grupos de compra y un parser de CSV que alguien escribió hace una década. Los &quot;títulos&quot; de producto son abreviaturas de factura escritas para los preparadores de pedidos del almacén. Y el tráfico de búsqueda que lo golpea es de los más densos en intención que existen: la mitad son números de parte exactos, el resto jerga del oficio como &quot;3/4 cxc 90 ell&quot;. Honestamente, no se me ocurre un entorno mejor para este manual. Las consultas son valiosas, los datos son reparables y, con unos pocos cientos de miles de SKU, un pase completo de LLM sobre el catálogo cuesta cientos de dólares. No millones. Cientos.</p>\n<p>Así es la forma de la auditoría, porque querrás reproducirla:</p>\n<pre class=\"mermaid\">flowchart TD\n    D[&quot;Volcado crudo del catálogo&lt;br/&gt;(JSONL, un registro por línea)&quot;] --&gt; C1[&quot;Agentes de cobertura por catálogo&lt;br/&gt;tasas de nulo, distribuciones, campos muertos&quot;]\n    D --&gt; C2[&quot;Agentes de dimensión&lt;br/&gt;texto · números de parte · marcas · precios&lt;br/&gt;especificaciones · categorías · medios · duplicados&quot;]\n    C1 --&gt; S[&quot;Síntesis: hallazgos ordenados por&lt;br/&gt;severidad, con registros de ejemplo&quot;]\n    C2 --&gt; S\n    S --&gt; F[&quot;Pipeline de corrección: reglas + enriquecimiento con LLM&lt;br/&gt;+ clasificación UNSPSC + compuertas de ingesta&quot;]</pre>\n<p>Una nota sobre el formato antes de los prompts. Todo lo de abajo funciona sobre un volcado genérico: un objeto JSON por línea, cada uno con un <code>id</code> único y los campos del registro. Elasticsearch, OpenSearch, Solr, Algolia, Typesense, un PIM, una exportación simple de base de datos —no importa. Cada plataforma puede producir esta forma, y cada prompt aquí se ejecuta contra ella.</p>\n<h2>Categoría 1: Fallas silenciosas del pipeline</h2>\n<p>Lo peor que encontré no fueron datos malos que alguien escribiera. Fueron datos que el pipeline destruyó en el camino de entrada, sin decirle a nadie.</p>\n<p>Estos catálogos construyen su texto de búsqueda principal en el momento de la ingesta, usando una regex scripteada que extrae dimensiones y unidades de los títulos de producto. En títulos largos, la regex supera el límite de complejidad del motor, el procesador falla y el registro se indexa de todos modos —con un campo de error que nadie lee y sin campo de búsqueda principal alguno.</p>\n<img alt=\"Documents indexed with no primary search field, by distributor\" src=\"/assets/images/b2b-search-silent-failures.png\" />\n<p>En toda la flota, 52 570 registros estaban sentados en el índice, invisibles para la ruta principal de consultas. En el peor catálogo, eso es uno de cada siete productos. Ningún dashboard lo detectó porque nada falló. El pipeline devolvió éxito todo el día, todos los días, durante meses.</p>\n<p>Dos hallazgos más de la misma familia. El espejo desactualizado: un campo contiene la verdad (un mapa de derechos por cuenta) y un segundo campo aplanado lo refleja para filtrar. En un catálogo, el espejo había divergido en el 19,85 % de los registros —31 000 productos activos ocultos erróneamente de la búsqueda filtrada por cuenta. Y el catálogo congelado: un índice no se había actualizado en diez semanas mientras sus hermanos se actualizaban diariamente. El tiempo de actividad se monitoreaba. La actualización de los datos no.</p>\n<p>Las correcciones son aburridas y ese es el punto. Alerta sobre la cobertura de campos derivados (campo derivado vacío mientras su fuente no lo está). No mantengas dos representaciones de un mismo hecho; deriva el campo filtrable en el momento de escritura. Vigila la actualización de los datos por catálogo como vigilarías el tiempo de actividad.</p>\n<p>Aquí está el prompt para encontrar todo esto en tu propio catálogo (Claude Code o <code>codex exec</code>; la mecánica al final):</p>\n<pre><code>Aquí está un volcado de mi catálogo de productos como archivos JSONL en ./dump/ —un registro JSON por línea, cada uno con un &quot;id&quot; único y los campos del producto. Mi definición de campo/esquema (si existe) está en schema.json.\n\nEscribe Python en streaming (no lo cargues todo en memoria) para encontrar fallas silenciosas del pipeline:\n1. Registros que lleven algún campo de error/excepción que el pipeline les estampó.\n2. Para cada campo DERIVADO (concatenaciones, variantes *_search, *_normalized): registros donde el campo derivado está vacío pero su campo fuente obvio no lo está.\n3. Pares de campos que parecen espejos el uno del otro (uno anidado/rico, uno aplanado/filtrable): cuantifica con qué frecuencia discrepan.\n4. La distribución de marcas de tiempo de actualización/indexación: ¿hay alguna porción del catálogo congelada mientras el resto se refresca?\n\nReporta cada hallazgo con conteos, % del catálogo, 5 ids de ejemplo, y si los registros afectados están activos/visibles. Ordena por severidad.</code></pre>\n<h2>Categoría 2: Marcadores de posición y valores centinela, o: datos que mienten</h2>\n<p>Las verificaciones de nulo son la herramienta de calidad de datos que todos ya tienen. Los marcadores de posición las derrotan, porque un marcador de posición está poblado. Simplemente no es verdad.</p>\n<p>Mi ejemplo favorito: en un catálogo de 313K SKU, el campo de marca tenía 741 valores distintos y un 99,99 % de población. Suena saludable. El valor principal, en el 88,8 % de todos los registros, era &quot;Approved Vendor&quot;. Un marcador de posición del ERP. La marca real más popular cubría el 0,3 % del catálogo. Así que cada faceta de marca, boost de marca y reescritura consciente de marca estaba efectivamente muerta para nueve décimas partes del catálogo, mientras que la UI de facetas ofrecía alegremente &quot;Approved Vendor&quot; como el filtro de marca #1.</p>\n<p>Una vez que empiezas a mirar, estas cosas están en todas partes:</p>\n<ul>\n<li>Un centinela de &quot;sin precio&quot; de <code>99999999.000000</code> en el 55 % de un catálogo. La mediana de precio de ese índice era de noventa y nueve millones de dólares.</li>\n<li>Nombres de producto literalmente <code>&quot;unknown&quot;</code> en 64 registros, que luego rankean para la consulta &quot;unknown&quot;.</li>\n<li>Un booleano <code>true</code> escrito en un campo de descripción de texto en 1 516 productos activos. El motor lo coaccionó a la cadena &quot;true&quot;, lo que hizo que esos productos se pudieran encontrar buscando &quot;true&quot;.</li>\n<li>227 UPC almacenados como <code>&quot;6.71E+11&quot;</code> —la notación científica de Excel, con 51 productos no relacionados compartiendo ese &quot;identificador&quot;— más 15 121 UPC adicionales a los que les falta su cero inicial. Excel vuelve a atacar.</li>\n<li>Un catálogo de fijaciones cuyo campo de marca contenía nombres de líneas de producto (&quot;C6L Lockbolts&quot;, &quot;Tool Parts&quot;) mientras que la marca real estaba en el campo de al lado.</li>\n</ul>\n<p>La lección que saqué de esta categoría: audita las distribuciones de valores top-N por campo, no las tasas de nulo. Un campo que está 100 % poblado puede ser 88 % basura, y ninguna verificación de nulo te lo dirá jamás. Luego pon en lista de bloqueo los centinelas en la ingesta, mapéalos a nulos reales con banderas explícitas <code>has_price</code> / <code>has_real_image</code>, haz aserciones de tipo en el límite, y valida los identificadores estructuralmente. Trata cualquier cosa que haya pasado por una hoja de cálculo como sospechosa.</p>\n<pre><code>Mismo volcado JSONL. Para cada campo en mi catálogo, calcula la distribución de valores top-20 (pase completo, en streaming).\n\nMarca: (a) cualquier valor único que cubra &gt;10 % de los registros —candidatos a marcador de posición/centinela como &quot;Approved Vendor&quot;, &quot;unknown&quot;, 99999999, 0.0; (b) valores cuyo tipo difiere del tipo dominante del campo (booleanos en campos de texto, flotantes entre cadenas); (c) campos identificadores (UPC/EAN/GTIN/números de parte): valida checksum y longitud, marca notación científica, ceros iniciales eliminados, espacios en blanco/unicode incrustados, e identificadores compartidos por múltiples registros; (d) valores tipo categoría o línea de producto sentados en campos de marca.\n\nPara cada marca: conteo, % del catálogo, 5 ejemplos textuales con ids, y una regla de ingesta propuesta de una línea que lo habría rechazado.</code></pre>\n<h2>Categoría 3: Contenido empobrecido</h2>\n<p>Los catálogos de distribuidores son escritos por ERP, no por merchandisers. El texto es taquigrafía de factura: <code>PROPRESS 2-1/2X1 CXC RED CPLG</code>, <code>HC HX 18X8 W</code>. En un catálogo, un tercio de los nombres de producto tenían menos del 60 % de palabras de diccionario. En otro, los campos crudos de nombre y descripción eran 100 % nulos —el texto solo existía dentro de blobs de búsqueda derivados, así que todo lo que leía los campos crudos (títulos de resultados, inputs de embedding, prompts de jueces de relevancia) no leía nada y nadie lo sabía.</p>\n<img alt=\"Field coverage across four production B2B indices\" src=\"/assets/images/b2b-search-field-coverage.png\" />\n<p>Ese mapa de calor es mi artefacto favorito de la auditoría. Cada uno de esos campos existe en cada esquema. Los números son cuánto de cada uno realmente contiene datos. La fila que me impacta es la de ML-descriptions: la capa de enriquecimiento que los esquemas prometían en cada registro estaba poblada en dieciocho documentos de 775 051. Dieciocho. Cada rama de &quot;usa el enriquecimiento si está presente&quot; en el pipeline de scoring era un no-op silencioso. El esquema es una aspiración; solo la cobertura es un hecho.</p>\n<p>Esta categoría es donde el manual publicado aplica más directamente —la extracción de atributos de DoorDash, la generación offline de Instacart— y la sección de costos de abajo lo cotiza. Pero cuatro reglas importan en un negocio de números de parte, aprendidas en parte de lo que el intento de enriquecimiento anterior hizo mal:</p>\n<ul>\n<li>Expande, no reemplaces. Genera el título legible para el cliente junto a la cadena cruda de factura e indexa ambos. La consulta del técnico de mostrador y la consulta del propietario deberían ambas acertar.</li>\n<li>Nunca verbalices códigos. ¿Esos dieciocho registros pioneros? El generador había deletreado los números de modelo en palabras: &quot;RGF one hundred eighty&quot;. Ningún contratista escribirá eso jamás. Los códigos permanecen textuales; las expansiones son adiciones, no reemplazos.</li>\n<li>Extrae estructura mientras estás ahí. El mismo pase que reescribe un título puede emitir <code>{size, material, connection_type}</code> para facetas.</li>\n<li>La jerga del oficio es un problema de sinónimos, no de reescritura. <code>CXC</code>, <code>ELL</code>, <code>CPLG</code>, &quot;t-stat&quot; pertenecen a la expansión de sinónimos a nivel de analizador, arreglada una vez. No pagues por reescribirlos en medio millón de registros.</li>\n</ul>\n<pre><code>Mismo volcado. Evalúa la calidad del texto de los campos orientados al cliente (nombre, descripción corta/larga) con un pase completo en streaming:\n\n1. Cobertura de título efectivo: % de registros ACTIVOS con un nombre de visualización no vacío.\n2. Legibilidad: % de nombres en MAYÚSCULAS; % con menos del 60 % de tokens de palabras de diccionario (ensalada de abreviaturas); nombres de menos de 10 caracteres; descripciones de solo dígitos.\n3. Basura: marcado HTML/CMS, artefactos de codificación, notas operativas incrustadas (*** NOT A PHYSICAL ITEM ***), desbordamiento de columnas CSV.\n4. Duplicación: descripciones cortas/largas idénticas; texto boilerplate compartido por 20+ SKU; clusters de longitud exacta (254/255/500 caracteres) que indican límites VARCHAR upstream.\n5. Verificación de realidad del enriquecimiento: para cada campo ML/enriquecido/embedding que el esquema promete, su cobertura real.\n\nNúmeros, 5 ejemplos textuales cada uno, severidad, y qué problemas necesitan un pase de enriquecimiento con LLM vs. una corrección del pipeline vs. una corrección de la capa de sinónimos.</code></pre>\n<h2>Categoría 4: Los números de parte son sagrados</h2>\n<p>La mitad del tráfico de búsqueda B2B es alguien escribiendo un número de parte. La coincidencia exacta es todo el juego ahí, y falla de maneras silenciosas.</p>\n<p>En un catálogo, el número de parte indexado era un SKU numérico interno en el 99,99 % de los registros. El número del fabricante —el que está impreso en la caja— existía solo dentro de descripciones de texto libre. 183 000 productos inalcanzables por el número que un cliente realmente escribiría.</p>\n<p>Otro catálogo tenía un sistema de expansión de variantes: quita los guiones, colapsa los segmentos, indexa las variantes para que la búsqueda por número de parte permisiva funcione. Buena idea. Pero el generador era combinatorio (hasta 80 variantes por producto), y en 11 826 registros una variante generada de un producto equivalía exactamente al número de parte canónico de un producto diferente. Las fijaciones son el caso brutal, porque la puntuación codifica dimensiones físicas: <code>702-1-5/32</code> es una pieza de 1-5/32 pulgadas y <code>702-15/32</code> es una pieza de 15/32 pulgadas, y ambas normalizan a <code>7021532</code>. Un cliente escribe un número de parte exacto y obtiene un volado entre la pieza correcta y su prima dimensional.</p>\n<p>También en esta categoría: referencias cruzadas de competidores (&quot;Tengo el número de Ferguson, ¿cuál es el tuyo?&quot;) almacenadas como blobs delimitados por tubería sin dividir como <code>19MU82|Fastenal 0269214|Ferguson M48222407</code>, en campos configurados como no buscables, así que un movimiento central de venta B2B simplemente no funciona. Y bifurcaciones de espacios en blanco —el mismo número de parte indexado tres veces (plano, rellenado con NBSP, espacio final)— más gemelos mojibake de UTF-8 decodificado dos veces.</p>\n<p>El principio que arregla la mayor parte de esto: lo exacto debe vencer a lo difuso estructuralmente, no probabilísticamente. Una cláusula exacta que preserve la puntuación puntuada estrictamente por encima de cualquier nivel normalizado, nunca una coincidencia plana donde una variante pueda empatar con un acierto canónico. Verifica las variantes generadas contra el espacio de números de parte canónicos antes de indexar y descarta las colisiones. Normaliza Unicode antes de derivar IDs de registro. Divide los blobs de referencias cruzadas en arrays; esa es una sola línea de código de ingesta que desbloquea toda una clase de consultas.</p>\n<pre><code>Mismo volcado. Mis usuarios buscan por número de parte; audita la integridad de coincidencia exacta:\n\n1. Qué campos tipo PN existen (part_number, mpn, PN alternativos/de competidor/del cliente, UPC), su cobertura, y cuáles están configurados como no buscables mientras contienen datos reales.\n2. Registros cuyo único token de PN buscable es un SKU interno (el número de parte real del fabricante aparece solo dentro del texto de descripción —muestra el patrón).\n3. Si hay un campo de expansión de variantes/keywords de PN: encuentra cada variante generada que iguale el PN canónico de un registro DIFERENTE (normaliza: minúsculas, quita puntuación). Muestra pares colisionantes —especialmente tamaños de fijaciones que llevan fracciones.\n4. PN que difieren solo por espacios en blanco/caracteres invisibles/mayúsculas/minúsculas del PN de otro registro (bifurcaciones de identidad duplicada).\n5. Campos de referencias cruzadas multivalor almacenados como blobs delimitados en lugar de arrays.\n\nConteos, ejemplos, y para cada problema la regla de ingesta o cambio en el constructor de consultas que lo arregla.</code></pre>\n<p>Algunas cosas que no encajaron arriba pero merecen una oración: un generador de sinónimos que convertía cualquier número en términos de calibre de alambre, así que <code>REF#259286</code> se convirtió en &quot;259286 awg&quot; y una rosca de tornillo <code>#8-32</code> se convirtió en &quot;8 gauge wire&quot; (miles de registros ahora coinciden con consultas eléctricas con las que no tienen nada que ver); banderas internas de una plataforma de comercio electrónico indexadas como especificaciones de producto buscables, 2,1 millones de pares clave-valor basura; y 18 campos de esquema poblados en cero registros en ninguna parte. Los generadores de expansión necesitan compuertas de contexto. El esquema muerto es una falsa promesa sobre la que alguien eventualmente construirá.</p>\n<h2>La capa faltante: UNSPSC, y productos que no saben lo que son</h2>\n<p>En mi auditoría, los campos de categoría faltaban en el 83 % de un catálogo. Las claves de atributo no tenían taxonomía alguna —7 068 claves de especificación distintas en un catálogo de 156K registros, el 64 % de ellas usadas en menos de diez productos, con deriva como <code>horse_power</code> vs <code>horsepower</code> dividiendo el mismo atributo entre facetas. Y el detalle al que vuelvo una y otra vez: dos de los cuatro catálogos tenían campos UNSPSC sentados en sus esquemas, mapeados y listos, poblados en exactamente cero registros. Alguien sabía que la categorización importaba, construyó el hueco y nunca lo llenó. Apostaría dinero a por qué: clasificar 300K SKU en una taxonomía a mano es un año de trabajo del equipo de catálogo, así que se quedó en el roadmap para siempre.</p>\n<p>Si estás fuera del B2B, UNSPSC es el Código de Productos y Servicios Estándar de la ONU, la taxonomía que hablan los sistemas de compras. Esta es la parte que la búsqueda de consumo no tiene: los sistemas de compras de tus clientes lo requieren. Los catálogos punchout, las plataformas de e-procurement y las herramientas de análisis de gasto están construidos alrededor de los códigos UNSPSC. Un distribuidor cuyo catálogo lleve códigos limpios puede conectarse al sistema de compras de un contratista o un hospital. Uno sin ellos es una lista de precios en PDF con una caja de búsqueda. Internamente, también es lo que potencia las facetas de categoría, el ranking por categoría (&quot;un número que se parsea como calibre de alambre solo debería boostear alambre&quot;), la deduplicación entre catálogos, y las compuertas de contexto para cada generador de expansión en la Categoría 4.</p>\n<p>Y ahora es un trabajo por lotes. Esta es la misma forma de problema que DoorDash describe resolver con LLM —etiquetado de alto volumen contra un vocabulario controlado— y el enfoque se transfiere directamente:</p>\n<ul>\n<li>Clasifica jerárquicamente, no de forma plana. UNSPSC tiene cuatro niveles (segmento, familia, clase, commodity). Haz que el modelo elija la familia entre ~450 opciones, luego la clase dentro de esa familia. Dos pequeñas elecciones restringidas vencen a una elección de 50 000 opciones, y puedes alimentar la porción relevante de la taxonomía en el contexto de la manera en que DoorDash restringe la vinculación de entidades a su vocabulario.</li>\n<li>Detente primero a nivel de clase. Los códigos de clase ya desbloquean facetas e integración de compras; la precisión a nivel de commodity puede venir después donde se gane su lugar.</li>\n<li>Enruta por confianza. Un modelo pequeño toma los casos claros, los registros de baja confianza escalan a un modelo más grande, y los desacuerdos persistentes van a una cola humana que también funciona como tu conjunto de evaluación.</li>\n</ul>\n<p>El costo es casi vergonzoso de escribir. La clasificación es una tarea de salida corta: aproximadamente 300 tokens de entrada por registro y 30 de salida. En Claude Haiku 4.5 con precios de Batch API, eso es unos 17 centavos por mil SKU. Toda mi flota de 775K registros se clasificaría por unos $130. Lo que estuvo en el roadmap durante años porque era un año de trabajo manual cuesta menos que el almuerzo del equipo donde lo discutirías.</p>\n<pre><code>Clasificas productos de distribuidores B2B en UNSPSC. Adjunto: la lista de familias UNSPSC (nivel 2, ~450 entradas) como datos de referencia.\n\nPara cada registro de producto (título, descripción, marca, número de parte, cualquier texto de categoría existente), emite JSON:\n- unspsc_family: el código de familia de 4 dígitos —elige SOLO de la lista adjunta\n- family_confidence: high | low\n- rationale: una frase corta (p. ej. &quot;copper press fitting -&gt; pipe fittings&quot;)\n\nReglas: juzga por la función del producto, no por su marca. Taquigrafía del oficio: CXC/FPT/MPT son conexiones de tubería, ELL es codo, CPLG es acoplamiento, una fracción+material desnuda suele ser un tamaño de accesorio. Si el registro no es un producto físico (líneas de flete, cargos adicionales, &quot;*** NOT A PHYSICAL ITEM ***&quot;), emite NOT_A_PRODUCT. Usa low confidence libremente —los registros de baja confianza reciben un segundo pase con la lista a nivel de clase.</code></pre>\n<h2>El manual de limpieza, con la factura real</h2>\n<p>El pipeline de corrección tiene tres niveles más el trabajo de clasificación. El truco es gastar en el nivel correcto, porque casi nunca necesitas una llamada a LLM por registro.</p>\n<pre class=\"mermaid\">flowchart LR\n    A[&quot;Nivel 0 - Reglas&lt;br/&gt;código determinista&lt;br/&gt;~$0&quot;] --&gt; B[&quot;Nivel 1 - LLM sobre valores únicos&lt;br/&gt;marcas · claves de espec · unidades&lt;br/&gt;decenas de dólares&quot;]\n    B --&gt; C[&quot;Nivel 2 - LLM por registro&lt;br/&gt;títulos · atributos · UNSPSC&lt;br/&gt;cientos de dólares&quot;]\n    C --&gt; G[&quot;Compuertas de ingesta&lt;br/&gt;cada corrección se convierte en un validador&quot;]</pre>\n<p><strong>El Nivel 0 es código determinista y básicamente es gratis.</strong> Quita HTML y decodifica entidades. Convierte centinelas en nulos reales con banderas explícitas. Repara UPC (relleno izquierdo, rechaza notación científica, valida el dígito de verificación). Normaliza Unicode en IDs. Divide las referencias cruzadas delimitadas por tubería. Descarta variantes de PN que colisionen con el número canónico de otro producto. Elimina esquemas muertos. Un agente escribe estos scripts en una sesión, y este nivel arregló aproximadamente la mitad de todo lo que encontró mi auditoría. Hazlo antes de cualquier enriquecimiento, o pagarás a un modelo para que reescriba bellamente títulos de productos que tu pipeline descartó silenciosamente.</p>\n<p><strong>El Nivel 1 ejecuta el LLM sobre valores únicos, no sobre registros.</strong> Este es el truco que hace que los problemas de vocabulario sean baratos: mi peor catálogo tenía 313K registros pero solo 741 cadenas de marca distintas. La normalización de marcas es un trabajo sobre 741 cadenas —agrupa las variantes de mayúsculas/minúsculas, mapea submarcas a padres, marca los marcadores de posición— no 313K llamadas. El mismo movimiento para claves de especificación y sufijos de unidad. Cada trabajo de vocabulario cuesta un dígito de dólares y su salida es una tabla de alias estática que tu ingesta aplica para siempre, de forma determinista. Llama a todo el nivel $20-50 para una flota, gastado principalmente en pases de revisión.</p>\n<pre><code>Adjunto: la distribución completa de valores distintos de mis campos de marca y fabricante (value, record_count). Produce una tabla de normalización:\n\ncanonical_brand, parent_manufacturer, [raw variants], confidence\n\nReglas: agrupa variantes de mayúsculas/minúsculas/puntuación/espacios en blanco; mapea submarcas a fabricantes padres como una columna separada (no las fusiones); marca valores de marcador de posición como NULL_SENTINEL; marca líneas de producto o categorías mal archivadas como marcas como NOT_A_BRAND. Marca clusters inciertos en lugar de adivinar. Emite CSV, luego escribe un script que lo aplique en la ingesta y registre valores nuevos no emparejados.</code></pre>\n<p><strong>El Nivel 2 es el pase por registro</strong>: un título legible para el cliente, expansiones de búsqueda, atributos estructurados y un número de parte del fabricante recuperado para cada producto. Por SKU es pequeño —alrededor de 400 tokens de entrada (el registro, más instrucciones compartidas que el cacheo de prompts hace casi gratis) y 250 de salida. Dos palancas antes de siquiera elegir un modelo: enriquece lo que está activo (en mi peor catálogo solo el 14 % de los registros estaban activos, un recorte del 86 % ahí mismo), y usa una API de batch donde el proveedor la tenga, ya que el enriquecimiento no tiene requisito de latencia y tanto Anthropic como OpenAI rebajan un 50 % por batch.</p>\n<p>Coticé el mismo trabajo en todo lo que plausiblemente usarías en 2026 —Claude, <a href=\"https://openai.com/index/advancing-the-price-performance-frontier-with-gpt-5-6/\">los tres niveles de GPT-5.6</a> (Sol, Terra, Luna), Kimi K3, GLM-5.2, Qwen3.5 y <a href=\"https://deepseek.ai/pricing\">DeepSeek V4</a>. Misma carga de trabajo, tarifas publicadas por los proveedores, descuento por batch aplicado donde existe:</p>\n<img alt=\"Cost to enrich 775K SKUs across models\" src=\"/assets/images/b2b-search-enrichment-cost-by-model.png\" />\n<p>Tuve que verificar dos veces estos números porque parecían incorrectos. La versión peor caso de este proyecto —un modelo frontera, cada SKU, sin filtrado alguno— llega a unos $3 800. El piso está por debajo de los cien dólares: DeepSeek V4-Flash enriquecería toda la flota por el precio de un taladro decente. La versión que realmente ejecutarías mezcla niveles: un modelo económico (Haiku, Luna, Qwen Flash, DeepSeek) para la mayoría mecánica, un modelo de gama media (Sonnet, Terra, GLM-5.2) para la cola de ensalada de abreviaturas que el pequeño marca como baja confianza, y un modelo frontera haciendo spot-check a una muestra del 1-2 % como compuerta de calidad. Eso aterriza en unos pocos cientos de dólares para los SKU activos sin importar qué proveedores elijas.</p>\n<p>Dos advertencias que el gráfico no puede mostrar. Los modelos baratos solo son baratos si su salida sobrevive tu evaluación —ejecuta la comparación de 200 muestras antes de comprometerte, porque un modelo económico que estropee el 5 % de los números de parte cuesta más que el modelo frontera que no lo hace. Y tu catálogo es dato competitivo: precios, referencias cruzadas y números de parte del cliente están en esos registros, así que verifica los términos de retención de datos y entrenamiento de cada proveedor antes de enviar 775K registros al endpoint más barato de la lista. Para muchos distribuidores, esa sola verificación incluye o excluye a algunos proveedores, y las opciones de peso abierto (DeepSeek, GLM, Qwen, Kimi) tienen la propiedad extra de que puedes autoalojarlas si los datos no pueden salir en absoluto.</p>\n<p>Suma el pase UNSPSC de ~$130 (que escala de la misma manera entre modelos —en el nivel económico baja a calderilla) y el trabajo de vocabulario, y toda la transformación del catálogo cuesta en algún lugar entre unos pocos cientos y unos pocos miles de dólares, frente a un trabajo que solía ser un año del equipo de merchandising. Es la misma economía de lotes offline que describe Instacart, solo que a escala de catálogo comercial donde los números se vuelven lo suficientemente pequeños para ponerlos en una tarjeta de crédito.</p>\n<p>Cómo se ve en un registro real de mi auditoría:</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&quot; x 1&quot; ProPress Copper Reducing Coupling\n     search_expansions:  [&quot;copper press fitting&quot;, &quot;reducing coupling&quot;,\n                          &quot;press x press coupling&quot;]\n     attributes:         {size_1: {value: 2.5, unit: in},\n                          size_2: {value: 1, unit: in},\n                          material: copper, connection: press}\n     extracted_mpn:      &quot;20685&quot;\n     unspsc_family:      4017 (pipe fittings)\n     confidence:         high</code></pre>\n<p>Mira la línea <code>extracted_mpn</code>. El mismo pase recupera números de parte del fabricante que antes estaban enterrados en el texto de descripción —en uno de mis catálogos, eso son 183K productos volviéndose encontrables por el número impreso en la caja. Eso solo paga el trabajo por lotes.</p>\n<pre><code>Enriqueces registros de productos de distribuidores B2B para búsqueda. Para cada registro de entrada (nombre crudo del ERP, descripciones, marca, número de parte, categoría) produce JSON:\n\n- display_title: legible para el cliente, &lt;=80 caracteres, Title Case. Expande abreviaturas del oficio (CXC -&gt; copper x copper connection, ELL -&gt; elbow, CPLG -&gt; coupling, RED -&gt; reducing). Mantén cada número de parte, código de modelo y dimensión VERBATIM tal como se escribió —nunca deletrees códigos en palabras.\n- search_expansions: 2-5 frases que un cliente podría escribir y que no aparecen en el texto crudo (tipo de producto en inglés llano, nombres comunes del oficio). Nunca inventes especificaciones ausentes en la fuente.\n- attributes: {name: {value, unit}} extraídos SOLO del texto fuente.\n- extracted_mpn: número de parte del fabricante si está presente en el texto de descripción (usualmente el token después de la marca) y ausente en los campos de PN, si no null.\n- confidence: high | low. Usa low siempre que tengas que adivinar; una respuesta low enrutada a revisión vence a una alucinación confiada.</code></pre>\n<p>Dos notas de producción: pon las instrucciones compartidas en un prefijo de prompt cacheado (el cacheo reduce el lado de entrada hasta un 90 % además del descuento por batch), y usa salidas estructuradas con un esquema JSON para que nunca pagues un impuesto por fallo de parseo.</p>\n<p><strong>El último nivel es el que la gente se salta, y es el que se capitaliza.</strong> La auditoría vale por una limpieza. Los validadores que genera valen por cada feed futuro. Termina la sesión de corrección con:</p>\n<pre><code>Convierte cada problema que acabamos de arreglar en una verificación automatizada que haga fallar ruidosamente el pipeline de ingesta: aserciones de cobertura de campos derivados, listas de bloqueo de centinelas, aserciones de tipo en campos de texto, validación de checksum de identificadores, verificaciones de colisión de variantes de PN, reglas de higiene de id, seguimiento de cobertura UNSPSC, y una alarma de frescura de datos por catálogo. Emítelos como tests que CI ejecute contra una muestra de cada nuevo feed.</code></pre>\n<p>Omit esto y las mismas exportaciones de ERP regenerarán la misma basura en un trimestre, y pagarás la limpieza dos veces. Lo sé porque dos de los bugs que encontró mi auditoría claramente se habían arreglado antes, y habían vuelto.</p>\n<h2>Ejecutando los prompts</h2>\n<p>Un paso de configuración: vuelca tu catálogo a JSONL, un objeto JSON por línea con un <code>id</code> único y los campos del registro. Sea cual sea tu plataforma —Elasticsearch, OpenSearch, Solr, Algolia, Typesense, un PIM, la base de datos detrás de todo— solo pídele al agente que escriba el exportador:</p>\n<pre><code>Escribe un script que exporte cada registro de producto de mi catálogo [describe: nombre del índice de búsqueda / tabla de base de datos / exportación de PIM] a ./dump/records-{n}.jsonl en fragmentos de 50k registros —un objeto JSON por línea con un &quot;id&quot; único más todos los campos— y mi definición de campo/esquema (si la plataforma tiene una) a schema.json. Verifica que el conteo exportado coincida con el conteo fuente.</code></pre>\n<p>Con Claude Code, suelta cualquier prompt de categoría en una sesión en ese directorio. Escribe y ejecuta el análisis él mismo, pases completos sin excusas de muestreo, y vuelve con recibos a nivel de registro. Cuando dices &quot;ahora arréglalo&quot;, la misma sesión produce el validador de ingesta, el script de backfill y el trabajo de enriquecimiento por lotes. Ejecuta las categorías como sesiones paralelas o subagentes; así ejecuté las mías, y toda la auditoría tomó unos doce minutos de tiempo de reloj. Con Codex, <code>codex exec</code> maneja los pases de análisis de solo lectura usando los mismos prompts; mantén las correcciones del lado de escritura en una sesión que revises.</p>\n<p>Tres reglas que aprendí a la mala:</p>\n<ol>\n<li>Exige pases completos y recibos. &quot;Analiza estos datos&quot; invita al muestreo y a las vibras. Pide conteos exactos y cinco IDs de registro de ejemplo por hallazgo, y cada afirmación se vuelve verificable.</li>\n<li>Reglas antes que enriquecimiento. Arregla la verdad antes de agregar prosa, o alucinarás marcas para el 88 % de los registros etiquetados &quot;Approved Vendor&quot;.</li>\n<li>Muestrea, evalúa, luego haz batch. Nunca dispares un batch de 775K registros desde un prompt no validado. 200 muestras, un pase de scoring, luego escala. El entorno de evaluación cuesta una sesión de agente y mitiga el riesgo de todo el gasto.</li>\n</ol>\n<h2>Los oficios merecen búsqueda de nivel marketplace</h2>\n<p>Amazon, DoorDash e Instacart no publicaron su trabajo de catálogo-LLM como caridad. Lo publicaron porque las técnicas son generales y la ventaja competitiva es la ejecución. Y las técnicas se transfieren a la distribución comercial mejor que casi en cualquier otro lugar que se me ocurra: los catálogos son lo suficientemente pequeños para que un pase completo sea barato, los datos son lo suficientemente malos como para que el margen de mejora sea enorme, las consultas llevan dinero real, y el mundo de las compras ya funciona sobre una taxonomía que un trabajo por lotes ahora puede poblar por unos $130.</p>\n<p>De las docenas de problemas que mi auditoría sacó a la luz en cuatro catálogos de distribuidores, ni uno solo era visible desde la capa de ranking. Todos la degradaban. La cadena de suministro que alimenta esos índices —las exportaciones de ERP, las hojas de cálculo de proveedores, los antiguos parsers de CSV— es exactamente lo que el manual publicado arregla. Los distribuidores que lo ejecuten tendrán búsqueda de nivel marketplace en catálogos donde sus competidores todavía no pueden encontrar una bobina de condensador.</p>\n<p>La pregunta &quot;¿hay algo mal con mis datos?&quot; solía costar dos semanas del tiempo de alguien, por eso nadie la hacía. Ahora cuesta un prompt. Hazla.</p>",
  "source_hash": "sha256:beacaae673c45f36f13a5677632c8df46a2339c6bdea51c65c49f762d7f0805c",
  "model": "moonshotai/kimi-k2.6",
  "generated_at": "2026-08-07T07:39:21.935368+00:00"
}