Skip to content

Commit 410b8de

Browse files
fix: CR 反馈 —— 补全训练型 UA 断言,注释按 CLAUDE.md §3 收敛
tests/robots.test.ts 原来只断言 5 个训练型 UA,而策略里有 12 个: 从 AI_TRAINING_CRAWLERS 删掉没被断言的那几个,测试照样绿,等于白守。 补全成 12 个(新增不用同步,放宽是安全方向)。变异验证过:删掉 Applebot-Extended 会红,还原后绿。 注释违反 CLAUDE.md §3「严禁历史叙事 / 大段 docstring 描述功能」: 删掉 public/robots.txt 的来龙去脉、doc-entry 的抽取过程、force-static 里那段 Vercel CPU 往事,只留维护时会踩的不变量 —— UA 专属组整体覆盖 `*` 不叠加(所以不给引用型开 Allow 组)、不要 import @/lib/source (会拖进 MDX 管线让 vitest 挂)、sitemap 与 llms.txt 的过滤必须同进同退。 Co-authored-by: copilot-pull-request-reviewer[bot] <198982749+copilot-pull-request-reviewer[bot]@users.noreply.github.com>
1 parent 3518d8b commit 410b8de

5 files changed

Lines changed: 27 additions & 43 deletions

File tree

‎app/llms.txt/route.ts‎

Lines changed: 3 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -3,14 +3,10 @@
33
/**
44
* @file app/llms.txt/route.ts
55
* @description
6-
* `/llms.txt` 路由(llmstxt.org 约定)。AI 引擎抓站时先读它拿全站索引。
6+
* `/llms.txt` 路由(llmstxt.org 约定)。
77
*
8-
* 为什么是 route handler 而不是 public/llms.txt:文档是 MDX,会增删改,
9-
* 手维护一份静态索引必然过期。这里从 `source` 现枚举,和 sitemap 同源。
10-
*
11-
* force-static:内容全部来自构建期的 MDX,没有请求相关的东西,
12-
* 构建时产出一次即可,别让它变成每次请求现算的 dynamic 路由
13-
* (i18n/routing.ts 文件头记着上次全站 dynamic 把 Vercel CPU 打爆的事)。
8+
* force-static 是必需的,不是优化:内容只依赖构建期的 MDX,漏了它这条路由
9+
* 会退化成每次请求现枚举全站文档的 dynamic 路由。
1410
*
1511
* @see https://llmstxt.org
1612
*/

‎app/robots.ts‎

Lines changed: 7 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -19,20 +19,8 @@
1919
* sitemap 指向 app/sitemap.ts 产出的 /sitemap.xml,hostname 复用同一份
2020
* NEXT_PUBLIC_SITE_URL。
2121
*
22-
* AI 爬虫策略(2026-08):按用途分开,不是一刀切。
23-
*
24-
* - **引用型**(OAI-SearchBot、ChatGPT-User、Claude-User、PerplexityBot…):
25-
* 用户实时提问时才来抓,抓完在回答里附出处链接。本站要的就是被引用,
26-
* 所以放行 —— 走上面的 `*` 组即可,**不单独开组**。robots.txt 里 UA 专属
27-
* 组会整体覆盖 `*` 而不是叠加,给它们开组就得把 admin/editor 那串 disallow
28-
* 再抄一遍,抄漏一条就等于把后台开放给它们。少写一组反而更安全。
29-
*
30-
* - **训练型**(见 AI_TRAINING_CRAWLERS):把正文收进训练语料,不产生任何
31-
* 回链。内容是 CC BY-NC-SA,整站 disallow。
32-
*
33-
* 这份策略取代了 public/robots.txt —— 那份手写文件把两类一起屏蔽,而且
34-
* 早就不生效了:App Router 下 app/robots.ts 才是线上实际服务的 /robots.txt,
35-
* 那份文件被静默遮蔽,读代码的人却会以为 AI 爬虫已经被挡住了。已删除。
22+
* AI 爬虫按用途分:引用型(实时取用并附出处链接)放行,训练型(收进语料、
23+
* 不给回链)整站 disallow —— 内容是 CC BY-NC-SA。
3624
*
3725
* @see https://nextjs.org/docs/app/api-reference/file-conventions/robots
3826
*/
@@ -55,10 +43,12 @@ const PRIVATE_PATHS = [
5543
];
5644

