背景:一个让每个站点工程师都该看一眼的案子

1 阅读7分钟

对话式 AI 平台 Character.AI 在 2026年10月13日向美国法院申请 Chapter 11 破产。公开报道披露的交易条件包括:Disney 以 2000 万美元购买部分资产并取得技术的非独占永久许可;法院文件载明的资产与负债为 5000 万至 1 亿美元;交割预计 11 月底或 12 月初,若没有其他报价则平台被清盘(来源:TechCrunch 于 2026年10月13日的报道,纯文字引用,不附链接)。

还有一条同样重要:报道称,2026年10月15日纽约总检察长联合 40 位总检察长在该破产案中提交利益通知,要求任何接手资产的买方落实用户数据保护。

作为站点的维护者,这篇笔记关心的不是交易本身,而是一个副产品——当主体退出、业务转让、产品下线时,我们留在 Web 上的那一层表述会变成什么。

关键挑战:三条撤不回去的旧信息

页面内容一旦发布,就会进入三重存储:搜索引擎索引与快照、第三方抓取与转述、LLM 训练与检索增强的语料。我们的页面更新能覆盖自己的 origin server,覆盖不了这三处。

具体到站点层面,长期观察下来最容易漏的有三类:

场景页面上残留的表述被 AI / 客户读出的问题
主体变更老主体的公司全称、统一社会信用代码、备案号"跟我签合同的是现在这家吗"
业务转让转让前写的"全国门店通用""终身售后""我上次买的卡还能用吗"
产品下线停产型号的在售描述"这款现在还能买到吗"

这三类页面的共同点是:HTTP 状态码还是 200,robots.txt 允许抓取,sitemap 还在提交,只是内容本身已经不成立了。搜索引擎与 RAG 系统没有任何信号知道它过期。

方案:把"主体状态"做成站点的一等公民

思路只有一条:凡是可能随时间失效的断言,都必须在同一个 HTTP 响应里带上可验证的时间戳与状态标记。 依赖外部公告页来兜底是行不通的,公告页会被时间沉到列表底部,而原详情页是持续被抓取的那一个。

1. JSON-LD 里区分 datePublished 与 dateModified,并补全主体信息

<script type="application/ld+json">
{
  "@context": "https://schema.org",
  "@type": "Product",
  "name": "示例型号 X-200",
  "sku": "X-200",
  "offers": {
    "@type": "Offer",
    "availability": "https://schema.org/Discontinued",
    "priceValidUntil": "2026-09-30"
  },
  "publisher": {
    "@type": "Organization",
    "name": "承接该业务的现行主体全称",
    "identifier": "统一社会信用代码(与营业执照一致)"
  },
  "datePublished": "2024-03-11",
  "dateModified": "2026-09-30"
}
</script>

两个坑:

  • availability 用 Discontinued,不要直接给 OutOfStock。 OutOfStock 的语义是"暂时缺货",留给客户和模型的是"再等等就有了"。
  • dateModified 必须是真实修改日期。 每次发布流程刷一遍全站时间戳,等于亲手把这个字段的信息量归零。这一条是所有 structured data 里最常被滥用的。

2. 下线产品页保留 200 + 首屏状态标记,不要跳走也不要删

# 反例:详情页 301 到列表页,或者直接 410 Gone
# rewrite ^/product/x-200/?$ /products permanent;

# 正例:保留原 URL 200,由应用层在模板首屏注入停售标记
location ~ ^/product/(?<slug>[\w-]+)/?$ {
    try_files $uri /index.php?route=product&slug=$slug;
}

保留 200 的理由很实在:一旦 301 到列表页或 410,原 URL 携带的实体信息(型号、参数、售后承接方)直接从抓取源里消失。客户搜到这个型号时,模型只能从第三方转述或过期快照里拼答案,比留着沉默.page 糟糕得多。

应用层在模板里注入的标记要出现在第一个 <p> 之前,而不是页脚。RAG 的常见截断窗口取的是首屏前若干百字。

