{
  "title": "在 AI 时代修复 B2B 商务搜索",
  "excerpt": "我审计了为四家 B2B 分销商提供搜索支持的 775,000 条产品记录。消费巨头已经公开发布了如何用 LLM 修复这类目录的方法，但贸易分销行业尚未拿起这本操作手册。这就是为暖通空调（HVAC）、管道和电气行业量身定制的版本，并附上了真实成本。",
  "content_html": "<p>B2B 商务搜索有一个不为人知的秘密：排名算法很少是问题的根源。</p>\n<p>当搜索结果不佳时，团队总会去拨弄那些有趣的杠杆：加权提升、同义词、嵌入向量、重排序器，以及最近的 LLM 查询理解。我自己也拨过所有这些杠杆。但上周我做了一件不那么光鲜的事：我把四个生产环境搜索索引中的每一条产品记录都导了出来——来自暖通空调（HVAC）、管道、工业用品和紧固件领域的四家 B2B 分销商，共计 775,051 条记录——并审计了数据本身。我并行运行了十二个 AI 智能体，每个负责一个维度：覆盖率、文本质量、零件编号、品牌、价格、规格、类目、媒体资源、重复项。</p>\n<p>返回的结果对任何做过分销商目录的人来说都平淡无奇，但对没做过的人来说则令人震惊。然而让我印象深刻的是这一点：解决方案早已公开。Amazon、DoorDash 和 Instacart 花了两年时间，在公开的工程博客中详细撰写了他们如何利用 LLM 大规模清洗、标注和丰富杂乱的商品目录。贸易分销行业却大多没有注意到。这很奇怪，因为他们的目录更乱，他们的查询价值更高（承包商订购的是价值 4,000 美元的冷凝器，而不是 12 美元的午餐），而且他们的目录规模实际上让经济性变得更简单。</p>\n<p>所以这篇文章就是那本操作手册，为贸易分销行业量身定制：破坏 B2B 搜索的数据问题、如何今天下午就用编程智能体发现它们、如何用 LLM 修复它们（包括 UNSPSC 分类），以及整套方案的成本。最后一点先剧透：比你猜的便宜两个数量级。</p>\n<h2>操作手册早已存在，只是不在我们行业</h2>\n<p>这些平台公司已经公开发布的部分内容包括：</p>\n<ul>\n<li>DoorDash 使用基于检索增强生成（RAG）的 LLM 来<a href=\"https://careersatdoordash.com/blog/how-doordash-leverages-llms-for-better-search-retrieval/\">构建其产品知识图谱并改进搜索检索</a>：在数百万商家提供的商品中自动提取品牌、提取属性并进行实体链接。</li>\n<li>Amazon 构建了 <a href=\"https://www.amazon.science/blog/building-commonsense-knowledge-graphs-to-aid-product-recommendation\">COSMO</a>，一个由 LLM 生成的知识图谱，将客户的真实意图（\"孕妇鞋\"）与产品本身（\"防滑鞋\"）连接起来。他们报告称，在离线测试中推荐性能提升了高达 60%。</li>\n<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>\n</ul>\n<p>共同的线索很容易被忽略：LLM 的胜利发生在目录侧，而且是离线的。这些公司在第一条查询到来之前就丰富了数据。发现系统分为离线侧——构建产物（目录、索引、嵌入向量）——和在线侧——基于这些产物进行检索和排序，而几乎所有公开发布的 LLM 价值都落在离线侧。排名层只能做到和其输入数据一样好。</p>\n<p>现在，把一本典型的暖通空调或管道分销商的目录放在旁边对比。它是由 ERP 导出数据、供应商电子表格、采购联盟数据流，以及某人十年前写的一个 CSV 解析器拼凑而成的。产品的\"标题\"是为仓库拣货员写的发票简写。而打在它上面的搜索流量几乎是意图密度最高的：一半是完全匹配的零件编号，其余是行业黑话，比如 \"3/4 cxc 90 ell\"。说实话，我想不出比这更适合这本操作手册的环境了。查询很有价值，数据是可修复的，而且对于几十万 SKU 的规模，用 LLM 完整跑一遍目录只需几百美元。不是几百万。是几百。</p>\n<p>以下是审计的架构，因为你会想要复现它：</p>\n<pre><code class=\"language-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>在进入提示词之前，先说明一下格式。下面所有内容都适用于一种通用的数据导出格式：每行一个 JSON 对象，每个对象包含唯一的 <code>id</code> 和该记录的字段。Elasticsearch、OpenSearch、Solr、Algolia、Typesense、PIM、普通的数据库导出——都不重要。每个平台都能产出这种格式，而这里的每个提示词都是针对它运行的。</p>\n<h2>类别 1：静默的流水线故障</h2>\n<p>我发现的最糟糕的问题不是任何人写错的数据，而是流水线在导入过程中悄无声息地破坏掉的数据。</p>\n<p>这些目录在导入时构建其主要搜索文本，使用脚本化的正则表达式从产品标题中提取尺寸和单位。遇到长标题时，正则表达式超出了引擎的复杂度上限，处理器失败，但记录仍然被索引——带有一个没人看的错误字段，而且完全没有主搜索字段。</p>\n<img src=\"/assets/images/b2b-search-silent-failures.png\" alt=\"按分销商统计的、没有主搜索字段的已索引文档\" />\n<p>在整个集群中，有 52,570 条记录躺在索引里，但对主查询路径不可见。在最糟糕的目录中，这相当于每七个产品中就有一个。没有仪表盘捕捉到它，因为没有发生任何失败。流水线每天、每月都返回成功。</p>\n<p>同一类别的另外两个发现。陈旧的镜像：一个字段保存真相（按账户的权限映射），第二个扁平化字段为其建立镜像用于过滤。在一个目录中，镜像在 19.85% 的记录上发生了漂移——31,000 个活跃产品被错误地从按账户过滤的搜索中隐藏了。以及冻结的目录：一个索引已经十周没有刷新，而其同级索引每天都在更新。运行时间受到了监控。新鲜度没有。</p>\n<p>修复方案很无聊，而这正是重点。对派生字段的覆盖率设置告警（派生字段为空而其源字段不为空）。不要维护同一事实的两种表示；在写入时派生可过滤的字段。像监控运行时间一样监控每个目录的数据新鲜度。</p>\n<p>以下是在你自己的目录中发现所有这些问题的提示词（使用 Claude Code 或 <code>codex exec</code>；操作方式见文末）：</p>\n<pre><code class=\"language-text\">以下是我的产品目录导出文件，以 JSONL 格式存放在 ./dump/ 中——每行一条 JSON 记录，每条记录包含唯一的 \"id\" 和产品字段。我的字段/模式定义（如有）在 schema.json 中。\n\n编写流式 Python（不要全部加载到内存中）来发现静默的流水线故障：\n1. 带有流水线标记的任何 error/exception 字段的记录。\n2. 对于每个派生字段（拼接字段、*_search、*_normalized 等变体）：派生字段为空但其明显源字段不为空的记录。\n3. 看起来互为镜像的字段对（一个嵌套/丰富，一个扁平/可过滤）：量化它们不一致的频率。\n4. updated/indexed 时间戳的分布：目录的某个切片是否在其余部分刷新时处于冻结状态？\n\n报告每个发现的数量、占目录百分比、5 个示例 id，以及受影响的记录是否为活跃/可见。按严重程度排序。\n</code></pre>\n<h2>类别 2：占位符与哨兵值，或者说：撒谎的数据</h2>\n<p>空值检查是每个人都已有的数据质量工具。占位符打败了它们，因为占位符是有值的。只是这个值不是真的。</p>\n<p>我最喜欢的例子：在一个 31.3 万 SKU 的目录中，品牌字段有 741 个不同的值，填充率高达 99.99%。听起来很健康。但排在第一位的值覆盖了所有记录的 88.8%，它是 \"Approved Vendor\"。一个 ERP 占位符。最受欢迎的真实品牌只覆盖了目录的 0.3%。因此，对于十分之九的目录来说，每个品牌分面、品牌加权提升和品牌感知重写实际上都失效了，而分面 UI 却兴高采烈地把 \"Approved Vendor\" 作为第一大品牌筛选项。</p>\n<p>一旦你开始留意，这类问题无处不在：</p>\n<ul>\n<li>一个目录中 55% 的记录使用了 <code>99999999.000000</code> 作为\"无价格\"哨兵值。该索引的价格中位数是九千九百九十九万美元。</li>\n<li>64 条记录的产品名称字面量就是 <code>\"unknown\"</code>，然后它们就会在搜索 \"unknown\" 时获得排名。</li>\n<li>在 1,516 个活跃产品的文本描述字段中写入了布尔值 <code>true</code>。引擎将其强制转换为字符串 \"true\"，这使得搜索 \"true\" 就能找到这些产品。</li>\n<li>227 个 UPC 以 <code>\"6.71E+11\"</code> 的形式存储——Excel 的科学计数法，51 个互不相关的产品共享这一个\"标识符\"——另外还有 15,121 个 UPC 丢失了前导零。Excel 再次发威。</li>\n<li>一个紧固件目录的品牌字段里放的是产品线名称（\"C6L Lockbolts\"、\"Tool Parts\"），而真正的品牌就在旁边一个字段里。</li>\n</ul>\n<p>我从这个类别中学到的教训是：审计每个字段的 Top-N 值分布，而不是空值率。一个填充率 100% 的字段可能有 88% 是垃圾，而空值检查永远发现不了。然后在导入时将哨兵值列入黑名单，用显式的 <code>has_price</code> / <code>has_real_image</code> 标志将它们映射为真正的空值，在边界处进行类型断言，并对标识符进行结构性验证。把任何曾经经过电子表格的东西都视为可疑对象。</p>\n<pre><code class=\"language-text\">同样的 JSONL 导出数据。对我目录中的每个字段，计算 Top-20 值分布（完整遍历，流式处理）。\n\n标记：(a) 任何覆盖超过 10% 记录的单一值——占位符/哨兵值候选，如 \"Approved Vendor\"、\"unknown\"、99999999、0.0；(b) 类型与字段主导类型不一致的值（文本字段中的布尔值、字符串中的浮点数）；(c) 标识符字段（UPC/EAN/GTIN/零件编号）：验证校验和与长度，标记科学计数法、被剥离的前导零、嵌入的空白/Unicode，以及被多条记录共享的标识符；(d) 坐在品牌字段里的类目或产品线值。\n\n对每个标记：数量、占目录百分比、5 个带 id 的原文示例，以及一条本可以拒绝它的导入规则建议。\n</code></pre>\n<h2>类别 3：贫瘠的内容</h2>\n<p>分销商的目录是由 ERP 写的，而不是商品经理。文本是发票简写：<code>PROPRESS 2-1/2X1 CXC RED CPLG</code>、<code>HC HX 18X8 W</code>。在一个目录中，三分之一的产品名称包含的词典词汇不到 60%。在另一个目录中，原始名称和描述字段 100% 为空——文本只存在于派生的搜索 blob 中，因此所有读取原始字段的东西（结果标题、嵌入输入、相关性判断提示词）读到的都是空，而没人知道。</p>\n<img src=\"/assets/images/b2b-search-field-coverage.png\" alt=\"四个生产环境 B2B 索引的字段覆盖率\" />\n<p>那张热力图是我这次审计中最喜欢的产物。这些字段中的每一个都存在于每个模式中。数字表示每个字段实际持有数据的比例。最让我震惊的是 ML-descriptions 那一行：模式承诺在每条记录上都存在的丰富层，在 775,051 条记录中只有 18 条被填充。18 条。评分流水线中每个\"如果存在丰富数据则使用\"的分支都是一个静默的无操作。模式是一种愿景；只有覆盖率才是事实。</p>\n<p>这个类别是已公开发布的操作手册最直接适用的领域——DoorDash 的属性提取、Instacart 的离线生成——而下面的成本部分会给出具体价格。但在一个以零件编号为生的行业里，有四条规则很重要，部分是从之前丰富化尝试的错误中学到的：</p>\n<ul>\n<li>扩展，不要替换。在原始发票字符串旁边生成客户可读的标题，并将两者都索引。柜台技师的查询和房主的查询都应该能命中。</li>\n<li>永远不要把代码读成单词。那 18 条先驱记录？生成器把型号编号拼成了单词：\"RGF one hundred eighty\"。没有承包商真的会这么输入。代码保持原文；扩展是补充，不是替换。</li>\n<li>顺手提取结构。同一次重写标题的过程可以输出 <code>{size, material, connection_type}</code> 用于分面。</li>\n<li>行业黑话是同义词问题，不是重写问题。<code>CXC</code>、<code>ELL</code>、<code>CPLG</code>、\"t-stat\" 属于分析器级别的同义词扩展，一次性修复即可。不要花钱把它们重写到五十万条记录里。</li>\n</ul>\n<pre><code class=\"language-text\">同样的导出数据。用完整的流式遍历评估面向客户的字段（名称、短/长描述）的文本质量：\n\n1. 有效标题覆盖率：拥有非空展示名称的 ACTIVE 记录百分比。\n2. 可读性：全大写名称的百分比；词典词汇 token 低于 60% 的百分比（缩写沙拉）；少于 10 个字符的名称；纯数字描述。\n3. 垃圾内容：HTML/CMS 标记、编码伪影、嵌入的操作备注（*** NOT A PHYSICAL ITEM ***）、CSV 列溢出。\n4. 重复：完全相同的短/长描述；被 20 个以上 SKU 共享的样板文本；精确长度聚类（254/255/500 字符），暗示上游 VARCHAR 上限。\n5. 丰富化现实检查：对于模式承诺的每个 ML/enriched/embedding 字段，其实际覆盖率。\n\n数字、每项 5 个原文示例、严重程度，以及哪些问题需要 LLM 丰富化、哪些需要流水线修复、哪些需要同义词层修复。\n</code></pre>\n<h2>类别 4：零件编号是神圣的</h2>\n<p>B2B 搜索流量中有一半是有人在输入零件编号。精确匹配是这里的全部关键，而它在悄无声息中失效。</p>\n<p>在一个目录中，99.99% 的记录所索引的零件编号是内部数字 SKU。制造商的编号——印在盒子上的那个——只存在于自由文本描述中。183,000 个产品无法通过客户实际会输入的编号找到。</p>\n<p>另一个目录有一个变体扩展系统：去掉连字符，折叠段落，索引变体以便实现容错零件编号搜索。好主意。但生成器是组合式的（每个产品最多 80 个变体），在 11,826 条记录中，一个产品的生成变体恰好等于另一个产品的规范零件编号。紧固件是最残酷的情况，因为标点符号编码了物理尺寸：<code>702-1-5/32</code> 是 1-5/32 英寸的零件，而 <code>702-15/32</code> 是 15/32 英寸的零件，两者都归一化为 <code>7021532</code>。客户输入一个精确的零件编号，却在正确零件和其尺寸近亲之间得到抛硬币般的结果。</p>\n<p>同样属于这一类：竞争对手交叉引用（\"我有 Ferguson 的编号，你们的是多少？\"）以未拆分的管道符分隔 blob 形式存储，如 <code>19MU82|Fastenal 0269214|Ferguson M48222407</code>，而字段被配置为不可搜索，因此一项核心的 B2B 销售行为根本无法运作。还有空白分叉——同一个零件编号被索引了三次（纯文本、NBSP 填充、尾部空格）——以及来自双重解码 UTF-8 的乱码双胞胎。</p>\n<p>修复大部分问题的原则是：精确匹配必须在结构上击败模糊匹配，而不是靠概率。一个保留标点的精确子句的得分必须严格高于任何归一化层级，绝不能采用变体可以与规范命中打平的扁平匹配。在索引前对照规范零件编号空间检查生成变体并丢弃冲突。在派生记录 ID 之前进行 Unicode 规范化。将交叉引用 blob 拆分为数组；这只是一行导入代码，却能解锁一整类查询。</p>\n<pre><code class=\"language-text\">同样的导出数据。我的用户按零件编号搜索；审计精确匹配的完整性：\n\n1. 存在哪些 PN 类字段（part_number、mpn、替代/竞争对手/客户 PN、UPC），它们的覆盖率，以及哪些字段持有真实数据却被配置为不可搜索。\n2. 唯一可搜索的 PN token 是内部 SKU 的记录（真实的制造商 PN 只出现在描述文本中——展示模式）。\n3. 如果存在 PN 变体/关键词扩展字段：找出每个等于另一条记录的规范 PN 的生成变体（归一化：小写、去除标点）。展示冲突对——尤其是带有分数的紧固件尺寸。\n4. 仅通过空白/不可见字符/大小写与另一条记录的 PN 不同的 PN（重复的身份分叉）。\n5. 以分隔 blob 而非数组形式存储的多值交叉引用字段。\n\n数量、示例，以及每个问题的修复方案：导入规则或查询构建器的更改。\n</code></pre>\n<p>还有一些不太适合上面分类但值得一提的事：一个同义词生成器把任何数字都变成了线规术语，于是 <code>REF#259286</code> 变成了 \"259286 awg\"，而 <code>#8-32</code> 的螺纹变成了 \"8 gauge wire\"（数千条记录现在会匹配到与它们毫无关系的电气查询）；一个电商平台的内部标志被索引为可搜索的产品规格，产生了 210 万对垃圾键值；以及 18 个模式字段在任何记录上的填充数都为零。扩展生成器需要上下文闸门。死模式是某人最终会在其上构建的虚假承诺。</p>\n<h2>缺失的层：UNSPSC，以及不知道自己是什么的产品</h2>\n<p>有第五个值得单独成节的问题，因为正是在这方面，贸易分销落后平台最远：分类。</p>\n<p>在我的审计中，一个目录有 83% 的记录缺失类目字段。属性键完全没有分类体系——在一个 15.6 万条记录的目录上有 7,068 个不同的规格键，其中 64% 使用在不到十个产品上，存在像 <code>horse_power</code> 与 <code>horsepower</code> 这样的漂移，把同一个属性拆到了不同的分面上。而我反复想到的一个细节是：四个目录中有两个的 UNSPSC 字段就躺在它们的模式里，映射好了，准备就绪，填充数却恰好为零。有人知道分类很重要，建好了槽位，却从未填充它。我敢打赌原因是什么：手动将 30 万 SKU 分类到分类体系中需要目录团队一年的工作量，所以它永远留在了路线图上。</p>\n<p>如果你不在 B2B 领域，UNSPSC 是联合国标准产品与服务代码，是采购系统使用的分类体系。这是消费级搜索所没有的部分：你客户的采购系统需要它。Punchout 目录、电子采购平台和支出分析工具都是围绕 UNSPSC 代码构建的。一个目录带有干净代码的分销商可以接入承包商或医院的采购系统。一个没有代码的分销商只是一个带搜索框的 PDF 价目表。在内部，它也是类目分面、类目限定排名（\"解析为线规的数字应该只提升电线\"）、跨目录去重，以及类别 4 中每个扩展生成器的上下文闸门的动力来源。</p>\n<p>而现在它只是一个批处理作业。这与 DoorDash 描述用 LLM 解决的问题形状相同——针对受控词汇表的高容量标注——而且方法可以直接迁移：</p>\n<ul>\n<li>分层分类，不要扁平分类。UNSPSC 有四个层级（segment、family、class、commodity）。让模型从约 450 个选项中挑选 family，然后在该 family 中挑选 class。两个小的受限选择胜过一个五万选一的抉择，而且你可以像 DoorDash 将其实体链接约束到自己的词汇表一样，将相关的分类体系切片输入上下文。</li>\n<li>先停在 class 层级。Class 代码已经能解锁分面和采购集成；commodity 级别的精度可以在它物有所值的地方后续补充。</li>\n<li>按置信度路由。小模型处理明确的案例，低置信度记录升级到大模型，持续存在分歧的进入人工队列，同时作为你的评估集。</li>\n</ul>\n<p>成本几乎让我不好意思打出来。分类是一个短输出任务：每条记录大约 300 个输入 token，30 个输出 token。使用 Claude Haiku 4.5 的 Batch API 定价，每千个 SKU 大约 17 美分。我整个 77.5 万条记录的集群分类下来大约 130 美元。那个因为需要一年手工工作而在路线图上搁置多年的东西，成本比你们讨论它的团队午餐还低。</p>\n<pre><code class=\"language-text\">你将 B2B 分销商产品分类到 UNSPSC。附件：UNSPSC family 列表（level 2，约 450 条）作为参考数据。\n\n对于每条产品记录（标题、描述、品牌、零件编号、任何现有类目文本），输出 JSON：\n- unspsc_family：4 位 family 代码——只能从附件列表中选择\n- family_confidence：high | low\n- rationale：一个短句（例如 \"copper press fitting -> pipe fittings\"）\n\n规则：根据产品的功能判断，而不是品牌。行业简写：CXC/FPT/MPT 是管道连接，ELL 是 elbow，CPLG 是 coupling，裸分数+材料通常是管件尺寸。如果记录不是实体产品（运费项、附加费、\"*** NOT A PHYSICAL ITEM ***\"），输出 NOT_A_PRODUCT。大胆使用 low 置信度——低置信度记录会用 class 级别列表进行第二次遍历。\n</code></pre>\n<h2>清理操作手册，附真实账单</h2>\n<p>修复流水线有三个层级，外加分类作业。诀窍是在正确的层级花钱，因为你几乎永远不需要为每条记录都调用一次 LLM。</p>\n<pre><code class=\"language-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>第 0 层是确定性代码，基本上免费。</strong>剥离 HTML 并解码实体。用显式标志将哨兵值转为真正的空值。修复 UPC（左填充、拒绝科学计数法、验证校验位）。对 ID 进行 Unicode 规范化。拆分管道符分隔的交叉引用。丢弃与另一产品规范编号冲突的 PN 变体。删除死模式。一个智能体在一轮会话中就能写出这些脚本，而这一层修复了我审计中发现的大约一半问题。在任何丰富化之前先做这一步，否则你会花钱请模型为你那些已被流水线静默丢弃的产品 beautifully 重写标题。</p>\n<p><strong>第 1 层让 LLM 运行在唯一值上，而不是记录上。</strong>这是让词汇问题变得便宜的诀窍：我最糟糕的目录有 31.3 万条记录，但只有 741 个不同的品牌字符串。品牌规范化是对 741 个字符串的一次作业——聚类大小写变体、将子品牌映射到母品牌、标记占位符——而不是 31.3 万次调用。规格键和单位后缀也用同样的方法。每个词汇作业只需个位数美元，其输出是一张静态别名表，你的导入流程可以永远确定性地应用它。整个层级在一批目录上花费 20 到 50 美元，大部分花在复核上。</p>\n<pre><code class=\"language-text\">附件：我的品牌和制造商字段的完整去重值分布（value, record_count）。生成一张规范化表：\n\ncanonical_brand, parent_manufacturer, [raw variants], confidence\n\n规则：聚类大小写/标点/空白变体；将子品牌映射到母制造商作为单独一列（不要合并）；将占位符值标记为 NULL_SENTINEL；将错放在品牌字段的产品线或类目标记为 NOT_A_BRAND。标记不确定的聚类，而不是猜测。输出 CSV，然后编写一个在导入时应用它并记录未匹配新值的脚本。\n</code></pre>\n<p><strong>第 2 层是逐条记录的处理</strong>：为每个产品生成客户可读的标题、搜索扩展、结构化属性，以及找回的制造商零件编号。每个 SKU 的处理量很小——大约 400 个输入 token（记录加上共享指令，而提示缓存让这部分几乎免费）和 250 个输出 token。在你甚至还没选定模型之前，有两个杠杆：只丰富活跃项（在我最糟糕的目录中只有 14% 的记录是活跃的，这就直接砍掉了 86%），以及使用供应商提供的 Batch API，因为丰富化没有延迟要求，而且 Anthropic 和 OpenAI 都对批处理提供 50% 的折扣。</p>\n<p>我为 2026 年你可能会用到的所有模型估算了同一项工作的价格——Claude、<a href=\"https://openai.com/index/advancing-the-price-performance-frontier-with-gpt-5-6/\">GPT-5.6 的三个层级</a>（Sol、Terra、Luna）、Kimi K3、GLM-5.2、Qwen3.5，以及 <a href=\"https://deepseek.ai/pricing\">DeepSeek V4</a>。相同的工作量，供应商公布的费率，在适用处应用批处理折扣：</p>\n<img src=\"/assets/images/b2b-search-enrichment-cost-by-model.png\" alt=\"各模型丰富化 77.5 万 SKU 的成本\" />\n<p>我不得不反复核对这些数字，因为它们感觉不对。这个项目的最坏情况版本——前沿模型、每个 SKU、完全不做过滤——最高大约 3,800 美元。下限不到一百美元：DeepSeek V4-Flash 丰富化整个集群的成本大约相当于一把不错的电钻。你实际会运行的版本是混合层级：用经济型模型（Haiku、Luna、Qwen Flash、DeepSeek）处理机械化的主体部分，用中端模型（Sonnet、Terra、GLM-5.2）处理小模型标记为低置信度的缩写沙拉长尾，再用前沿模型对 1-2% 的样本进行抽检作为质量闸门。无论选哪家供应商，活跃 SKU 的成本都落在几百美元。</p>\n<p>图表无法显示两点注意事项。便宜的模型只有在它们的输出能通过你的评估时才真的便宜——在全面投入前先做 200 条样本对比，因为一个搞砸了 5% 零件编号的经济型模型，成本比不犯错的前沿模型更高。而且你的目录是竞争性数据：价格、交叉引用和客户零件编号都在这些记录里，所以在把 77.5 万条记录发往列表上最便宜的端点之前，先检查每个供应商的数据保留和训练条款。对很多分销商来说，仅此一项检查就能决定某些供应商是否可用，而开源权重选项（DeepSeek、GLM、Qwen、Kimi）还有一个额外优势：如果数据完全不能离境，你可以自行托管它们。</p>\n<p>加上约 130 美元的 UNSPSC 处理（它在不同模型间的扩展方式相同——在经济型层级上降到零花钱级别）和词汇工作，整个目录改造的运行成本在几百到几千美元之间，而过去这相当于商品团队一年的工作量。这与 Instacart 描述的离线批处理经济学相同，只是在贸易目录的规模上，数字小到可以刷信用卡支付。</p>\n<p>在我审计的一条真实记录上，它看起来是这样的：</p>\n<pre><code class=\"language-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>看看 <code>extracted_mpn</code> 这一行。同一次处理找回了先前埋在描述文本中的制造商零件编号——在我的一个目录中，这意味着 18.3 万个产品可以通过印在盒子上的编号被找到。仅此一项就值回了批处理作业的成本。</p>\n<pre><code class=\"language-text\">你为搜索丰富化 B2B 分销商产品记录。对于每条输入记录（原始 ERP 名称、描述、品牌、零件编号、类目），输出 JSON：\n\n- display_title：客户可读，<=80 字符，首字母大写（Title Case）。扩展行业缩写（CXC -> copper x copper connection，ELL -> elbow，CPLG -> coupling，RED -> reducing）。保持每个零件编号、型号代码和尺寸与输入完全一致——永远不要把代码读成单词。\n- search_expansions：客户可能输入的 2-5 个短语，不出现在原始文本中（纯英文产品类型、常见商品名）。绝不编造来源中不存在的规格。\n- attributes：{name: {value, unit}}，仅从来源文本中提取。\n- extracted_mpn：如果描述文本中存在制造商零件编号（通常在品牌之后的 token）且 PN 字段中不存在，则提取，否则为 null。\n- confidence：high | low。只要你不得不猜测，就用 low；一个被送去复核的低置信度答案，胜过自信满满的幻觉。\n</code></pre>\n<p>两条生产环境注意事项：将共享指令放在缓存的提示前缀中（缓存在批处理折扣之上还能将输入端成本削减高达 90%），并使用带 JSON schema 的结构化输出，这样你就永远不会为解析失败买单。</p>\n<p><strong>最后一层是人们最容易跳过、却最能产生复利的一层。</strong>审计值一次清理。它生成的验证器值每一次未来的数据流。在修复会话结束时执行：</p>\n<pre><code class=\"language-text\">把我们刚刚修复的每个问题都变成一条自动检查，让导入流水线大声失败：派生字段覆盖率断言、哨兵黑名单、文本字段类型断言、标识符校验和验证、PN 变体冲突检查、ID 卫生规则、UNSPSC 覆盖率追踪，以及每个目录的数据新鲜度告警。将它们作为 CI 针对每个新数据流样本运行的测试输出。\n</code></pre>\n<p>跳过这一步，同样的 ERP 导出数据会在一个季度内重新生成同样的垃圾，你会为清理工作付两次钱。我知道这一点，因为我审计发现的两个 bug 显然以前被修复过，然后又回来了。</p>\n<h2>运行这些提示词</h2>\n<p>一个准备步骤：将你的目录导出为 JSONL，每行一个 JSON 对象，包含唯一的 <code>id</code> 和记录的字段。无论你的平台是什么——Elasticsearch、OpenSearch、Solr、Algolia、Typesense、PIM、支撑这一切的数据库——直接让智能体写导出器：</p>\n<pre><code class=\"language-text\">编写一个脚本，将我的目录中的每条产品记录[描述：搜索索引名称 / 数据库表 / PIM 导出]导出到 ./dump/records-{n}.jsonl，每 5 万条记录一个分块——每行一个 JSON 对象，包含唯一的 \"id\" 和所有字段——并将我的字段/模式定义（如果平台有的话）导出到 schema.json。验证导出数量与源数量一致。\n</code></pre>\n<p>使用 Claude Code 时，把任何类别的提示词丢进该目录下的一个会话中。它会自己编写并运行分析，完整遍历，没有采样的借口，并返回记录级别的凭据。当你说\"现在修复它\"时，同一个会话会生成导入验证器、回填脚本和批量丰富化作业。将各个类别作为并行会话或子智能体运行；我就是这样运行我的审计的，整个审计只花了大约十二分钟的挂钟时间。使用 Codex 时，<code>codex exec</code> 可以用同样的提示词处理只读分析遍历；将写入端的修复保留在你审查的会话中。</p>\n<p>三条我通过惨痛教训学到的规则：</p>\n<ol>\n<li>要求完整遍历和凭据。\"分析这些数据\"会招致采样和凭感觉。要求每个发现都有精确数量和五个示例记录 ID，这样每个主张都可核查。</li>\n<li>先规则，后丰富化。先修复真相再添加文本，否则你会为 88% 标记为 \"Approved Vendor\" 的记录幻觉出品牌。</li>\n<li>先采样，再评估，最后批处理。永远不要用一个未验证的提示词直接发射 77.5 万条记录的批处理。200 条样本，一次评分遍历，然后再扩展。评估框架只需一个智能体会话的成本，却能让整个支出去风险化。</li>\n</ol>\n<h2>贸易行业配得上平台级的搜索</h2>\n<p>Amazon、DoorDash 和 Instacart 公开他们的目录-LLM 工作并非出于慈善。他们公开是因为这些技术是通用的，而护城河在于执行。而且这些技术迁移到贸易分销行业的效果比我能想到的几乎任何地方都好：目录小到完整遍历很便宜，数据差到提升空间巨大，查询承载着真金白银，而采购世界运行的分类体系现在只需一个批处理作业、大约 130 美元就能填充。</p>\n<p>在我审计的四家分销商目录中浮现的几十个问题里，没有一个能从排名层看到。但它们都在降级排名层。喂养这些索引的供应链——ERP 导出、供应商电子表格、古老的 CSV 解析器——正是已公开发布的操作手册所修复的东西。运行它的分销商将拥有平台级的搜索，而他们的竞争对手仍然无法在目录中找到一个冷凝器盘管。</p>\n<p>\"我的数据有什么问题吗？\"这个问题过去要花费某人两周的时间，所以没人会问。现在它只需一个提示词。去问吧。</p>",
  "source_hash": "sha256:beacaae673c45f36f13a5677632c8df46a2339c6bdea51c65c49f762d7f0805c",
  "model": "moonshotai/kimi-k2.6",
  "generated_at": "2026-08-07T07:39:59.043593+00:00"
}