补上价格区间和支付方式之后:priceRange 与 paymentAccepted 对门店 AI 推荐位的影响

2026-09-20 01:19:06 5 次浏览
GEO本地生活Schema.orgJSON-LD结构化数据

适用读者:连锁服务门店(维修、家政、口腔诊所这类)做官网和落地页的前端 / SEO 工程师;门店页已经在铺结构化数据(structured data),却在生成式引擎优化(Generative Engine Optimization, GEO)的验收里发现,AI 被问到"大概多少钱""能不能扫码"时要么答错、要么干脆不答的那批人。

用户在 AI 搜索里问"XX 区补个牙大概多少钱",回答列了三家机构,两家的价格栏写着"约 300-800 元",我们那家是空的。门店页的 NAP(名称、地址、电话,即 Name-Address-Phone)三项一个不缺,评分和营业时间也早挂上了。真正缺的是价格区间(price range)和支持的支付方式(payment accepted)这两条。补字段本身花了两天,有意思的是后面 45 天的观测。

改造前,AI 对价格类问题一律绕着走

先说口径。样本是某连锁服务品牌的 26 个门店页,化名"H 家修",做维修加口腔两类业务。我们固定了 12 组提问模板,覆盖"多少钱""人均多少""能扫码吗""支持刷卡吗"这些真实用户会问的句式,每周跑两轮,两个通用大模型加一个 AI 搜索入口,人工判定回答里有没有价格数字、有没有点名到门店。基线跑两周,改造后跟了 45 天。这是我们自己的受控采样记录,样本量小,不能当行业统计看,看趋势就好。

门店价格与支付字段主题图:店铺图标带价格标签

基线两周的结果挺扎心:208 次提问机会里,只有 31 次点名到我们的门店;出现价格数字的 12% 里,一半还是模型自己从正文"起价""优惠"里抠出来的残缺数字。支付类问题更惨,0 次命中——页面正文压根没提过微信和支付宝,模型无米下锅。

改造前的门店节点长这样,只有 NAP 加营业时间,价格与支付一个字段都没写。

// 改造前的门店页结构化数据,内联在页面 <head> 里
// 环境:静态站点(Hugo 构建),无运行时依赖
// 校验工具:Rich Results Test、validator.schema.org
// 说明:jsonc 里的 // 注释仅为讲解,落盘时删掉即为合法 JSON
{
  "@context": "https://schema.org",
  // Dentistry 是 LocalBusiness 的子类,维修门店换 HomeAndConstructionBusiness
  "@type": "Dentistry",
  "name": "H 家修口腔(某某店)",
  "telephone": "+86-571-8888-0000",
  // 门店页 URL,AI 引用时的落点,必须与 @id 同源
  "url": "https://example.com/stores/hangzhou-xh-01",
  "address": {
    "@type": "PostalAddress",
    // 地址四项拆开写,别糊成一整个字符串
    "streetAddress": "某某路 100 号 2 层",
    "addressLocality": "某市",
    "addressRegion": "某省",
    "postalCode": "310000",
    "addressCountry": "CN"
  },
  // 营业时间规格,历史文章讲过,这里不展开
  "openingHoursSpecification": {
    "@type": "OpeningHoursSpecification",
    "dayOfWeek": "Monday",
    "opens": "09:00",
    "closes": "18:00"
  }
  // 到这里就结束了:没有 priceRange
  // 没有 paymentAccepted,也没有 currenciesAccepted
}

价格区间怎么写,直接决定 AI 抄不抄

priceRange 在 Schema.org 上是 Text 类型,不是数字,也不是结构化对象。这条决定了它能表达的自由度,也决定了它容易被写废。我们内部试过五种写法,AI 的抄法完全不同。

priceRange 写法 AI 回答里的呈现 我们的判定
¥120-¥260 原样引用"约 120-260 元" 可用,命中率最高
$$ 表述成"中档价位",无数字 能过校验但答不出钱数
120 抽成"120 元",被当成固定价 误读,弃用
面议 / 电议 不引用,价格栏留空 等于没写
新客 99 元起 抽成"99 元",与正文常态价冲突 制造冲突,弃用

三点经验。区间要写闭区间,两端都给,模型才敢说"大概多少";只给下限,它会当固定价念。币种单独用 currenciesAccepted 声明,走 ISO 4217 的三字母码,写 CNY 而不是 RMB 这类口语写法。支付方式用 paymentAccepted 写具体渠道名,"微信支付、支付宝、现金、银行卡"这种;写"多种支付方式支持"是白写,模型抽不出任何可断言的东西。

