含税价还是不含税价:PriceSpecification 家族与 ValueAddedTaxIncluded 的规范写法
8 月中旬排查一个真实的翻车现场:某商城 17 个重点 SKU 里,5 个在三家 AI 搜索入口的回答中出现两套价格——页面展示的是含税到手价 699 元,商品接口快照里却是裸价 618.58 元,AI 把两个数字拼进同一句话;另有 2 个 SKU 因为口径判断不出来,AI 干脆不给价格,只甩一条链接。两套价格差的那 80.42 元,就是 13% 的增值税。问题全部指向同一个被忽略的字段:valueAddedTaxIncluded。
一、现场回放:AI 引擎抓到两个价格之后
复盘日志时看到的路径很典型。AI 爬虫先抓商品详情页的 JSON-LD,拿到 Offer.price = 699.00,这一层没有声明是否含税;接着它又从另一个入口(合作方比价源)拿到 618.58 这个裸价,同样没有口径声明。两份报价都"可信"、都无法确认含税与否,模型的处理方式只有三种:弃用价格只给链接、随机选一个、或者两个都列出来让用户自己分辨。这三种,对转化都是伤害。

GEO 的价格类内容有一条铁律:AI 引擎不做税务换算,也不猜测口径。含税与否无法判断时,它宁可弃用你的报价。
这篇只解决"含税口径与价格构成声明"这一个问题,UnitPriceSpecification 的单价换算细节不在本篇展开。
二、原理剖析:PriceSpecification 家族的分工
schema.org 里价格不是单个字段,而是一个家族。Offer.price 是最简单的标量写法,只能给一个数字;只要价格有附加语义——含税口径、阶梯数量、单价基准、分期构成——就应该下沉到 Offer.priceSpecification,它期望的类型是 PriceSpecification 基类。基类之下,UnitPriceSpecification 负责"每件/每盒/每月"这类单价换算,CompoundPriceSpecification 负责用 priceComponent 把总价拆成多段。价格构成的性质由 PriceComponentTypeEnumeration 表达,它目前是 pending 状态(源自 schemaorg 仓库 issue #2689,由 Google 提出),共六个枚举值:Installment(分期)、Subscription(订阅)、Downpayment(首付)、ActivationFee(开通费)、CleaningFee(清洁费)、DistanceFee(距离费),通过 priceType 属性挂在价格段上。
含税口径则由 valueAddedTaxIncluded 声明。它是 PriceSpecification 上的 Boolean 属性,官方定义一句话:"指明适用增值税是否已包含在该价格中"。因为 Offer 的 priceSpecification 期望类型是 PriceSpecification,这个属性既能写在 Offer 直接层级,也能写在每一段价格规格里——两处都写、口径一致,是后面所有改造的基础。
classDiagram
Offer --> PriceSpecification : priceSpecification
PriceSpecification <|-- UnitPriceSpecification : 单价与计费周期
PriceSpecification <|-- CompoundPriceSpecification : 总价拆多段
CompoundPriceSpecification --> PriceSpecification : priceComponent[]
UnitPriceSpecification : priceType → PriceComponentTypeEnumeration
PriceSpecification : valueAddedTaxIncluded Boolean
PriceSpecification : eligibleQuantity QuantitativeValue
家族成员各自管什么,一张表说清楚:
| 类型/属性 | 层级 | 职责 | AI 引擎的使用方式 |
|---|---|---|---|
| Offer.price | Offer | 单一标量价,最简写法 | 高置信度直接引用 |
| Offer.valueAddedTaxIncluded | Offer | 该报价是否含增值税 | 决定回答里报 699 还是 618.58 |
| PriceSpecification | 基类 | 承载口径、区间、适用量等语义 | 与 Offer 层对齐后采信 |
| UnitPriceSpecification | 子类 | 每件/每盒单价、计费单位 | 用于"单价约 X 元/件"类回答 |
| CompoundPriceSpecification | 子类 | priceComponent 拆分总价 | 用于分期/订阅类价格回答 |
| PriceComponentTypeEnumeration | 枚举 | 标记价格段性质(分期、订阅等) | 当前权重低,但方向正确 |
三、B2C 零售价:两个层级的口径必须对齐
改造前的 B2C 商品页是最常见的错法:Offer 上写了 price: "699.00",valueAddedTaxIncluded 压根没写;priceSpecification 里又复述了一个 618.58 的裸价(接口同学塞进来的),同样没写口径。AI 面前等于摆了两张价格牌、两张都没落款。
改造后的 B2C 写法如下。依赖与环境:schema.org 词表当前稳定版(13.x);验证用 Google 富媒体搜索测试与 schema.org 官方 Validator,均为 2026 年 9 月在线版。注意 JSON-LD 严格语法不支持注释,以下 // 行仅为讲解,部署时删除。
// 环境:schema.org 词表 13.x;上线前用 schema.org Validator + Google 富媒体搜索测试各验一遍
{
// 顶层用 Product 类型,商品结构化数据的固定入口
"@context": "https://schema.org",
"@type": "Product",
"name": "无线降噪耳机 X3",
"sku": "HP-X3-2026",
// offers 节点只放当前有效报价,历史价与裸价一律不进标记
"offers": {
"@type": "Offer",
// 币种用 ISO 4217 代码
"priceCurrency": "CNY",
// 价格用字符串保留两位小数,与页面展示逐位一致
"price": "699.00",
// 关键声明一:Offer 层明确该价已含 13% 增值税
"valueAddedTaxIncluded": true,
// 注意:必须写布尔值 true,字符串 "true" 会被判 invalid value
"priceValidUntil": "2026-10-31",
// 有效期到期前必须刷新,过期价会被 AI 降权
"availability": "https://schema.org/InStock",
"url": "https://www.example.com/p/hp-x3",
// priceSpecification 期望类型是 PriceSpecification 基类
"priceSpecification": {
"@type": "PriceSpecification",
// 子对象价格与 Offer 层逐位一致,不许出现另一套价
"price": "699.00",
"priceCurrency": "CNY",
// 关键声明二:价格规格层口径必须与 Offer 层完全一致
"valueAddedTaxIncluded": true,
// 对外只报 699.00 这个含税到手价,618.58 裸价一律不进标记
"eligibleTransactionVolume": {
"@type": "PriceSpecification",
"price": "699.00",
"priceCurrency": "CNY",
// 第三处口径声明,覆盖解析器只读子对象的情形
"valueAddedTaxIncluded": true
}
}
}
}
逐字段对照 schema.org 官方定义核一遍,每一项都不能想当然:
| 字段 | 官方定义要点 | 写法要求 |
|---|---|---|
| valueAddedTaxIncluded | Boolean,指明适用增值税是否已含在价格中 | 必须是布尔值 true/false,不能写字符串 "true" |
| Offer.price | 任一数值类型,通常配合 priceCurrency | 用字符串带两位小数,如 "699.00",与页面展示逐位一致 |
| priceSpecification | 期望类型 PriceSpecification | 子对象与 Offer 层价格、口径逐项一致,禁止放另一套价 |
| priceValidUntil | 日期,报价有效期 | 到期前更新,过期价会被 AI 降权 |
| eligibleTransactionVolume | 期望类型 PriceSpecification | 描述该报价适用的交易量条件,口径声明一并带上 |
四、B2B 批发阶梯价:eligibleQuantity 加统一含税声明
B2B 场景更麻烦。批发页面上是"1-9 件 128 元/件,10 件以上 115 元/件,均含 13% 税"这类阶梯价,很多站直接把三行表格文本丢给 AI,结果 AI 回答时随手挑一档,或者把含税价按裸价报出。正确做法是把每一段阶梯写成一个 UnitPriceSpecification,用 eligibleQuantity 圈定数量区间,每一段都带口径声明。同样的环境约定:schema.org 13.x,改动上线前先用 Validator 过一遍。
{
// 环境:schema.org 词表 13.x;B2B 页用与 B2C 同一套 Validator 流程
"@context": "https://schema.org",
// B2B 商品页同样以 Product 为顶层类型
"@type": "Product",
"name": "工业级温湿度记录仪 T8",
"sku": "T8-BULK",
"offers": {
"@type": "Offer",
"priceCurrency": "CNY",
// Offer.price 取最低档含税价,保证标量价有兜底
"price": "115.00",
// Offer 层统一声明:以下全部阶梯价均为含税价
"valueAddedTaxIncluded": true,
// 库存状态枚举值写完整 URL,B2B 页同样不能省
"availability": "https://schema.org/InStock",
// 阶梯价的核心:价格规格用数组,每段一个区间
"priceSpecification": [
// 第一段阶梯:用 UnitPriceSpecification 承载单价与数量区间
{
"@type": "UnitPriceSpecification",
// 本档含税单价,与页面表格逐位一致
"price": "128.00",
// 币种代码每段都写,方便解析器单独抽取该档
"priceCurrency": "CNY",
// 第一档:1-9 件,含税
"valueAddedTaxIncluded": true,
// UN/CEFACT 代码 H87 表示"件"
"unitCode": "H87",
"unitText": "件",
// eligibleQuantity 圈定本档适用数量,内部也要带量纲
"eligibleQuantity": {
"@type": "QuantitativeValue",
"minValue": 1,
"maxValue": 9,
"unitCode": "H87"
}
},
// 第二段阶梯:区间上不封顶,用 minValue 单独表达
{
"@type": "UnitPriceSpecification",
// 档位价 115.00 同时兜底 Offer.price,两处必须一致
"price": "115.00",
"priceCurrency": "CNY",
// 第二档:10 件起,同样含税,口径不许变
"valueAddedTaxIncluded": true,
// 每一段都要重复量纲声明,缺了整段可能被弃用
"unitCode": "H87",
"unitText": "件",
// 只给 minValue 就表示"N 件及以上"
"eligibleQuantity": {
"@type": "QuantitativeValue",
"minValue": 10,
"unitCode": "H87"
}
}
]
}
}
三处细节是 8 月调试时真踩过的:unitCode 用 UN/CEFACT 代码,H87 就是"件";eligibleQuantity 内也要带 unitCode,否则解析器对不上量纲;数组里每一段都要重复写 valueAddedTaxIncluded: true,实测有解析器只读数组中匹配区间的那一段,段上缺口径就整段弃用。
五、口径统一后的 30 天数据
改造在 8 月 29 日晚全量上线(生成端按模板统一注入,含 17 个重点 SKU 与 213 个长尾 SKU)。监测方法是固定 60 条真实问法("XX 多少钱""XX 含税吗""批发 20 台多少钱"),每周对三家 AI 搜索入口各跑一轮,记录回答价格与页面含税价完全一致的比例。上线前基线是 47%(60 条里 28 条价格正确或可采信)。
| 指标 | 改造前(8/23-8/29) | 改造后(9/22-9/28) |
|---|---|---|
| 价格回答准确率 | 47% | 88% |
| 双口径混报的 SKU 数 | 5 | 0 |
| 因口径不明弃用报价的次数 | 12/60 条 | 1/60 条 |
| "含税吗"类追问回答正确 | 9/15 条 | 14/15 条 |
| 报出裸价 618.58 的次数 | 每周 6-9 次 | 0 次 |
xychart-beta
title "AI 回答价格准确率(周度,%)"
x-axis ["W1 基线", "W2", "W3", "W4", "W5"]
y-axis "准确率 %" 0 --> 100
line [47, 52, 61, 78, 88]
曲线的形状值得记一笔:第 2 周只涨到 52%,因为三家引擎的抓取周期不同,最慢的一家 10 天后才重新抓到新标记;第 3 周起加速,说明双层级口径对齐让模型从"二选一"变成"直接采信"。剩下 12% 的错误集中在 3 个调价频繁的 SKU,靠把 priceValidUntil 缩短到 7 天后,9 月最后一周错误清零。
六、执行清单与踩坑记录
给准备动手的团队一份浓缩清单,全部来自这次 30 天实操:
valueAddedTaxIncluded是 Boolean,写成"true"字符串会被 Validator 报 invalid value,而且 AI 侧大概率忽略;- Offer 层与
priceSpecification层至少各写一次口径,两层价格必须逐位一致,分、角都不能差; - 阶梯价的每一段规格都要带口径与量纲,缺一段就可能在那一档被弃用;
- 调价后同步更新
priceValidUntil,我们 9 月 2 日观察到过期标记的 SKU 在 AI 回答里被降权了整整一周; - 分期、订阅类价格如需拆分,用
CompoundPriceSpecification的priceComponent配PriceComponentTypeEnumeration,每段同样带口径。
GEO 的价格标记没有捷径,口径声明做得越显式,AI 搜索里的报价就越接近你想让用户看到的那个数字。如果你的站点也在被含税价、阶梯价、订阅价折磨,欢迎在评论区贴出你的 JSON-LD,一起对口径。
参考与延伸
- schema.org PriceSpecification 类型定义:https://schema.org/PriceSpecification
- valueAddedTaxIncluded 属性定义:https://schema.org/valueAddedTaxIncluded
- PriceComponentTypeEnumeration 枚举(含六个成员值):https://schema.org/PriceComponentTypeEnumeration
- Google 搜索中心 · 商品(Product)结构化数据文档:https://developers.google.com/search/docs/appearance/structured-data/product
关键词:GEO、AI搜索、PriceSpecification、ValueAddedTaxIncluded、JSON-LD、价格规范、商品被AI推荐