{
  "title": "AI 시대의 B2B 커머스 검색 문제 해결하기",
  "excerpt": "4개 B2B 유통업체의 검색을 지원하는 775,000개의 제품 레코드를 감사했습니다. 소비재 대기업들은 이미 LLM을 사용하여 이러한 카탈로그를 수정하는 방법을 공개했지만, 도매 유통업계는 그 플레이북을 채택하지 않았습니다. 여기 HVAC, 배관, 전기 분야에 맞게 조정하고 실제 비용을 포함한 플레이북이 있습니다.",
  "content_html": "<p>B2B 커머스 검색에는 더러운 비밀이 있습니다. 순위 알고리즘이 문제인 경우는 드물다는 것입니다.</p><p>검색 결과가 좋지 않을 때, 팀들은 재미있는 레버를 당깁니다. 부스팅, 동의어, 임베딩, 재순위화, 그리고 최근에는 LLM 쿼리 이해까지. 저도 그 모든 레버를 직접 사용해 봤습니다. 지난주에는 대신 화려하지 않은 일을 했습니다. HVAC, 배관, 산업용 공급품, 패스너 분야의 4개 B2B 유통업체에 걸친 4개의 프로덕션 검색 인덱스에서 모든 제품 레코드(775,051개)를 덤프하고 데이터 자체를 감사했습니다. 각각 커버리지, 텍스트 품질, 부품 번호, 브랜드, 가격, 사양, 카테고리, 미디어, 중복이라는 한 가지 차원을 담당하는 12개의 AI 에이전트를 병렬로 실행했습니다.</p><p>돌아온 결과는 유통업체 카탈로그에서 일해 본 사람에게는 평범한 것이었고, 그렇지 않은 사람에게는 충격적이었습니다. 하지만 제게 가장 인상 깊었던 부분은 이것입니다. 해결책은 이미 공개되어 있다는 것입니다. Amazon, DoorDash, Instacart는 2년 동안 공개 엔지니어링 블로그를 통해 LLM을 사용하여 대규모로 지저분한 카탈로그를 정리, 레이블링, 강화하는 방법을 정확히 설명해 왔습니다. 도매 유통업계는 대부분 알아차리지 못했습니다. 유통업계의 카탈로그가 더 지저분하고, 쿼리의 가치가 더 높으며(12달러짜리 점심이 아닌 4,000달러짜리 콘덴서를 주문하는 계약자), 카탈로그 규모가 실제로 경제성을 더 쉽게 만들기 때문에 이상한 일입니다.</p><p>따라서 이 글은 도매 유통에 맞게 조정된 해당 플레이북입니다. B2B 검색을 망가뜨리는 데이터 문제, 오늘 오후에 코딩 에이전트로 찾는 방법, UNSPSC 분류를 포함한 LLM으로 수정하는 방법, 그리고 전체 비용이 얼마인지에 대한 내용입니다. 마지막 항목에 대한 스포일러: 예상보다 두 자릿수 적습니다.</p><h2>플레이북은 이미 존재하지만, 우리 업계에는 없습니다</h2><p>마켓플레이스 기업들이 공개한 몇 가지 내용:</p><ul><li>DoorDash는 LLM과 검색 증강 생성을 사용하여 <a href=\"https://careersatdoordash.com/blog/how-doordash-leverages-llms-for-better-search-retrieval/\">제품 지식 그래프를 구축하고 검색 검색을 개선</a>합니다: 수백만 개의 판매자 제공 품목에 걸친 자동 브랜드 추출, 속성 추출, 엔터티 연결.</li><li>Amazon은 <a href=\"https://www.amazon.science/blog/building-commonsense-knowledge-graphs-to-aid-product-recommendation\">COSMO</a>를 구축했습니다. 이는 고객이 의미하는 바(&quot;임산부용 신발&quot;)와 제품이 무엇인지(&quot;미끄럼 방지 신발&quot;)를 연결하는 LLM 생성 지식 그래프입니다. 오프라인 테스트에서 추천 성능이 최대 60% 향상되었다고 보고합니다.</li><li>Instacart는 LLM을 검색 스택에 넣어 <a href=\"https://tech.instacart.com/supercharging-discovery-in-search-with-llms-556c585d4720\">디스커버리 콘텐츠를 생성</a>하고 <a href=\"https://www.instacart.com/company/tech-innovation/building-the-intent-engine-how-instacart-is-revamping-query-understanding-with-llms\">쿼리 이해를 재구축</a>하고 있습니다. 비용을 정확히 낮추기 위해 무거운 생성은 오프라인에서 배치로 수행됩니다.</li></ul><p>공통점을 놓치기 쉽습니다. LLM의 승리는 카탈로그 측과 오프라인 측에서 이루어집니다. 이들 기업은 단 하나의 쿼리가 도착하기 전에 데이터를 강화합니다. 디스커버리 시스템은 아티팩트(카탈로그, 인덱스, 임베딩)를 구축하는 오프라인 측과 그 위에서 검색하고 순위를 매기는 온라인 측으로 나뉘며, 게시된 LLM 가치는 거의 모두 오프라인에 있습니다. 순위 레이어는 공급받는 데이터만큼만 좋을 수 있습니다.</p><p>이제 일반적인 HVAC 또는 배관 유통업체의 카탈로그를 그 옆에 놓고 상상해 보십시오. ERP 내보내기, 공급업체 스프레드시트, 구매 그룹 피드, 그리고 누군가 10년 전에 작성한 CSV 파서로 구성되어 있습니다. 제품 &quot;제목&quot;은 창고 피킹 직원을 위해 작성된 인보이스 속기입니다. 그리고 이를 타격하는 검색 트래픽은 검색 트래픽 중에서도 의도 밀도가 가장 높습니다. 절반은 정확한 부품 번호이고, 나머지는 &quot;3/4 cxc 90 ell&quot;과 같은 업계 전문 용어입니다. 솔직히, 이 플레이북에 더 좋은 환경은 생각할 수 없습니다. 쿼리는 가치 있고, 데이터는 수정 가능하며, 수십만 개의 SKU에서 카탈로그에 대한 전체 LLM 패스 비용은 수백 달러입니다. 수백만 달러가 아닙니다. 수백 달러요.</p><p>감사 형태는 다음과 같습니다. 직접 재현하고 싶을 것이기 때문입니다:</p><pre><code class=\"language-mermaid\">flowchart TD\n    D[&quot;Raw catalog dump&lt;br/&gt;(JSONL, one record per line)&quot;] --&gt; C1[&quot;Per-catalog coverage agents&lt;br/&gt;null rates, distributions, dead fields&quot;]\n    D --&gt; C2[&quot;Dimension agents&lt;br/&gt;text · part numbers · brands · pricing&lt;br/&gt;specs · categories · media · duplicates&quot;]\n    C1 --&gt; S[&quot;Synthesis: findings ranked by&lt;br/&gt;severity, with example records&quot;]\n    C2 --&gt; S\n    S --&gt; F[&quot;Fix pipeline: rules + LLM enrichment&lt;br/&gt;+ UNSPSC classification + ingest gates&quot;]\n</code></pre><p>프롬프트 전에 형식에 대한 한 가지 참고 사항입니다. 아래의 모든 것은 일반 덤프에서 작동합니다. 각 줄에 하나의 JSON 객체가 있으며, 각각 고유한 <code>id</code>와 레코드의 필드가 있습니다. Elasticsearch, OpenSearch, Solr, Algolia, Typesense, PIM, 일반 데이터베이스 내보내기 등 모든 플랫폼이 이 형태를 생성할 수 있으며, 여기의 모든 프롬프트는 이에 대해 실행됩니다.</p><h2>카테고리 1: 무음 파이프라인 오류</h2><p>제가 찾은 최악의 것은 누군가가 작성한 잘못된 데이터가 아니었습니다. 파이프라인이 들어오는 길에 아무에게도 알리지 않고 파괴한 데이터였습니다.</p><p>이러한 카탈로그는 수집 시에 기본 검색 텍스트를 구축하며, 제품 제목에서 치수와 단위를 추출하는 스크립팅된 정규식을 사용합니다. 긴 제목에서 정규식은 엔진의 복잡성 한계를 초과하고, 프로세서는 실패하며, 레코드는 어쨌든 인덱싱됩니다. 아무도 읽지 않는 오류 필드와 기본 검색 필드가 전혀 없는 상태로 말이죠.</p><p><img alt=\"기본 검색 필드 없이 인덱싱된 문서, 유통업체별\" src=\"/assets/images/b2b-search-silent-failures.png\" /></p><p>전체 fleet에서 52,570개의 레코드가 인덱스에 존재하여 기본 쿼리 경로에서 보이지 않았습니다. 최악의 카탈로그에서는 제품 7개 중 1개꼴이었습니다. 아무것도 실패하지 않았기 때문에 어떤 대시보드도 이를 포착하지 못했습니다. 파이프라인은 매일, 몇 달 동안 성공을 반환했습니다.</p><p>같은 계열에서 두 가지 더 많은 발견 사항이 있습니다. 오래된 미러: 한 필드가 진실(계정별 자격 맵)을 보유하고 있고, 두 번째 평면화된 필드가 필터링을 위해 이를 미러링합니다. 한 카탈로그에서 미러는 레코드의 19.85%에서 드리프트되었습니다. 즉, 31,000개의 활성 제품이 계정 필터링된 검색에서 잘못 숨겨졌습니다. 그리고 동결된 카탈로그: 한 인덱스는 다른 인덱스가 매일 업데이트되는 동안 10주 동안 새로 고쳐지지 않았습니다. 가동 시간은 모니터링되었습니다. 신선도는 그렇지 않았습니다.</p><p>해결책은 지루하며, 그것이 요점입니다. 파생 필드 커버리지에 대해 경고하십시오(소스가 비어 있지 않은데 파생 필드가 비어 있는 경우). 하나의 사실에 대한 두 가지 표현을 유지하지 마십시오. 쓰기 시간에 필터링 가능한 필드를 파생시키십시오. 가동 시간을 모니터링하는 것처럼 카탈로그별 데이터 신선도를 관찰하십시오.</p><p>자체 카탈로그에서 이 모든 것을 찾기 위한 프롬프트는 다음과 같습니다(Claude Code 또는 <code>codex exec</code>, 메커니즘은 마지막에):</p><pre><code>다음은 ./dump/ 디렉토리에 JSONL 파일로 된 내 제품 카탈로그 덤프입니다. 각 줄은 하나의 JSON 레코드이며, 각각 고유한 &quot;id&quot;와 제품 필드가 있습니다. 내 필드/스키마 정의(있는 경우)는 schema.json에 있습니다.\n\n무음 파이프라인 오류를 찾기 위해 스트리밍 Python(메모리에 모두 로드하지 않음)을 작성하십시오:\n1. 파이프라인이 스탬프한 오류/예외 필드를 전달하는 레코드.\n2. 모든 DERIVED 필드(연결, *_search, *_normalized 변형)에 대해: 파생 필드가 비어 있지만 명백한 소스 필드는 비어 있지 않은 레코드.\n3. 서로 미러처럼 보이는 필드 쌍(하나는 중첩/풍부, 하나는 평면/필터링 가능): 얼마나 자주 일치하지 않는지 정량화.\n4. 업데이트/인덱싱된 타임스탬프의 분포: 카탈로그의 어떤 부분이 나머지는 새로 고쳐지는 동안 동결되어 있습니까?\n\n각 발견 사항을 개수, 카탈로그 대비 %, 5개의 예시 ID, 그리고 영향을 받는 레코드가 활성/표시 가능한지 여부와 함께 보고하십시오. 심각도별로 순위를 매기십시오.\n</code></pre><h2>카테고리 2: 플레이스홀더와 센티널, 또는 거짓말하는 데이터</h2><p>널 검사는 모든 사람이 이미 가지고 있는 데이터 품질 도구입니다. 플레이스홀더는 이를 무력화시킵니다. 플레이스홀더는 채워져 있기 때문입니다. 단지 사실이 아닐 뿐입니다.</p><p>제가 가장 좋아하는 예: 313K SKU 카탈로그에서 브랜드 필드는 741개의 고유한 값과 99.99%의 채움률을 가지고 있었습니다. 건강해 보입니다. 최상위 값은 전체 레코드의 88.8%에서 &quot;승인된 공급업체&quot;였습니다. ERP 플레이스홀더입니다. 가장 인기 있는 실제 브랜드는 카탈로그의 0.3%를 차지했습니다. 따라서 모든 브랜드 패싯, 브랜드 부스트, 브랜드 인식 재작성은 카탈로그의 9/10에서 사실상 죽어 있었고, 패싯 UI는 &quot;승인된 공급업체&quot;를 #1 브랜드 필터로 쾌활하게 제공했습니다.</p><p>일단 찾기 시작하면 이런 것들이 도처에 있습니다:</p><ul><li>한 카탈로그의 55%에서 <code>99999999.000000</code>의 &quot;가격 없음&quot; 센티널. 해당 인덱스의 중간 가격은 9,900만 달러였습니다.</li><li>말 그대로 <code>&quot;unknown&quot;</code>인 제품 이름이 64개 레코드에 있으며, 이는 &quot;unknown&quot; 쿼리에 대해 순위가 매겨집니다.</li><li>1,516개의 라이브 제품에 텍스트 설명 필드에 기록된 부울 <code>true</code>. 엔진은 이를 문자열 &quot;true&quot;로 강제 변환하여 해당 제품이 &quot;true&quot;를 검색하여 찾을 수 있게 만들었습니다.</li><li><code>&quot;6.71E+11&quot;</code>로 저장된 227개의 UPC - Excel의 과학적 표기법으로, 51개의 관련 없는 제품이 해당 &quot;식별자&quot;를 공유하고 있으며, 추가로 15,121개의 UPC가 선행 0을 잃어버렸습니다. Excel의 또 다른 공격입니다.</li><li>브랜드 필드에 제품 라인 이름(&quot;C6L Lockbolts&quot;, &quot;Tool Parts&quot;)을 보유하고 실제 브랜드는 한 필드 옆에 있는 패스너 카탈로그.</li></ul><p>이 카테고리에서 얻은 교훈: 널 비율이 아닌 필드별 상위 N 값 분포를 감사하십시오. 100% 채워진 필드는 88%가 쓰레기일 수 있으며, 널 검사는 절대 알려주지 않습니다. 그런 다음 수집 시 센티널을 블록리스트에 추가하고, 명시적인 <code>has_price</code> / <code>has_real_image</code> 플래그로 실제 널에 매핑하고, 경계에서 유형을 어설션하고, 식별자를 구조적으로 검증하십시오. 스프레드시트를 통과한 모든 것은 의심스러운 것으로 취급하십시오.</p><pre><code>동일한 JSONL 덤프. 내 카탈로그의 모든 필드에 대해 상위 20개 값 분포를 계산하십시오(전체 패스, 스트리밍).\n\n플래그: (a) 레코드의 &gt;10%를 차지하는 단일 값 - &quot;승인된 공급업체&quot;, &quot;unknown&quot;, 99999999, 0.0과 같은 플레이스홀더/센티널 후보; (b) 유형이 필드의 지배적인 유형과 다른 값(텍스트 필드의 부울, 문자열 사이의 부동 소수점); (c) 식별자 필드(UPC/EAN/GTIN/부품 번호): 체크섬과 길이를 검증하고, 과학적 표기법, 제거된 선행 0, 포함된 공백/유니코드, 여러 레코드가 공유하는 식별자를 플래그; (d) 브랜드 필드에 있는 카테고리형 또는 제품 라인 값.\n\n각 플래그에 대해: 개수, 카탈로그 대비 %, 5개의 축어적 예시와 ID, 그리고 이를 거부했을 수 있는 한 줄 제안 수집 규칙.\n</code></pre><h2>카테고리 3: 빈약한 콘텐츠</h2><p>유통업체 카탈로그는 머천다이저가 아닌 ERP에 의해 작성됩니다. 텍스트는 인보이스 속기입니다: <code>PROPRESS 2-1/2X1 CXC RED CPLG</code>, <code>HC HX 18X8 W</code>. 한 카탈로그에서 제품 이름의 3분의 1이 사전 단어의 60% 미만을 가지고 있었습니다. 다른 카탈로그에서는 원시 이름과 설명 필드가 100% 널이었습니다. 텍스트는 파생된 검색 블롭 내부에만 존재했기 때문에 원시 필드를 읽는 모든 것(결과 제목, 임베딩 입력, 관련성 판사 프롬프트)은 아무것도 읽지 않고 있었고 아무도 몰랐습니다.</p><p><img alt=\"4개의 프로덕션 B2B 인덱스 전체의 필드 커버리지\" src=\"/assets/images/b2b-search-field-coverage.png\" /></p><p>그 히트맵은 감사에서 얻은 제가 가장 좋아하는 아티팩트입니다. 그 필드들 각각은 모든 스키마에 존재합니다. 숫자는 각각이 실제로 보유하는 데이터의 양입니다. 제 마음을 사로잡는 행은 ML-설명입니다. 모든 레코드에 대해 스키마가 약속한 강화 레이어는 775,051개 문서 중 18개에만 채워져 있었습니다. 18개. 점수 매기기 파이프라인의 모든 &quot;강화가 있으면 사용&quot; 분기는 무음 no-op였습니다. 스키마는 열망일 뿐입니다. 커버리지만이 사실입니다.</p><p>이 카테고리는 게시된 플레이북이 가장 직접적으로 적용되는 곳입니다. DoorDash의 속성 추출, Instacart의 오프라인 생성, 그리고 아래 비용 섹션에서 가격을 책정합니다. 그러나 부품 번호 비즈니스에서는 네 가지 규칙이 중요하며, 이전 강화 시도에서 잘못된 점을 부분적으로 배웠습니다:</p><ul><li>확장하고, 대체하지 마십시오. 원시 인보이스 문자열과 함께 고객이 읽을 수 있는 제목을 생성하고 둘 다 인덱싱하십시오. 기술자의 쿼리와 주택 소유자의 쿼리가 모두 적중해야 합니다.</li><li>코드를 말로 표현하지 마십시오. 그 18개의 개척 레코드? 생성기가 모델 번호를 단어로 철자했습니다: &quot;RGF one hundred eighty.&quot; 어떤 계약자도 그렇게 입력하지 않을 것입니다. 코드는 그대로 유지됩니다. 확장은 대체가 아닌 추가입니다.</li><li>작업하는 동안 구조를 추출하십시오. 제목을 다시 작성하는 동일한 패스는 패싯을 위해 <code>{size, material, connection_type}</code>을 내보낼 수 있습니다.</li><li>업계 전문 용어는 동의어 문제이지, 재작성 문제가 아닙니다. <code>CXC</code>, <code>ELL</code>, <code>CPLG</code>, &quot;t-stat&quot;는 분석기 수준의 동의어 확장에 속하며, 한 번만 수정하면 됩니다. 50만 개 레코드로 다시 작성하는 데 비용을 지불하지 마십시오.</li></ul><pre><code>동일한 덤프. 전체 스트리밍 패스로 고객 대상 필드(이름, 짧은/긴 설명)의 텍스트 품질을 평가하십시오:\n\n1. 유효 제목 커버리지: 비어 있지 않은 표시 이름을 가진 ACTIVE 레코드의 %.\n2. 가독성: ALL-CAPS 이름의 %; 사전 단어 토큰이 60% 미만인 %(약어 샐러드); 10자 미만 이름; 숫자만 있는 설명.\n3. 쓰레기: HTML/CMS 마크업, 인코딩 아티팩트, 포함된 운영 메모(*** NOT A PHYSICAL ITEM ***), CSV 열 유출.\n4. 중복: 동일한 짧은/긴 설명; 20+ SKU가 공유하는 상용구; VARCHAR 한계를 나타내는 정확한 길이 클러스터(254/255/500자).\n5. 강화 현실 확인: 스키마가 약속하는 모든 ML/강화/임베딩 필드에 대해 실제 커버리지.\n\n숫자, 각각 5개의 축어적 예시, 심각도, 그리고 어떤 문제가 LLM 강화 패스 대 파이프라인 수정 대 동의어 레이어 수정이 필요한지.\n</code></pre><h2>카테고리 4: 부품 번호는 신성합니다</h2><p>B2B 검색 트래픽의 절반은 누군가가 부품 번호를 입력하는 것입니다. 정확히 일치하는 것이 전부이며, 조용히 실패합니다.</p><p>한 카탈로그에서 인덱싱된 부품 번호는 레코드의 99.99%에서 내부 숫자 SKU였습니다. 제조업체 번호(상자에 인쇄된 번호)는 자유 텍스트 설명 내부에만 존재했습니다. 183,000개의 제품이 고객이 실제로 입력할 번호로는 도달할 수 없었습니다.</p><p>다른 카탈로그에는 변형 확장 시스템이 있었습니다. 대시를 제거하고, 세그먼트를 축소하고, 관대한 PN 검색이 작동하도록 변형을 인덱싱합니다. 좋은 생각입니다. 그러나 생성기는 조합적이었고(제품당 최대 80개 변형), 11,826개 레코드에서 한 제품의 생성된 변형이 다른 제품의 표준 부품 번호와 정확히 일치했습니다. 패스너는 잔인한 경우입니다. 구두점이 물리적 치수를 인코딩하기 때문입니다. <code>702-1-5/32</code>는 1-5/32 인치 부품이고 <code>702-15/32</code>는 15/32 인치 부품이며, 둘 다 <code>7021532</code>로 정규화됩니다. 고객이 정확한 부품 번호를 입력하면 올바른 부품과 치수적으로 유사한 부품 사이에서 동전 던지기를 하게 됩니다.</p><p>또한 이 카테고리에는 경쟁사 교차 참조(&quot;Ferguson 번호가 있는데, 당신 것은 무엇입니까?&quot;)가 분할되지 않은 파이프로 구분된 블롭(<code>19MU82|Fastenal 0269214|Ferguson M48222407</code>)으로 저장되어 있고, 검색 불가능으로 구성된 필드에 있어 핵심 B2B 판매 동작이 작동하지 않습니다. 그리고 공백 포크(동일한 부품 번호가 세 번 인덱싱됨(일반, NBSP 패딩, 후행 공백)), 이중 디코딩된 UTF-8의 모지바케 쌍둥이도 있습니다.</p><p>이 대부분을 수정하는 원칙: 정확히 일치하는 것은 확률적으로가 아니라 구조적으로 퍼지보다 우선해야 합니다. 구두점을 보존하는 정확한 절은 정규화된 계층보다 엄격하게 높은 점수를 받아야 하며, 변형이 표준 적중과 동점을 이룰 수 있는 단일 평면 일치가 있어서는 안 됩니다. 인덱싱 전에 생성된 변형을 표준 PN 공간에 대해 확인하고 충돌을 제거하십시오. 레코드 ID를 파생하기 전에 유니코드를 정규화하십시오. 교차 참조 블롭을 배열로 분할하십시오. 이것은 전체 쿼리 클래스를 잠금 해제하는 한 줄의 수집 코드입니다.</p><pre><code>동일한 덤프. 내 사용자는 부품 번호로 검색합니다. 정확히 일치하는 무결성을 감사하십시오:\n\n1. 어떤 PN 유사 필드가 존재하는지(part_number, mpn, alt/competitor/customer PN, UPC), 그 커버리지, 그리고 실제 데이터를 보유하면서 검색 불가능으로 구성된 것은 무엇인지.\n2. 검색 가능한 유일한 PN 토큰이 내부 SKU인 레코드(실제 제조업체 PN은 설명 텍스트 내부에만 나타남 - 패턴을 보여주십시오).\n3. PN-변형/키워드 확장 필드가 있는 경우: 다른 레코드의 표준 PN과 동일한 모든 생성된 변형을 찾으십시오(정규화: 소문자, 구두점 제거). 충돌 쌍을 보여주십시오 - 특히 분수를 포함하는 패스너 크기.\n4. 공백/보이지 않는 문자/대소문자만 다른 PN(중복 ID 포크).\n5. 배열 대신 구분된 블롭으로 저장된 다중 값 교차 참조 필드.\n\n개수, 예시, 그리고 각 문제에 대해 이를 수정하는 수집 규칙 또는 쿼리 빌더 변경.\n</code></pre><p>위에 맞지 않지만 한 문장은 가치 있는 몇 가지 사항: 숫자를 전선 게이지 용어로 바꾸는 동의어 생성기(따라서 <code>REF#259286</code>은 &quot;259286 awg&quot;가 되고 <code>#8-32</code> 나사산은 &quot;8 gauge wire&quot;가 됨, 수천 개의 레코드가 관련 없는 전기 쿼리와 일치하게 됨); 전자상거래 플랫폼의 내부 플래그가 검색 가능한 제품 사양으로 인덱싱됨, 210만 개의 정크 키-값 쌍; 그리고 어디에서도 0개의 레코드에 채워진 18개의 스키마 필드. 확장 생성기에는 컨텍스트 게이트가 필요합니다. 죽은 스키마는 누군가가 결국 구축할 거짓 약속입니다.</p><h2>누락된 레이어: UNSPSC, 그리고 자신이 무엇인지 모르는 제품들</h2><p>다섯 번째 문제가 있으며, 이는 자체 섹션이 필요합니다. 도매 유통이 마켓플레이스보다 가장 뒤처져 있는 부분이기 때문입니다.</p><p>제 감사에서 카테고리 필드는 한 카탈로그의 83%에서 누락되었습니다. 속성 키에는 전혀 분류 체계가 없었습니다. 156K 레코드 카탈로그에 7,068개의 고유한 사양 키가 있었고, 그중 64%는 10개 미만의 제품에 사용되었으며, <code>horse_power</code> 대 <code>horsepower</code>와 같은 드리프트가 동일한 속성을 패싯으로 분할했습니다. 그리고 제가 계속 생각나는 세부 사항: 4개의 카탈로그 중 2개는 스키마에 UNSPSC 필드가 있었고, 매핑되어 준비되었으며, 정확히 0개의 레코드에 채워져 있었습니다. 누군가는 분류가 중요하다는 것을 알고 있었고, 슬롯을 구축했으며, 결코 채우지 않았습니다. 이유에 대해 돈을 걸겠습니다. 300K SKU를 분류 체계로 수동으로 분류하는 것은 카탈로그 팀의 1년 작업이므로 로드맵에 영원히 남아 있었습니다.</p><p>B2B 외부에 있다면, UNSPSC는 UN 표준 제품 및 서비스 코드로, 조달 시스템이 사용하는 분류 체계입니다. 이것은 소비자 검색에는 없는 부분입니다. 고객의 구매 시스템이 이를 요구합니다. 펀치아웃 카탈로그, 전자 조달 플랫폼, 지출 분석 도구는 UNSPSC 코드를 기반으로 구축됩니다. 깨끗한 코드가 있는 카탈로그를 가진 유통업체는 계약자나 병원의 구매 시스템에 연결할 수 있습니다. 없는 유통업체는 검색 상자가 있는 PDF 가격표일 뿐입니다. 내부적으로는 카테고리 패싯, 카테고리 범위 순위(&quot;전선 게이지로 분석되는 숫자는 전선만 부스트해야 함&quot;), 카탈로그 간 중복 제거, 그리고 카테고리 4의 모든 확장 생성기에 대한 컨텍스트 게이트를 지원합니다.</p><p>그리고 이제는 배치 작업입니다. 이것은 DoorDash가 LLM으로 해결한다고 설명하는 문제(통제된 어휘에 대한 대량 레이블링)와 동일한 형태이며, 접근 방식이 직접적으로 이전됩니다:</p><ul><li>평면이 아닌 계층적으로 분류하십시오. UNSPSC는 4단계(세그먼트, 패밀리, 클래스, 커머디티)가 있습니다. 모델이 ~450개의 옵션에서 패밀리를 선택한 다음, 해당 패밀리 내에서 클래스를 선택하게 하십시오. 두 개의 작은 제한된 선택이 하나의 50,000개 선택보다 낫고, DoorDash가 엔터티 연결을 어휘로 제한하는 방식처럼 관련 분류 체계 조각을 컨텍스트에 공급할 수 있습니다.</li><li>먼저 클래스 수준에서 중단하십시오. 클래스 코드는 이미 패싯과 조달 통합을 잠금 해제합니다. 커머디티 수준의 정밀도는 가치가 있는 곳에서 나중에 올 수 있습니다.</li><li>신뢰도별로 라우팅하십시오. 작은 모델이 명확한 경우를 처리하고, 신뢰도가 낮은 레코드는 더 큰 모델로 에스컬레이션되며, 지속적인 불일치는 평가 세트 역할을 하는 인간 큐로 이동합니다.</li></ul><p>비용은 입력하기 부끄러울 정도입니다. 분류는 짧은 출력 작업입니다. 레코드당 약 300개의 입력 토큰과 30개의 출력 토큰입니다. Batch API 가격의 Claude Haiku 4.5에서 SKU 1,000개당 약 17센트입니다. 775K 레코드 전체 fleet은 약 $130에 분류될 것입니다. 수동 작업 1년이었기 때문에 수년간 로드맵에 있었던 것이 논의할 팀 점심 비용보다 적게 듭니다.</p><pre><code>당신은 B2B 유통업체 제품을 UNSPSC로 분류합니다. 참조 데이터로 UNSPSC 패밀리 목록(레벨 2, ~450개 항목)이 첨부되어 있습니다.\n\n각 제품 레코드(제목, 설명, 브랜드, 부품 번호, 기존 카테고리 텍스트)에 대해 JSON을 출력하십시오:\n- unspsc_family: 4자리 패밀리 코드 - 첨부된 목록에서만 선택\n- family_confidence: high | low\n- rationale: 한 문장 설명(예: &quot;copper press fitting -&gt; pipe fittings&quot;)\n\n규칙: 제품의 기능으로 판단하고, 브랜드로 판단하지 마십시오. 업계 속기: CXC/FPT/MPT는 파이프 연결, ELL은 엘보, CPLG는 커플링, 베어 분수+재료는 일반적으로 피팅 크기입니다. 레코드가 물리적 제품이 아닌 경우(운임 라인, 추가 요금, &quot;*** NOT A PHYSICAL ITEM ***&quot;), NOT_A_PRODUCT를 출력하십시오. 신뢰도를 관대하게 사용하십시오. 신뢰도가 낮은 레코드는 클래스 수준 목록으로 두 번째 패스를 받습니다.\n</code></pre><h2>정리 플레이북, 실제 청구서 포함</h2><p>수정 파이프라인은 분류 작업과 함께 3개의 계층으로 구성됩니다. 비결은 올바른 계층에 지출하는 것입니다. 레코드당 LLM 호출이 거의 필요하지 않기 때문입니다.</p><pre><code class=\"language-mermaid\">flowchart LR\n    A[&quot;Tier 0 - Rules&lt;br/&gt;deterministic code&lt;br/&gt;~$0&quot;] --&gt; B[&quot;Tier 1 - LLM on unique values&lt;br/&gt;brands · spec keys · units&lt;br/&gt;tens of dollars&quot;]\n    B --&gt; C[&quot;Tier 2 - LLM per record&lt;br/&gt;titles · attributes · UNSPSC&lt;br/&gt;hundreds of dollars&quot;]\n    C --&gt; G[&quot;Ingest gates&lt;br/&gt;every fix becomes a validator&quot;]\n</code></pre><p><strong>계층 0은 결정론적 코드이며 기본적으로 무료입니다.</strong> HTML을 제거하고 엔터티를 디코딩하십시오. 센티널을 명시적 플래그가 있는 실제 널로 바꾸십시오. UPC를 수정하십시오(왼쪽 패딩, 과학적 표기법 거부, 체크 디지트 검증). ID를 유니코드 정규화하십시오. 파이프로 구분된 교차 참조를 분할하십시오. 다른 제품의 표준 번호와 충돌하는 PN 변형을 삭제하십시오. 죽은 스키마를 삭제하십시오. 에이전트가 한 세션에서 이러한 스크립트를 작성하며, 이 계층은 제 감사에서 발견된 것의 대략 절반을 수정했습니다. 어떤 강화보다 먼저 수행하십시오. 그렇지 않으면 파이프라인이 조용히 드롭한 제품의 제목을 아름답게 다시 작성하기 위해 모델에 비용을 지불하게 됩니다.</p><p><strong>계층 1은 레코드가 아닌 고유 값에 대해 LLM을 실행합니다.</strong> 이것이 어휘 문제를 저렴하게 만드는 비결입니다. 최악의 카탈로그는 313K 레코드가 있었지만 고유한 브랜드 문자열은 741개뿐이었습니다. 브랜드 정규화는 741개 문자열에 대한 하나의 작업입니다. 대소문자 변형을 클러스터링하고, 하위 브랜드를 상위에 매핑하고, 플레이스홀더를 플래그하는 것입니다. 313K 호출이 아닙니다. 사양 키와 단위 접미사에도 동일한 방법을 사용하십시오. 각 어휘 작업은 한 자릿수 달러이며, 그 출력은 수집이 영원히 결정론적으로 적용하는 정적 별칭 테이블입니다. 전체 계층을 fleet당 $20-50으로 부르며, 주로 검토 패스에 사용됩니다.</p><pre><code>첨부: 내 브랜드 및 제조업체 필드의 전체 고유 값 분포(값, record_count). 정규화 테이블을 생성하십시오:\n\ncanonical_brand, parent_manufacturer, [raw variants], confidence\n\n규칙: 대소문자/구두점/공백 변형을 클러스터링하십시오. 하위 브랜드를 상위 제조업체에 별도 열로 매핑하십시오(병합하지 마십시오). 플레이스홀더 값을 NULL_SENTINEL로 표시하십시오. 브랜드로 잘못 분류된 제품 라인 또는 카테고리를 NOT_A_BRAND로 표시하십시오. 불확실한 클러스터는 추측하지 말고 플래그하십시오. CSV를 출력한 다음, 수집 시 이를 적용하고 일치하지 않는 새 값을 기록하는 스크립트를 작성하십시오.\n</code></pre><p><strong>계층 2는 레코드별 패스입니다.</strong> 모든 제품에 대해 고객이 읽을 수 있는 제목, 검색 확장, 구조화된 속성, 복구된 제조업체 부품 번호입니다. SKU당 작습니다. 약 400개의 입력 토큰(레코드와 프롬프트 캐싱이 거의 무료로 만드는 공유 지침)과 250개의 출력 토큰입니다. 모델을 선택하기 전에 두 가지 레버가 있습니다. 라이브인 것을 강화하십시오(최악의 카탈로그에서 레코드의 14%만 활성 상태였으며, 즉시 86% 삭감). 그리고 제공자가 있는 경우 배치 API를 사용하십시오. 강화에는 지연 시간 요구 사항이 없고 Anthropic과 OpenAI 모두 배치에 대해 50%를 할인해 주기 때문입니다.</p><p>2026년에 합리적으로 사용할 수 있는 모든 모델(Claude, <a href=\"https://openai.com/index/advancing-the-price-performance-frontier-with-gpt-5-6/\">GPT-5.6의 3계층</a>(Sol, Terra, Luna), Kimi K3, GLM-5.2, Qwen3.5, <a href=\"https://deepseek.ai/pricing\">DeepSeek V4</a>)에 대해 동일한 작업의 가격을 책정했습니다. 동일한 워크로드, 제공자 게시 가격, 배치 할인이 있는 경우 적용됩니다.</p><p><img alt=\"모델별 775K SKU 강화 비용\" src=\"/assets/images/b2b-search-enrichment-cost-by-model.png\" /></p><p>이 숫자가 잘못된 것 같아서 다시 확인해야 했습니다. 이 프로젝트의 최악의 경우(프론티어 모델, 모든 SKU, 전혀 필터링 없음)는 약 $3,800에서 최고점을 찍습니다. 최저점은 100달러 미만입니다. DeepSeek V4-Flash는 괜찮은 드릴 가격으로 전체 fleet을 강화할 것입니다. 실제로 실행할 버전은 계층을 혼합합니다. 기계적인 대다수에는 예산 모델(Haiku, Luna, Qwen Flash, DeepSeek)을, 작은 모델이 신뢰도가 낮다고 플래그하는 약어 샐러드 테일에는 중간 계층 모델(Sonnet, Terra, GLM-5.2)을, 품질 게이트로 1-2% 샘플을 점검하는 프론티어 모델을 사용합니다. 선택한 공급업체에 관계없이 라이브 SKU의 경우 수백 달러에 불과합니다.</p><p>차트가 보여줄 수 없는 두 가지 주의 사항. 저렴한 모델은 평가에서 출력이 살아남는 경우에만 저렴합니다. 커밋하기 전에 200개 샘플 비교를 실행하십시오. 부품 번호의 5%를 망치는 예산 모델은 그렇지 않은 프론티어 모델보다 더 많은 비용이 듭니다. 그리고 카탈로그는 경쟁 데이터입니다. 가격, 교차 참조, 고객 부품 번호가 해당 레코드에 있으므로 목록에서 가장 저렴한 엔드포인트로 775K 레코드를 보내기 전에 각 제공자의 데이터 보존 및 교육 조건을 확인하십시오. 많은 유통업체에서 이 확인만으로 일부 공급업체가 포함되거나 제외되며, 오픈 가중치 옵션(DeepSeek, GLM, Qwen, Kimi)은 데이터를 전혀 보낼 수 없는 경우 자체 호스팅할 수 있다는 추가 속성이 있습니다.</p><p>~$130 UNSPSC 패스(모델 전체에서 동일하게 확장됨 - 예산 계층에서는 주머니 돈 수준으로 떨어짐)와 어휘 작업을 추가하면 전체 카탈로그 변환은 수백 달러에서 수천 달러 사이에 위치하며, 이전에는 머천다이징 팀의 1년이었던 작업에 비해 훨씬 적습니다. Instacart가 설명하는 것과 동일한 오프라인 배치 경제학이며, 숫자가 신용 카드에 올릴 수 있을 정도로 작아지는 도매 카탈로그 규모에서 말이죠.</p><p>제 감사에서 실제 레코드로 보면 다음과 같습니다:</p><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\n</code></pre><p><code>extracted_mpn</code> 줄을 보십시오. 동일한 패스가 이전에 설명 텍스트에 묻혀 있던 제조업체 부품 번호를 복구합니다. 제 카탈로그 중 하나에서 이는 183,000개의 제품이 상자에 인쇄된 번호로 찾을 수 있게 됨을 의미합니다. 이것만으로도 배치 작업 비용을 충당합니다.</p><pre><code>당신은 검색을 위해 B2B 유통업체 제품 레코드를 강화합니다. 각 입력 레코드(원시 ERP 이름, 설명, 브랜드, 부품 번호, 카테고리)에 대해 JSON을 생성하십시오:\n\n- display_title: 고객이 읽을 수 있는, &lt;=80자, Title Case. 업계 약어를 확장하십시오(CXC -&gt; copper x copper connection, ELL -&gt; elbow, CPLG -&gt; coupling, RED -&gt; reducing). 모든 부품 번호, 모델 코드, 치수를 입력된 그대로 VERBATIM으로 유지하십시오. 코드를 단어로 철자하지 마십시오.\n- search_expansions: 고객이 입력할 수 있는 2-5개 구문으로, 원시 텍스트에는 나타나지 않음(일반 영어 제품 유형, 일반적인 업계 이름). 소스에 없는 사양을 절대 발명하지 마십시오.\n- attributes: {name: {value, unit}} 소스 텍스트에서만 추출.\n- extracted_mpn: 설명 텍스트에 있고(보통 브랜드 뒤의 토큰) PN 필드에는 없는 경우 제조업체 부품 번호, 그렇지 않으면 null.\n- confidence: high | low. 추측해야 할 때마다 low를 사용하십시오. low 답변은 검토로 라우팅되는 것이 확신에 찬 환각보다 낫습니다.\n</code></pre><p>두 가지 프로덕션 참고 사항: 공유 지침을 캐시된 프롬프트 접두사에 넣으십시오(캐싱은 배치 할인 위에 입력 측을 최대 90%까지 줄입니다). 그리고 JSON 스키마와 함께 구조화된 출력을 사용하여 구문 분석 실패 비용을 지불하지 않도록 하십시오.</p><p><strong>마지막 계층은 사람들이 건너뛰는 것이며, 복리 효과가 있는 것입니다.</strong> 감사는 한 번의 정리 작업 가치가 있습니다. 감사가 생성하는 검증기는 모든 미래 피드의 가치가 있습니다. 수정 세션을 다음으로 끝내십시오:</p><pre><code>방금 수정한 모든 문제를 수집 파이프라인을 실패시키는 자동화된 검사로 전환하십시오: 파생 필드 커버리지 어설션, 센티널 블록리스트, 텍스트 필드의 유형 어설션, 식별자 체크섬 검증, PN-변형 충돌 검사, ID 위생 규칙, UNSPSC 커버리지 추적, 카탈로그별 데이터 신선도 알람. 이를 모든 새 피드의 샘플에 대해 CI가 실행하는 테스트로 내보내십시오.\n</code></pre><p>이것을 건너뛰면 동일한 ERP 내보내기가 분기 내에 동일한 쓰레기를 재생성할 것이며, 정리 비용을 두 번 지불하게 될 것입니다. 제 감사에서 발견된 두 가지 버그가 이전에 분명히 수정되었었다가 다시 돌아왔기 때문에 알고 있습니다.</p><h2>프롬프트 실행</h2><p>한 가지 설정 단계: 카탈로그를 JSONL로 덤프하십시오. 각 줄에 하나의 JSON 객체이며, 고유한 <code>id</code>와 레코드의 필드가 있습니다. 플랫폼이 무엇이든(Elasticsearch, OpenSearch, Solr, Algolia, Typesense, PIM, 그 뒤에 있는 데이터베이스) 에이전트에게 익스포터를 작성하도록 요청하십시오:</p><pre><code>내 카탈로그 [설명: 검색 인덱스 이름 / 데이터베이스 테이블 / PIM 내보내기]의 모든 제품 레코드를 50K 레코드 청크로 ./dump/records-{n}.jsonl에 내보내는 스크립트를 작성하십시오. 각 줄은 하나의 JSON 객체이며, 고유한 &quot;id&quot;와 모든 필드가 있습니다. 그리고 내 필드/스키마 정의(플랫폼에 있는 경우)는 schema.json에 저장하십시오. 내보낸 개수가 소스 개수와 일치하는지 확인하십시오.\n</code></pre><p>Claude Code를 사용하면 해당 디렉토리 세션에 카테고리 프롬프트를 드롭하십시오. 분석 자체를 작성하고 실행하며, 샘플링 변명 없이 전체 패스를 수행하고 레코드 수준의 증거를 가지고 돌아옵니다. &quot;이제 수정하십시오&quot;라고 말하면 동일한 세션이 수집 검증기, 백필 스크립트, 배치 강화 작업을 생성합니다. 카테고리를 병렬 세션 또는 하위 에이전트로 실행하십시오. 그것이 제가 실행한 방식이며, 전체 감사는 약 12분의 벽시계 시간이 걸렸습니다. Codex를 사용하면 <code>codex exec</code>가 동일한 프롬프트를 사용하여 읽기 전용 분석 패스를 처리합니다. 쓰기 측 수정은 검토하는 세션에 보관하십시오.</p><p>어렵게 배운 세 가지 규칙:</p><ol><li>전체 패스와 증거를 요구하십시오. &quot;이 데이터를 분석하십시오&quot;는 샘플링과 분위기를 초대합니다. 정확한 개수와 발견 사항당 5개의 예시 레코드 ID를 요청하면 모든 주장을 확인할 수 있습니다.</li><li>강화 전에 규칙을 적용하십시오. 산문을 추가하기 전에 진실을 수정하십시오. 그렇지 않으면 &quot;승인된 공급업체&quot;로 레이블이 지정된 88%의 레코드에 대해 브랜드를 환각하게 될 것입니다.</li><li>샘플링, 평가, 그 다음 배치. 검증되지 않은 프롬프트에서 775K 레코드 배치를 절대 실행하지 마십시오. 200개 샘플, 점수 매기기 패스, 그 다음 확장하십시오. 평가 하네스는 하나의 에이전트 세션이 소요되며 전체 지출의 위험을 제거합니다.</li></ol><h2>도매업계는 마켓플레이스 수준의 검색을 받을 자격이 있습니다</h2><p>Amazon, DoorDash, Instacart는 자선 활동으로 카탈로그-LLM 작업을 공개하지 않았습니다. 기술이 일반적이고 해자는 실행이기 때문에 공개했습니다. 그리고 그 기술은 제가 생각할 수 있는 거의 다른 어떤 곳보다 도매 유통에 더 잘 이전됩니다. 카탈로그는 전체 패스가 저렴할 정도로 충분히 작고, 데이터는 개선 여지가 엄청날 정도로 충분히 나쁘며, 쿼리는 실제 돈을 수반하고, 조달 세계는 이미 배치 작업이 약 $130에 채울 수 있는 분류 체계에서 실행됩니다.</p><p>4개의 유통업체 카탈로그에서 제 감사가 표면화한 수십 가지 문제 중 순위 레이어에서 볼 수 있었던 것은 하나도 없었습니다. 모두가 그것을 저하시켰습니다. 해당 인덱스에 공급하는 공급망(ERP 내보내기, 공급업체 스프레드시트, 오래된 CSV 파서)은 정확히 게시된 플레이북이 수정하는 것입니다. 이를 실행하는 유통업체는 경쟁업체가 여전히 콘덴서 코일을 찾을 수 없는 카탈로그에서 마켓플레이스 수준의 검색을 갖게 될 것입니다.</p><p>&quot;내 데이터에 문제가 있습니까?&quot;라는 질문은 한때 누군가의 2주 시간이 들었고, 그것이 아무도 묻지 않은 이유입니다. 이제는 하나의 프롬프트가 듭니다. 물어보십시오.</p>",
  "source_hash": "sha256:beacaae673c45f36f13a5677632c8df46a2339c6bdea51c65c49f762d7f0805c",
  "model": "deepseek/deepseek-v4-flash",
  "generated_at": "2026-08-07T08:11:52.448634+00:00"
}