{# 产品详情页模板首屏,位于 h1 之后 #}
{% if product.status == 'discontinued' %}
<p class="status-flag">
  本型号已于 {{ product.discontinued_at }} 停产。整机保修与配件供应
  自该日起由 {{ product.successor_entity }} 承接,最后一批交付时间为 {{ product.last_shipment_date }}。
</p>
{% endif %}

3. 主体变更时用脚本做全站一致性巡检

把"营业执照上的公司全称"当作唯一真源,用一个脚本全站 grep,比人工过页面可靠得多。

#!/usr/bin/env python3
"""全站主体信息一致性巡检:输入主体的权威字段,输出受影响页面清单。"""
import pathlib
import re
import sys

ROOT = pathlib.Path("./public")

# 唯一真源:以当前营业执照为准,改主体时只改这里
CANON = {
    "legal_name": "承接业务后的现行主体全称",
    "uscc": "91310000XXXXXXXXXX",
    "icp": "沪ICP备XXXXXXXX号-1",
}

# 反面:所有可能残留在页面上的旧主体写法
LEGACY = {
    "legal_name": [r"旧主体简称", r"OldEntity Inc\.?"],
    "uscc": [r"91310000YYYYYYYYYY"],
}

SKIP_DIRS = {".git", "node_modules", "vendor"}


def iter_html(root: pathlib.Path):
    for p in root.rglob("*.html"):
        if SKIP_DIRS & set(p.parts):
            continue
        yield p


def scan() -> int:
    hit = 0
    for page in iter_html(ROOT):
        text = page.read_text(encoding="utf-8", errors="ignore")
        for field, patterns in LEGACY.items():
            for pat in patterns:
                for m in re.finditer(pat, text):
                    line = text.count("\n", 0, m.start()) + 1
                    print(f"{page}:{line}\t{field}\t命中: {m.group(0)} -> 应为 {CANON[field]}")
                    hit += 1
    return hit


if __name__ == "__main__":
    found = scan()
    print(f"\n共发现 {found} 处旧主体表述")
    sys.exit(1 if found else 0)

把它挂到 CI 上,退出码非 0 就阻断部署。这比"发个公告提醒运营改一下"有效得多——公告会被忘,CI 不会。

踩坑记录

  1. sitemap.xml 的 lastmod 全站自动刷新。 很多 CMS 每次构建把所有 URL 的 lastmod 设成构建时间。抓取方据此判断"这站天天在更新",实际上是零信息。正确做法是给 lastmod 取该 URL 内容的真实最后修改时间,构建脚本读 git log 或内容库的更新时间。
  2. 把承接声明塞进独立公告页。 上面提到过:详情页才是持续被抓的那个。公告页在发布三天后就掉出首页列表,客户和模型都到不了。
  3. 停售页面用了 noindex。 有人想减少"坏页面"占比,给停产页加 noindex。结果是模型抓不到"已停产"这个状态,反而继续把页面当在售商品用——因为第三方快照里的旧版还在流通。
  4. 对话/客服记录的处置没有书面留痕。 这一条超出代码范围但同样属于工程纪律:历史用户消息在新主体下的处置策略(删除/迁移/脱敏)要写成正式文档并由责任人签字。具体到个人信息保护法的适用,需要法务或执业律师的意见,工程师不要自己拍。

这套做法解决不了的部分

  • 救不了经营本身。 上述案例走向破产,起因是诉讼与监管调查,不是页面表述。
  • 约束不了交易对手。 页面上写谁接手,能不能约束买方,取决于交易文件,不取决于 HTTP 响应。
  • 覆盖不了第三方语料。 别人什么时候更新、更新到哪一版,是我们不可控的。我们只能保证自己的 origin server 给出的是当前真实状态。

顺带修正一处正在流传的技术解读:德国两起关于 AI Overviews 的案件,据 The Decoder 在 2026年10月19日的报道原文,慕尼黑一案以和解结案、上级法院未给出判定,亚琛一案为临时禁令且未终局。将这类未生效的地区法院说理当作通行规则写进文档,是我们自己也会踩的信息污染源。

适用边界

  • 适用:有稳定主体、有对外承诺、有产品 lineage 的站点。
  • 不适用:主体尚在注册或拆分过程中(还没东西可以核对);纯代工且无终端客户承诺;以及指望靠改页面改变第三方负面信源的——那是外联 + PR 的事,和 structured data 无关。

本文所有案例事实均来自公开报道的纯文字转述,不含链接。工程部分为通用做法,不含实测数据,未按任何具体业务的口径做过验证。第一次写这类维护笔记,欢迎在评论区补充你们踩过的坑。