[控场AI]
· 7 分钟阅读· 3,727 字

llms.txt 日志分析:谁在真正读取?

llms.txt 日志分析:谁在真正读取?

用 Nginx 日志验证 llms.txt 是否被爬虫请求,并厘清其对 GEO 的有限意义。

文章介绍了一种不依赖第三方面板的验证方法:直接分析 Nginx 的 access.log,确认 llms.txt 与 llms-full.txt 是否真的被客户端请求。具体做法是用 grep 按路径过滤日志行,再用 awk 以双引号为分隔符提取 User-Agent 字段,经 sort/uniq 聚合后按 GPTBot、ClaudeBot、PerplexityBot、Googlebot 等家族分桶统计。作者强调这种日志取证的价值边界:日志只能证明某时某 IP 以自报 UA 请求了某 URL,无法证明身份真实、内容被存储、被训练或被引用,四层断层层层递减。因此对 GEO 政策执行情况只能做相关性观察,但 llms.txt 仍是声明机器可读偏好的实用入口,日志构成最基础的低技术反馈回路。

引言:llms.txt 的落地之问

llms.txt 和 llms-full.txt 作为面向大语言模型的站点声明文件,已经在不少站点上线。但一个更实际的问题随之而来:到底有没有客户端真的来请求它们? 技术博主 richardlemon 通过分析 Nginx 访问日志,给出了一个不依赖任何第三方面板的验证方法,并借此讨论了对 GEO(生成式引擎优化)的实际意义。

llms.txt 日志分析示意

日志取证:从 Nginx access.log 入手

在典型的 Nginx + VPS 环境中,访问日志通常位于 /var/log/nginx/access.log,并伴随轮转文件 access.log.1、access.log.2.gz 等。要验证 llms.txt 的访问情况,只需关注两个字段:请求路径和用户代理(User-Agent)。前者告诉你哪个文件被请求,后者告诉你来者是谁。

原文强调,这是一种“没有仪表盘、没有直觉”的原始取证方式——直接读日志,让事实说话。

Nginx combined 日志格式是 Nginx 默认的访问日志格式,每行由空格分隔但含引号字段的若干部分构成,典型形态为:$remote_addr - $remote_user [$time_local] "$request" $status $body_bytes_sent "$http_referer" "$http_user_agent"。理解其字段划分是解读日志的前提——由于 request、referer、user_agent 三项各自被双引号包裹且内部可能含空格,直接按空格切分会导致字段错位,正确做法是以双引号作为分隔符来定位字段。在此格式下,第 1 段是客户端 IP,第 2 段是请求行(含方法、路径、协议),第 3 段是状态码等信息,第 6 段即 User-Agent。这也解释了后文 awk 使用 -F '"' 而非默认空格分隔的原因。若站点使用自定义 log_format,字段位置会变化,分析前应先在 nginx.conf 中确认格式定义。

过滤与聚合:用 grep、awk 提取请求

第一步是把日志中涉及 llms.txt 和 llms-full.txt 的行单独提取出来:

cd /var/log/nginx
grep -hE "llms\.txt|llms-full\.txt" access.log* > llms-requests.log

其中 -h 隐藏文件名,-E 启用扩展正则,access.log* 覆盖当前及未压缩的轮转日志;若有 .gz 文件,可改用 zgrep。

第二步是从每行中提取 User-Agent 并统计频次。在标准 combined 日志格式中,User-Agent 是最后一个引号字符串(字段 6):

awk -F '"' '{print $6}' llms-requests.log \
  | sort | uniq -c | sort -nr > llms-user-agents.txt

这一步输出的是“谁请求了、请求了多少次”的原始清单。

分桶归类:识别 GPTBot、ClaudeBot 等主流爬虫

原始 UA 字符串杂乱,需要按已知爬虫家族分桶。原文列出的常见对象包括:

  • GPTBot(OpenAI)
  • ClaudeBot(Anthropic)
  • PerplexityBot
  • Googlebot(作为对照,并非同类 LLM 爬虫)
  • Other(浏览器、随机爬虫、SEO 工具等)

分类本身可以用一段 awk 完成:提取 UA 后,用不区分大小写的正则依次匹配关键字,默认归入 Other,最后 sort | uniq -c | sort -nr 得到各家族请求量排名。这个脚本可以定期运行,观察请求构成随时间的变化。

