实测llms.txt新版发现规则与解析问题
文章解读llms.txt提案的修订,展示代理如何发现站点说明文件及Markdown内容,并报告参考解析器处理本站文件时崩溃。它强调该文件用于推理时的信息访问,仍属提案,不能替代robots.txt。
AI 深度解读
给网站放一份 llms.txt,Agent 就能找到并正确读取吗?这篇文章拆开了两个经常被混在一起的问题:2026 年 8 月的 v2 修订补上了发现路径,但仓库里的参考解析器,连作者网站和提案自己的文件都没能正确处理。
对维护文档站的前端和全栈开发者,这几分钟值得花。你能看懂如何通过响应头把页面、Markdown 和 llms.txt 连起来,也能知道为什么一份看起来正常的 Markdown,交给程序后可能直接报错。
v2 先解决了「从当前页面去哪找」
llms.txt 是给 Agent 准备的站点入口:用 Markdown 写清网站名称、简短介绍、补充信息,以及适合模型阅读的内容链接。Jeremy Howard 在 2024 年 9 月发布了最初提案,目前它仍然开放社区讨论,并非 W3C 或 IETF 标准。
它和 robots.txt 的职责不同。robots.txt 表达自动访问的许可边界;llms.txt 面向推理阶段,帮助正在替用户查资料的 Agent 找内容,不是训练用途的声明。
v2 的关键,是把「文件放在哪里」和「页面如何指向它」讲清楚了。
首先,llms.txt 可以放在任意路径。/docs/llms.txt 覆盖 /docs/ 下的内容;多个文件同时适用时,选择路径最具体的那个。因此,无法修改域名根目录的 GitHub Pages 项目站也能参与。
其次,Markdown 地址允许两种形式。v1 只支持追加 .md,例如 page.html.md;v2 也允许替换扩展名,得到 page.md。没有文件名的目录地址,则使用 index.html.md 或 index.md。
最后,页面可以通过链接关系明确声明两个入口:rel="alternate" 配合 type="text/markdown" 指向 Markdown,rel="describedby" 指向适用的 llms.txt。既可以写进 HTML 的 <head>,也可以放进 HTTP 响应头。
下面这条响应头同时告诉 Agent,当前页面的 Markdown 和站点说明文件在哪里:
Link: </docs/page.html.md>; rel="alternate"; type="text/markdown", </docs/llms.txt>; rel="describedby"
要看清两个 rel 各自对应的 URL,不能只声明其中一个,就以为两个入口都已经关联好了。
响应头的实用之处在于,可以从服务器或 CDN 配置统一添加,不必逐页修改 HTML,也能用于非 HTML 文件。不过,声明地址和生成内容是两件事:这些 URL 对应的文件仍然需要站点提供。
路径规则不复杂,但代码只验证了这些规则
作者用 Node 跑了两个函数:一个找出覆盖当前路径的 llms.txt,另一个生成 Markdown 地址。它们把提案中的路径规则变成了容易检查的程序行为:
// 覆盖当前路径的 llms.txt,路径最具体的排在前面。
function coveringLlms(path, files) {
return files
.filter(f => path.startsWith(f.slice(0, f.lastIndexOf('/') + 1)))
.sort((a, b) => b.length - a.length);
}
// page.html 转为 page.html.md(append)或 page.md(replace)。
function markdownUrl(path, mode) {
if (path.endsWith('/')) return path + (mode === 'append' ? 'index.html.md' : 'index.md');
return mode === 'append' ? path + '.md' : path.replace(/\.[^./]+$/, '') + '.md';
}
const files = ['/llms.txt', '/docs/llms.txt'];
coveringLlms('/docs/api/fetch.html', files); // ['/docs/llms.txt', '/llms.txt']
markdownUrl('/docs/api/fetch.html', 'replace'); // '/docs/api/fetch.md'
markdownUrl('/docs/', 'append'); // '/docs/index.html.md'
最关键的是 coveringLlms 最后的排序:它让 /docs/llms.txt 排在根目录文件之前。作者的演示里,取消 /docs/llms.txt 的存在状态后,文档页面就回退到 /llms.txt。
这里也有一个边界:files 是预先传入的文件列表。这段代码验证了匹配顺序和地址转换,没有实现网络请求,也没有证明某个真实 Agent 会按这套流程访问网站。
另外,v1 的上下文扩展工具已经从提案移除,## Optional 随之失去特殊处理含义。它现在只是次要链接的组织惯例,不能再据此假定工具会自动执行某种扩展逻辑。
人能读懂的 Markdown,解析器未必接受
提案希望 llms.txt 能被传统解析器和正则表达式固定处理,因此格式并非任意 Markdown:
先是网站名称的 H1,这也是唯一必需部分;然后是引用块形式的摘要;接着可以放没有标题的段落或列表;最后用 H2 划分章节,章节列表采用 [name](url),后面可以接冒号和说明。
作者检查了仓库中约 20 行的 llms_txt/miniparse.py,又做了一份逐行对应的 JavaScript 移植版。两者处理相同的 7 份文件时,结果完全一致,样本包含作者网站和提案自身的 llms.txt。
实际问题集中在几处:
- 章节内每个非空行都必须含有 Markdown 链接。纯 URL 列表项会触发
AttributeError;一个列表项折到下一行,也会因为逐行解析而报错。 - 多行引用摘要只保留第一行,后续引用行会被放进详细信息。
- 摘要后若直接进入第一个
##,解析结果的summary会是None,摘要内容反而进入info。提案仓库自己的文件也出现了这个问题。 - 如果第一个
##前只有 H1,解析器会抛出AttributeError;章节分割模式是^##,所以### Getting started也会被切成章节,名称变成# Getting started。
作者网站同时存在纯 URL 列表项和折行内容,因此解析失败。他给出的低成本修复是:每条链接独占一行,使用真正的 Markdown 链接,并在摘要后补一小段说明。
格式要求和参考实现的行为,需要分别检查。
例如,提案只要求 H1 必需,但参考解析器处理某些仅含 H1 的结构时会报错。不能把实现缺陷都解释成作者文件违反了规范。
我的判断
v2 最有价值的改动,是让页面能够明确指向自己的 Markdown 和 llms.txt。对于已有静态文档产物、能够配置响应头的团队,这个接入方式容易理解,也便于验证。
但文章没有提供 Agent 采用率、检索效果或回答质量的对照数据。文档平台会生成 llms.txt,AI 实验室会为自己的文档发布它,都不能证明你关心的 Agent 会读取它,更不能证明它是排名因素。
作者的实验可靠地展示了参考解析器的几个失败条件,结论范围也应停在这里。7 份文件不是整个生态的兼容性测试;纯 Markdown 阅读不受这些解析问题影响,也不代表所有消费工具都会宽容处理。
我的取舍是:把 llms.txt 当作额外的文档入口,配合现有 HTML 和 Markdown 使用。如果团队还没有稳定的文档生成流程,先做好内容可访问和链接有效,比追求文件存在更有用。至于「用了之后 AI 更容易推荐」,原文没有证据支持。
能拿来做什么
- 维护前端组件库或 SDK 文档时,先明确根目录与
/docs/各自覆盖什么内容,再检查页面是否指向最具体的 llms.txt,避免子项目落到无关的站点总入口。 - 使用 Node 构建文档时,统一选择
append或replace的 Markdown 地址策略,让产物路径与响应头保持一致,并实际请求这些地址确认可读。 - 已经发布 llms.txt 的团队,可以用参考解析器检查链接是否成功提取,重点排查纯 URL、列表折行和摘要后的结构;修复时也要分清规范要求与实现兼容问题。
- 日常使用 AI 编程工具查文档时,先确认目标工具是否明确支持 llms.txt;没有支持说明,就继续提供具体文档页或 Markdown 地址,不把入口文件当成自动生效的能力。