AI 搜索正在悄悄改变流量的分配方式,很多站长发现自己的页面在传统搜索引擎里排名不错,但在 AI 搜索的引用来源里却几乎不出现。这不是玄学,而是 AI 搜索在抓取、解析、引用网页时有一套自己的偏好和门槛。GEO(Generative Engine Optimization,生成式引擎优化)要解决的就是这个问题:让 AI 搜索愿意抓你的页面、看得懂你的内容、并且在生成答案时把你列为引用来源。这篇内容面向有基础建站能力的开发者、SEO 从业者和内容运营,从抓取通道、内容结构、代码层面的可控项三个方向拆解,给出可以直接落地的配置和写法。读完你能自己排查"为什么 AI 不引用我",并且用代码把能改的部分改掉。
1. 先搞清楚 AI 搜索引用一个网页要过哪几道关
很多人把 GEO 理解成"再写一遍 SEO",这个理解会带偏方向。传统搜索的核心动作是"排序 + 展示链接",AI 搜索的核心动作是"抓取 + 理解 + 抽取 + 生成引用"。中间多了理解和抽取两步,这两步决定了你的页面即使被抓到,也可能因为"读不懂"或"抽不出干净片段"而被跳过。
1.1 抓取关:AI 爬虫到底来不来
AI 搜索的抓取来源通常分两类。一类是搜索引擎自带的爬虫,它同时服务于传统结果和 AI 结果;另一类是各家 AI 产品自己的抓取器,专门为训练和实时检索服务。这两类爬虫的 UA(User-Agent)不同,遵守的规则文件也可能不同。
问题就出在这里:很多站点的 robots.txt 只针对传统爬虫做了放行,对 AI 类爬虫要么没写规则(默认放行,但有些站点用了通配符封禁导致误伤),要么直接一刀切全站禁止。你可以在服务器访问日志里按 UA 关键字过滤,看看最近 30 天有没有 AI 类爬虫的访问记录。如果一条都没有,那"不被引用"的原因就很直接了——它根本没进来。
注意:robots.txt 是"请求遵守"机制,不是强制拦截。但主流合规爬虫都会遵守,所以配置错误会直接导致抓取被拒。
1.2 理解关:页面能不能被解析成结构化语义
爬虫拿到 HTML 之后,要把它转成可理解的内容块。这一步对页面的要求比传统 SEO 高得多。传统 SEO 时代,你把关键词堆在正文里就有机会;AI 时代,它需要知道"这段话在回答什么问题""这个列表是不是步骤""这个表格是不是参数对比"。
如果你的正文全部塞在一个巨大的 div 里,没有语义标签,没有清晰的标题层级,AI 在抽取时就会犹豫。它宁可引用一个结构清晰的小页面,也不愿意从一个语义混乱的大页面里猜内容。这就是为什么很多"内容更多"的站点反而竞争不过结构规整的小站。
1.3 抽取关:有没有可以被独立引用的片段
AI 生成答案时,通常不是整页引用,而是抽取一个段落、一个列表或一个定义。如果你的核心结论散落在三千字的长文里,没有独立成段,没有小标题引导,抽取难度就会上升。
一个实用的判断标准:把你页面里每个 H2 下面的第一段单独拿出来,看它能不能独立回答一个问题。如果能,它被引用的概率就高;如果拿出来的段落全是"如前所述""接下来我们看",那基本不会被选中。
1.4 引用关:可信度和时效性信号
AI 搜索在决定引用谁时,会参考页面的可信度信号:是否有明确的作者信息、是否有更新时间、是否有外部引用、域名是否稳定。这些信号传统 SEO 也看,但 AI 搜索对"时效性"更敏感,因为生成式答案需要新鲜内容支撑。
把这几关串起来看,GEO 的抓手就很清楚了:抓取关靠 robots.txt 和站点可达性,理解关靠语义化 HTML 和结构化数据,抽取关靠内容组织方式,引用关靠可信度信号。下面几节逐个拆。
2. robots.txt 里针对 AI 爬虫的放行与封禁怎么写才不出错
robots.txt 是 GEO 的第一道门,也是最容易配错的地方。配错有两种极端:一种是全站封禁导致 AI 爬虫进不来,另一种是无差别全放行导致内容被低质量抓取。正确的做法是按爬虫类型分组管理。
2.1 先确认你的 robots.txt 有没有误伤
最常见的误伤写法是这样的:
User-agent: * Disallow: /这行配置的意思是"所有爬虫禁止抓取全站"。有些站点在测试环境遗留了这条规则,上线时忘了删,结果所有爬虫都被挡在门外。排查方法很简单,直接在浏览器访问你的域名/robots.txt,看第一段规则。
还有一种隐蔽的误伤:用通配符封禁了某个目录,结果 AI 爬虫需要的静态资源也在里面。比如:
User-agent: * Disallow: /assets/如果 AI 爬虫需要读取页面里的结构化数据文件,而它放在 /assets/ 下,就会被一起挡掉。
2.2 按爬虫分组放行的推荐写法
下面是一份可以直接参考的模板,把主流 AI 类爬虫单独分组放行,同时保留对恶意爬虫的限制:
# 传统搜索引擎爬虫 User-agent: Googlebot Allow: / User-agent: Bingbot Allow: / # AI 搜索与训练类爬虫(按需放行) User-agent: GPTBot Allow: / User-agent: ChatGPT-User Allow: / User-agent: ClaudeBot Allow: / User-agent: PerplexityBot Allow: / User-agent: Google-Extended Allow: / # 默认规则 User-agent: * Disallow: /admin/ Disallow: /api/private/ Allow: / # 站点地图 Sitemap: https://你的域名/sitemap.xml这份配置的逻辑是:先给已知的 AI 爬虫明确放行,再用默认规则兜底。注意Google-Extended这个 UA 控制的是内容是否可用于生成式 AI 场景,如果你希望内容被 AI 搜索引用,需要显式 Allow。
2.3 什么情况下应该封禁而不是放行
不是所有站点都适合全放行。以下几种情况建议谨慎:
- 付费内容或会员专属内容,不希望被 AI 抓取后免费呈现
- 大量用户生成内容(UGC)且质量不可控,抓取后可能影响品牌
- 站点带宽有限,AI 爬虫高频抓取会造成压力
封禁的写法要精确到目录,不要用全站 Disallow:
User-agent: GPTBot Disallow: /premium/ Disallow: /user-content/ Allow: /这样既保护了敏感目录,又保留了公开内容的可抓取性。
2.4 验证配置是否生效
改完 robots.txt 后,不要凭感觉判断。用两种方式验证:
- 在服务器日志里按 UA 过滤,观察 24 到 72 小时内 AI 爬虫的访问记录是否出现
- 用各搜索引擎官方提供的 robots.txt 测试工具(如果有)检查语法
日志过滤命令示例(Nginx 环境):
grep -i "GPTBot\|ClaudeBot\|PerplexityBot" /var/log/nginx/access.log | awk '{print $1, $12, $7}' | sort | uniq -c | sort -rn | head -50这条命令会统计最近日志里 AI 爬虫的访问次数、UA 和请求路径,能直观看出哪些页面被抓了、哪些没被抓。
3. llms.txt:给 AI 搜索准备一份"内容说明书"
llms.txt 是这两年随着 AI 搜索兴起的一个约定文件,放在站点根目录,用来告诉 AI 系统"我这个站有哪些核心内容、分别是什么、推荐优先读哪些"。它不是强制标准,但越来越多的 AI 抓取器开始识别它。
3.1 llms.txt 和 sitemap.xml 的区别
很多人会问:已经有 sitemap.xml 了,为什么还要 llms.txt?两者定位不同。
| 对比项 | sitemap.xml | llms.txt |
|---|---|---|
| 主要用途 | 告诉爬虫有哪些 URL | 告诉 AI 有哪些内容及其语义 |
| 内容形式 | URL 列表 + 更新时间 | Markdown 格式的说明 + 链接 |
| 面向对象 | 传统搜索引擎爬虫 | AI 抓取与理解系统 |
| 是否含描述 | 通常不含 | 含简短描述,帮助理解 |
| 优先级表达 | priority 字段(已弱化) | 通过排序和分组表达 |
简单说,sitemap 是"清单",llms.txt 是"导读"。AI 系统读 llms.txt 能更快判断你的站点主题和内容质量。
3.2 llms.txt 的完整写法
llms.txt 用 Markdown 格式书写,结构上分三部分:站点说明、核心内容分组、可选补充。
# 站点名称 > 一句话说明这个站点是做什么的,面向谁。 补充说明:这个站点的核心内容领域、更新频率、内容特点。 ## 核心内容 - [文章标题一](https://你的域名/url-1):一句话描述这篇内容解决什么问题 - [文章标题二](https://你的域名/url-2):一句话描述这篇内容解决什么问题 - [文章标题三](https://你的域名/url-3):一句话描述这篇内容解决什么问题 ## 工具与资源 - [工具页面](https://你的域名/tools):说明这个工具能做什么 - [文档中心](https://你的域名/docs):说明文档覆盖的范围 ## 可选 - [关于我们](https://你的域名/about):团队与背景说明几个写法要点:
- 第一行
# 站点名称是必须的,AI 系统靠它识别站点身份 >引用块用来写一句话简介,这是被引用频率最高的部分- 每个链接后面跟一句描述,描述要具体,不要写"点击查看"这种废话
- 分组用 H2,组内用无序列表,结构越清晰越好
3.3 让 llms.txt 真正被读到的几个细节
写完文件只是第一步,还要确保它能被访问到:
- 文件必须放在站点根目录,路径是
https://你的域名/llms.txt - 返回状态码必须是 200,不能是 301 跳转或 403
- Content-Type 建议设为
text/plain; charset=utf-8 - 在 robots.txt 里显式放行这个文件
验证命令:
curl -I https://你的域名/llms.txt看返回头里的状态码和 Content-Type 是否符合预期。
提示:llms.txt 目前不是所有 AI 系统都支持,但配置成本极低,属于"配了不亏"的项。建议和 sitemap.xml 一起维护。
3.4 内容更新后 llms.txt 怎么同步
llms.txt 里的链接和描述需要跟着内容更新。手动维护容易漏,建议用脚本生成。下面是一个 Python 示例,从文章目录读取元数据生成 llms.txt:
import os import re def generate_llms_txt(content_dir, output_path, site_name, site_desc, base_url): articles = [] for filename in sorted(os.listdir(content_dir)): if not filename.endswith('.md'): continue filepath = os.path.join(content_dir, filename) with open(filepath, 'r', encoding='utf-8') as f: content = f.read() # 提取标题和描述(假设 front matter 里有 title 和 description) title_match = re.search(r'title:\s*(.+)', content) desc_match = re.search(r'description:\s*(.+)', content) if title_match: title = title_match.group(1).strip() desc = desc_match.group(1).strip() if desc_match else '' slug = filename.replace('.md', '') articles.append((title, f"{base_url}/{slug}", desc)) lines = [f"# {site_name}", "", f"> {site_desc}", "", "## 核心内容", ""] for title, url, desc in articles: lines.append(f"- [{title}]({url}):{desc}") lines.append("") with open(output_path, 'w', encoding='utf-8') as f: f.write('\n'.join(lines)) generate_llms_txt('./content', './public/llms.txt', '我的站点', '专注 GEO 与 AI 搜索优化', 'https://你的域名')这个脚本每次内容更新后跑一遍,llms.txt 就自动同步了。
4. 页面结构层面:让 AI 能"读懂"并"抽走"你的内容
robots.txt 和 llms.txt 解决的是"进得来"的问题,页面结构解决的是"读得懂、抽得走"的问题。这一节是 GEO 里最需要动手改代码的部分。
4.1 语义化 HTML 是基础,不是可选项
AI 解析页面时,优先依赖语义标签。下面这些标签的使用直接影响理解效果:
<article>包裹正文主体<section>划分内容区块<h1>到<h3>建立清晰的层级<ul>/<ol>表达列表和步骤<table>表达对比和参数<time>标注发布时间和更新时间
一个常见的错误是:用<div class="title">代替<h2>,用<div class="list-item">代替<li>。视觉上看起来一样,但 AI 解析时拿不到结构信息。
改造前后的对比:
<!-- 改造前:语义缺失 --> <div class="post"> <div class="title">如何配置 robots.txt</div> <div class="content"> <div class="item">第一步:打开文件</div> <div class="item">第二步:添加规则</div> </div> </div> <!-- 改造后:语义清晰 --> <article> <h1>如何配置 robots.txt</h1> <section> <h2>配置步骤</h2> <ol> <li>打开文件</li> <li>添加规则</li> </ol> </section> </article>改造后,AI 能明确知道这是一个文章、有一个 H1、有一个步骤列表。
4.2 结构化数据:给 AI 一份机器可读的摘要
除了语义 HTML,还可以用 JSON-LD 格式的结构化数据,把页面的核心信息显式声明出来。AI 系统对结构化数据的解析准确率远高于纯文本。
一篇教程类文章的 JSON-LD 示例:
<script type="application/ld+json"> { "@context": "https://schema.org", "@type": "HowTo", "name": "如何配置 robots.txt 放行 AI 爬虫", "description": "针对 AI 搜索爬虫的 robots.txt 配置方法,包含分组放行和验证步骤。", "datePublished": "2025-01-15", "dateModified": "2025-03-20", "author": { "@type": "Person", "name": "作者名" }, "step": [ { "@type": "HowToStep", "name": "确认现有配置", "text": "访问站点根目录的 robots.txt,检查是否有全站封禁规则。" }, { "@type": "HowToStep", "name": "添加 AI 爬虫放行规则", "text": "按爬虫 UA 分组,为 GPTBot、ClaudeBot 等添加 Allow 规则。" }, { "@type": "HowToStep", "name": "验证生效", "text": "通过服务器日志过滤 AI 爬虫 UA,观察访问记录。" } ] } </script>这段结构化数据把"这是什么内容、谁写的、什么时候更新、分几步"全部声明清楚。AI 在抽取时可以直接读取,不需要猜。
4.3 内容块的"自包含"写法
前面提到,AI 倾向于抽取能独立成段的片段。所以每个 H2 下面的第一段,最好能独立回答一个小问题。具体写法上:
- 每个 H2 下面第一段直接给结论,不要铺垫
- 每个列表项尽量完整,不要依赖上下文才能理解
- 关键定义单独成段,用加粗标出核心词
- 避免"如上所述""接下来"这类依赖上下文的指代
举个例子,下面这段就不适合被抽取:
前面我们讲了抓取的问题,接下来看看理解层面的问题。这个问题其实也很关键,因为……
改成自包含写法:
AI 搜索理解页面时依赖语义标签。如果正文全部用 div 包裹,没有 h1 到 h3 的层级,AI 在抽取内容块时会降低置信度,导致页面即使被抓取也不被引用。
改后的段落单独拿出来也能读懂,被引用的概率明显更高。
4.4 用代码检查页面的语义化程度
改完之后要验证。可以用一段简单的 Python 脚本检查页面里语义标签的使用情况:
from bs4 import BeautifulSoup import requests def check_semantics(url): resp = requests.get(url, timeout=10) soup = BeautifulSoup(resp.text, 'html.parser') report = { 'h1_count': len(soup.find_all('h1')), 'h2_count': len(soup.find_all('h2')), 'h3_count': len(soup.find_all('h3')), 'article_tag': len(soup.find_all('article')), 'section_tag': len(soup.find_all('section')), 'list_count': len(soup.find_all(['ul', 'ol'])), 'table_count': len(soup.find_all('table')), 'jsonld_count': len(soup.find_all('script', type='application/ld+json')), 'has_time_tag': len(soup.find_all('time')) > 0, } print(f"页面语义化检查:{url}") for k, v in report.items(): print(f" {k}: {v}") # 简单判断 if report['h1_count'] != 1: print(" 警告:H1 数量应为 1") if report['h2_count'] < 2: print(" 警告:H2 数量偏少,内容层级可能不清晰") if report['jsonld_count'] == 0: print(" 警告:未检测到结构化数据") check_semantics('https://你的域名/your-article')跑一遍就能看出页面在语义化上的短板,按报告逐项补。
5. 内容策略:AI 搜索偏爱什么样的页面
代码和配置解决的是"通道"问题,内容本身解决的是"竞争力"问题。同样被 AI 抓取,为什么有的页面被引用、有的不被引用?差别在内容组织方式。
5.1 问答式结构比叙述式结构更容易被引用
AI 搜索的最终产物是"回答一个问题"。所以内容如果本身就是问答结构,抽取成本最低。具体做法:
- 用 H2 或 H3 直接写成问题形式,比如"robots.txt 误伤 AI 爬虫怎么排查"
- 问题下面第一段直接给答案,再展开解释
- 一个页面覆盖一组相关问题,而不是一个大主题
对比两种写法:
叙述式:
在配置 robots.txt 的过程中,我们需要注意很多细节。首先,要检查现有规则……
问答式:
robots.txt 误伤 AI 爬虫怎么排查?访问站点根目录的 robots.txt,检查第一段是否有
User-agent: *加Disallow: /的组合。如果有,说明全站被封禁,需要删除或改为精确目录封禁。
问答式的段落被 AI 直接引用的概率高得多,因为它本身就是"问题 + 答案"的完整单元。
5.2 数据和参数要具体,不要模糊
AI 搜索在生成答案时偏好具体信息。如果你的页面写"抓取频率要合理",AI 没法引用;如果写"建议将爬虫抓取间隔设置为不低于 1 秒,单 IP 并发不超过 5",这就是可引用的具体参数。
具体化的几个方向:
- 时间:给出具体时长,如"24 到 72 小时"
- 数量:给出具体数值,如"至少 3 个 H2 章节"
- 比例:给出具体百分比,如"语义化改造后引用率提升约 40%"
- 版本:给出具体版本号,如"Python 3.9 以上"
模糊表述和具体表述的对比:
| 模糊表述 | 具体表述 |
|---|---|
| 尽快更新内容 | 建议每 30 天更新一次核心页面 |
| 配置合理的缓存 | 设置 Cache-Control 为 max-age=3600 |
| 使用结构化数据 | 添加 HowTo 类型的 JSON-LD,包含 step 字段 |
具体表述不仅更容易被引用,也更有实操价值。
5.3 时效性信号怎么给足
AI 搜索对时效性敏感,页面需要明确告诉它"我是新的"。几个做法:
- 在页面显眼位置显示更新时间,用
<time>标签包裹 - 在 JSON-LD 里填
dateModified - 在 sitemap.xml 里更新
lastmod - 在 llms.txt 的描述里体现内容的新版本
<p>最后更新:<time datetime="2025-03-20">2025 年 3 月 20 日</time></p>这四个信号叠加,AI 系统能明确判断页面是活跃维护的,引用优先级会提升。
5.4 内链和外链的用法
内链帮助 AI 理解站点结构,外链帮助 AI 判断内容可信度。用法上有区别:
- 内链:指向同主题的相关页面,锚文本用描述性文字,不要用"点击这里"
- 外链:指向权威来源,用于支撑数据和观点,不要指向低质量站点
内链锚文本对比:
<!-- 差 --> <a href="/robots-guide">点击这里</a> <!-- 好 --> <a href="/robots-guide">robots.txt 针对 AI 爬虫的配置方法</a>好的锚文本本身就是内容的一部分,AI 读取时能获得额外语义信息。
6. 排查链路:AI 不引用你的站点,按这个顺序查
前面讲的是"怎么改",这一节讲"怎么查"。当你发现 AI 搜索不引用自己的站点时,按下面的顺序排查,能快速定位问题在哪一环。
6.1 第一步:确认爬虫有没有来
打开服务器访问日志,按 AI 爬虫 UA 过滤:
grep -iE "GPTBot|ClaudeBot|PerplexityBot|Google-Extended" /var/log/nginx/access.log | tail -100三种结果对应三种问题:
- 完全没有记录:robots.txt 或防火墙拦截,回到第 2 节检查
- 有记录但都是 403/404:页面不可访问或路径错误
- 有记录且是 200:爬虫进来了,问题在理解或抽取环节
这一步能排除掉一半的可能性,务必先做。
6.2 第二步:确认页面能被正确解析
用 curl 抓取页面,看返回的 HTML 是不是完整的:
curl -A "Mozilla/5.0 (compatible; GPTBot/1.0)" https://你的域名/your-page -o page.html重点检查:
- 返回的 HTML 里有没有正文内容(有些站点对爬虫返回空壳,靠 JS 渲染)
- 语义标签是否完整
- JSON-LD 是否存在且格式正确
如果正文靠 JS 渲染,AI 爬虫很可能拿不到内容。解决方案是服务端渲染(SSR)或预渲染。
6.3 第三步:检查内容块的可抽取性
把页面里每个 H2 下面的第一段单独复制出来,看能不能独立成段。如果大部分段落都依赖上下文,说明内容组织方式需要调整,回到第 4.3 节改写法。
6.4 第四步:对比被引用的竞品页面
找几个在 AI 搜索里被引用的同主题页面,对比它们的结构:
| 对比项 | 你的页面 | 被引用的竞品页面 |
|---|---|---|
| H2 数量 | 2 | 6 |
| 是否有问答结构 | 否 | 是 |
| 是否有结构化数据 | 否 | 是 |
| 更新时间是否可见 | 否 | 是 |
| 是否有具体参数 | 少 | 多 |
这个对比表能直观看出差距在哪,按差距逐项补。
6.5 第五步:观察调整后的效果
GEO 调整不是立竿见影的,AI 搜索的索引和引用有延迟。建议:
- 调整后等 2 到 4 周再观察
- 用日志持续监控 AI 爬虫的抓取频率和路径
- 记录每次调整的内容和对应的引用变化
我自己的经验是,语义化改造和结构化数据这两项见效最快,通常 2 周内能看到爬虫抓取频率上升;内容结构的调整见效慢一些,需要等 AI 重新索引。
7. 几个容易踩的坑和实操心得
这一节是我在实际操作中踩过的坑,以及一些文档里不会写的细节。
7.1 robots.txt 改完不生效的常见原因
改完 robots.txt 后爬虫没反应,通常是这几个原因:
- CDN 缓存了旧的 robots.txt,需要手动刷新缓存
- 文件权限不对,爬虫拿到 403
- 文件编码有问题,规则解析失败
- 爬虫有自己的缓存周期,不会立即重新读取
排查顺序:先用 curl 确认文件能正常访问,再检查 CDN 缓存,最后等爬虫的缓存周期过去。
7.2 llms.txt 写了但没人读
llms.txt 不是强制标准,写了不代表一定被读。提高被读概率的做法:
- 在 robots.txt 里显式放行
- 在 sitemap.xml 里也列出这个文件
- 在页面 head 里加
<link rel="llms" href="/llms.txt">(部分系统识别) - 保持文件更新,内容质量高
即使暂时没被读,维护成本也低,属于长期投入。
7.3 结构化数据写错的隐蔽问题
JSON-LD 写错不会报错,但 AI 读不到。常见错误:
- 引号用了中文引号
- 字段名拼写错误,如把
dateModified写成date_modify - 嵌套结构层级不对
- 多个 JSON-LD 块之间有语法冲突
验证方法:用浏览器的开发者工具看控制台有没有 JSON 解析错误,或者用在线 JSON 校验工具检查。
7.4 内容更新后要同步的地方
内容更新后,需要同步的地方不止一处:
- 页面本身的
<time>标签 - JSON-LD 里的
dateModified - sitemap.xml 里的
lastmod - llms.txt 里的描述(如果内容定位变了)
- CDN 缓存刷新
漏掉任何一处,AI 系统拿到的时效性信号就不一致,可能影响引用判断。
7.5 不要为了 GEO 牺牲可读性
最后一条心得:GEO 的所有调整,前提是不破坏真人阅读体验。语义化标签、结构化数据、问答结构,这些对真人读者也是友好的。如果某个调整让页面变得难读,那大概率方向错了。
我见过有人为了"让 AI 好抓",把页面改成纯列表堆砌,结果真人读者直接跳出。AI 搜索的引用最终还是要服务于真人点击,可读性和可抓取性要平衡。
8. 把 GEO 当成持续工程而不是一次性配置
GEO 和传统 SEO 最大的区别在于,它的规则还在快速变化。AI 搜索的抓取策略、引用偏好、支持的文件格式,每隔几个月就可能有调整。所以正确的姿势是把它当成持续工程:
- 每月检查一次 robots.txt 和 llms.txt 的有效性
- 每季度对比一次被引用情况,找出差距
- 每次内容更新同步时效性信号
- 关注 AI 搜索官方文档的更新
我在实际操作中的体会是,GEO 里 80% 的效果来自 20% 的基础工作:robots.txt 配对、语义化 HTML 到位、结构化数据完整、内容自包含。这四件事做好,剩下的就是持续维护和观察。不用追求花哨的技巧,把基础打牢,AI 搜索自然会开始引用你的页面。