设备型号页 GEO 踩坑:ProductModel 与 isVariantOf 缺位让 AI 总引用错型号
先说一个真实的尴尬场面。去年 12 月,一家做工业离心风机的厂商找我帮忙排查怪事:客户在 AI 搜索里问「FJ-315 的电机功率是多少」,十次里有三次,AI 答的是 FJ-400 的 22 kW——而正确答案是 11 kW。他们技术负责人周工把截图发过来的时候,原话是这么说的:「咱们的参数表明明写得清清楚楚,AI 瞎了?」
AI 没瞎,是页面结构让它瞎的。这家厂商把 6 个型号的全部参数塞在一个家族页上,我们抽了 100 条 AI 引用做人工审计,把 A 型号参数安到 B 型号头上的错配率是 31%。用 Schema.org 的 ProductModel 与 isVariantOf/hasVariant 把家族和型号拆开重做,6 周后复测,错配率降到 4%。更麻烦的是这事儿不止影响观感——他们销售那阵子接到好几起询盘,客户张口就问「FJ-315 能不能配 22 千瓦电机」,销售一度以为市场突然多了非标需求。这篇文章把整个踩坑和改造过程拆开讲,做生成式引擎优化(Generative Engine Optimization, GEO)的朋友大概率能对上号。
参数全堆一页,AI 就在页内抓阄
还原一下他们原来的页面。URL 是 /products/fj-series,一页纵向排开 6 个型号,从 FJ-200 到 FJ-450,每个型号一段参数表,页面 H1 写的是「FJ 系列工业离心风机」。做传统 SEO 的同事当时挺满意:一个页面权重集中,收录快,长尾词覆盖广。

