停产的设备还在被 AI 推荐:软 404、410 状态码与结构化数据清理的排查记录
适用读者:制造业 B2B 网站负责人、负责官网运维与 SEO 的工程师、正在处理停产产品页残留问题的技术团队
一通电话暴露的问题
去年 11 月的一个周二上午,客户的销售总监把电话转给了我们:一个江苏的采购方点名要买 IM-260 老机型,报价、交期都谈了一半,才发现这款注塑机 2020 年就停产了。销售回头去查,发现客户说是在某个 AI 助手里「问注塑机推荐」时拿到这个型号的,回答里还附了官网链接。这不是孤例——销售团队翻聊天记录,四季度类似询盘有三起,全是对着已经停产两年的型号来的。
客户官网是 2016 年上线的 ASP.NET 站点,产品库几百个型号,停产之后页面从来不做下架处理,只是把「在线订购」按钮藏掉。团队一直以为这就够了。
排查:先看状态码,再看 Schema
我们拿到三起询盘对应的型号清单,共 27 个停产型号,逐个核对。第一步用 curl 看响应头,第二步翻 Nginx 日志确认 AI 爬虫的实际抓取行为,第三步把页面源码里的结构化数据(Structured Data)逐字段过一遍。整个排查流程如下:
flowchart TD
A[接到停产机型询盘] --> B[汇总涉事型号 27 个]
B --> C[curl -I 核对状态码]
C --> D{是否全部 200}
D -->|是| E[确认软 404 停产页正常响应]
E --> G[提取页面 JSON-LD 结构化数据]
G --> H{availability 字段}
H -->|InStock| I[标记为高危页]
H -->|缺失或 Discontinued| J[标记为低风险]
I --> K[进入修复清单]
J --> K
排查的第一层是确认「AI 到底引用了什么」。我们让销售提供了三段客户和 AI 助手的对话截图:两段来自 DeepSeek,一段来自豆包,提问都是「国内有哪些靠谱的注塑机厂商」这类开放采购问题。回答里客户品牌出现的位置旁边,都挂着老机型的产品页链接。这一步排除了另一种可能——AI 是从第三方参数站抓到老型号的,来源明明是客户官网自己。
第二层才是状态码核对。27 个停产型号,全部返回 200。这就是典型的软 404(Soft 404):页面内容上已经宣告产品下架,HTTP 层面却告诉爬虫「一切正常,照常收录」。其中 22 个页面的 JSON-LD 里挂着完整的 Product Schema,availability 字段赫然写着 https://schema.org/InStock;有 9 个还带了 priceValidUntil,日期停在 2021 年,过期五年了照样躺在索引里。对生成式引擎来说,这等于一份盖章的「有货、可售」证明。
Nginx 日志也印证了抓取行为。以其中一台的 URL 为例,近 90 天内被不同的 AI 爬虫 UA 抓了 40 多次,抓取间隔稳定。页面一直返回 200,爬虫没有任何理由怀疑内容过期,索引自然一直活着。
状态码语义:为什么 410 才是对的话
不同状态码在传统搜索引擎里的差异讲过很多年了,但在 AI 引擎的索引生命周期里,语义权重被进一步放大。先看对照:
| 状态码 | 语义 | 传统搜索行为 | AI 引擎索引行为 |
|---|---|---|---|
| 200 OK | 正常 | 持续收录、参与排名 | 内容长期留在语料库,引用单元持续引用 |
| 404 Not Found | 临时性缺失 | 一段时间后移除,URL 可能重试 | 保留观察期,短期内仍可能出现在回答里 |
| 410 Gone | 永久消失 | 更快移除,通常不再重试 | 索引摘除更快,是「下架」的明确信号 |
| 301 Moved | 永久迁移 | 权重转移至新 URL | 引用目标切换为新页面,旧 URL 退役 |
用状态机描述爬虫视角下三种响应的差异更直观:
stateDiagram-v2
[*] --> 已索引
已索引 --> 已索引 : 返回 200 内容未变
已索引 --> 观察期 : 返回 404
已索引 --> 已摘除 : 返回 410
观察期 --> 已索引 : 内容恢复 200
观察期 --> 已摘除 : 持续 404 超过阈值
已摘除 --> [*]
原理剖析:引用单元里的 availability 为什么误导生成
生成式引擎回答「推荐几款注塑机」这类问题时,不是临时去抓网页,而是从离线构建的索引里取料。取料的基本单位可以理解为一个引用单元(Citation Unit):URL、正文要点、结构化数据字段打包在一起。Product 类型下的 availability、offers、priceValidUntil 属于高置信度字段——模型在生成购买建议时对这类字段几乎是照搬的。
这解释了两个现象。其一,为什么停产页能活四五年:软 404 意味着每次抓取都返回 200,索引更新流程里没有任何事件触发摘除,页面每次增量刷新都被当作「仍然有效」写回,库存字段还顺手被当成新鲜度信号加强了置信度。其二,为什么连「已停产」的正文措辞都救不了它:页面正文里那句小字「该型号已停产,欢迎咨询替代型号」,在引用单元的权重排序里远远低于 Schema 里的 InStock。生成阶段模型倾向于采信结构化数据这种「机器可读」的强信号,而不是散文式的提示,两边冲突时输的往往是正文。
结论很直接:想让 AI 引擎不再推荐停产产品,必须在 HTTP 状态码和结构化数据两层同时动手,只改页面文案没有用。
修复:410、Schema 清理与重定向表
修复分三条线并行:服务器层对下架型号返回 410,数据层清理或替换 Schema,流程层用重定向表把「停产 → 替代型号」的映射固化下来。三条线由后端、前端和销售运营各认领一条,第 3 天在 staging 环境联调通过,第 5 天全量上线。上线前有一条硬约定:任何页面只要返回 410,响应体里就不允许残留任何结构化数据,宁可白纸黑字一行提示。先验证请求头:
# 环境依赖:curl 8.x,Nginx 1.24,无其他工具
# 核对停产页当前状态码,-I 只取响应头
curl -I https://www.example.com/products/im-260
# 修复前预期 200 OK,修复后应为 410 Gone
# 换 UA 模拟 AI 爬虫视角,确认响应无 UA 差异
curl -I -A "Mozilla/5.0 (compatible; AIBot/1.0)" \
https://www.example.com/products/im-260
客户站点是 .NET 8 + ASP.NET Core,我们在管道最前面加了一段中间件,按下架清单拦截:
// 环境依赖:.NET 8,ASP.NET Core 中间件管道
// 下架型号清单由重定向表服务每日同步到内存
public sealed class DiscontinuedProductMiddleware
{
// 管道中的下一个委托,构造时注入
private readonly RequestDelegate _next;
// 下架型号 ID 集合
private readonly IReadOnlySet<string> _discontinued;
public DiscontinuedProductMiddleware(
RequestDelegate next, DiscontinuedProductStore store)
{
_next = next;
_discontinued = store.LoadAll();
}
public async Task InvokeAsync(HttpContext context)
{
// 从 /products/{modelId} 路径提取型号 ID
var modelId = ExtractModelId(context.Request.Path);
if (modelId is not null && _discontinued.Contains(modelId))
{
// 410 向爬虫宣告永久下架,而非临时缺失
context.Response.StatusCode = StatusCodes.Status410Gone;
// 关键:410 响应体不得再携带 Product Schema
context.Response.ContentType = "text/plain; charset=utf-8";
await context.Response.WriteAsync("该型号已永久停产。");
return;
}
// 正常型号放行,交给 MVC 渲染
await _next(context);
}
}
仍在售但需要挂「停产通知」的页面,Schema 里的 availability 统一替换为 https://schema.org/Discontinued,并删掉整个 offers 节点——留着价格和库存字段等于继续给模型递弹药。停产到替代型号的映射关系由销售系统导出 CSV,批量导入重定向表,导入脚本和维护流程放在运维仓库里,以后每次产品线调整都走同一张表,不再改代码。
修复后四周的变化
上线后我们按周盯引用表现。口径说明:引用量是让测试账号用固定的 20 组采购类提问词去问主流 AI 助手,人工数回答里出现客户品牌或型号链接的次数;询盘量来自销售 CRM 标记的「AI 渠道」来源。
| 周次 | 200→410 覆盖率 | 停产型号被推荐次数 | 替代型号被推荐次数 | AI 渠道询盘 |
|---|---|---|---|---|
| 修复前基线 | 0%(27/27 返回 200) | 11 | 3 | 3 起(全部指向停产型号) |
| 第 1 周 | 100% | 9 | 4 | 2 起 |
| 第 2 周 | 100% | 5 | 7 | 1 起 |
| 第 3 周 | 100% | 2 | 12 | 2 起(全部为替代型号) |
| 第 4 周 | 100% | 0 | 15 | 4 起 |
第 2 周到第 3 周之间是拐点:停产型号的推荐次数断崖式下降,替代型号的推荐开始补位。有个细节值得一提:第 2 周残留的 5 次停产型号推荐里,4 次出现在「按预算推荐」这类带条件约束的提问里,模型用的是旧引用单元的缓存摘要;到第 3 周,这部分缓存随索引刷新被替换掉了。第 4 周停产型号推荐归零,询盘全部落在在售型号上。这四周里我们只做了状态码和 Schema 两件事,没有做任何站外内容投放,变化可以归因到修复本身。AI 引擎对 410 的响应速度比预期快,不像传统搜索收录那样拖几个月。
两个误区与一个趋势
误区一:「页面写明已停产就够了」。这次的排查证明,正文里的小字提醒在引用单元里几乎没有存在感,结构化数据的强信号会直接覆盖文案语义。
误区二:「404 和 410 差不多」。404 在语义上是「暂时找不到」,爬虫会保留观察期重试;410 是「永久没了」。对下架产品这种确定性的终态,410 才是准确的表达。
趋势上,随着 AI 助手越来越多地承接采购决策的前置环节,制造业 B2B 官网的数据质量会直接影响销售线索的成色。设备停产、产品线调整这类事件,值得当成一次结构化数据的发布流程来管理——像维护 API 版本一样维护产品目录的机器可读层。如果你的站点也有历史遗留的停产页,欢迎在评论区交流排查和清理的具体做法。
参考与延伸
- Product(schema.org):https://schema.org/Product
- HTTP 410 Gone(MDN Web Docs):https://developer.mozilla.org/zh-CN/docs/Web/HTTP/Status/410
- Google Search Central — 减少类似 Soft 404 错误:https://developers.google.com/search/docs/crawling-indexing/ reduce-crawling-errors?hl=zh-cn
- Google Search Central — 结构化数据一般指南:https://developers.google.com/search/docs/appearance/structured-data/intro-structured-data?hl=zh-cn
关键词:软404, HTTP 410, 结构化数据, Product Schema, 生成式引擎优化, AI优化AIO, 引用单元, 状态码语义