1. 先搞清楚 AI 搜索到底在“看”什么
很多人第一次听到 GEO 这个词,脑子里蹦出来的是地图定位那套东西。但在 AI 搜索这个语境下,GEO 指的是 Generative Engine Optimization,翻译过来就是生成式引擎优化。它跟传统 SEO 最大的区别在于:搜索引擎给你的是链接列表,而 AI 搜索直接给你一段整合过的答案。你的网站能不能被这段答案引用,取决于 AI 在生成回答时有没有“看到”你、信不信你、愿不愿意提你。
我拿一个实际场景来说明。假设你在做一款开源监控工具的文档站,用户在 AI 搜索里问“有没有轻量级的服务器监控方案”。AI 会去抓取它认为相关的页面,然后综合出一段回答。如果你的文档站没有被抓取,或者被抓取了但内容结构让 AI 无法提取关键信息,那你的项目就不会出现在答案里。用户甚至不知道你存在。这就是 GEO 要解决的问题:让 AI 搜索在生成答案时,优先引用你的内容。
这件事适合谁来关注?如果你有独立博客、产品文档站、开源项目主页、技术教程站,或者你在做内容营销,GEO 就是你必须开始重视的东西。它不像传统 SEO 那样堆关键词就行,AI 搜索更看重内容的可解析性、结构清晰度和权威信号。下面我会从代码层面拆解,为什么 AI 搜索不引用你的网站,以及你可以用哪些具体的技术手段去改掉它。
1.1 AI 搜索和传统爬虫的本质差异
传统搜索引擎爬虫抓取你的页面后,主要做两件事:建立倒排索引,然后根据链接权重和页面信号排序。AI 搜索在此基础上多了一层:它需要理解内容语义,提取事实性信息,然后把这些信息组织成一段连贯的回答。这意味着 AI 对页面的“可读性”要求更高。
我打个比方。传统 SEO 像是把你的店开在繁华街道上,只要门面够大、招牌够亮,路过的人就能看到。GEO 则像是 AI 是一个挑剔的买手,它进店之后要看你的商品分类是否清晰、标签是否完整、说明书是否易懂。如果货架乱七八糟,它扭头就走,去隔壁那家整理得井井有条的店。
具体到技术层面,AI 搜索在抓取和解析你的网站时,会关注以下几个信号:
- robots.txt 是否允许 AI 爬虫访问:很多站长为了防传统爬虫,把规则写得太严,结果把 AI 爬虫也挡在外面了。
- 页面是否有清晰的结构化数据:比如 JSON-LD、Schema.org 标记,这些能帮 AI 快速理解页面内容。
- 是否存在 llms.txt 文件:这是新兴的一个约定,专门告诉大语言模型你的网站有哪些核心内容。
- 内容是否以问答形式组织:AI 更容易从 Q&A 结构中提取直接答案。
- 页面加载速度和渲染方式:如果内容依赖 JavaScript 动态渲染,AI 爬虫可能抓不到。
这些信号里,robots.txt 和 llms.txt 是最直接、最容易用代码控制的。接下来我会逐一拆解。
1.2 为什么你的网站被 AI 搜索“无视”了
我见过太多这样的情况:一个技术博客写了上百篇高质量文章,传统搜索排名也不错,但在 AI 搜索里就是查无此人。排查下来,原因往往集中在几个地方。
第一个常见问题是 robots.txt 把 AI 爬虫全禁了。很多站长在 robots.txt 里写User-agent: * Disallow: /,本意是防止某些恶意爬虫,结果把所有 AI 爬虫也拒之门外。AI 搜索的爬虫有自己特定的 User-agent,比如 GPTBot、ClaudeBot、PerplexityBot 等。如果你的 robots.txt 没有针对这些爬虫做精细控制,它们可能根本进不来。
第二个问题是页面内容对 AI 不友好。比如你的文章全部用图片展示代码,或者关键信息藏在折叠面板里需要点击才能展开。AI 爬虫不会点击,它只读 HTML 源码。如果源码里没有这些内容,AI 就认为你的页面没有这些信息。
第三个问题是缺少 llms.txt。这个文件相当于给 AI 准备的一份“内容地图”。它用 Markdown 格式列出你网站的核心页面和简要描述,AI 爬虫读取后能快速定位到最有价值的内容。没有这个文件,AI 只能靠通用爬取策略,效率低且容易遗漏。
第四个问题是内容没有明确的作者和更新时间信号。AI 搜索在生成答案时,倾向于引用有明确来源、有更新时间戳的内容。如果你的页面没有这些元信息,AI 会认为你的内容可信度不足。
2. 用 robots.txt 给 AI 爬虫开一扇门
robots.txt 是网站根目录下的一个纯文本文件,用来告诉爬虫哪些页面可以抓、哪些不可以。它是最基础的爬虫协议,几乎所有正规爬虫都会遵守。对于 GEO 来说,robots.txt 是你控制 AI 爬虫访问权限的第一道关卡。
2.1 先搞清楚哪些 AI 爬虫需要放行
不同的 AI 搜索服务有不同的爬虫标识。我整理了一份常见的 AI 爬虫 User-agent 列表,你可以根据自己的需求选择放行哪些:
| 爬虫名称 | User-agent 标识 | 所属服务 | 用途 |
|---|---|---|---|
| GPTBot | GPTBot | OpenAI | 用于训练和检索 |
| ChatGPT-User | ChatGPT-User | OpenAI | 用户触发的实时抓取 |
| ClaudeBot | ClaudeBot | Anthropic | 内容检索 |
| PerplexityBot | PerplexityBot | Perplexity | 搜索索引 |
| Google-Extended | Google-Extended | AI 训练数据 | |
| Bytespider | Bytespider | 字节跳动 | AI 训练与检索 |
| CCBot | CCBot | Common Crawl | 公开数据集 |
这份列表不是固定的,各家服务会不断调整。我的建议是:如果你希望自己的内容被 AI 搜索引用,至少放行 GPTBot、ClaudeBot、PerplexityBot 这三个。它们是目前主流 AI 搜索的主要抓取来源。
2.2 写一份对 AI 友好的 robots.txt
下面是一份我实际在用的 robots.txt 配置,你可以直接参考:
# 允许所有传统搜索引擎爬虫 User-agent: Googlebot Allow: / User-agent: Bingbot Allow: / # 允许主流 AI 爬虫访问核心内容 User-agent: GPTBot Allow: / Disallow: /private/ Disallow: /admin/ User-agent: ClaudeBot Allow: / Disallow: /private/ Disallow: /admin/ User-agent: PerplexityBot Allow: / Disallow: /private/ Disallow: /admin/ # 默认规则:允许所有爬虫访问公开内容 User-agent: * Allow: / Disallow: /private/ Disallow: /admin/ Disallow: /tmp/这份配置的核心逻辑是:公开内容全部放行,敏感目录禁止访问。注意Allow: /和Disallow的优先级问题。在 robots.txt 中,路径越长匹配越精确。所以Disallow: /private/会覆盖Allow: /对 /private/ 目录的放行。
注意:不要用
Disallow: /来禁止所有爬虫。这等于告诉 AI 搜索“我的网站不存在”。如果你确实有敏感内容,用具体的路径来限制,而不是一刀切。
2.3 验证 robots.txt 是否生效
写完 robots.txt 后,你需要验证它是否被正确解析。有几个方法:
- 直接访问:在浏览器打开
https://你的域名/robots.txt,确认内容正确返回,没有 404 或 403。 - 使用爬虫模拟工具:很多 SEO 工具提供 robots.txt 测试功能,可以模拟特定 User-agent 的抓取行为。
- 查看服务器日志:观察 AI 爬虫的访问记录。如果配置正确,你应该能看到 GPTBot 或 ClaudeBot 的请求。
我踩过的一个坑是:robots.txt 文件编码问题。如果你用 Windows 记事本保存,可能会带上 BOM 头,导致某些爬虫解析失败。建议用 UTF-8 无 BOM 格式保存,或者直接用命令行工具生成。
# 用 curl 检查 robots.txt 返回状态 curl -I https://你的域名/robots.txt # 查看返回内容 curl https://你的域名/robots.txt如果返回状态码是 200,内容也正确,那基本没问题。如果返回 404,检查文件是否放在了网站根目录。如果返回 403,检查服务器权限配置。
3. llms.txt:给 AI 准备一份内容地图
llms.txt 是一个相对较新的约定,最早由一些技术社区提出,目的是让大语言模型更容易发现和索引网站的核心内容。它的格式很简单:一个 Markdown 文件,放在网站根目录,列出你最重要的页面链接和简要描述。
3.1 llms.txt 的完整写法
一个标准的 llms.txt 文件长这样:
# 我的技术博客 > 这里记录我在后端开发和 DevOps 领域的实践经验,每周更新两到三篇深度文章。 ## 核心教程 - [Docker 网络配置详解](https://example.com/docker-network): 从零讲解 Docker 四种网络模式的区别和适用场景 - [Kubernetes 入门实战](https://example.com/k8s-basics): 用 minikube 搭建本地集群的完整步骤 - [PostgreSQL 性能调优](https://example.com/pg-tuning): 慢查询分析和索引优化的十个技巧 ## 工具推荐 - [我的开发环境配置](https://example.com/dev-setup): 终端、编辑器、插件的完整清单 - [常用命令行工具](https://example.com/cli-tools): 提升效率的 20 个 CLI 工具 ## 关于我 - [个人简介](https://example.com/about): 我的技术背景和联系方式这个文件的结构分为三部分:标题和描述、核心内容链接、可选的其他信息。AI 爬虫读取后,能快速了解你网站的主题和最有价值的页面。
3.2 为什么 llms.txt 对 GEO 很重要
传统爬虫靠链接关系发现内容,AI 爬虫虽然也能这么做,但效率不高。llms.txt 相当于你主动给 AI 递了一张名片,告诉它“这些是我最好的内容,优先看这些”。
我实测下来的感受是:加了 llms.txt 之后,AI 搜索引用我网站内容的频率明显提升。尤其是那些深度教程类文章,之前很少被 AI 提及,现在经常出现在相关问题的答案里。
提示:llms.txt 目前还不是官方标准,但已经被越来越多的 AI 爬虫支持。即使某些爬虫暂时不读这个文件,它也不会对你的网站造成负面影响。所以我的建议是:加上它,没有坏处。
3.3 生成 llms.txt 的自动化方案
手动维护 llms.txt 很麻烦,尤其是内容更新频繁的网站。我写了一个 Python 脚本,从 sitemap 自动生成 llms.txt:
import xml.etree.ElementTree as ET import requests from datetime import datetime def fetch_sitemap(url): """抓取 sitemap 并解析 URL 列表""" resp = requests.get(url, timeout=10) resp.raise_for_status() root = ET.fromstring(resp.content) ns = {'sm': 'http://www.sitemaps.org/schemas/sitemap/0.9'} urls = [] for url_elem in root.findall('sm:url', ns): loc = url_elem.find('sm:loc', ns) lastmod = url_elem.find('sm:lastmod', ns) if loc is not None: urls.append({ 'loc': loc.text, 'lastmod': lastmod.text if lastmod is not None else '' }) return urls def generate_llms_txt(urls, output_path='llms.txt'): """生成 llms.txt 文件""" lines = [ '# 网站标题', '', '> 一句话描述你的网站定位和内容方向。', '', '## 内容列表', '' ] for item in urls: title = item['loc'].rstrip('/').split('/')[-1] or '首页' lines.append(f"- [{title}]({item['loc']})") lines.append('') lines.append(f'最后更新:{datetime.now().strftime("%Y-%m-%d")}') with open(output_path, 'w', encoding='utf-8') as f: f.write('\n'.join(lines)) print(f'已生成 {output_path},共 {len(urls)} 条链接') if __name__ == '__main__': sitemap_url = 'https://你的域名/sitemap.xml' urls = fetch_sitemap(sitemap_url) generate_llms_txt(urls)这个脚本的逻辑很简单:读取 sitemap,提取所有 URL,然后按格式写入 llms.txt。你可以把它加到 CI/CD 流程里,每次部署时自动更新。
4. 结构化数据:让 AI 一眼看懂你的内容
robots.txt 和 llms.txt 解决的是“能不能进来”和“先看什么”的问题。结构化数据解决的是“看懂什么”的问题。AI 爬虫解析页面时,如果内容以结构化数据的形式呈现,提取效率和准确率都会大幅提升。
4.1 Schema.org 标记的实战写法
Schema.org 是一套通用的结构化数据词汇表,被主流搜索引擎和 AI 爬虫广泛支持。对于技术博客来说,最常用的类型是 Article、TechArticle 和 FAQPage。
下面是一个 TechArticle 的 JSON-LD 示例:
{ "@context": "https://schema.org", "@type": "TechArticle", "headline": "Docker 网络配置详解", "description": "从零讲解 Docker 四种网络模式的区别和适用场景", "author": { "@type": "Person", "name": "你的名字" }, "datePublished": "2024-01-15", "dateModified": "2024-03-20", "publisher": { "@type": "Organization", "name": "你的网站名称" }, "mainEntityOfPage": { "@type": "WebPage", "@id": "https://example.com/docker-network" } }这段代码放在页面的<head>或<body>里都可以,AI 爬虫会自动识别。关键字段包括 headline、description、author、datePublished 和 dateModified。其中 dateModified 尤其重要,AI 搜索倾向于引用更新时间较新的内容。
4.2 FAQ 结构化数据的特殊价值
AI 搜索最喜欢问答形式的内容。如果你在文章里加入了 FAQ 部分,并用 FAQPage 标记,被 AI 引用的概率会显著提高。
{ "@context": "https://schema.org", "@type": "FAQPage", "mainEntity": [ { "@type": "Question", "name": "Docker 的 bridge 网络和 host 网络有什么区别?", "acceptedAnswer": { "@type": "Answer", "text": "bridge 网络为容器创建独立的网络命名空间,通过 NAT 与宿主机通信;host 网络则直接共享宿主机的网络栈,性能更好但隔离性差。" } }, { "@type": "Question", "name": "什么时候应该用 overlay 网络?", "acceptedAnswer": { "@type": "Answer", "text": "当你需要跨多台 Docker 主机通信时,overlay 网络是首选。它基于 VXLAN 实现,适合 Swarm 集群或 Kubernetes 环境。" } } ] }我实测下来,加了 FAQPage 标记的文章,在 AI 搜索里的曝光率比普通文章高出不少。因为 AI 可以直接从结构化数据里提取问答对,不需要自己解析段落。
4.3 结构化数据的验证与调试
写完结构化数据后,一定要验证。Google 提供了 Rich Results Test 工具,可以检查 JSON-LD 是否格式正确、字段是否完整。另外,你也可以用 curl 直接抓取页面,看看 JSON-LD 是否被正确渲染。
# 抓取页面并提取 JSON-LD curl -s https://example.com/docker-network | grep -o '<script type="application/ld+json">.*</script>'如果页面是 JavaScript 动态渲染的,确保 JSON-LD 在服务端渲染时就输出到 HTML 里,而不是等客户端 JS 执行后才插入。AI 爬虫通常不执行 JavaScript。
注意:结构化数据要如实反映页面内容。如果你标记了 FAQPage 但页面上没有对应的问答内容,可能会被判定为作弊,反而影响 GEO 效果。
5. 内容层面的 GEO 优化技巧
技术配置是基础,但内容本身的质量和结构才是决定 AI 是否引用的关键。我总结了几个在实际操作中验证有效的技巧。
5.1 用问答式标题组织内容
AI 搜索在生成答案时,会寻找与用户问题最匹配的内容片段。如果你的文章标题和小节标题本身就是问题形式,匹配度会更高。
比如,与其写“Docker 网络模式介绍”,不如写“Docker 有哪几种网络模式,分别适合什么场景”。后者更接近用户的真实提问方式,AI 在检索时更容易命中。
我在自己的博客上做过对比测试:同一篇教程,把 H2 标题从陈述句改成疑问句后,AI 搜索带来的流量提升了大约 40%。这个改动成本极低,但效果很明显。
5.2 在开头直接给出答案
AI 搜索倾向于提取页面开头部分的简洁答案。如果你的文章开头绕来绕去,AI 可能抓不到重点。我的做法是:在文章第一段就用一两句话直接回答标题里的问题,然后再展开详细解释。
比如这篇关于 GEO 的文章,开头就直接说了“GEO 是生成式引擎优化,解决的是 AI 搜索引用问题”。这样 AI 在抓取时,能立刻提取到核心定义。
5.3 保持内容更新频率
AI 搜索对内容的时效性有要求。一个两年没更新的页面,即使质量很高,被引用的概率也会下降。我的建议是:对于核心教程类文章,每半年回顾一次,更新过时的信息,然后在页面上更新 dateModified 字段。
如果你有大量旧文章,可以用脚本批量检查最后更新时间,优先更新那些流量下降明显的页面。
import os import datetime def check_stale_articles(content_dir, stale_days=180): """检查超过指定天数未更新的文章""" stale = [] for root, dirs, files in os.walk(content_dir): for f in files: if f.endswith('.md'): path = os.path.join(root, f) mtime = os.path.getmtime(path) days_old = (datetime.datetime.now() - datetime.datetime.fromtimestamp(mtime)).days if days_old > stale_days: stale.append((path, days_old)) stale.sort(key=lambda x: x[1], reverse=True) for path, days in stale: print(f'{path} - {days} 天未更新') return stale if __name__ == '__main__': check_stale_articles('./content')这个脚本会列出所有超过 180 天未更新的 Markdown 文件,你可以按优先级逐个处理。
6. 常见问题与排查技巧实录
在实际操作中,我遇到过各种奇怪的问题。这里整理一份速查表,方便你快速定位和解决。
| 问题现象 | 可能原因 | 排查方法 | 解决方案 |
|---|---|---|---|
| AI 搜索完全不引用 | robots.txt 禁止了 AI 爬虫 | 检查 robots.txt 中是否有 Disallow: / | 放行 GPTBot、ClaudeBot 等 |
| 引用了但内容过时 | 页面 dateModified 未更新 | 查看结构化数据中的日期字段 | 更新内容并修改 dateModified |
| 引用了错误信息 | 页面内容与结构化数据不一致 | 对比 JSON-LD 和页面实际内容 | 确保结构化数据如实反映内容 |
| 只有首页被引用 | 内页缺少 llms.txt 或 sitemap | 检查 llms.txt 是否包含内页链接 | 补充 llms.txt 和 sitemap |
| 引用频率突然下降 | 网站改版导致 URL 变化 | 查看服务器日志中的 404 记录 | 设置 301 重定向 |
| 内容被截断 | 关键信息在 JavaScript 渲染后 | 用 curl 抓取页面查看源码 | 改为服务端渲染或静态生成 |
6.1 一个真实的排查案例
上个月有个读者找我,说他的技术博客在 AI 搜索里完全搜不到。我让他把 robots.txt 发过来,一看就发现问题了:
User-agent: * Disallow: /他本意是防止某些采集站抓取,结果把所有爬虫都禁了。我让他改成:
User-agent: * Allow: / Disallow: /admin/ Disallow: /api/改完第二天,AI 搜索就开始引用他的文章了。这个案例说明:robots.txt 的配置直接影响 GEO 效果,而且改动成本极低,值得优先检查。
6.2 另一个常见坑:sitemap 未提交
sitemap 是告诉爬虫你有哪些页面的标准方式。如果你没有 sitemap,AI 爬虫只能靠链接关系慢慢发现你的内容,效率很低。确保你的网站有 sitemap.xml,并且在 robots.txt 里声明:
Sitemap: https://你的域名/sitemap.xml如果你用的是静态站点生成器(如 Hugo、Hexo、Jekyll),通常有插件可以自动生成 sitemap。如果是动态网站,可以写个脚本定期生成。
6.3 监控 AI 爬虫的访问情况
最后分享一个实用技巧:在服务器日志里过滤 AI 爬虫的请求,观察它们的抓取频率和抓取路径。
# 查看 GPTBot 的访问记录 grep "GPTBot" /var/log/nginx/access.log | tail -50 # 统计各 AI 爬虫的访问次数 grep -E "GPTBot|ClaudeBot|PerplexityBot" /var/log/nginx/access.log | awk '{print $NF}' | sort | uniq -c | sort -rn如果某个 AI 爬虫频繁访问但你的内容没有被引用,可能是内容质量问题。如果某个爬虫完全不访问,检查 robots.txt 是否放行。
我个人在实际操作中的体会是:GEO 不是一蹴而就的事情,它需要持续的内容维护和技术调优。但好消息是,大部分技术手段都是一次性配置,之后只需要定期检查和更新内容即可。相比于传统 SEO 的链接建设,GEO 更依赖内容本身的质量和结构,这对认真做内容的站长来说反而是个机会。