这套逻辑在传统搜索里确实成立。但生成式引擎的工作方式不一样,它不是把整个页面甩给用户,而是把页面拆成实体和论断,检索的时候按问题挑最相关的片段。问题就出在这:6 个型号的参数在同一个 URL 里,模型做实体切分时只能把它们当成一个实体候选。用户问 FJ-315,向量检索召回的是「FJ 系列」这一大块内容,参数行里又没有型号锚点——表格里就写着「风量 31500 m³/h」,前头连型号名都没带——模型凭什么知道这行参数属于谁?它只能靠语义近邻去猜,猜错了,就是你看到的那个 31%。
周工后来复盘时自己也认账:「当年为了省页面数,把型号页合并了,等于亲手把实体的边界抹掉了。」
错配的机制:实体对齐缺了一条边
把这件事抽象一下,AI 搜索引用一个设备参数要过三道关:爬取、实体对齐、检索引用。
爬取不用多说,页面能抓就行。真正的关键环节是实体对齐——引擎把页面内容映射到知识图谱的节点上,节点之间靠关系边连接。「FJ-315」应该是一个节点,「FJ 系列」是另一个节点,两个节点之间需要一条明确的变体关系边。纯 HTML 页面里,这条边只能靠模型自己的阅读理解去补;结构化数据里,这条边就是 isVariantOf / hasVariant 声明。改造前后的实体图,大致是下面这个对比:
graph TD
subgraph BEFORE[改造前:六个型号挤成一个实体]
A[家族页一个 URL] --> B[一个实体节点]
B --> C[六套参数混在一个属性池]
Q[提问:FJ-315 电机功率] --> C
C --> W[向量近邻去猜:答成 FJ-400]
end
subgraph AFTER[改造后:家族与型号各有节点]
D[家族页 ProductModel] -- hasVariant --> E[型号页 FJ-315]
E -- isVariantOf --> D
Q2[提问:FJ-315 电机功率] --> E
E --> R[命中正确参数 11 kW]
end
缺了这条边,错误有两种形态。一种是张冠李戴,A 型号的参数被安到 B 型号头上,他们撞上的主要是这种。另一种更隐蔽,叫家族级属性下渗——「FJ 系列标配变频控制柜」这句话,AI 可能把家族级描述安到每个型号头上,万一某个型号恰恰走的是基础配电方案,就是售前事故。他们的审计里真抓到过一条:AI 回答说 FJ-200 也标配变频柜,实际不是。这种错配客户不会怀疑 AI,只会怀疑你产品页写得乱。
拆页方案:ProductModel 当家族,Product 当型号
Schema.org 里这对类型就是为这个场景准备的。ProductModel 表示产品家族或母型号,具体变体用 Product 表示,两个方向各有一条关系属性:家族页用 hasVariant 列子型号,型号页用 isVariantOf 回指家族。做 GEO 改造的第一步不是写代码,是先把 URL 规划好——家族页保持原地址 /products/fj-series 不动,6 个型号各开一个独立页,地址就用 /products/fj-315 这种 slug,短、稳、不带查询参数。
先看家族页落地的 JSON-LD:
// 家族页 /products/fj-series 的 JSON-LD,整段放该页 <head> 里
{
"@context": "https://schema.org",
// @id 用家族页规范 URL,全站固定不变,别拿 ERP 物料编码凑数
"@id": "https://www.example-fan.com/products/fj-series",
// 类型用 ProductModel:表示产品家族,不是某个可购买的型号
"@type": "ProductModel",
"name": "FJ 系列工业离心风机",
// hasVariant 列全部子型号,只写 @id 指针,参数一律不在这里展开
"hasVariant": [
// 每条指针的 URL 必须就是该型号页的规范地址
{ "@id": "https://www.example-fan.com/products/fj-200" },
{ "@id": "https://www.example-fan.com/products/fj-250" },
// 六条指针一条不能少,漏一条就是悬空引用,下文有坑
{ "@id": "https://www.example-fan.com/products/fj-315" },
{ "@id": "https://www.example-fan.com/products/fj-355" },
{ "@id": "https://www.example-fan.com/products/fj-400" },
{ "@id": "https://www.example-fan.com/products/fj-450" }
],
// 家族级只放共性信息:品牌、产品大类
"brand": { "@type": "Brand", "name": "FJ" },
// 风量、功率这类差异化参数,塞进家族页就是埋雷
"category": "工业离心风机"
}
再看型号页,以 FJ-315 为例:
// 型号页 /products/fj-315 的 JSON-LD,六个型号页各放一份
{
"@context": "https://schema.org",
// 型号页自身 @id,必须和家族页 hasVariant 里那条指针一字不差
"@id": "https://www.example-fan.com/products/fj-315",
// 具体型号用 Product 类型:可购买、有条码、有参数
"@type": "Product",
"name": "FJ-315 离心风机",
// isVariantOf 回指家族页,这条边就是实体对齐的关键
"isVariantOf": {
"@id": "https://www.example-fan.com/products/fj-series",
// 引用里带上 ProductModel 类型声明,引擎才能把两端类型对上
"@type": "ProductModel"
},
// GTIN 挂在型号这一层,家族级不挂条码
"gtin13": "06912345678901",
// sku 同样只在型号级出现
"sku": "FJ-315-STD",
// 差异化参数只写在型号页,家族页不再重复维护
"additionalProperty": [
// 每条参数建议补 unitText,引擎解析数值更稳
{ "@type": "PropertyValue", "name": "风量", "value": "31500", "unitText": "m3/h" },
{ "@type": "PropertyValue", "name": "全压", "value": "1800", "unitText": "Pa" },
{ "@type": "PropertyValue", "name": "电机功率", "value": "11", "unitText": "kW" }
]
}
@id 的纪律就一条
@id 必须用对外可访问的规范 URL,全站固定不变。他们第一版里有人提议拿 ERP 物料编码当 @id,被周工否了——AI 引擎抓取时没法把一个内部编码解析回页面,这条边等于断的。用 URL 当 @id 还有个附带好处:JSON-LD 里的引用和 指向同一地址,两套信号互相印证,引擎对实体边界的判断会更有把握。
GTIN 挂在哪一层
GTIN 是给具体商品实体的编码,家族不是商品,不挂。他们 6 个型号各有独立的 13 位 GTIN,全部下放到型号页的 Product 节点上。哪类信息放哪一层,整理成一张决策表:
| 信息 | 挂载层级 | 理由 |
|---|---|---|
| GTIN-13 / SKU | 型号页 Product | 条码对应可购买的具体商品,家族没有条码 |
| 风量 / 全压 / 电机功率 | 型号页 Product | 型号差异全在这,也是错配重灾区 |
| 品牌名 / 产品大类 / 认证 | 家族页 ProductModel | 家族级共性信息,六处重复维护必出不一致 |
| 共性描述(如标配变频柜) | 家族页总述 + 型号页覆写 | 型号页按实际情况写明有无,防止属性下渗 |
家族页和型号页要双向引用
结构化数据之外,HTML 本身也要配合:家族页正文给 6 个型号页各留一个带型号名的链接;型号页面包屑里放家族页链接。有同事问过只写 JSON-LD 行不行,周工的答复是别赌——结构化数据是给机器声明的边,HTML 链接是给爬虫的通路,两条都留着,成本不高,收益是叠加的。
六周改造与验证记录
改造本身不重,重的是节奏。他们的时间线是这样:第一周做家族页加 FJ-315 一个型号打样;第二周铺完剩余 5 个型号;第三周起每周固定抽 50 条 AI 引用做人工标注,标注口径很朴素——回答里的参数是否属于被问的那个型号。
两个验证工具每一轮都跑:
| 工具 | 用途 | 他们的使用姿势 |
|---|---|---|
| Schema.org Validator(validator.schema.org) | 校验 JSON-LD 语法与类型关系 | 本地改完先跑它,isVariantOf 指向写错会直接报 |
| Google Rich Results Test | 校验 Google 可识别的富结果类型 | 每页上线前跑一遍,确认 Product 结构能被解析 |
中间有个小坑值得记一笔:validator 一度报「hasVariant 引用的 @id 无法解析」,原因是打样周只上线了 FJ-315,家族页却把 6 条指针全列上了,另外 5 个 URL 还是 404。机器爬到悬空引用,关系边照样算断。所以上线顺序要反过来:先把 6 个型号页全部发上去,等全部可访问,最后发家族页。
六周复测数据放在这里,前后抽样口径一致,都是每周 50 条人工标注:
| 指标 | 改造前 | 改造后(第 6 周) |
|---|---|---|
| 型号参数错配率 | 31% | 4% |
| AI 回答中型号页 URL 出现率 | 0(只有家族页) | 68% |
| 家族页节点与型号节点正确建边 | 无法区分 | 91% |
| 平均每条回答引用的准确参数条数 | 2.1 | 3.4 |
整个验证流程画出来是这样,环形的,因为错配样本会反哺下一轮修改:
flowchart LR
A[修改 JSON-LD] --> B[Validator 本地校验]
B --> C[Rich Results Test 上线前校验]
C --> D[先发六个型号页,最后发家族页]
D --> E[每周抽 50 条 AI 引用]
E --> F{参数属于被问型号吗}
F -- 属于 --> G[计入正确样本]
F -- 不属于 --> H[记录错配形态并反查声明]
H --> A
错配率没有降到 0,剩下那 4% 基本是引擎缓存了旧页面快照,等快照刷新自己就掉了。这件事说明 GEO 改造不是发完就收工,得留观察期,数据要看趋势不看单周。
误区澄清与趋势预判
两个误区先说清。有人觉得 ProductModel 是电商专属,卖设备的用不上——类型定义里写得很明白,凡是以变体形式供货的产品都适用,工业设备是典型场景。还有人把 isVariantOf 指到型号页自己身上,形成自环,validator 未必报错,但关系边等于没建,AI 照样串参数,这类问题用画图工具把 @id 引用关系画一遍就能看出来。
趋势上,主流 AI 搜索引擎对实体关系的依赖只会加重。设备站内容竞争的重心正在从「关键词覆盖」转向「实体边密度」:型号、家族、配件、耗材之间的关系声明得越完整,内容被准确引用的概率越高。周工团队现在把这条写进了上线流程——JSON-LD 不进模板,页面不许发布。你要是也在做设备站的 GEO,评论区聊聊你撞到的错配形态,看看还有没有第三种。
参考与延伸
- Schema.org ProductModel 类型定义:https://schema.org/ProductModel
- Schema.org 官方结构化数据校验器:https://validator.schema.org/
- Google 搜索中心结构化数据文档:https://developers.google.com/search/docs/appearance/structured-data
GEO、ProductModel、isVariantOf、JSON-LD、实体对齐、制造业获客