Content-Signal:告诉 AI 它可以拿你的内容做什么

robots.txt 只回答一个问题,也从来只回答过这一个:你能不能抓取这个。逐条路径、逐个机器人,是或否。而大多数站长真正想表达的立场,它没有词汇可用:收录我、引用我、给我带读者,但别拿我写的东西去训练模型。

于是大家只好去拉唯一那根杆子。一个 Disallow 全部封死,训练没了,流量也跟着没了。

允许抓取不等于允许使用

这是两个不同的问题,只有一个跟你的带宽有关。有人问该买什么,爬虫读了你的定价页并把它引用出来,这是在帮你。同样这些字节被倒进训练集,则是另一桩完全不同的交易,而你不在其中。

全部封死会把两件事压成同一个「否」。对付费档案库来说也许没错。对一家想被找到、被推荐的公司来说,这是错误的默认:消失在答案里的是你,不是你的竞争对手。

Content-Signal 就是让你把两者拆开的那一层。

三个信号

Content-Signal: search=yes, ai-input=yes, ai-train=no
  • search:建立搜索索引并返回结果,也就是链接和短摘录。不包括 AI 生成的摘要,那是下一个信号的事。
  • ai-input:在作答的那一刻把你的页面喂给模型。RAG、grounding,以及生成答案下方列出的来源。
  • ai-train:用你的内容训练或微调模型。

三者互相独立。任何组合都合法,其中好几种是深思熟虑的立场,而不是配错了。

取值只有 yesno。没有 maybe,没有按路径的写法,也没有有效期。

漏写一个信号不等于 no。按照这套约定,你没有表态的用途既未授予也未限制,你只是没回答。我们的生成器每次都把三个都写出来,这是对的习惯,因为沉默是唯一一种没人能据以行事的回答。

写在哪里

两个地方,代价都很低。

写在 robots.txt 里,放进某个 user-agent 组内:

User-agent: *
Allow: /
Content-Signal: search=yes, ai-input=yes, ai-train=no

Sitemap: https://example.com/sitemap.xml

以及作为 HTTP 响应头:

Content-Signal: search=yes, ai-input=yes, ai-train=no

agentready.md 两处都提供。上面这个响应头会出现在每一次响应上:每个页面、每份 .md 版本、每次 API 调用。

nginx:

add_header Content-Signal "search=yes, ai-input=yes, ai-train=no" always;

Apache:

<IfModule mod_headers.c>
  Header set Content-Signal "search=yes, ai-input=yes, ai-train=no"
</IfModule>

响应头值得占这个位置。robots.txt 是偶尔到根目录去取的,而一个因为别人贴了链接而直接落在深层 URL 上的智能体,可能从头到尾都没读过它。响应头则跟着被取走的东西一起走。

还有 meta 标签的形式:<meta name="content-signal" content="search=yes, ai-input=yes, ai-train=no">。服务器配置不归你管时用它。响应头更好,因为它同样覆盖那些不是 HTML 的响应。

三个真实立场

想要署名的出版方。

Content-Signal: search=yes, ai-input=yes, ai-train=no

带着链接出现在答案里就是分发,相当于当下版本的「被引用」。训练是没人付钱的那部分,而且不会给你送回任何人。

想被推荐的 SaaS。

Content-Signal: search=yes, ai-input=yes, ai-train=yes

文档、定价、更新日志。有人问助手某件事该用什么,你想成为那个答案;而进入训练数据,正是模型什么都不抓取时你仍被点名的途径。这里没有什么要保护的,这些材料本身就是营销。

付费档案库。

Content-Signal: search=yes, ai-input=no, ai-train=no

你想被找到,因为搜索结果就是那句销售说辞。你不想要的,是文章的实质内容免费出现在别人的答案里。这正是信号能做而 Disallow 做不到的事:封掉抓取,会把你在搜索里的位置一并带走。

如果某个机器人该有不同条件,就给它单独一组:

User-agent: *
Allow: /
Content-Signal: search=yes, ai-input=yes, ai-train=no

User-agent: GPTBot
Allow: /
Content-Signal: search=yes, ai-input=yes, ai-train=yes

适用 robots.txt 一贯的优先规则:找到自己名字的机器人只读那一组,完全忽略 *

它到底是什么

一项年轻的约定。不是 RFC,不是 W3C 标准,也不是任何爬虫有义务遵守的东西。没有谁以你能据以主张的方式承诺过遵守。如果你读到 Content-Signal 能保护你的内容,那是广告。

那为什么还要写这一行。

因为机器能读,而且几乎不花成本:在一个你本来就在提供的文件里加一行,在一个你本来就有的配置块里加一个响应头。这套约定附带的前言,把 no 表述为依据欧盟 2019/790 指令第 4 条作出的明示权利保留,也就是文本与数据挖掘的退出声明。它在你所在的法域是否站得住脚,那是律师的问题;而一个你从未表达过的意愿,在哪里都站不住。

还因为它能说出 Disallow 根本没有词汇表达的意思。「别拿我训练」和「走开」是两句不同的话,而在此之前你只能发出后者。

确认你的确实送到了

curl -sI https://example.com/ | grep -i content-signal
curl -s https://example.com/robots.txt | grep -i content-signal

再拿第一条命令去试一个非首页的页面。如果响应头是写在某个 location 块里的,它覆盖的范围可能比你以为的小。

如果你在 CDN 后面,再加一条:

curl -sI https://example.com/robots.txt | grep -i "server\|cf-cache-status"

确认回来的 robots.txt 是你自己的。我们的源站连着好几个月返回 404,而 Cloudflare 在边缘用一份我们从未写过的托管策略文件作答,我们做的每一次检查都收到了看起来无比可信的 200

生成你的 Content-Signal · 生成你的 robots.txt