完整节点长这样,注意 priceRange 挂在门店自己身上。

// 改造后的门店节点:新增三个字段,其余不动
// 环境同上;校验同上;落盘前记得删掉注释
{
  "@context": "https://schema.org",
  "@type": "Dentistry",
  "@id": "https://example.com/stores/hangzhou-xh-01#store",
  // @id 用页面 URL 加片段,跨页面交叉引用时不会认错实体
  "name": "H 家修口腔(某某店)",
  // 电话带 +86 国际区号,AI 回答里常被渲染成可拨打链接
  "telephone": "+86-571-8888-0000",
  // url 与 @id 同源,避免同一门店被判成两个实体
  "url": "https://example.com/stores/hangzhou-xh-01",
  "address": {
    "@type": "PostalAddress",
    "streetAddress": "某某路 100 号 2 层",
    "addressLocality": "某市",
    "addressRegion": "某省",
    "postalCode": "310000",
    "addressCountry": "CN"
  },
  // 价格区间:闭区间写法,两端都要有
  // 区间语义是"常态人均",不是活动价
  "priceRange": "¥120-¥260",
  // 币种:ISO 4217 三字母码,多个用逗号分隔
  "currenciesAccepted": "CNY",
  // 支付方式:Text 类型,没有官方枚举
  // 写用户真正会用的渠道名,别写"多种方式"
  "paymentAccepted": "微信支付, 支付宝, 银行卡, 现金",
  // 父级组织只做兜底,门店级字段优先
  "parentOrganization": {
    "@type": "Organization",
    "name": "H 家修",
    "url": "https://example.com"
  }
}

AI 到底凭什么答或不答价格

机制剖析:属性级抽取、置信度打分与缺字段降级

AI 搜索的流水线大致分三段:召回、片段化、生成。结构化数据在第二段就被单独拎出来了——它密度高、噪声低,解析器会把 JSON-LD 里的键值对摊成一张"事实表",跟正文切片分开存。

关键在第三段:属性级抽取。 模型不是看到 @type: LocalBusiness 就整体给分,而是先把问题意图映射成需要的属性槽位。问"多少钱"→ 找 priceRangepriceSpecification;问"能扫码吗"→ 找 paymentAccepted。槽位有值且和正文表述一致,置信度拉满,回答里会出现数字加点名;槽位有值但和正文冲突(比如结构化写 120-260,正文写"人均 300"),置信度掉一档,模型通常只挑一个值说,还常常挑错那个。

槽位空着的时候是第三种处理:降级。实测下来模型有两个常见动作——要么从正文里硬猜一个(猜不出来就跳过价格,只说"建议到店咨询"),要么把这一栏从回答里整个抹掉。抹掉比猜错更常见,也更隐蔽:门店还留在推荐位里,但价格栏空白,用户扫一眼就划走了。这也是改造前 31 次点名、转化却几乎为零的原因。

flowchart TD
    A["用户提问:补牙大概多少钱"] --> B["意图识别:价格类"]
    B --> C{"priceRange 槽位"}
    C -->|"有值"| D{"与正文一致?"}
    C -->|"缺失"| E["降级路径"]
    D -->|"一致"| F["高置信:引用数字 + 点名门店"]
    D -->|"冲突"| G["中置信:挑一个值,常挑错"]
    E --> H["从正文硬猜或跳过价格"]
    H --> I["推荐位里价格栏空白"]
    I --> J["用户划走,转化归零"]

45 天观测记录:改了什么、涨了多少

字段上线分两批:第 1 周铺 12 家试点门店,第 3 周全量 26 家。中间第 2 周做过一次写法修正(把 120 改成闭区间、多种支付方式 改成渠道名),所以下表取的是修正后满 30 天的稳定期,跟基线两周对比。

指标 改造前(基线 2 周) 改造后(30 天稳定期) 变化
回答中出现价格数字的比例 12% 57% +45pt
门店被点名进入推荐位次数 / 208 次机会 31 89 +187%
"多少钱"类问题给出明确答复的比例 8% 63% +55pt
支付类问题能说出微信 / 支付宝的比例 0% 71% 从无到有
价格数字与页面标注不一致的次数 9 2 -78%
门店页来自 AI 入口的会话数(同周期环比) 100(基准) 168 +68%

最后一行的会话数我们只当参考,中间夹了投放和节假日的噪音。真正干净的信号是第二行和第三行:点名次数涨了近两倍,且价格不再缺栏。

