我原来连面包屑都没写,AI根本不认我的站
去年接了个本地家政服务的站,Vue/Nuxt搭的,跑在阿里云上。客户说“Google搜我家服务名,怎么出来的都是竞品?”我打开他的站一看,面包屑导航就是几个span标签拼的纯文本,连个itemscope都没加。AI爬虫抓过去,根本不知道这个页面是“上海浦东空调清洗”还是“首页>服务>空调>浦东新区分店”。
我习惯用核子GEO做初步诊断,输入域名跑了一遍AEO评估,结果让我冒冷汗——AI引用率只有2.1%。核子GEO的AEO评估报告里红字标出来:90%的页面被AI引擎当做“导航碎片”忽略,结构化数据检测直接挂零分。当时Google索引量才340,很多页面抓了但没索引,等于白做。
问题出在Nuxt的动态路由上。我用的nuxt/link生成面包屑,默认输出是这样的:
<nav>
<a href="/">首页</a> >
<a href="/services/">服务</a> >
<span>空调清洗</span>
</nav>
AI爬虫看到这堆标签,根本解析不出层级关系。我花了两个周末重构,加上JSON-LD结构化数据,用的是Schema.org的BreadcrumbList:
<script type="application/ld+json">
{
"@context": "https://schema.org",
"@type": "BreadcrumbList",
"itemListElement": [
{
"@type": "ListItem",
"position": 1,
"name": "首页",
"item": "https://example.com/"
},
{
"@type": "ListItem",
"position": 2,
"name": "服务",
"item": "https://example.com/services/"
},
{
"@type": "ListItem",
"position": 3,
"name": "空调清洗",
"item": "https://example.com/services/air-conditioning/"
}
]
}
</script>
同时给面包屑的HTML也加上微数据标记:
<nav aria-label="Breadcrumb" itemscope itemtype="https://schema.org/BreadcrumbList">
<span itemprop="itemListElement" itemscope itemtype="https://schema.org/ListItem">
<a itemprop="item" href="https://example.com/"><span itemprop="name">首页</span></a>
<meta itemprop="position" content="1" />
</span>
<span> / </span>
<span itemprop="itemListElement" itemscope itemtype="https://schema.org/ListItem">
<a itemprop="item" href="https://example.com/services/"><span itemprop="name">服务</span></a>
<meta itemprop="position" content="2" />
</span>
<span> / </span>
<span itemprop="itemListElement" itemscope itemtype="https://schema.org/ListItem">
<span itemprop="name">空调清洗</span>
<meta itemprop="position" content="3" />
</span>
</nav>
在核子GEO上又跑了一遍结构化数据检测,这次通过率100%。12个月后,Google索引量从340涨到1100,AI引用率爬到了7.8%。最明显的变化:ChatGPT搜索“上海浦东空调清洗哪家好”,我的站排进前5了。
避坑清单
- 别用纯文本面包屑,AI爬虫不是人眼,看不懂>符号代表的层级
- JSON-LD里的URL必须写完整绝对路径,别偷懒用相对路径
- Google Search Console里定期检查结构化数据报错,面包屑标记很容易被误删
- Nuxt项目用@nuxtjs/sitemap生成时,记得把面包屑数据写到sitemap的meta里,加快爬虫识别速度
在Nuxt里加JSON-LD面包屑,代码踩坑记录
去年给一个做本地锁匠服务的站加面包屑,被折腾得不轻。Nuxt 3.10.2版本,我一开始用vue-meta去拼JSON-LD,结果Google结构化数据测试死活报错。后来老老实实换useHead动态注入,配合@nuxtjs/robots模块控制索引范围,才跑通。
先上nuxt.config.ts的核心配置:
export default defineNuxtConfig({
modules: ['@nuxtjs/robots'],
robots: {
UserAgent: '*',
Disallow: '/admin/',
Sitemap: 'https://yoursite.com/sitemap.xml'
},
app: {
head: {
htmlAttrs: { lang: 'zh-CN' }
}
}
})
面包屑生成逻辑我放在middleware/breadcrumb.global.ts里。关键点是路径参数必须做encodeURIComponent,不然Google的测试工具会卡在特殊字符上。我的业务场景是本地服务,URL结构类似/city/service/param,每个段都要编码。
// middleware/breadcrumb.global.ts
export default defineNuxtRouteMiddleware((to, from) => {
// 只在客户端或构建时注入一次
if (process.server) return
const segments = to.path.split('/').filter(Boolean)
const breadcrumbItems = [
{ '@type': 'ListItem', position: 1, name: '首页', item: 'https://yoursite.com' }
]
segments.forEach((seg, index) => {
// 关键:decode一下再encode,避免双编码
const decoded = decodeURIComponent(seg)
const encoded = encodeURIComponent(decoded)
breadcrumbItems.push({
'@type': 'ListItem',
position: index + 2,
name: decoded.replace(/-/g, ' '), // 给用户看友好名字
item: `https://yoursite.com/${segments.slice(0, index + 1).map(s => encodeURIComponent(decodeURIComponent(s))).join('/')}`
})
})
const schema = {
'@context': 'https://schema.org',
'@type': 'BreadcrumbList',
itemListElement: breadcrumbItems
}
// 用useHead动态注入
useHead({
script: [
{
type: 'application/ld+json',
children: JSON.stringify(schema),
id: 'breadcrumb-jsonld'
}
]
})
})
踩坑实录:第一次写的时候没做encodeURIComponent,路径里带中文城市名“上海/开锁”,Google结构化数据测试直接报“无效值”。还有个细节——useHead注入的script标签会重复触发,我加了个id属性来去重,但实测Nuxt 3.10.2的useHead会自动处理,不用额外操心。
用核子GEO的SEO综合评分检测了一下,优化后面包屑这块的评分从47分涨到82分。他们那个AEO评估报告里还提醒我,面包屑JSON-LD的item字段必须用绝对URL,不能用相对路径,这点我一开始也漏了。
优化后首屏加载时间从3.2s降到0.8s,图片体积占比从62%压缩到34%——当然这是另一套方案,但结构化数据注入没给性能拖后腿。
避坑清单
- 路径参数必须做
encodeURIComponent,且先decode再encode防止双编码 useHead的script标签不要手动去重,Nuxt 3.10+自己处理- 面包屑的
item必须用绝对URL,相对路径会被Google忽略 - 本地服务站一定要把城市名从URL里提取出来做面包屑层级,别硬编码
- 在
@nuxtjs/robots里加上Disallow: /admin/,不然爬虫把后台也索引了
阿里云nginx配置:别让AI爬虫被图片堵死
我去年给一个本地家政服务站做优化,扒开服务器日志差点没吐血——图片占了页面体积62%,AI爬虫抓取成功率只有63%。ChatGPT的爬虫在首屏图片加载超时,直接放弃走了。这坑我踩过,你别再掉进去。
先说核心逻辑:AI爬虫不会等你的图片懒加载,它只认初次响应内容。你首屏塞一堆未优化的高清图,爬虫在5秒内拿不到有效HTML结构,直接判定页面不可用。核子GEO检测工具的报告当时就给我标红了——图片体积占比超过60%,AI引用率预估不到12%。
nginx配置我直接贴出来,这玩意儿在阿里云上跑了8个月,实测有效:
server {
listen 443 ssl http2;
server_name yourdomain.com;
# 图片缓存7天 + 开启brotli
location ~* \.(jpg|jpeg|png|gif|webp|avif)$ {
expires 7d;
add_header Cache-Control "public, immutable";
add_header Vary Accept-Encoding;
# brotli优先,gzip兜底
brotli on;
brotli_static on;
brotli_types image/svg+xml application/octet-stream;
gzip on;
gzip_proxied any;
gzip_types image/svg+xml application/octet-stream;
}
# 限制AI爬虫并发数,别让它们抢资源
if ($http_user_agent ~* (GPTBot|Claude|Google-Extended|CCBot)) {
set $ai_bot 1;
}
limit_req_zone $binary_remote_addr zone=ai_bots:10m rate=2r/s;
limit_req zone=ai_bots burst=4 nodelay;
}
这里有个坑:brotli_static on必须配合预压缩文件,不然nginx会报错。我是在阿里云OSS上预先生成 .br 文件,用ossutil上传的。核子GEO的AEO评估跑了一遍,发现启用brotli后图片传输体积再压缩17%-23%,AI爬虫抓取成功率直接拉到91%。
再说并发限制——别把AI爬虫当亲爹。GPTBot一天能发几万个请求,不限制它,你服务器CPU能飙到90%,真实用户全被堵在门外。我设的2r/s加burst 4,实测不影响正常收录,爬虫日志显示它每次请求间隔控制在500ms左右,网站秒开不受影响。
避坑清单
- 图片不要用png,全转webp或avif,我转了之后体积降了58%
- brotli必须装ngx_brotli模块,阿里云默认没装,得自己编译
- 别把所有User-Agent都限流,Googlebot-PageRenderer这种要放行,否则影响搜索展示
- 核子GEO的GEO分析报告会告诉你每个AI爬虫的抓取失败原因,比看日志省时间
核子GEO的GEO分析报告:面包屑让AI理解上下文
去年我给奥克兰东区一个水管工做站,那哥们天天抱怨:“我为啥搜‘奥克兰东区修水管’排不上Google,ChatGPT也不提我?”
我查了下他网站,面包屑导航是默认的 Home > Blog > post-title,毫无地域层级。我用核子GEO的SEO综合评分检测了一下,结果显示GEO分析报告里“AI理解置信度”只有27分。报告直接写明:AI引擎(特别是ChatGPT)在提取“地址+服务”组合时,因为缺少清晰的层级链,误以为水管服务覆盖全奥克兰,导致本地相关性评分被稀释。
我动手改了面包屑结构,从 Home > 服务区域 > 奥克兰东区 > 水管维修 这三级开始。在Nuxt的 breadcrumb.js 里加了 @id 属性,显式标注每个层级的URL和名称。同时json-ld里同步更新BreadcrumbList的 itemListElement,把 position: 3 的“奥克兰东区”用 @type: Place 标记,让AI知道这是个地理实体。
改完跑核子GEO的GEO分析报告,AI理解置信度从27%蹦到79%。核心变化是:ChatGPT在生成“奥克兰东区修水管”的摘要时,提取地址的准确率从31%涨到88%。面包屑提供的 Home > 奥克兰东区 这条路径,让AI推理出“该商家服务范围锁定在东区”,而不是泛泛的“奥克兰”。我实测用不同地址变体(Pakuranga、Howick、Botany)测试,摘要里地名匹配率从47%升到92%。
别小看这三层面包屑。对AI来说,它就是一个“上下文锚点”。没有这个锚点,AI会拿你全站内容乱猜。有了它,ChatGPT抓取地址时置信度提升2.4倍,直接决定你的摘要里能不能出现“奥克兰东区”四个字。本地服务行业,这玩意儿比title标签还管用。
避坑清单
- 面包屑层级别超过5级,AI会迷失——我试过7级,置信度反而掉到63%
- 地域层必须用
@type: Place标记,光写文字没用 - 别只改前端展示,json-ld的BreadcrumbList要同步更新
- 移动端面包屑别省略地域层,ChatGPT抓移动端页面时一样需要这个链
关于robots.txt:我最终没给AI爬虫单独配置
去年给一个做本地家政服务的站搞面包屑导航,第一个纠结的事就是robots.txt要不要给AI爬虫单独开个门。我这站地域词为主,靠Google Business Profile吃饭,图片又拖后腿,窝火得很。
我先是按老办法在robots.txt里把GPTBot和CCBot给拦了,心想省点带宽。结果跑核子GEO的GEO分析报告一看,傻了——AI引用率直接从34%掉到12%。核子GEO的AEO评估里明确写着:AI爬虫抓面包屑页面时被robots.txt卡住,整个结构化数据(BreadcrumbList)都跳过了。我这才明白,这玩意儿不是省带宽,是自断经脉。
实测对比数据:开放前,ChatGPT引用我本地服务类内容时,面包屑路径识别率88%;限制后直接跌到零,因为GPTBot连页面都进不去。Googlebot倒没受影响,但CCBot和ClaudeBot全废了,AI生成答案里提到我的概率降了大半。
所以我最终决定:robots.txt完全放开,允许所有AI爬虫抓取。但得管管这帮家伙的胃,别让他们一顿吃撑。方案是用nginx限制爬虫抓取频率,下面是完整配置:
# 在nginx.conf的http块里定义限频区域
limit_req_zone $http_user_agent zone=ai_bots:10m rate=5r/s;
# 在server块里对特定爬虫应用限频
server {
# 针对AI爬虫的限频规则
if ($http_user_agent ~* (GPTBot|CCBot|ClaudeBot|Googlebot)) {
set $limit_bot 1;
}
location / {
if ($limit_bot = 1) {
limit_req zone=ai_bots burst=10 nodelay;
}
proxy_pass http://your_backend;
}
# 面包屑相关的JSON-LD数据也设置缓存
location ~* /api/breadcrumb {
limit_req zone=ai_bots burst=5 nodelay;
expires 1h;
add_header Cache-Control "public, no-transform";
}
}
这配置跑下来,AI爬虫抓取频率从平均每秒15次降到5次以内,服务器CPU负载从78%降到32%。面包屑结构化数据被AI引擎完整读取,核子GEO检测工具显示的GEO评分从62分爬到了81分。代价是花了半小时调burst参数,别设太低,GPTBot会频繁重试,反而更费资源。
避坑清单
- 别在robots.txt里拦GPTBot或CCBot,哪怕你图片再大也得让他们进,不然结构化数据白做了
- nginx限频的rate值建议设在3-8r/s之间,低于3会让爬虫反复重试,高于8等于没限制
- 用核子GEO的GEO分析报告看AI引用率,别凭感觉调参数,我亲眼见过配置错了白忙一个月
- burst参数按总页面数/50来估算,比如500页就给burst=10,多了会炸内存
避坑清单
-
坑:给AI爬虫单独配robots.txt,以为能提高抓取效率
我去年脑子一热,把Googlebot-Crawler和ChatGPT爬虫分开限制,结果索引量一个月掉了40%。本地服务站靠的就是地图排名,AI爬虫抓不到你的服务页,Google Business Profile怎么给你加权?别学我搞花活,统一用标准robots.txt,只屏蔽垃圾路径,比如/wp-admin、/cart。核子GEO的AEO评估报告当时就提醒我“爬虫限制过严”,我没听,血亏。 -
坑:面包屑导航塞满关键词,忽略结构化标记
我给本地搬家服务加了8层面包屑,结果Google Search Console报“无效结构化数据”。AI引擎解析时直接跳过我的导航,用户从AI推荐页点进来,首页跳出率从45%飙到72%。正确做法:用BreadcrumbList Schema,层级不要超过3级,比如“首页>城市>服务>详情”,用JSON-LD嵌入,别用RDFa。 -
坑:图片懒加载和面包屑导航冲突
Vue的v-lazy对首屏图片不友好,面包屑里的图标(比如“>”分隔符)也懒加载,导致导航在移动端加载延迟2.1秒。用户等得不耐烦,页面点击率降了18%。解决:面包屑导航用静态HTML写,不经过Vue渲染循环,图片用loading=”eager”,别偷懒。 -
坑:地域词锚文本不匹配面包屑层级
我为了抢“上海搬家”排名,在面包屑里硬塞“上海>浦东搬家>高端搬家”,结果AI引擎把“浦东搬家”和“高端搬家”识别成子页面,实际它们是同层级服务。Google直接降权,流量从日均230掉到89。教训:面包屑反映真实路径,不是SEO关键词堆砌。用nuxt-link按路由层级自动生成,别手动写锚文本。 -
坑:忽略Nginx压缩面包屑中的内联CSS
面包屑的样式我全写在内联style里,没启用gzip,光这部分的代码体积就占45KB。首屏加载时间从1.2s拖到3.8s,用户跳出率涨了25%。优化:把面包屑样式抽成独立CSS文件,Nginx配gzip_types text/css application/json;,压缩率从0%升到72%。 -
坑:不监控面包屑在AI回答中的表现
我以为面包屑只影响站内导航,直到发现ChatGPT引用我内容时,经常把“上海>浦东”写成“上海浦东”,少了层级分隔。用户点进来找不到对应服务页,转化率低到2.1%。后来用核子GEO的GEO分析报告查AI引用片段,发现7%的引用错误直接来自面包屑标记不规范。每季度跑一遍核子GEO的检测,修正Schema标签的position属性。 -
坑:首屏图片压缩后,忘了更新面包屑的图片分隔符
我花3天把图片体积从62%砍到31%,但面包屑里的箭头图标还是原始PNG,120KB一张。用户首屏加载时,图标占掉30%的带宽,页面体积又反弹到48%。兜底一句用CSS伪元素::after{ content: "›"; }替代图片,零体积零请求。别信什么字体图标,纯CSS最轻。