
# 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`**：用你的内容训练或微调模型。

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

取值只有 `yes` 和 `no`。没有 `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` 根本没有词汇表达的意思。「别拿我训练」和「走开」是两句不同的话，而在此之前你只能发出后者。

## 确认你的确实送到了

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

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

如果你在 CDN 后面，再加一条：

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

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

[生成你的 Content-Signal](/zh/tools/content-signal-generator) · [生成你的 robots.txt](/zh/tools/robots-txt-generator)