常见 LLM 爬虫 User-Agent 标识各有固定关键字,匹配时通常取 UA 字符串中的产品令牌即可:GPTBot 的 UA 形如 Mozilla/5.0 ... GPTBot/1.x,部分 OpenAI 抓取还使用 OAI-SearchBot、ChatGPT-User;ClaudeBot 对应 Anthropic 的抓取,另有 Claude-Web、anthropic-ai 等历史标识;PerplexityBot 属于 Perplexity 的索引爬虫,用户实时提问触发的抓取则可能显示 Perplexity-User;Googlebot 用于 Google 搜索索引,与 LLM 训练无关,仅作对照。此外还有 Bytespider(字节)、CCBot(Common Crawl,众多模型的语料来源)、Amazonbot、Applebot 等。分桶正则宜不区分大小写并覆盖这些变体,否则真实流量会被误归入 Other,低估实际关注度。

日志能证明什么,不能证明什么

这是原文最核心的警示。看到 GPTBot 请求了 llms.txt,很容易得出“我的内容已被用于训练”的结论,但日志并不支持这种跳跃。日志只能证明:在某个时间、某个 IP、某个自称特定 UA 的客户端请求了某个 URL 并得到了某个 HTTP 状态码。

具体来说,有几层断层:

  • 身份是自报的。UA 可以伪造,没有反向 DNS 和 IP 段校验,无法确认请求真来自 OpenAI 或 Anthropic。
  • 抓取不等于存储。爬虫可能只是读取 policy 后决定不抓或不保留内容,llms.txt 可能纯粹用作路由或过滤提示。
  • 存储不等于训练。缓存不代表进入训练集,厂商通常将抓取、索引、训练管线分离。
  • 训练不等于引用。即使内容进入训练集,也不保证在生成输出中被引用或展示。

所以“日志里有 GPTBot”是一个可观测事实,而“GPTBot 用我的内容训练”和“GPTBot 会引用我的内容”则是厂商侧的策略与实现细节,强度依次递减。

对 GEO 实践的真实含义

围绕 llms.txt 和 LLM 专属 robots 指令的讨论很多,但访问日志对 GEO 政策执行情况的说明力有限。

从日志可以稳妥地说:某爬虫家族似乎知晓 llms.txt 并会抓取;某爬虫从某些 IP 段以特定频率访问。但不能说:某厂商完全遵守了你的 GEO 指令;你的内容已被排除在所有地区的未来训练之外;修改 llms.txt 后会在某个具体日期全球生效。

充其量,你能做的是相关性观察:发布或修改 llms.txt,看到某 bot 来抓取,然后假设对方提及该文件的策略已经生效。真正的执行逻辑和时间线,掌握在别人的 API 和发布说明里。

仍然值得维护 llms.txt 的理由

尽管有上述局限,原文作者仍认为 llms.txt 和日志分析是有价值的:

  • 它们提供了一个清晰、机器可读的偏好声明位置。
  • 访问日志至少能验证部分爬虫在关注。
  • 当政策或厂商变化时,有一个具体文件可以更新,而不是猜测本月哪个 meta 标签或 header 起作用。

但不要把它当魔法。如果你关心内容在 LLM 中的使用方式,日志只是最基础的低技术反馈回路——它告诉你谁敲了门,却不告诉你数据离开服务器后发生了什么。

背景补充

GEO 与 llms.txt/robots 声明的关系需要厘清。GEO(Generative Engine Optimization,生成式引擎优化)指针对 ChatGPT、Perplexity、AI Overviews 等生成式检索系统优化内容的可见性,其目标是让内容更易被 AI 引擎抓取、理解并在回答中被引用,与传统 SEO 关注蓝链排名不同。llms.txt 是 2024 年提出的一种约定文件,以 Markdown 形式在站点根目录列出面向 LLM 的关键页面与摘要(llms-full.txt 则提供完整内容),供模型或代理高效获取站点结构;但它并非 W3C 或任何标准化组织的正式标准,主流厂商也未公开承诺遵守。传统 robots.txt 的 User-agent 段配合 Disallow 才是被广泛承认的抓取控制机制,而针对 LLM 的扩展指令(如禁止训练)同样缺乏强制约束力。因此 GEO 声明文件的实际效力,最终取决于各家爬虫是否主动读取并遵循,这也正是访问日志只能提供相关性证据、无法证明合规执行的根源。

#llms.txt#Nginx 日志分析#GPTBot#ClaudeBot#GEO#LLM 爬虫#访问日志
分享:

相关推荐