5745
/**
58-
* 训练语料型爬虫:只取内容不给回链,整站 disallow。
46+
* 训练语料型爬虫,整站 disallow。
5947
*
60-
* 刻意不含 ChatGPT-User / Claude-User / OAI-SearchBot / PerplexityBot ——
61-
* 那几个是用户提问时实时取用并产生引用的,属于放行的一侧(见文件头)。
48+
* 刻意不含 OAI-SearchBot / ChatGPT-User / Claude-User / PerplexityBot:
49+
* 它们靠 `*` 组放行就够了。**不要**为它们再开一个 Allow 组 —— robots.txt 里
50+
* UA 专属组整体覆盖 `*` 而不是叠加,开了就得把 PRIVATE_PATHS 再抄一遍,
51+
* 抄漏一条等于把后台放给它们。
6252
*/
6353
const AI_TRAINING_CRAWLERS = [
6454
"GPTBot", // OpenAI 训练语料

‎lib/doc-entry.ts‎

Lines changed: 3 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -3,16 +3,11 @@
33
/**
44
* @file lib/doc-entry.ts
55
* @description
6-
* 文档页 → URL / 可见性的共享判定。
7-
*
8-
* 原来这两个函数是 `app/sitemap.ts` 的私有函数。`app/llms.txt/route.ts`
9-
* 要枚举同一批文档,如果各写一份,早晚会出现「sitemap 过滤了 draft、
10-
* llms.txt 没过滤」这种单边漂移 —— 草稿泄漏给 AI 引擎和泄漏给搜索引擎
11-
* 一样糟。抽到这里,两边共用一份,理由同 `lib/site-url.ts` 文件头。
6+
* sitemap 与 llms.txt 共用的文档过滤 / URL 编码,两边必须同进同退:
7+
* 只有一边过滤 draft 的话,草稿会静默泄漏给另一边的抓取方。
128
*
139
* 刻意不 import `@/lib/source`:那条链会把整个 fumadocs-mdx 管线拖进来,
14-
* vitest 没配 MDX 插件会直接 parse 失败。入参用结构化的宽类型,
15-
* 让本文件保持纯函数、可单测。
10+
* vitest 没配 MDX 插件会直接 parse 失败。入参因此用结构化宽类型。
1611
*/
1712

1813
import type { PageData } from "@/app/types/doc";

‎lib/llms-txt.ts‎

Lines changed: 4 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -3,17 +3,11 @@
33
/**
44
* @file lib/llms-txt.ts
55
* @description
6-
* `/llms.txt` 正文生成器(llmstxt.org 约定)。
6+
* `/llms.txt` 正文生成器(llmstxt.org 约定)。只出索引不出全文 —— 三百多篇
7+
* 正文拼进去是几 MB,会挤爆它本来要省的上下文。
78
*
8-
* 干什么用:AI 引擎(ChatGPT / Perplexity / Claude 等)抓站时先看这个文件,
9-
* 拿到一份无导航噪音的全站索引,再决定深入读哪几篇。sitemap.xml 只有 URL,
10-
* 模型得逐个抓才知道讲什么;llms.txt 一次给全 标题 + 描述 + 链接。
11-
*
12-
* 只做索引不做全文:站内 152 篇中文 + 152 篇英文,全文拼进去是几 MB,
13-
* 反而挤爆上下文。约定本身也是「索引 + 链接」。
14-
*
15-
* 纯函数,不 import `@/lib/source`(那条链会拖进 fumadocs-mdx 管线,
16-
* vitest 起不来)。枚举文档的活儿在 `app/llms.txt/route.ts` 里干。
9+
* 不 import `@/lib/source`:那条链会拖进 fumadocs-mdx 管线,vitest 起不来。
10+
* 枚举文档在 `app/llms.txt/route.ts`,这里保持纯函数。
1711
*/
1812

1913
export interface LlmsTxtEntry {

‎tests/robots.test.ts‎

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,13 +24,22 @@ describe("robots", () => {
2424
expect(wildcard.disallow).toContain("/*/editor/");
2525
});
2626

27+
// 列全当前策略里的每一个训练型 UA:少列几个的话,从 app/robots.ts 删掉
28+
// 没列到的那些测试照样绿,等于白守。新增不用同步(放宽是安全方向)。
2729
it("训练型爬虫整站 disallow", () => {
2830
for (const ua of [
2931
"GPTBot",
3032
"ClaudeBot",
33+
"anthropic-ai",
3134
"Google-Extended",
32-
"CCBot",
35+
"Applebot-Extended",
36+
"meta-externalagent",
37+
"FacebookBot",
3338
"Bytespider",
39+
"Amazonbot",
40+
"CCBot",
41+
"Omgilibot",
42+
"DataForSeoBot",
3443
]) {
3544
expect(blockedAgents).toContain(ua);
3645
}

0 commit comments

Comments
 (0)