分业务看还有个有意思的差别。口腔类门店的"多少钱"回答率高于维修类,我们猜是因为口腔的价格区间更标准化,正文也常有价目表佐证;维修类的"上门费 + 工时费"是复合价格,一个 priceRange 塞不下,模型经常答了区间又补一句"具体看师傅报价"。

业务类型 价格类回答率 常见失败模式
口腔诊所 74% 多,价目表与区间冲突时挑错值
家电维修 52% 复合计价,答完区间还要加限定语
家政保洁 61% 按小时和按面积两套价,区间容易串

踩过的坑,以及怎么绕开的

优惠价千万别写进 priceRange。 第一版有门店写"新客 99 元起",模型把 99 当常态价念,用户到店发现是 260,投诉直接打到客服。区间的语义就是常态人均,活动价走 hasOfferCatalog 里的报价目录(OfferCatalog)或 SpecialOffer,别混。

多门店场景要防父级覆盖。 我们的模板最初把 priceRange 写在父级 Organization 上,子门店不写,结果 6 家定位偏高的门店被答成低价。修复方式很土:门店节点必须自带 priceRange,父级只留兜底值。

flowchart LR
    O["父级 Organization 兜底 priceRange"] --> B1["门店节点自带 priceRange"]
    O --> B2["门店节点不写"]
    B1 --> R1["门店级值优先,回答与到店价一致"]
    B2 --> R2["沿用兜底值,高端门店被答成低价"]

别拿富结果测试工具当验收标准。 priceRange 不参与 Google 的富结果判定,跑 Rich Results Test 会告诉你"未检测到富结果",这是正常的,它本来就只为语义抽取服务。我们内部改用两条硬指标验收:一是结构化数据里三个字段的覆盖率(后来上了脚本扫),二是固定提问模板的人工抽检。

# 环境:Python 3.10+,仅标准库(json / pathlib),无第三方依赖
# 用途:批量扫门店页 JSON,统计三个字段的缺失情况
import json
import pathlib

# 三个字段一起查,缺一个就进不了 AI 的属性槽位
FIELDS = ["priceRange", "paymentAccepted", "currenciesAccepted"]

# 只统计门店节点,父级 Organization 不参与
STORE_TYPES = {"Dentistry", "HomeAndConstructionBusiness", "LocalBusiness"}

def scan(root):
    # root 下每家门店一个 json 文件,文件名即门店 ID
    miss = {f: [] for f in FIELDS}
    for f in pathlib.Path(root).glob("*.json"):
        data = json.loads(f.read_text(encoding="utf-8"))
        # 节点可能是数组,逐个看
        nodes = data if isinstance(data, list) else [data]
        for n in nodes:
            # 跳过兜底用的父级节点,避免把总部的缺失算进门店铺设率
            if n.get("@type") not in STORE_TYPES:
                continue
            for k in FIELDS:
                # 空串也算缺失:值存在但抽不到内容
                if not str(n.get(k, "")).strip():
                    miss[k].append(f.stem)
    # 返回结构:字段名 -> 缺失门店 ID 列表
    return miss

# 覆盖率 = 1 - 缺失数 / 门店总数,日报里画成折线看补齐进度
print(json.dumps(scan("./stores"), ensure_ascii=False, indent=2))

误区和接下来的趋势

一个常见误会是 paymentAccepted 有官方枚举值。没有,它是 Text,写 "Cash""现金""微信支付" 都能过校验,校验器不拦不代表模型读得懂。同理,能过校验和能被引用是两件事,这是做 GEO 时最容易混淆的地方。

另一个误会:觉得这类字段属于"SEO 细节",排期永远排不上。从这次数据看,属性槽位的完整度在 AI 搜索里是被直接折算进推荐位竞争力的——信息全的机构被优先点名,缺栏的被挤到后面或者干脆整栏留白。

趋势上我倾向于认为,AI 搜索正在从"认实体"走向"答属性"。前一阶段拼的是名字出现频次和实体对齐,接下来拼的是属性槽位填得全不全、跟正文一不一致。priceRangepaymentAccepted 是最低垂的两个果子,值得先摘。

你们在门店页上还补过哪些"用户一定会问、页面从来不写"的字段?评论区聊聊,我挑几个有代表性的再跑一轮对比。

参考与延伸

GEO, AI优化AIO, 本地服务 AI 获客, LocalBusiness, priceRange, paymentAccepted, JSON-LD, Schema.org

🤖
本内容由 AI 辅助生成,经人工校对审核;部分素材、资料来源于公开网络,仅作个人观点分享与交流使用,无任何商业侵权意图。若内容、图片、文字涉及您的合法著作权、版权权益,请联系本人,核实后将第一时间删除、修改相关内容。