{
  "title": "B2B-Commerce-Suche im Zeitalter der KI reparieren",
  "excerpt": "Ich habe 775.000 Produktdatensätze geprüft, die die Suche für vier B2B-Distributoren steuern. Die Konsumgiganten haben bereits veröffentlicht, wie man solche Kataloge mit LLMs repariert, aber der Handel hat das Playbook noch nicht übernommen. Hier ist es, angepasst für HVAC, Sanitär und Elektrotechnik, mit echten Kosten.",
  "content_html": "<p>B2B-Commerce-Suche hat ein schmutziges Geheimnis: Der Ranking-Algorithmus ist selten das Problem.</p>\n<p>Wenn die Ergebnisse schlecht sind, greifen Teams nach den spannenden Hebeln. Boosts, Synonyme, Embeddings, Reranker und in letzter Zeit LLM-Query-Understanding. Ich habe all diese Hebel selbst gezogen. Letzte Woche habe ich stattdessen das unglamuröse Ding getan: Ich habe jeden Produktdatensatz aus vier produktiven Suchindizes exportiert – 775.051 Datensätze über vier B2B-Distributoren in HVAC, Sanitär, Industriebedarf und Befestigungsmaterial – und die Daten selbst auditiert. Ich habe zwölf KI-Agenten parallel eingesetzt, jeder einer Dimension zugeordnet: Coverage, Textqualität, Teilenummern, Marken, Preise, Spezifikationen, Kategorien, Medien, Duplikate.</p>\n<p>Was zurückkam, wäre für jeden, der schon einmal an einem Distributoren-Katalog gearbeitet hat, unremarkable, und für jeden, der das nicht hat, schockierend. Aber der Teil, der bei mir hängen blieb, ist dieser: Die Lösung ist bereits veröffentlicht. Amazon, DoorDash und Instacart haben zwei Jahre lang in öffentlichen Engineering-Blogs genau aufgeschrieben, wie sie LLMs nutzen, um unordentliche Kataloge im Maßstab zu bereinigen, zu labeln und anzureichern. Der Handel hat es größtenteils nicht bemerkt. Was seltsam ist, denn seine Kataloge sind unordentlicher, seine Suchanfragen sind mehr wert (ein Auftragnehmer, der einen 4.000-$-Kondensator bestellt, kein 12-$-Mittagessen) und seine Kataloggrößen machen die Ökonomie tatsächlich einfacher.</p>\n<p>Dieser Beitrag ist also dieses Playbook, angepasst für den Handel: die Datenprobleme, die die B2B-Suche kaputt machen, wie man sie an diesem Nachmittag mit einem Coding-Agent findet, wie man sie mit LLMs repariert – einschließlich UNSPSC-Kategorisierung – und was das Ganze kostet. Spoiler zum letzten Punkt: zwei Größenordnungen weniger, als Sie vermuten würden.</p>\n<h2>Das Playbook existiert bereits, nur nicht in unserer Branche</h2>\n<p>Etwas von dem, was die Marketplace-Unternehmen veröffentlicht haben:</p>\n<ul>\n<li>DoorDash nutzt LLMs mit Retrieval-Augmented Generation, um <a href=\"https://careersatdoordash.com/blog/how-doordash-leverages-llms-for-better-search-retrieval/\">seinen Produkt-Knowledge-Graph zu bauen und die Such-Retrieval zu verbessern</a>: automatisierte Markenextraktion, Attributextraktion und Entity-Linking über Millionen von Händler-artikeln.</li>\n<li>Amazon hat <a href=\"https://www.amazon.science/blog/building-commonsense-knowledge-graphs-to-aid-product-recommendation\">COSMO</a> gebaut, einen LLM-generierten Knowledge-Graph, der verbindet, was Kunden meinen (\"Schuhe für schwangere Frauen\") mit dem, was Produkte sind (\"rutschfeste Schuhe\"). Sie berichten von bis zu 60 % Verbesserung der Empfehlungsleistung in Offline-Tests.</li>\n<li>Instacart hat LLMs in den Such-Stack integriert, um <a href=\"https://tech.instacart.com/supercharging-discovery-in-search-with-llms-556c585d4720\">Discovery-Inhalte zu generieren</a> und <a href=\"https://www.instacart.com/company/tech-innovation/building-the-intent-engine-how-instacart-is-revamping-query-understanding-with-llms\">das Query-Understanding darum herum neu aufzubauen</a> – wobei die schwere Generierung offline in Batches erfolgt, gerade um die Kosten niedrig zu halten.</li>\n</ul>\n<p>Der gemeinsame Faden ist leicht zu übersehen: Die LLM-Gewinne liegen auf der Katalog-Seite und offline. Diese Unternehmen reichern die Daten an, bevor eine einzige Suchanfrage eintrifft. Discovery-Systeme spalten sich in eine Offline-Seite, die Artefakte baut (den Katalog, die Indizes, die Embeddings), und eine Online-Seite, die darüber abruft und rankt, und nahezu der gesamte veröffentlichte LLM-Wert landet offline. Die Ranking-Schicht kann nur so gut sein, wie das, was sie gefüttert bekommt.</p>\n<p>Stellen Sie sich nun einen typischen HVAC- oder Sanitär-Distributoren-Katalog daneben vor. Er ist zusammengestückelt aus ERP-Exporten, Lieferanten-Tabellenkalkulationen, Einkaufsgruppen-Feeds und einem CSV-Parser, den jemand vor einem Jahrzehnt geschrieben hat. Die Produkt-\"Titel\" sind Rechnungs-Kurzschrift, geschrieben für Lager-Picker. Und der Such-Traffic, der darauf trifft, ist etwa so intent-dicht wie Such-Traffic nur sein kann: die Hälfte exakte Teilenummern, der Rest Fachjargon wie \"3/4 cxc 90 ell.\" Ehrlich gesagt, ich kann mir keine bessere Umgebung für dieses Playbook vorstellen. Die Suchanfragen sind wertvoll, die Daten sind reparierbar, und bei ein paar hunderttausend SKUs kostet ein vollständiger LLM-Durchlauf über den Katalog ein paar hundert Dollar. Nicht Millionen. Hunderte.</p>\n<p>Hier ist die Audit-Form, weil Sie sie reproduzieren wollen:</p>\n<pre><code class=\"mermaid\">flowchart TD\n    D[\"Raw catalog dump&lt;br/&gt;(JSONL, one record per line)\"] --&gt; C1[\"Per-catalog coverage agents&lt;br/&gt;null rates, distributions, dead fields\"]\n    D --&gt; C2[\"Dimension agents&lt;br/&gt;text · part numbers · brands · pricing&lt;br/&gt;specs · categories · media · duplicates\"]\n    C1 --&gt; S[\"Synthesis: findings ranked by&lt;br/&gt;severity, with example records\"]\n    C2 --&gt; S\n    S --&gt; F[\"Fix pipeline: rules + LLM enrichment&lt;br/&gt;+ UNSPSC classification + ingest gates\"]\n</code></pre>\n<p>Eine Anmerkung zum Format vor den Prompts. Alles unten funktioniert auf einem generischen Dump: ein JSON-Objekt pro Zeile, jedes mit einer eindeutigen <code>id</code> und den Feldern des Datensatzes. Elasticsearch, OpenSearch, Solr, Algolia, Typesense, ein PIM, ein einfacher Datenbank-Export – egal. Jede Plattform kann diese Form produzieren, und jeder Prompt hier läuft dagegen.</p>\n<h2>Kategorie 1: Stille Pipeline-Fehler</h2>\n<p>Das Schlimmste, was ich fand, waren keine schlechten Daten, die jemand geschrieben hat. Es waren Daten, die die Pipeline auf dem Weg herein zerstört hat, ohne es jemandem zu sagen.</p>\n<p>Diese Kataloge bauen ihren primären Suchtext zur Ingest-Zeit, mit einem geskripteten Regex, der Dimensionen und Einheiten aus Produkttiteln extrahiert. Bei langen Titeln sprengt der Regex die Komplexitäts-Grenze der Engine, der Prozessor scheitert, und der Datensatz wird trotzdem indiziert – mit einem Fehlerfeld, das niemand liest, und überhaupt keinem primären Suchfeld.</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>Über die gesamte Flotte hinweg saßen 52.570 Datensätze im Index, unsichtbar für den Haupt-Query-Pfad. Im schlechtesten Katalog ist das jedes siebte Produkt. Kein Dashboard hat es erfasst, weil nichts fehlgeschlagen ist. Die Pipeline gab den ganzen Tag, jeden Tag, monatelang Erfolg zurück.</p>\n<p>Zwei weitere Befunde aus derselben Familie. Der veraltete Mirror: Ein Feld enthält die Wahrheit (eine pro-Konto-Berechtigungs-Map), und ein zweites, flachgedrücktes Feld spiegelt sie für das Filtern. In einem Katalog war der Mirror bei 19,85 % der Datensätze abgewichen – 31.000 aktive Produkte fälschlich versteckt vor der kontogefilterten Suche. Und der eingefrorene Katalog: Ein Index hatte sich in zehn Wochen nicht aktualisiert, während seine Geschwister täglich aktualisiert wurden. Uptime wurde überwacht. Freshness nicht.</p>\n<p>Die Fixes sind langweilig, und das ist der Punkt. Alarmieren Sie bei Derived-Field-Coverage (abgeleitetes Feld leer, während seine Quelle es nicht ist). Pflegen Sie nicht zwei Repräsentationen einer Tatsache; leiten Sie das filterbare Feld zur Schreibzeit ab. Überwachen Sie die Daten-Freshness pro Katalog so, wie Sie Uptime überwachen.</p>\n<p>Hier ist der Prompt, um all dies in Ihrem eigenen Katalog zu finden (Claude Code oder <code>codex exec</code>; Mechaniken am Ende):</p>\n<pre><code class=\"text\">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>Kategorie 2: Platzhalter und Sentinels, oder: Daten, die lügen</h2>\n<p>Null-Checks sind das Datenqualitäts-Werkzeug, das jeder bereits hat. Platzhalter machen sie zunichte, denn ein Platzhalter ist gefüllt. Er ist nur nicht wahr.</p>\n<p>Mein Lieblingsbeispiel: In einem 313K-SKU-Katalog hatte das Markenfeld 741 verschiedene Werte und 99,99 % Coverage. Klingt gesund. Der Top-Wert, bei 88,8 % aller Datensätze, war \"Approved Vendor.\" Ein ERP-Platzhalter. Die beliebteste echte Marke deckte 0,3 % des Katalogs ab. Also war jede Marken-Facet, jeder Marken-Boost und jede Marken-bewusste Umschreibung für neun Zehntel des Katalogs praktisch tot, während die Facet-UI fröhlich \"Approved Vendor\" als #1-Markenfilter anbot.</p>\n<p>Wenn man anfängt zu suchen, ist dieses Zeug überall:</p>\n<ul>\n<li>Ein \"kein Preis\"-Sentinel von <code>99999999.000000</code> bei 55 % eines Katalogs. Der Median-Preis dieses Index lag bei neunundneunzig Millionen Dollar.</li>\n<li>Produktnamen, die wörtlich <code>\"unknown\"</code> waren, bei 64 Datensätzen, die dann für die Suchanfrage \"unknown\" ranken.</li>\n<li>Ein boolesches <code>true</code>, das in ein Text-Beschreibungsfeld bei 1.516 Live-Produkten geschrieben wurde. Die Engine wandelte es in den String \"true\" um, wodurch diese Produkte durch die Suche nach \"true\" findbar wurden.</li>\n<li>227 UPCs, gespeichert als <code>\"6.71E+11\"</code> – Excels wissenschaftliche Notation, wobei 51 unverwandte Produkte diesen einen \"Identifier\" teilten – plus 15.121 weitere UPCs, denen die führende Null fehlte. Excel schlägt wieder zu.</li>\n<li>Ein Befestigungsmittel-Katalog, dessen Markenfeld Produklinien-Namen enthielt (\"C6L Lockbolts\", \"Tool Parts\"), während die eigentliche Marke ein Feld weiter saß.</li>\n</ul>\n<p>Die Lektion, die ich aus dieser Kategorie zog: Auditieren Sie Top-N-Wertverteilungen pro Feld, nicht Null-Raten. Ein Feld, das zu 100 % gefüllt ist, kann zu 88 % Müll sein, und kein Null-Check wird es Ihnen je sagen. Dann blockieren Sie die Sentinels beim Ingest, mappen Sie sie zu echten Nulls mit expliziten <code>has_price</code> / <code>has_real_image</code>-Flags, typ-asserten Sie an der Grenze, und validieren Sie Identifier strukturell. Behandeln Sie alles, was jemals eine Tabellenkalkulation durchlaufen hat, als verdächtig.</p>\n<pre><code class=\"text\">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>Kategorie 3: Verarmte Inhalte</h2>\n<p>Distributoren-Kataloge werden von ERPs geschrieben, nicht von Merchandisern. Der Text ist Rechnungs-Kurzschrift: <code>PROPRESS 2-1/2X1 CXC RED CPLG</code>, <code>HC HX 18X8 W</code>. In einem Katalog hatte ein Drittel der Produktnamen weniger als 60 % Wörterbuch-Wörter. In einem anderen waren die Roh-Felder für Name und Beschreibung zu 100 % null – der Text existierte nur innerhalb abgeleiteter Such-Blobs, also las alles, was die Roh-Felder las (Ergebnis-Titel, Embedding-Inputs, Relevance-Judge-Prompts), nichts und niemand wusste davon.</p>\n<p><img src=\"/assets/images/b2b-search-field-coverage.png\" alt=\"Field coverage across four production B2B indices\" /></p>\n<p>Diese Heatmap ist mein absolutes Lieblings-Artefakt aus dem Audit. Jedes dieser Felder existiert in jedem Schema. Die Zahlen zeigen, wie viel davon tatsächlich Daten hält. Die Zeile, die mich trifft, ist die ML-Descriptions-Zeile: Die Anreicherungsschicht, die die Schemata bei jedem Datensatz versprachen, war auf achtzehn Dokumenten von 775.051 gefüllt. Achtzehn. Jeder \"use enrichment if present\"-Zweig in der Scoring-Pipeline war ein stilles No-Op. Schema ist eine Aspiration; nur Coverage ist eine Tatsache.</p>\n<p>Diese Kategorie ist, wo das veröffentlichte Playbook am direktesten anwendbar ist – DoorDashs Attributextraktion, Instacarts Offline-Generierung – und der Kostenabschnitt unten preist es aus. Aber vier Regeln sind in einem Teilenummern-Geschäft wichtig, teils gelernt aus dem, was der vorherige Anreicherungsversuch falsch machte:</p>\n<ul>\n<li>Erweitern, nicht ersetzen. Generieren Sie den kundenlesbaren Titel neben dem rohen Rechnungs-String und indizieren Sie beide. Die Suchanfrage des Technikers und die des Hausbesitzers sollten beide treffen.</li>\n<li>Codes niemals verbalisieren. Diese achtzehn Pioneer-Datensätze? Der Generator hatte Modellnummern in Worte ausgeschrieben: \"RGF one hundred eighty.\" Kein Techniker wird das je tippen. Codes bleiben wörtlich; Erweiterungen sind Ergänzungen, keine Ersetzungen.</li>\n<li>Struktur extrahieren, während Sie dabei sind. Derselbe Durchlauf, der einen Titel umschreibt, kann <code>{size, material, connection_type}</code> für Facets ausgeben.</li>\n<li>Fachjargon ist ein Synonym-Problem, kein Umschreibungs-Problem. <code>CXC</code>, <code>ELL</code>, <code>CPLG</code>, \"t-stat\" gehören in Analyzer-Level-Synonym-Erweiterung, einmalig behoben. Zahlen Sie nicht dafür, sie in eine halbe Million Datensätze umzuschreiben.</li>\n</ul>\n<pre><code class=\"text\">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>Kategorie 4: Teilenummern sind heilig</h2>\n<p>Die Hälfte des B2B-Such-Traffics ist jemand, der eine Teilenummer tippt. Exaktes Match ist dort das ganze Spiel, und es scheitert auf stille Weise.</p>\n<p>In einem Katalog war die indizierte Teilenummer bei 99,99 % der Datensätze eine interne numerische SKU. Die Nummer des Herstellers – die auf der Verpackung gedruckte – existierte nur innerhalb von Freitext-Beschreibungen. 183.000 Produkte, nicht erreichbar über die Nummer, die ein Kunde tatsächlich tippen würde.</p>\n<p>Ein anderer Katalog hatte ein Varianten-Expansionssystem: Striche entfernen, Segmente zusammenfassen, Varianten indizieren, damit fehlerverzeihende PN-Suche funktioniert. Gute Idee. Aber der Generator war kombinatorisch (bis zu 80 Varianten pro Produkt), und bei 11.826 Datensätzen glich eine generierte Variante eines Produkts exakt der kanonischen Teilenummer eines anderen Produkts. Befestigungsmittel sind der brutale Fall, weil Zeichensetzung physische Dimensionen kodiert: <code>702-1-5/32</code> ist ein 1-5/32-Zoll-Teil und <code>702-15/32</code> ist ein 15/32-Zoll-Teil, und beide normalisieren zu <code>7021532</code>. Ein Kunde tippt eine exakte Teilenummer und bekommt einen Münzwurf zwischen dem richtigen Teil und seinem dimensionalen Cousin.</p>\n<p>Auch in dieser Kategorie: Wettbewerber-Cross-References (\"Ich habe die Ferguson-Nummer, was ist Ihre?\") gespeichert als ungetrennte Pipe-delimited Blobs wie <code>19MU82|Fastenal 0269214|Ferguson M48222407</code>, in Feldern, die als unsearchable konfiguriert sind, sodass eine zentrale B2B-Verkaufsbewegung einfach nicht funktioniert. Und Whitespace-Forks – dieselbe Teilenummer dreimal indiziert (plain, NBSP-padded, trailing-space) – plus Mojibake-Zwillinge aus doppelt dekodiertem UTF-8.</p>\n<p>Das Prinzip, das das meiste davon repariert: Exakt muss strukturell über Fuzzy siegen, nicht probabilistisch. Eine Zeichensetzung-bewahrende exakte Klausel, die strikt über jeder normalisierten Ebene rangiert, niemals ein flaches Match, wo eine Variante einen kanonischen Treffer einholen kann. Prüfen Sie generierte Varianten gegen den kanonischen PN-Raum vor dem Indizieren und verwerfen Sie Kollisionen. Unicode-normalisieren Sie, bevor Sie Datensatz-IDs ableiten. Splitten Sie die Cross-Reference-Blobs in Arrays; das ist eine einzelne Zeile Ingest-Code, die eine gesamte Query-Klasse freischaltet.</p>\n<pre><code class=\"text\">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>Ein paar Dinge, die oben nicht reinpassten, aber einen Satz verdienen: ein Synonym-Generator, der jede Zahl in Draht-Gauge-Begriffe verwandelte, sodass <code>REF#259286</code> zu \"259286 awg\" wurde und ein <code>#8-32</code>-Schraubengewinde zu \"8 gauge wire\" (Tausende Datensätze matchen jetzt elektrische Suchanfragen, mit denen sie nichts zu tun haben); die internen Flags einer E-Commerce-Plattform, indiziert als durchsuchbare Produkt-Specs, 2,1 Millionen Junk-Key-Value-Paare; und 18 Schema-Felder, die auf null Datensätzen irgendwo gefüllt waren. Expansions-Generatoren brauchen Context-Gates. Totes Schema ist ein falsches Versprechen, auf dem irgendwann jemand aufbauen wird.</p>\n<h2>Die fehlende Schicht: UNSPSC, und Produkte, die nicht wissen, was sie sind</h2>\n<p>Es gibt ein fünftes Problem, das einen eigenen Abschnitt verdient, weil es dort ist, wo der Handel am weitesten hinter den Marketplaces zurückliegt: Kategorisierung.</p>\n<p>In meinem Audit fehlten Kategorie-Felder bei 83 % eines Katalogs. Attribut-Keys hatten überhaupt keine Taxonomie – 7.068 verschiedene Spec-Keys in einem 156K-Datensatz-Katalog, 64 % davon bei weniger als zehn Produkten verwendet, mit Drift wie <code>horse_power</code> vs <code>horsepower</code>, die dasselbe Attribut über Facets spaltete. Und das Detail, zu dem ich immer wieder zurückkomme: Zwei der vier Kataloge hatten UNSPSC-Felder in ihren Schemata, gemappt und bereit, gefüllt auf exakt null Datensätzen. Jemand wusste, dass Kategorisierung wichtig war, baute den Slot und füllte ihn nie. Ich würde Geld darauf wetten, warum: 300K SKUs per Hand in eine Taxonomie zu klassifizieren, ist ein Jahr Arbeit für das Katalog-Team, also blieb es für immer auf der Roadmap.</p>\n<p>Wenn Sie außerhalb von B2B sind: UNSPSC ist der UN Standard Products and Services Code, die Taxonomie, die Beschaffungssysteme sprechen. Das ist der Teil, den Konsum-Suche nicht hat: Die Beschaffungssysteme Ihrer Kunden verlangen es. Punchout-Kataloge, E-Procurement-Plattformen und Spend-Analysis-Tools sind um UNSPSC-Codes herum gebaut. Ein Distributor, dessen Katalog saubere Codes trägt, kann sich in das Beschaffungssystem eines Auftragnehmers oder eines Krankenhauses einklinken. Einer ohne sie ist eine PDF-Preisliste mit einem Suchfeld. Intern ist es auch das, was Kategorie-Facets, Kategorie-scoped Ranking (\"eine Zahl, die als Draht-Gauge parst, sollte nur Draht boosten\"), Cross-Katalog-Dedup und die Context-Gates für jeden Expansions-Generator in Kategorie 4 antreibt.</p>\n<p>Und es ist jetzt ein Batch-Job. Dies ist dieselbe Art von Problem, das DoorDash beschreibt, mit LLMs gelöst zu werden – High-Volume-Labeling gegen ein kontrolliertes Vokabular – und der Ansatz überträgt sich direkt:</p>\n<ul>\n<li>Hierarchisch klassifizieren, nicht flach. UNSPSC hat vier Ebenen (Segment, Family, Class, Commodity). Lassen Sie das Modell die Family aus ~450 Optionen wählen, dann die Class innerhalb dieser Family. Zwei kleine eingeschränkte Entscheidungen schlagen eine 50.000-fache Wahl, und Sie können den relevanten Taxonomie-Slice in den Kontext einspeisen, wie DoorDash Entity-Linking auf sein Vokabular einschränkt.</li>\n<li>Zuerst auf Class-Ebene stoppen. Class-Codes erschließen bereits Facets und Procurement-Integration; Commodity-Level-Präzision kann später kommen, wo sie sich rentiert.</li>\n<li>Nach Confidence routen. Ein kleines Modell nimmt die klaren Fälle, Low-Confidence-Datensätze eskalieren zu einem größeren Modell, und persistente Uneinigkeiten gehen in eine Human-Queue, die gleichzeitig Ihr Eval-Set ist.</li>\n</ul>\n<p>Die Kosten sind fast peinlich zu tippen. Klassifizierung ist eine Short-Output-Aufgabe: grob 300 Input-Token pro Datensatz und 30 Out. Mit Claude Haiku 4.5 zu Batch-API-Preisen sind das etwa 17 Cent pro tausend SKUs. Meine gesamte 775K-Datensatz-Flotte würde für etwa 130 $ klassifiziert. Das Ding, das jahrelang auf der Roadmap stand, weil es ein Jahr manueller Arbeit war, kostet weniger als das Team-Mittagessen, bei dem Sie es besprechen würden.</p>\n<pre><code class=\"text\">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>Das Cleanup-Playbook, mit der echten Rechnung</h2>\n<p>Die Fix-Pipeline hat drei Tiers plus den Klassifizierungs-Job. Der Trick ist, auf der richtigen Ebene auszugeben, weil Sie fast nie einen LLM-Aufruf pro Datensatz brauchen.</p>\n<pre><code class=\"mermaid\">flowchart LR\n    A[\"Tier 0 - Rules&lt;br/&gt;deterministic code&lt;br/&gt;~$0\"] --&gt; B[\"Tier 1 - LLM on unique values&lt;br/&gt;brands · spec keys · units&lt;br/&gt;tens of dollars\"]\n    B --&gt; C[\"Tier 2 - LLM per record&lt;br/&gt;titles · attributes · UNSPSC&lt;br/&gt;hundreds of dollars\"]\n    C --&gt; G[\"Ingest gates&lt;br/&gt;every fix becomes a validator\"]\n</code></pre>\n<p><strong>Tier 0 ist deterministischer Code und im Grunde kostenlos.</strong> HTML strippen und Entities dekodieren. Sentinels in echte Nulls mit expliziten Flags verwandeln. UPCs reparieren (links auffüllen, wissenschaftliche Notation ablehnen, Check-Digit validieren). Unicode-normalisieren von IDs. Die Pipe-delimited Cross-References splitten. PN-Varianten verwerfen, die mit der kanonischen Nummer eines anderen Produkts kollidieren. Totes Schema löschen. Ein Agent schreibt diese Skripte in einer Session, und diese Ebene hat etwa die Hälfte von allem repariert, was mein Audit fand. Machen Sie es vor jeder Anreicherung, sonst zahlen Sie einem Modell dafür, wunderschön Titel für Produkte umzuschreiben, die Ihre Pipeline still gedroppt hat.</p>\n<p><strong>Tier 1 führt das LLM über eindeutige Werte aus, nicht über Datensätze.</strong> Das ist der Trick, der Vokabular-Probleme billig macht: Mein schlechtester Katalog hatte 313K Datensätze, aber nur 741 verschiedene Marken-Strings. Marken-Normalisierung ist ein Job über 741 Strings – Casing-Varianten clustern, Sub-Marken auf Parents mappen, Platzhalter flaggen – nicht 313K Aufrufe. Dasselbe Vorgehen für Spec-Keys und Einheiten-Suffixe. Jeder Vokabular-Job kostet einstellige Dollar-Beträge und sein Output ist eine statische Alias-Tabelle, die Ihr Ingest für immer deterministisch anwendet. Nennen wir die gesamte Ebene 20–50 $ für eine Flotte, meist für Review-Durchläufe.</p>\n<pre><code class=\"text\">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>Tier 2 ist der Per-Record-Durchlauf</strong>: ein kundenlesbarer Titel, Such-Erweiterungen, strukturierte Attribute und eine wiederhergestellte Hersteller-Teilenummer für jedes Produkt. Pro SKU ist es klein – etwa 400 Input-Token (der Datensatz plus gemeinsame Instruktionen, die Prompt-Caching nahezu kostenlos macht) und 250 Out. Zwei Hebel, bevor Sie überhaupt ein Modell wählen: Reichern Sie an, was live ist (in meinem schlechtesten Katalog waren nur 14 % der Datensätze aktiv, eine 86 %-Kürzung gleich dort), und nutzen Sie eine Batch-API, wo der Anbieter eine hat, da Anreicherung keine Latenz-Anforderung hat und sowohl Anthropic als auch OpenAI 50 % für Batch geben.</p>\n<p>Ich habe denselben Job über alles preislich bewertet, was Sie 2026 plausibel nutzen würden – Claude, <a href=\"https://openai.com/index/advancing-the-price-performance-frontier-with-gpt-5-6/\">GPT-5.6s drei Tiers</a> (Sol, Terra, Luna), Kimi K3, GLM-5.2, Qwen3.5 und <a href=\"https://deepseek.ai/pricing\">DeepSeek V4</a>. Gleiche Workload, vom Anbieter veröffentlichte Raten, Batch-Rabatt angewendet, wo er existiert:</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>Ich musste diese Zahlen doppelt prüfen, weil sie falsch wirkten. Die Worst-Case-Version dieses Projekts – ein Frontier-Modell, jede einzelne SKU, gar kein Filtering – liegt bei etwa 3.800 $. Das Minimum liegt unter hundert Dollar: DeepSeek V4-Flash würde die gesamte Flotte für etwa den Preis eines anständigen Akkuschraubers anreichern. Die Version, die Sie tatsächlich fahren würden, mischt Tiers: ein Budget-Modell (Haiku, Luna, Qwen Flash, DeepSeek) für die mechanische Mehrheit, ein Mid-Tier-Modell (Sonnet, Terra, GLM-5.2) für den Abkürzungs-Salat-Schwanz, den das kleine als Low-Confidence flaggt, und ein Frontier-Modell, das eine 1–2 %-Stichprobe als Qualitäts-Gate spot-checkt. Das landet bei ein paar hundert Dollar für die Live-SKUs, unabhängig davon, welche Anbieter Sie wählen.</p>\n<p>Zwei Vorbehalte, die das Chart nicht zeigen kann. Billige Modelle sind nur billig, wenn ihr Output Ihr Eval übersteht – führen Sie den 200-Sample-Vergleich durch, bevor Sie sich festlegen, denn ein Budget-Modell, das 5 % der Teilenummern vermasselt, kostet mehr als das Frontier-Modell, das das nicht tut. Und Ihr Katalog ist wettbewerbsrelevante Daten: Preise, Cross-References und Kunden-Teilenummern sind in diesen Datensätzen, also prüfen Sie die Datenretentions- und Trainings-Bedingungen jedes Anbieters, bevor Sie 775K Datensätze zum billigsten Endpoint auf der Liste schicken. Für viele Distributoren entscheidet diese Prüfung allein über manche Anbieter, und die Open-Weight-Optionen (DeepSeek, GLM, Qwen, Kimi) haben die zusätzliche Eigenschaft, dass Sie sie selbst hosten können, wenn die Daten gar nicht rausdürfen.</p>\n<p>Rechnen Sie den ~130 $ UNSPSC-Durchlauf hinzu (der sich über Modelle gleich skaliert – auf der Budget-Ebene sinkt er auf Kleingeld) und die Vokabular-Arbeit, und die gesamte Katalog-Transformation läuft irgendwo zwischen ein paar hundert und ein paar tausend Dollar, gegen Arbeit, die früher ein Jahr eines Merchandising-Teams war. Es ist dieselbe Offline-Batch-Ökonomie, die Instacart beschreibt, nur in Handels-Katalog-Skala, wo die Zahlen klein genug werden, um sie auf eine Kreditkarte zu packen.</p>\n<p>Wie es bei einem echten Datensatz aus meinem Audit aussieht:</p>\n<pre><code class=\"text\">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>Schauen Sie auf die <code>extracted_mpn</code>-Zeile. Derselbe Durchlauf stellt Hersteller-Teilenummern wieder her, die zuvor in Beschreibungstexten vergraben waren – in einem meiner Kataloge werden das 183K Produkte, die über die auf der Verpackung gedruckte Nummer findbar werden. Das allein zahlt den Batch-Job.</p>\n<pre><code class=\"text\">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>Zwei Produktions-Notizen: Packen Sie die gemeinsamen Instruktionen in ein gecachtes Prompt-Prefix (Caching kürzt die Input-Seite um bis zu 90 % zusätzlich zum Batch-Rabatt), und nutzen Sie strukturierte Outputs mit einem JSON-Schema, damit Sie nie eine Parse-Fehler-Steuer zahlen.</p>\n<p><strong>Die letzte Ebene ist die, die Leute überspringen, und es ist die, die sich verzinst.</strong> Das Audit ist einen Cleanup wert. Die Validatoren, die es erzeugt, sind jeden zukünftigen Feed wert. Beenden Sie die Fix-Session mit:</p>\n<pre><code class=\"text\">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>Überspringen Sie das, und dieselben ERP-Exporte werden innerhalb eines Quartals denselben Müll regenerieren, und Sie zahlen zweimal für den Cleanup. Ich weiß es, weil zwei der Bugs, die mein Audit fand, offensichtlich schon einmal repariert worden waren und zurückgekommen waren.</p>\n<h2>Die Prompts ausführen</h2>\n<p>Ein Setup-Schritt: Exportieren Sie Ihren Katalog als JSONL, ein JSON-Objekt pro Zeile mit einer eindeutigen <code>id</code> und den Feldern des Datensatzes. Was auch immer Ihre Plattform ist – Elasticsearch, OpenSearch, Solr, Algolia, Typesense, ein PIM, die Datenbank dahinter – bitten Sie den Agenten einfach, den Exporter zu schreiben:</p>\n<pre><code class=\"text\">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>Mit Claude Code werfen Sie einen beliebigen Kategorie-Prompt in eine Session in diesem Verzeichnis. Es schreibt und führt die Analyse selbst aus, vollständige Durchläufe ohne Sampling-Ausreden, und kommt mit Datensatz-Ebene-Belegen zurück. Wenn Sie \"now fix it\" sagen, produziert dieselbe Session den Ingest-Validator, das Backfill-Skript und den Batch-Anreicherungs-Job. Führen Sie die Kategorien als parallele Sessions oder Subagents aus; so habe ich meine ausgeführt, und das gesamte Audit dauerte etwa zwölf Minuten Wall-Clock-Time. Mit Codex erledigt <code>codex exec</code> die Read-Only-Analyse-Durchläufe mit denselben Prompts; behalten Sie die Write-Side-Fixes in einer Session, die Sie reviewen.</p>\n<p>Drei Regeln, die ich auf die harte Tour gelernt habe:</p>\n<ol>\n<li>Vollständige Durchläufe und Belege verlangen. \"Analysiere diese Daten\" lädt Sampling und Vibes ein. Fordern Sie exakte Counts und fünf Beispiel-Datensatz-IDs pro Befund, und jede Behauptung wird überprüfbar.</li>\n<li>Regeln vor Anreicherung. Reparieren Sie die Wahrheit, bevor Sie Prosa hinzufügen, sonst halluzinieren Sie Marken für die 88 % der Datensätze, die \"Approved Vendor\" heißen.</li>\n<li>Sample, eval, dann batch. Niemals einen 775K-Datensatz-Batch aus einem unvalidierten Prompt feuern. 200 Samples, ein Scoring-Durchlauf, dann skalieren. Das Eval-Harness kostet eine Agent-Session und de-risikt die gesamten Ausgaben.</li>\n</ol>\n<h2>Die Trades verdienen Marketplace-Grade-Suche</h2>\n<p>Amazon, DoorDash und Instacart haben ihre Katalog-LLM-Arbeit nicht als Wohltätigkeit veröffentlicht. Sie haben sie veröffentlicht, weil die Techniken allgemein sind und der Burggraben die Umsetzung ist. Und die Techniken übertragen sich auf den Handel besser als fast überall sonst, wo ich mir vorstellen kann: Die Kataloge sind klein genug, dass ein vollständiger Durchlauf billig ist, die Daten sind schlecht genug, dass der Spielraum enorm ist, die Suchanfragen tragen echtes Geld, und die Beschaffungswelt läuft bereits auf einer Taxonomie, die ein Batch-Job jetzt für etwa 130 $ füllen kann.</p>\n<p>Von den Dutzenden Problemen, die mein Audit über vier Distributoren-Kataloge zutage förderte, war nicht eines von der Ranking-Schicht aus sichtbar. Alle haben sie degradiert. Die Lieferkette, die diese Indizes füttert – die ERP-Exporte, die Lieferanten-Tabellenkalkulationen, die antiken CSV-Parser – ist genau das, was das veröffentlichte Playbook repariert. Die Distributoren, die es umsetzen, werden Marketplace-Grade-Suche auf Katalogen haben, auf denen ihre Konkurrenten noch immer keine Kondensator-Spule finden können.</p>\n<p>Die Frage \"Ist etwas falsch mit meinen Daten?\" kostete früher zwei Wochen von jemandes Zeit, deshalb hat sie niemand gestellt. Sie kostet jetzt einen Prompt. Stellen Sie sie.</p>",
  "source_hash": "sha256:729970b39c1b22c143ba55272659d6cc431b0f8889282089a4ea4eaa71f75000",
  "model": "z-ai/glm-5.2",
  "generated_at": "2026-08-06T09:54:25.519108+00:00"
}