Astro SEO 是做什么的?
审计并优化 Astro 网站的 SEO 设置,遵循 Astro SEO: the definitive guide 中描述的完整栈。该技能涵盖九个方面——技术基础、结构化数据、内容、站点结构、性能、站点地图和索引、智能体发现、重定向和分析——并为任何缺失或薄弱环节生成可直接使用的代码。
该技能的核心是基于 @jdevalk/astro-seo-graph 的。大多数修复都通过它进行。如果项目尚未使用它,安装它是首要建议。
代码配方存放在 AGENTS.md 中——在需要实施特定修复时阅读它。此文件包含工作流程和审计清单。
工作流程
- 检测项目——确认这是一个 Astro 站点并了解其结构。
- 审计——评估九个类别并生成可行的发现。
- 改进——生成或修改文件以弥补差距。配方在
AGENTS.md中。 - 元数据检查——对技能生成的每个短字符串(标题、描述、schema
description字段、FAQ 答案、frontmatter 摘录)调用metadata-check。 - 验证——运行构建,检查验证是否通过,提醒用户注意非文件任务(Search Console、Bing Webmaster Tools、IndexNow 密钥验证)。
阶段 0:检测项目
在审计前确认基本情况:
astro.config.mjs/astro.config.ts存在。package.json将astro列为依赖项。- 在
astro.config中设置了site:——URL 规范、站点地图和 OG 图像 URL 都来源于此。如果缺失、为空或为http://localhost,则将其标记为阻塞问题,优先处理。这是最常见的配置错误。 src/content/(或旧版src/pages/markdown)中的内容集合。- 部署目标——读取
package.json、vercel.json、netlify.toml、wrangler.toml或public/_headers以确定主机。这决定了阶段 2 中的重定向和标头语法。 @jdevalk/astro-seo-graph是否已安装? 如果是,记录版本和已集成的功能(grep 查找<Seo、seoGraph(、createSchemaEndpoint、createSchemaMap、FuzzyRedirect、createIndexNowKeyRoute、createMarkdownEndpoint、createApiCatalog、gitLastmod)。使用npm view @jdevalk/astro-seo-graph version检查已安装版本与 npm 上的最新版本。 如果项目版本落后,建议在审计功能差距前在阶段 2 进行升级——该包定期发布新的默认值和修复,过时的版本可能是任何审计发现的合理原因。阶段 2 会据此分支。- 站点是否为多语言? 检查
astro.config中的i18n或src/content/下多个语言目录。如果是,则 hreflang 很重要;如果否,则跳过。
只询问无法检测到的问题。不要询问用户网站是关于什么的——读取 astro.config.mjs 和首页内容即可。
阶段 1:审计
每个类别评分满分 10 分。对于每个类别,给出 2–4 个具体发现,引用实际代码或配置。在每个类别中,检查按层级划分:
- 必须——发布阻塞项。这里的失败会导致明显的 SEO 退步。
- 应该——标准实践。跳过会损失排名。
- 不错——前瞻性或特定情境下的。对每个网站都有用,但不是基线要求。
对于小型个人博客,跳过不错检查,除非用户要求完整处理。
1. <Seo> 组件和头部元数据 (/10)
- 必须——所有头部元数据使用单个组件(而不是分散在布局中)。
- 必须——
astro.config中的site:设置为生产环境来源。 - 必须——根据
site配置派生 URL 规范,并去除跟踪参数。 - 必须——当
noindex为 true 时省略 URL 规范(根据 Google 的建议)。 - 必须——缺失 SEO 字段的降级链:
seo.title → title → siteName;seo.description → excerpt → first paragraph。标题或描述为空的页面是降级链损坏最常见的症状。 - 应该——
robots元标记包含max-snippet:-1、max-image-preview:large、max-video-preview:-1。 - 应该——当 Twitter 标签与 Open Graph 重复时抑制(Twitter 会自动回退)。
- 应该——多语言站点上出现
hreflang替代项。单语言则跳过。 - 不错——使用
@jdevalk/astro-seo-graph的<Seo>组件,而不是手动编写的代码。(能覆盖上述所有内容的手动代码也可以;本技能倾向于推荐该包,因为它默认处理降级链和 robots 规则。)
2. 结构化数据 / JSON-LD 图 (/10)
- 是单个扁平的
Article对象,还是包含多个实体的链接@graph? - 实体是否使用
@id引用连接? WebSite、Blog/WebPage、Person/Organization、BlogPosting/Article、BreadcrumbList、ImageObject在相关位置是否都存在?- 信任信号:
publishingPrinciples、copyrightHolder、copyrightYear、knowsAbout、SearchAction? - 在 Rich Results Test 和 ClassySchema 中验证通过?
3. 内容集合和 SEO schema (/10)
- 内容集合是否使用 Zod schemas 定义?
@jdevalk/astro-seo-graph的seoSchema是否强制执行标题(5–120)和描述(15–160)长度?- 必需字段(
publishDate、title、excerpt)是否在构建时强制执行? - 去除 Markdown 的
articleBody是否通过 schema 端点暴露(最多 10K 字符)?
4. Open Graph 图像 (/10)
- 每个页面都有 OG 图像,还是很多缺失?
- 尺寸 1200×675(Google Discover 最小宽度 1200px,16:9 比例)?
- 是否在构建时通过 satori + sharp 生成,还是手动?
- JPEG 格式(社交平台不保证支持 WebP/AVIF)?
- OG URL 路由是否自动从 slug 派生?
- 渲染的 HTML 中的每个
<img>是否有alt属性(或装饰性图像使用alt=""/role="presentation")?seoGraph()中的validateImageAlt在 ≥ 1.1.0 的构建时捕获此问题。
5. 站点地图和索引 (/10)
- 必须——安装了
@astrojs/sitemap,站点地图索引可访问。 - 必须——
robots.txt引用站点地图索引。 - 必须——存在 RSS 提要(
@astrojs/rss),通过<link rel="alternate" type="application/rss+xml">宣传,包含完整文章内容(而非截断的摘要)。 - 应该——通过
chunks选项按集合拆分(sitemap-posts-0.xml等)——在 GSC 中调试索引要容易得多。 - 应该——
lastmod从 git 提交时间戳填充,而不是 frontmatter 日期或 CI 文件时间戳。@jdevalk/astro-seo-graph≥ 1.4.0 导出了gitLastmod(filePath, { excludeCommits, depth })用于此目的——它返回最近一次未排除提交的提交者日期,该提交影响了该文件,如果 git 不可用则返回null。将其连接到站点地图的serialize回调中。如果代码库有手动编写的execSync('git log ...')辅助函数,请将其替换为包导出——该导出处理批量提交排除(导入、格式化),这是简单的-1查找无法做到的。 - 应该——集成 IndexNow 并在每次构建时提交,密钥验证路由在
/[key].txt。≥ 1.0.1 默认排除/404提交。将提交限制在生产环境主机上(例如process.env.CF_PAGES === '1' && CF_PAGES_BRANCH === 'main'、VERCEL_ENV === 'production'、CONTEXT === 'production')。无条件提交会每次本地npm run build和预览部署时 ping 端点,使用生产环境主机尚未提供过的 URL,这会导致密钥被标记为无效(403)并强制轮换。
6. 智能体发现 (/10)
- 应该——schema 端点(
/schema/*.json)暴露全站范围的 JSON-LD。 - 应该——schema 地图(
/schemamap.xml)列出所有端点,并在robots.txt中包含Schemamap:指令。 - 应该——站点根目录下的
llms.txt列出页面(标题 + 描述)供 LLM 消费者使用。@jdevalk/astro-seo-graph≥ 0.9.0 通过llmsTxt集成选项生成此文件。 - 应该——Markdown 替代 URL(
/blog/post.md与/blog/post/相邻)提供带有 YAML frontmatter 的干净 Markdown,供 AI 代理无需解析 HTML 即可使用。@jdevalk/astro-seo-graph≥ 1.2.0 提供了createMarkdownEndpoint用于路由和markdownAlternate: true集成选项,该选项在每个页面上发出<link rel="alternate" type="text/markdown">。≥ 1.3.0 增加了构建后验证:集成会遍历构建输出,并删除任何目标.md不在磁盘上的链接(每次出现时发出warn)——因此配置错误的端点会显示为构建警告,而不是提供 404。配合 Cloudflare Transform Rule(使用wildcard_replace进行 URL 重写,无Vary: Accept标头——CF 会剥离自定义 Vary 值)可用于在无需 SSR 的情况下根据Accept: text/markdown进行内容协商。 - 应该——根据 RFC 9727 在
/.well-known/api-catalog提供 API 目录。@jdevalk/astro-seo-graph≥ 1.4.0 提供了createApiCatalog,它会自动将 schema 端点类型化为其https://schema.org/<Type>URL,并将路径相对于siteUrl进行绝对化。列出 schema 端点、schema 地图和任何站点特定的 API(/ask、/feed.xml等)。RFC 已最终确定,因此格式稳定;采用尚早,但成本仅为一条路由文件。 - 应该——在
robots.txt中添加 Content Signals 指令(例如Content-Signal: ai-train=yes, search=yes, ai-input=yes)。它独立于爬取访问,声明对 AI 训练、搜索基础化和 AI 输入的偏好。规范是 IETF 草案,采用尚早,但这是每个网站已有的文件中的一行。 - 应该——在
/*上设置Link标头,指向发现文件(sitemap、llms.txt、api-catalog、schemamap 以及站点发布的任何 MCP / A2A 卡片)。读取响应标头的代理无需解析 HTML 即可找到它们。在 Cloudflare Pages / Netlify 上,此配置在public/_headers中;在 Vercel 上,在vercel.json中。 - 不错——在
/.well-known/mcp/server-card.json提供 MCP 服务器卡片(SEP-1649)和/或在/.well-known/agent-card.json提供 A2A 代理卡片(A2A protocol)。仅当站点实际暴露 MCP 服务器或 A2A 代理时才相关。两者都是声明端点、能力和技能的静态 JSON 文件。否则跳过。 - 不错——
<link rel="nlweb">指向对话端点。NLWeb 尚早;该标签只有一行,值得拥有,但在 2026 年它不是评分障碍。 - 不错——ARD (Agentic Resource Discovery) 目录在
/.well-known/ai-catalog.json,列出域提供的内容(MCP 服务器、A2A 代理、OKF 捆绑包、站点特定 API)。v0.9 草案,因此可选——但它是 MCP / A2A 卡片和 OKF 捆绑包实现回报的发现层。两个注意事项:基础规范(Agent-Card/ai-catalog)将 media-type 字段命名为mediaType,而 ARD 层(ards-project/ard-spec)将其命名为type——发出两个具有相同值的键,以便条目在任一读取下都能通过验证(两个规范都要求消费者忽略未知键)。ARD 还添加了每个条目的可选representativeQueries示例提示数组。 - 不错——OKF (Open Knowledge Format) 捆绑包:一棵类型化的 Markdown 概念文件树(每个页面一个,路径镜像规范 URL),打包为单个
.tar.gz,中间有索引文件。提供和发现不是 OKF 的明确目标——这就是 ARD 目录条目的用途。v0.9 草案,可选。尚无注册的媒体类型,因此临时字符串是application/okf-bundle+gzip(在 knowledge-catalog#111 和 ard-spec#27 中跟踪);将其标记为临时,可能会更改。最好作为现有内容管道的另一个输出生成,而不是手动维护的副本。
7. 性能 (/10)
- 默认静态输出(不需要 SSR 的页面上没有 SSR)?
- 除非岛组件需要,否则零客户端 JS?
- 所有内容图像使用 Astro
<Image>组件(响应式 srcset、WebP、懒加载、async)? - 主要网络字体以 woff2 格式预加载?
<ClientRouter />使用defaultStrategy: 'viewport'进行预取?/_astro/下的哈希资产提供Cache-Control: public, max-age=31536000, immutable?No-Vary-Search响应标头从缓存键中去除 UTM 参数?
8. 重定向和错误处理 (/10)
- 对曾经存在且已移动的每个 URL,维护
public/_redirects(或等效文件)? - 永久移动使用 301 而非 302?
- 来自
@jdevalk/astro-seo-graph的FuzzyRedirect组件是否集成到 404 页面? - 404 页面本身返回 404 状态,而非 200?
9. 构建时验证和内容质量 (/10)
- 必须——每次构建运行
seoGraph()集成,并启用validateH1和validateUniqueMetadata。对于 JSON-LD 验证,在seo-graph-core的assembleGraph()中传递warnOnDanglingReferences: true——这是组装时检查,不是集成选项。 - 应该——在
seoGraph()上启用validateImageAlt、validateMetadataLength和validateInternalLinks(均在 ≥ 1.1.0 中默认为true)。它们捕获缺少的 alt 文本、超出 SERP 边界的标题或描述(默认值:标题 30–65,描述 70–200),以及导致 404 或尾斜杠不匹配的内部链接。如果项目在 1.1.0 上,请升级到 ≥ 1.1.1——该补丁版本修复了两个验证器错误:validateInternalLinks现在将public/资产识别为有效目标(不再对/images/*或/fonts/*产生误报),并且validateMetadataLength不再截断包含 HTML 实体的描述。 - 应该——
validateMetadataLength中的minDescriptionLength和maxDescriptionLength检查正确使用字符数,而不是字节数。 - 应该——使用
validateImageAlt检查所有<img>标签的 alt 文本。 - 应该——使用
validateInternalLinks检查内部链接。