从llms.txt到GEO:用Python实验验证生成引擎优化是否有效?

📅 发布时间:2026/10/12 6:32:27
从llms.txt到GEO:用Python实验验证生成引擎优化是否有效?
最近在翻一些个人站点的根目录时发现了一个很有意思的文件cats.txt。用cat命令打开后里面只有一句话llms.txt evidence is GEO astrology这句话初看像一句莫名其妙的玩梗但细想其实触及了当前 AI 搜索优化圈子里一个很核心的争议“给网站加了一个llms.txt文件就能证明你在做 GEO 了吗”在很多讨论里llms.txt被吹成了生成引擎时代的robots.txt好像只要放上这个文件AI 搜索引擎就一定会优先引用你的站点。但从工程角度看这种说法更像是一种“占星术式”的推断看到一个文件就脑补出了因果链缺少可验证的实验过程。本文就从cats.txt这个梗出发把llms.txt、GEO、以及“占星术式优化”这三个概念讲清楚并带大家写一套简单的 Python 实验用本地数据和代码判断llms.txt到底能不能作为 GEO 的证据以及我们应该用什么方法来验证一个 GEO 策略是否真的有效。如果你是网站开发者、SEO 从业者或者正在研究“怎么让大模型引用我的网站”这篇文章会比较适合你。读完后你不仅会知道llms.txt怎么写还会掌握一套可以复用到真实项目中的“GEO 假设验证”思路。1. 背景与核心概念1.1 从 cats.txt 说起cats.txt并不是什么技术标准文件它就是一个普通的纯文本文件。这次事件里作者把一段观点写在了cats.txt里再用“猫”这个无关联的名词命名明显是一种自嘲式的表达llms.txt的证据其实和占星术一样属于“信则有不信则无”。这个动作本身也揭示了一个现象现在不少人判断一个技术方案是否有效不是靠实验和统计而是靠“别人都在说有效”、“我加了之后好像有点用”这类主观感受。llms.txt的基础用法确实简单简单到只需要在网站根目录放一个 Markdown 文件。但“简单”不等于“有效”“有文件”也不等于“被生成引擎引用”。所以与其争论这句话对不对不如自己动手做一个对照实验。1.2 什么是 llms.txtllms.txt是由社区提出的一种站点级文本文件规范目标是给大语言模型提供“关于这个网站的结构化概述”。可以把它理解成一个面向 AI 助手的站点地图。robots.txt是告诉搜索引擎“哪些路径不能抓”sitemap.xml是告诉搜索引擎“我有哪些 URL”而llms.txt的思路更进一步直接用 Markdown 写清楚“这个网站是什么、有哪些重点内容、推荐访问哪些页面”。大模型如果读取了llms.txt就有机会在回答问题时引用站点信息。一个最简单的llms.txt大概长这样# 猫村小站 猫村小站是一个关于猫咪日常、养护与行为解读的中文科普站点。 ## 猫咪养护 - [猫咪饮食指南](cats.html) - [猫咪行为解读](cats.html) ## 关于本站 - [猫村小站介绍](index.html)这个文件解决了两个问题LLM 抓取网页时常常把 HTML 里的导航、广告、版权信息当成正文导致理解偏差llms.txt提供了干净的 Markdown 源。LLM 可能不知道一个网站内部有哪些重要页面llms.txt直接把链接和锚文本列出来相当于人工为 AI 划了重点。但请注意这个文件只是“提供了增强理解的可能性”并不等于“一定被读取”更不等于“一定带来流量”。这一点是后面所有实验的核心前提。1.3 什么是 GEOGEO 的全称是 Generative Engine Optimization中文常译作“生成引擎优化”。它和传统的 SEO 有一点核心区别SEO 优化的是“搜索结果页排名”目标是让用户点击链接GEO 优化的是“生成式回答中的引用率”目标是让大模型在生成答案时提到你、引用你甚至直接给出你的链接。例如用户问“猫咪软便应该怎么办”传统搜索引擎会返回一堆文章标题用户自己点进去而生成式引擎可能直接生成一段回答“根据猫村小站的文章猫咪软便首先要观察食欲其次要注意是否换粮过快……”在这个回答里“猫村小站”就是被引用了即使网页没有被点击也获得了品牌曝光。GEO 的常见手段包括提供干净的、可被机器阅读理解的内容。在页面中写清楚“是谁、在什么场景、解决什么问题”。使用结构化数据比如 JSON-LD。维护llms.txt、sitemap.xml等机器可读文件。让内容具备独立观点和可引用的事实。看起来llms.txt和 GEO 关系非常密切但这并不等于“有了llms.txt就有了 GEO 效果”。1.4 为什么说“GEO astrology”“astrology”就是占星术。占星术的特点不是“完全没道理”而是“永远无法证伪”无论发生什么事后都可以用星座运势圆回来。当一个人说“加了llms.txt后AI 搜索一定会引用我”这句话就具有占星术的特征如果可以引用他会说“你看有效吧”如果不能引用他会说“还没到时间或者你文件写得不对”。这种论证方式的根本问题是缺少一个可以重复验证的对照组。真正的工程思维应该是提出假设、设计实验、收集数据、得出结论。比如假设llms.txt能提升生成引擎对我站点摘要的引用率。实验准备两个相同内容的站点一个有llms.txt一个没有让同一个生成引擎分别回答同一组问题。数据统计 100 个查询中两个站点被引用的次数差异。结论如果差异显著再谈llms.txt的价值如果不显著则说明它只是一个锦上添花的文件而不是地理大发现。下面我们就照着这个流程做一次完整的实验。2. 环境准备与版本说明2.1 运行环境本文实验以 Python 为主只需要一个本地终端和一个文本编辑器。版本上不做严格要求建议使用 Python 3.10 以上版本避免旧版本语法上的小问题。如果系统里还没有 Python可以装一个比较新的稳定版本然后再创建虚拟环境。本实验会用到以下 Python 库markdown-it-py解析llms.txt中的 Markdown 文本。beautifulsoup4解析 HTML 页面提取正文。requests如果你不想用本地文件想看线上站点时可以用它请求llms.txt。安装命令如下mkdir geo-lab cd geo-lab python -m venv .venv source .venv/bin/activate # Windows 下执行 .venv\Scripts\activate pip install markdown-it-py beautifulsoup4 requests版本不需要刻意锁定安装最新版本即可。本文重点是代码思路不依赖某个特定版本特性。2.2 项目结构整个实验会维持下面这样的目录结构geo-lab/ ├── site/ │ ├── index.html │ ├── cats.html │ ├── cats.txt │ └── llms.txt ├── fetch_site.py └── mini_geo_engine.py其中site目录模拟一个极简的“猫村小站”fetch_site.py负责读取页面和llms.txt文件mini_geo_engine.py负责模拟一个最简单的生成引擎对比“有llms.txt”和“没有llms.txt”两种情况下引擎回答的差异。3. llms.txt 格式拆解3.1 文件放哪里llms.txt的约定位置是网站根目录。如果网站域名是https://example.com那么文件地址就是https://example.com/llms.txt这个位置和robots.txt、favicon.ico一样属于“约定优于配置”。生成引擎想找的时候会先尝试在根目录请求这个文件所以不建议放在子目录下。有些站点会做多语言也可以考虑为每个语言子站准备各自的llms.txt但要确保和实际部署路径一致。3.2 内容怎么写llms.txt的内容采用 Markdown 语法但建议保持简洁重点突出。常见结构如下# 站点名称 一句话或一段话介绍站点定位、目标用户、核心优势。 ## 分类一 - [页面标题](相对链接或绝对链接) - [页面标题](相对链接或绝对链接) ## 分类二 - [页面标题](相对链接或绝对链接)编写时有几个建议第一段不要写废话要让模型一眼看懂这个站点是什么。链接的锚文本要语义明确不要用“点击这里”“更多”这类模糊词。不要把所有 URL 都堆上去只列高价值页面。如果站点内容更新频繁要同步更新llms.txt。可以再看一个更完整的示例# 猫村小站 这里是猫村小站一个专门整理猫咪行为观察与家庭养护知识的中文内容站。适合养猫新手、猫行为研究爱好者以及宠物行业作者参考。 ## 猫咪养护 - [猫咪饮食指南](cats.html) - [猫咪软便的常见原因](cats.html) ## 猫咪行为 - [如何理解猫的呼噜声](cats.html) - [猫咪夜间跑酷怎么办](cats.html) ## 关于本站 - [猫村小站介绍](index.html)3.3 Python 如何解析可以用markdown-it-py把 Markdown 转成 HTML再用BeautifulSoup提取标题与链接下面先给出一个最简单的解析脚本骨架# 文件路径geo-lab/parse_llms.py from pathlib import Path from markdown_it import MarkdownIt from bs4 import BeautifulSoup def parse_llms(file_path): content Path(file_path).read_text(encodingutf-8) html MarkdownIt().render(content) soup BeautifulSoup(html, html.parser) title soup.find(h1).get_text(stripTrue) if soup.find(h1) else paragraphs [p.get_text(stripTrue) for p in soup.find_all(p)] links [{text: a.get_text(stripTrue), href: a.get(href)} for a in soup.find_all(a)] return { title: title, summary: .join(paragraphs), links: links, } if __name__ __main__: data parse_llms(site/llms.txt) print(data)这段代码并不复杂但它是后面实验的基础。通过解析我们可以从llms.txt里拿到站点的标题、摘要和推荐链接从而模拟“生成引擎已经理解了站点结构”的情况。4. 完整实战验证 llms.txt 对 GEO 的影响4.1 实验设计这次实验不调用任何大模型 API而是自己写一个极简的伪生成引擎。虽然它不会真的理解语义但它能体现两种信息获取路径的差异路径 A无llms.txt引擎只能从 HTML 页面里抓出p标签中的文字然后按关键词匹配拼接回答。路径 B有llms.txt引擎会先读取llms.txt得到站点摘要和推荐链接再结合对应页面拼出回答。变量只有一个是否提供llms.txt。查询词、页面内容、抓取逻辑完全一致。需要提前说明的是这个“伪生成引擎”的智能程度和商业产品差距很大它无法证明真实生成引擎的最终行为。但它的方法是有价值的你可以把同样的对比逻辑迁移到真实的搜索引擎或用本地模型复现而不是停留在“加个文件就有效”的感觉层面。4.2 搭建迷你猫站首先创建site/index.html!-- 文件路径geo-lab/site/index.html -- !DOCTYPE html html langzh-CN head meta charsetUTF-8 title猫村小站/title /head body article h1猫村小站/h1 p猫村小站是一个关于猫咪科普与日常养护的中文内容站。/p p我们关注猫咪饮食、行为、健康等多个方向适合养猫人和宠物行业读者。/p /article /body /html再创建site/cats.html!-- 文件路径geo-lab/site/cats.html -- !DOCTYPE html html langzh-CN head meta charsetUTF-8 title猫咪养护/title /head body article h1猫咪养护/h1 p猫咪换粮时需要逐步过渡不要一次全部替换否则容易出现软便。/p p观察猫咪喝水情况很重要很多泌尿问题都和饮水不足有关。/p p如果猫咪突然食欲下降需要先排除环境应激再考虑疾病因素。/p /article /body /html然后是site/llms.txt# 猫村小站 猫村小站是一个关于猫咪科普与日常养护的中文内容站适合养猫人和宠物行业读者参考。 ## 猫咪养护 - [猫咪养护指南](cats.html) ## 关于本站 - [猫村小站介绍](index.html)最后是那个自带梗的site/cats.txtllms.txt evidence is GEO astrology这个文件在实验中不参与实际逻辑只用于呼应标题。实验真正比较的是没有llms.txt时引擎能不能把“猫村小站”和“猫咪换粮”这类主题关联起来有llms.txt时引擎是不是更容易给出结构化推荐。4.3 抓取与解析脚本创建fetch_site.py# 文件路径geo-lab/fetch_site.py from pathlib import Path from bs4 import BeautifulSoup from markdown_it import MarkdownIt SITE_DIR Path(site) def load_page(filename): html (SITE_DIR / filename).read_text(encodingutf-8) soup BeautifulSoup(html, html.parser) title soup.title.get_text(stripTrue) if soup.title else filename article soup.find(article) or soup paragraphs [p.get_text(stripTrue) for p in article.find_all(p)] return { title: title, content: .join(paragraphs), } def load_llms(): path SITE_DIR / llms.txt if not path.exists(): return None text path.read_text(encodingutf-8) html MarkdownIt().render(text) soup BeautifulSoup(html, html.parser) title soup.find(h1).get_text(stripTrue) if soup.find(h1) else summary .join(p.get_text(stripTrue) for p in soup.find_all(p)) links [{text: a.get_text(stripTrue), href: a.get(href)} for a in soup.find_all(a)] return { title: title, summary: summary, links: links, }这段代码把“读页面”和“读 llms.txt”统一封装好。后面两个引擎模块都会用到它。4.4 无 llms.txt 的引擎回答创建mini_geo_engine.py先实现“无 llms.txt”的逻辑# 文件路径geo-lab/mini_geo_engine.py import re from fetch_site import load_page, load_llms PAGES [index.html, cats.html] def simple_keyword_score(content, query): score 0 for word in query.split(): score content.count(word) return score def answer_without_llms(query): best_page None best_score -1 for filename in PAGES: page load_page(filename) score simple_keyword_score(page[content], query) if score best_score: best_score score best_page page if best_page is None or best_score 0: return 抱歉我没有找到相关信息。 words best_page[content].split(。) answer 。.join(words[:2]) 。 return answer if __name__ __main__: print(answer_without_llms(猫咪换粮))运行一下python mini_geo_engine.py输出大致是猫咪换粮时需要逐步过渡不要一次全部替换否则容易出现软便。观察猫咪喝水情况很重要很多泌尿问题都和饮水不足有关。可以看到伪引擎确实能给出相关内容但它并不知道“猫村小站”这个站点的整体定位也不会推荐“关于本站”的页面。回答像一个从文章里摘出的碎句缺少站点品牌信息。4.5 有 llms.txt 的引擎回答然后在同一个文件里追加“有 llms.txt”的逻辑def answer_with_llms(query): llms load_llms() if llms is None: return answer_without_llms(query) parts [] # 先用 llms.txt 中的站点摘要作为背景 parts.append(llms[summary]) # 找出 llms.txt 中锚文本和查询词有关联的链接 related_links [] for link in llms[links]: if query in link[text] or query in link[href]: related_links.append(link) else: related_links.append(link) # 为了防止推荐列表太长只保留前两个 for link in related_links[:2]: page load_page(link[href]) sentence page[content].split(。)[0] 。 parts.append(f根据推荐页面《{page[title]}》{sentence}) return \n.join(parts) if __name__ __main__: print( 没有 llms.txt ) print(answer_without_llms(猫咪换粮)) print( 有 llms.txt ) print(answer_with_llms(猫咪换粮))上面的related_links逻辑故意写得很宽松目的是模拟“生成引擎把llms.txt当作索引后至少会把相关推荐页列出来”的情况。运行结果大致如下 没有 llms.txt 猫咪换粮时需要逐步过渡不要一次全部替换否则容易出现软便。观察猫咪喝水情况很重要很多泌尿问题都和饮水不足有关。 有 llms.txt 猫村小站是一个关于猫咪科普与日常养护的中文内容站适合养猫人和宠物行业读者参考。 根据推荐页面《猫咪养护》猫咪换粮时需要逐步过渡不要一次全部替换否则容易出现软便。对比之后能明显看到有llms.txt时回答里多出了“猫村小站”的品牌介绍和页面推荐。如果这个行为发生在真实的生成引擎里站点就获得了引用和曝光。4.6 结果对比与分析把两种回答放到一起比较可以看到llms.txt的价值点维度无 llms.txt有 llms.txt是否包含网站品牌名未出现出现在摘要中是否主动推荐页面不会会按链接推荐回答结构直接拼接正文先背景后推荐结构更完整数据来源页面正文页面正文 站点索引但这里必须再强调一次这个实验只证明了“如果生成引擎读取了 llms.txt它有可能会引用站点”。它没有证明“所有生成引擎都会读取 llms.txt”。真实世界里的生成引擎有各自不同的爬虫策略、索引策略和答案生成策略llms.txt可能只是其中一个很小的信号。所以正确的结论是llms.txt可以作为增强被引用概率的“基础设施”但它不是 GEO 的银弹。如果有人说“我加了 llms.txt所以我在做 GEO”这和说“我看到了一个星座特征所以今天会有好运”没有本质区别。要用数据验证就得把实验放到真实环境中统计 AI 引用率、推荐点击率、品牌提及次数等指标。5. 常见问题与排查思路5.1 问题现象表问题现象常见原因解决思路访问https://你的域名/llms.txt返回 404文件没有放到站点根目录或静态文件服务未配置确认文件在 web 根目录检查 Nginx/Apache 是否允许访问.txt文件中文内容乱码文件编码不是 UTF-8或响应头缺少charsetutf-8统一保存为 UTF-8 编码服务器配置中设置正确的 charset生成引擎不读取llms.txt当前生成引擎还没有支持该规范或需要先通过站点验证查阅引擎官方文档暂时继续使用sitemap.xml和结构化数据添加llms.txt后没有变化页面内容本身质量不足或引擎索引周期较长提升内容深度与差异性同时观察至少一到两周本地模型实验时内存不足模型参数量过大换成更小的量化模型或使用云 APIBeautifulSoup解析不到页面内容HTML 结构不是标准的article改用main、body等选择器或先查看页面结构再写解析规则5.2 一个较难排查的案例如果你已经确认llms.txt放在正确位置内容也很规范但线上大模型回答里始终不引用你可以先按下面的顺序排查用curl直接请求llms.txt确认文件可以被访问。用搜索引擎的“抓取测试”或站点日志观察确认生成引擎爬虫有没有抓取这个文件。换一个查询词比如把你最核心的领域词放到问题里看大模型是否会有反应。有时候不是文件没生效而是问题太冷门。检查llms.txt里的链接是否用的是相对路径。如果生成引擎不在你的域名下解析相对路径可能失效。建议改成绝对链接或者确保生成引擎能正确处理相对路径。确认页面本身能被正常访问没有被robots.txt屏蔽也没有被加密墙挡住。这些排查步骤的核心思路是一样的把“看不见的生成引擎”当成一个普通用户看看它到底能拿到什么、能理解什么。如果不确定就一步步缩小问题范围。6. 最佳实践与工程建议6.1 把 llms.txt 当成“站点导游”而不是 SEO 外挂很多人在写llms.txt时会不自觉地把所有 URL 都堆进去觉得链接越多越有效。这其实是把llms.txt当成了sitemap.xml。更好的做法是把它当成一个“站点导游”先介绍你是谁再把你最想让 AI 知道的几个页面列出来。这样既方便生成引擎理解也不会因为文件过于冗长而让重要信息被淹没。同时建议把llms.txt纳入站点版本管理。它可以像代码一样被 review、被测试。每次内容大改之后都要同步检查llms.txt里的站点摘要和推荐链接是否还准确。6.2 建立 GEO 可衡量的指标体系如果你真的想把 GEO 做成一项可以持续优化的工程建议先定义指标。常见的指标包括AI 引用率在设定好的测试问题集合中AI 回答里出现你站点名称的频率。品牌提及率回答中是否提到你的品牌或域名。推荐点击率用户看到 AI 回答后是否点击了你的链接。转化率从 AI 搜索进入页面后用户是否完成了注册、购买、阅读等动作。曝光位置当你的站点被引用时它出现在回答的前半段还是后半段。有了指标就可以做 A/B 实验。例如先保持页面内容不变分别测试“有 llms.txt”和“没有 llms.txt”两个版本每个版本跑一周收集 100 个以上的测试问题再对比引用率差异。注意不要在同一天频繁切换版本因为搜索引擎和生成引擎都有缓存短时间切换容易污染数据。6.3 安全与维护把llms.txt放在根目录相当于主动向所有 AI 爬虫公开了站点摘要。因此要注意安全边界不要在里面写内部 API 地址、数据库连接串、后台路径。不要把未发布的文章、隐私政策之外的私人信息放进推荐链接。如果某些页面只面向登录用户不要把它们写进llms.txt。如果站点有临时活动页活动结束后要及时从llms.txt移除避免生成引擎持续引用一个已经下线的页面。另外llms.txt不应该替代robots.txt和sitemap.xml。三者各司其职robots.txt管抓取边界sitemap.xml管 URL 发现llms.txt管内容理解。不要为了追求“新规范”而忽略传统 SEO 基础设施。7. 从实验到结论把 GEO 做成一门可检验的工程回到标题里的cats.txt。它一句话质疑了“把 llms.txt 当成 GEO 证据”的做法而我们在本文里做了一次小实验通过一个极简的伪生成引擎看到了llms.txt在“信息组织和推荐表达”上的作用也看到了它的局限。llms.txt不是没有价值它的价值是“让生成引擎更容易理解你的站点”。这种价值需要建立在两个前提之上生成引擎确实读取并信任这个文件。你的页面内容本身具备被引用的价值。如果只做了第一个前提却忽略了第二个那确实容易陷入“GEO 占星术”的陷阱。真正可靠的优化路径是不断用数据验证自己的假设。你可以先仿照本文搭建一个本地实验环境再逐步扩展到真实搜索流量分析、AI 引用监测和指标看板。把cats.txt这句话当作一个提醒不要让一个简单的文件成为你停止思考的借口。下一步可以尝试的事情很简单打开你的项目目录创建一份llms.txt再用自己真实的页面内容和查询词跑一遍同样的对照实验。如果实验效果符合预期再去设置流量统计和 AI 引用监测如果效果不明显那就回头优化内容。动手实践永远比争论“有效还是无效”更有价值。