web-index

给需反复查阅的网站 / 文档站建本地网页索引(.web-index/{site}/):抓 llms.txt / sitemap.xml / 导航,产出「要做什么 → 去哪一页(含锚点)」的路由表;已索引站点按路由表直接查(消费模式),只做链接索引、不镜像正文。触发:"给这个网站建个索引"、"整理一下这个文档的链接"、"网页索引"、"查一下网页索引"、"web index"、"这站要反复参考";只查

SKILL.md

GitHub

网页索引(Web Index)

概述

目的:把「这个站该看哪一页」的一次性探索成本固化成本地资产,终结 AI 每次零知识进站、现场找链接的重复浪费。

功能:

  • 抓站点一手地图:llms.txt > sitemap.xml(含索引递归) > 导航/侧边栏 > web_search 兜底
  • 产出路由表而非链接收藏:每条 = 任务视角的「我要…」→ URL + 锚点 + 分区
  • 大站自动分区到 topics/,index.md 只留分区索引 + 高频直达,按需加载
  • 配套脚本 scripts/fetch_site_map.py 完成确定性抓取,skill 只做薄封装
  • 双模式:消费模式(查已有索引 → fetch)与建造模式(采集建库)显式分离,避免"每次从头重建"把省下的成本翻倍赔回去
  • 定义事后使用协议:先查索引再 fetch,避免索引建完被架空

使用场景:

  • 用户给出某个文档站 / API 站,明确说或可判断会反复查阅("后面都按这个文档做")
  • AI 在同一任务里第二次不知道该翻这个站的哪一页
  • 想把一类外部知识(框架文档、平台文档、规范站)固化成本地路标,跨会话复用
  • 用户说"给这个网站建个索引"、"整理一下这个文档的链接"、"网页索引"、"web index" 时
  • 之前建过索引的站点再次被问起——先查 .web-index/INDEX.md 进消费模式,而不是重头建一遍

核心原则

  1. 路由表,不是链接收藏:每条必须有任务视角的「我要…」列。只给链接等于没索引——AI 拿到一堆 URL 仍不知道跳哪页。
  2. 只索引,不镜像:不抓正文、不抄代码示例。正文留给 web_fetch 现取,否则立刻过期且上下文爆炸。
  3. 一手地图优先:llms.txt > sitemap.xml > 站点导航 > web_search。能用地图就不用搜索引擎——后者结果随机、不可复现。
  4. 范围闸门 + 反门槛:不设 scope 与上限会对着上千页失控;只查一次的站禁止建索引(见阶段 0)。
  5. 不臆造链接:URL 必须来自站点实际返回。禁止按路径规律拼链接、凭记忆写 URL;拿不准的标 [待确认]。
  6. 快照制(只建不管):产物是一次性快照,元信息记录生成日期 / scope / 条目数供新鲜度判断。不提供自动刷新与版本 diff,失效即整站重跑覆盖重建。
  7. 可见性由集成方负责:产物落在隐藏目录,本 skill 不擅自往用户的 AGENTS.md / 规则里写钩子。独立使用时需项目侧有一行发现声明;被其它 skill 集成时,由调用方在自身流程中声明"先查 INDEX.md"——发现钩子随集成走,不污染全局。落点同理:本文件的 .web-index/ 只是默认值,调用方覆盖落点时(见「已知调用方」表,如 topic-teach 落在 {topic-slug}/web-index/),其流程里的发现钩子与路径一律指向调用方指定的位置,本文件不再干预。

产物结构

.web-index/
├── INDEX.md              # 必存在:全站登记表(一行一站)—— 后续会话的发现入口
└── {site-slug}/
    ├── index.md          # 必存在:元信息 + 怎么用 + 分区索引(+ 高频直达)
    └── topics/
        ├── {分区A}.md     # 分区路由表
        └── {分区B}.md

INDEX.md 是这个机制的生命线:.web-index/ 是隐藏目录,新会话的 AI 不会凭空知道它存在。每次建索引都必须同步更新它——没有发现机制的索引等于没建。

# 网页索引登记表

> 涉及下列站点的问题,先查对应条目所在的分区/路由表,再 web_fetch 取正文

| 站点 | slug | 起始 URL | 范围 | 条数 | 生成日期 |
|------|------|----------|------|------|----------|
| MinIO Docs | minio | https://min.io/docs/minio/linux | /docs/minio/linux | 87 | 2026-09-10 |

slug 规则:去掉协议与 www.,取主机主名 + 首个有意义路径段,小写连字符。例:docs.min.io → minio;example.com/docs/api → example-api。同一 host 不同产品线必须用不同 slug(example-api / example-cli),避免合在一个目录里互相污染。

index.md 模板

# {站点名} 网页索引

> 起始 URL:{url}
> 生成日期:2026-09-10 · 范围(scope):{prefix 或「全站」} · 条目数:87 · 一次性快照
> 只索引不镜像:需要正文时用 web_fetch 打开对应 URL(带锚点直达)

## 怎么用

1. 按「我要…」列定位条目(不确定先看下方分区索引)
2. 用 web_fetch 打开该条 URL 取细节
3. 本表是快照,链接大面积失效时整站重跑重建

## 高频直达

| 我要… | 去哪一页 | 分区 |
|-------|----------|------|
| 给服务配 HTTPS 证书 | [网络与加密](https://example.com/network-encryption.html#tls) | security |

## 分区索引

| 分区 | 文件 | 条数 | 覆盖内容 |
|------|------|------|----------|
| security | [topics/security.md](./topics/security.md) | 12 | TLS、证书、KMS |
| cli | [topics/cli.md](./topics/cli.md) | 31 | mc / mc admin 子命令 |

topics/{分区}.md 模板

# {分区名}({站点名} · 共 {N} 条)

> 范围:{scope} · 生成日期:2026-09-10

| 我要… | 去哪一页 | 锚点 | 关键词 | 相关 |
|-------|----------|------|--------|------|
| 查 mc alias 怎么写 | [mc alias](https://example.com/mc-alias.html) | #mc-alias-set | alias、凭证、endpoint | |
| 看 mc cp 的镜像参数 | [mc cp](https://example.com/mc-cp.html) | #mirror | cp、复制、mirror | [#sync 子命令](https://example.com/mc-mirror.html) |

若站点总条目 ≤ 15 条,不建 topics/,路由表直接放 index.md。

分区名的唯一来源:阶段 2 脚本输出里的「分区建议」列(llms.txt 用站点自己的一级标题,sitemap 用 scope 之后的第一个路径段)。必须照抄并与 topics/ 文件名保持一致——index.md 的分区索引表按它拼文件路径,自造分区名会导致指向的文件不存在。

该列为空的含义不是"漏了",而是站点结构里没有天然分区(页面扁平贴在同一层):此时按页面名前缀人工归并(sql-* → sql),并在 index.md 标注"分区为人工归并,非站点原结构"。


工作流

第一步先判模式(必做,不要跳过直接进入建造流程):读 {落点}/INDEX.md(不存在则视为首次;默认落点 .web-index/,被集成时为调用方指定位置,见「已知调用方」表)。

情况 模式 路径
目标站点已在册,本次是来问某个功能/答案 消费模式 见下方「消费模式」,查到就走——不重建
未收录,或用户明确要求建 / 重建 建造模式 走阶段 0 → 阶段 5

混用这两种模式的代价:把它当成"每次都从头建"的技能,索引就从省成本变成加倍成本。这条比后面任何一条规则都重要。

消费模式(查表 → fetch)

  1. 读 .web-index/INDEX.md → 拿到 slug
  2. 读 .web-index/{slug}/index.md,按「我要…」列或分区索引定位条目
  3. 命中分区时只读该 topics/{分区}.md,不读全部分区(省上下文)
  4. web_fetch 目标 URL(带锚点)取正文作答
  5. 没命中才现场查找;确认是常用页后,可手动往对应 topics 补一行(重跑会丢失)

只有建造模式才允许跑抓取脚本。 消费模式跑通即止,不要"顺便重建一下"。

建造模式:
阶段 0:准入判断   → 该不该建?不该建就直说,走正常 web_fetch
阶段 1:确定 scope → 站点标识 + 范围前缀 + 上限(唯一的用户确认点)
阶段 2:抓地图     → 脚本四级优先链拿候选链接
阶段 3:标注用途   → 给每条写「我要…」+ 锚点(本 skill 的核心增值步骤)
阶段 4:落盘       → 写 INDEX.md + index.md + topics/*.md
阶段 5:交付       → 输出结算 + 宣告后续使用协议

阶段 0:准入判断(AI 自主,不必问用户)

信号 判定
目标站点已在 INDEX.md 在册 ➡️ 转消费模式,本次不重建(用户要求重建除外)
本次只查一次 ❌ 不建,直接 web_fetch / web_search
站点仅 1-3 页、无结构可言 ❌ 不建,URL 直接写进对话或项目文档
需登录 / 付费墙 / 明确反爬 ⚠️ 告知用户,降级为「用户提供链接清单 + AI 结构化」,不在此处尝试绕过
同一站点本次已出现 ≥2 次查找,或用户明确"后面会反复参考" ✅ 建
用户主动给出某个文档站的入口并说"按这个文档做/后面都用这个" ⚠️ 先一句话确认:"这个站后面会反复查吗?"(一次性任务直接 fetch 更省),确认后再建
地图与导航都拿不到,且站点极大(规模不可知) ⚠️ 告知"无法穷举,只能按已知页面建部分索引",经同意再建

判定不建时,一句话说明理由后回到正常查阅流程,不产出任何文件。

阶段 1:确定 scope

先读 .web-index/INDEX.md(若已存在):目标站点已在册 → 直接告知用户"已有索引,看 slug 是否要重建",不重复采集。

向用户确认一次(这是建造模式唯一的用户确认点;阶段 4 遇到同名 slug 时另有一次重建确认):

📇 网页索引 · 范围确认
━━━━━━━━━━━━━━━━━━━━

站点:{站点名}  ({起始 URL})
产出目录:{落点}/{slug}/        # 默认 .web-index/;被集成时改用调用方落点
覆盖范围:{URL 前缀 或 导航分支名 或 「全站」}
条目上限:{300}

请确认范围是否正确?是否需要排除某些分支(如 changelog / blog / 版本快照)?

范围参数约定:

  • 优先用 URL 前缀(--scope /docs/api):可机器过滤,最可靠
  • 拿不到前缀时用导航一级分支名做命名依据,过滤仍在拿到链接后人工判定
  • 建议用 --exclude 显式排除:版本快照目录、blog/、changelog、非默认语言的副本(脚本不做任何隐式排除)
  • 上限默认 300,硬上限 1000;超限说明站点太大,须先收窄 scope

阶段 2:抓地图

优先用脚本(确定性、省 token):

timeout 30s python3 {skill-dir}/scripts/fetch_site_map.py {起始URL} \
  --scope {前缀} --max 300 --out temp/web-index-{slug}-map.md

执行约定:网络请求类命令前置 timeout(Linux timeout 30s / Mac gtimeout 30s);中间产物落在工作空间的 temp/ 下(temp/ 不存在则先创建),只增不删,完成后向用户报告中间文件位置,清理由用户决定。 Python 运行方式({skill-dir} 为本技能安装目录):项目有既有的 venv / requirements.txt 时按其命令执行,否则优先 uv run python;uv 不存在时不擅自安装,直接退回系统 python3。本脚本零依赖无需建环境。完整约定 SSOT 见 topic-teach 的 ops.md「运行环境约定」章节。

脚本按四级优先链自动降级,退出码与处置见下表(完整细节见 reference.md):

退出码 含义 处置
0 拿到候选链接 进入阶段 3
2 无 llms.txt / sitemap.xml 用 web_fetch 抓起始页,从导航/侧边栏人工提取链接列表
3 网络失败 / 超时 / 站点拒绝(403、429、Disallow: /) 报告用户,换个入口页重试一次;被明确拒绝则停止,不绕过
4 有地图但过滤后为空 放宽 scope(多半是前缀写错)后重试一次
5 入参非法(URL 缺 scheme/host、--max 超上限、--sitemap 指向空地图) 修正参数后重跑,重试同一命令没有意义

--out 会把表格写进文件、stdout 只留一行写入提示——落盘后读该文件,作为阶段 3 的输入。 退出码非 0 一律不得进入阶段 3(尤其别把失败当"没条目"处理,否则会产出一份空索引却看起来正常)。上表未列出的退出码 → 视为运行失败,报告用户,不自行重试。

分层索引站点(根 llms.txt 只列子索引指针,如 docs.langchain.com):脚本会自动跟随起点所在分区的子索引一层,无需干预;匹配错了用 --llms /{分区} 钉死。

脚本拿不到(退出码 2)时的备选:

  1. web_fetch 起始 URL,让 AI 列出导航中的链接与其文案
  2. 有 /sitemap-index.xml、/sitemap_index.xml、根 /sitemap.txt 可再试一次 --sitemap <url> 手动指定
  3. 仍无解且站点不大 → 逐页 fetch 收集(每次只提取链接、不读正文),控制在 5 页以内
  4. 站点极大且无结构 → 回到阶段 0 的 ⚠️ 分支告知用户

抓取礼仪:单次请求、不并发打站、robots.txt 禁止的路径直接放弃;返回 403 / 429 立即停止,不重试换 UA 硬抓。

阶段 3:标注用途(核心)

对每条候选链接补齐表格四列。跳过这步等于白做——只有 URL 的索引无法支撑路由决策。

「我要…」列的写法(任务/问题视角,不是标题复读):

❌ 差 ✅ 好
"TLS" "给服务配 HTTPS 证书,改哪个配置项"
"mc alias 页面" "查 mc alias 的写法与生效位置"
"API 参考" "查创建桶接口的请求参数与错误码"

成本闸门(重要):本技能的全部价值建立在"建索引的成本 < 反复查找的成本"上,一旦失控就赢了道理输了账。

  • 用于确认用途的 web_fetch 不超过 10 次;其余一律按 URL 语义 + 导航文案推断,推断拿不准写 [待确认]——宁可有少量待确认条目,也不要为了填满而逐页 fetch
  • 一次的花费明显超过"直接 fetch 几页"时立即止损:砍掉上限、收窄 scope,或中止并告知用户

补充规则:

  • 用途来源优先级:① llms.txt 自带描述(最准)② URL 路径 + 导航文案推断 ③ 抓不准时才 web_fetch 该页读标题与首段确认(只读标题和首段,不读正文,计入上面 10 次预算)
  • .md 端点保留原样:地图给出 …/xxx.md 时不改回 .html——那通常就是站点给 LLM 准备的干净 Markdown 版(细节见 reference.md §1)
  • 同一功能多条链接时保留最权威的一条进表,其余写进同行的"相关"附注
  • 锚点只在确有定位价值时写(页面很长、单个 anchor 直达小节),否则留空
  • 关键词 3-5 个,写用户会用的口头词而非 URL 词干("证书"而非 "network-encryption")

阶段 4:落盘

  1. 检查目标目录 {落点}/{slug}/ 是否已存在(落点默认 .web-index/;被集成时以调用方指定位置为准,见「已知调用方」表):存在则先告知用户"将整站覆盖重建"(快照制没有增量合并),得到确认再写
  2. 同步更新 {落点}/INDEX.md(新增或覆盖该站那一行)。缺这步,后续会话的 AI 发现不了这份索引
  3. 分区拆分规则:
    • ≤15 条 → 全部进 index.md,不建 topics/
    • >15 条 → 按导航一级分支拆到 topics/{分区}.md
    • 单分区 >60 条 → 按二级分支再拆(security-tls.md / security-kms.md)
    • 分区名为空 → 先按页面名前缀人工归并再分组;空名分区会生成 topics/.md 这种损坏产物,绝不允许出现
  4. index.md 的「高频直达」取 5-10 条用户最可能问起的任务(宁少勿多,它是目录不是索引主体)
  5. 写入完成后自检:所有 URL 均来自阶段 2/3 实际产出,无凭空拼写的链接;存在 [待确认] 条目时如实保留

阶段 5:交付

✅ 网页索引已生成

位置:{落点}/{slug}/        # 默认 .web-index/;被集成时为调用方落点
站点:{站点名}({起始 URL})
范围:{scope} · 条目 {N} 条 · 分区 {M} 个

| 文件 | 内容 |
|------|------|
| index.md | 高频直达 + 分区索引 |
| topics/{A}.md | {A 覆盖内容}({n} 条) |

⚠️ 一次性快照:链接失效或站点改版时整站重跑重建,无自动刷新。
`.web-index/` 默认不入库——若不想污染 git,可加入 .gitignore(**被集成且落点被调用方覆盖时,遵循调用方的 git 约定**:如 `topic-teach` 落在教程目录内的索引属教学产物,须入库)。
⚠️ 隐藏目录不会被自动发现:**独立使用**本 skill 时,需要项目在 AGENTS.md / 规则里加一行
   "涉及外部站点的问题,先查 .web-index/INDEX.md 再决定 fetch 哪一页"(加不加由你决定,本 skill 不代劳);
   **被其它 skill 集成**时,钩子由调用方在其流程中声明。

后续用法:涉及该站的问题先查本索引的「我要…」列定位页面,再 web_fetch 取正文。

反模式

  • ❌ 只有 URL 没有「我要…」:AI 仍不知道跳哪页,索引名存实亡
  • ❌ 把正文/代码示例抄进索引:立刻过期 + 上下文爆炸("只索引不镜像"是硬规则)
  • ❌ 不设 scope 全站爬:文档站动辄上千页,产物大到没人会读
  • ❌ 按路径规律拼链接:…/v1/guide/ 猜 …/v2/guide/ 是典型的臆造来源
  • ❌ 给只查一次的站建索引:建索引本身要花一轮上下文,一次性查阅直接 fetch 更省
  • ❌ 遇 403 / 429 / robots 禁止仍硬抓:属于授权边界,停下来报告用户
  • ❌ 把多个产品线塞进同一个 slug:混在一起后每次都要全表扫描,等于没分区
  • ❌ 漏更新 .web-index/INDEX.md:索引藏在隐藏目录里,没有登记表就再也没人(包括下一次的 AI)找得到它

行为边界

  • 只索引,不抓取/不留存正文:索引文件只含链接、用途、锚点、关键词
  • 快照制:不生成刷新计划、不做版本 diff、不校验链接存活;失效按"整站重跑覆盖重建"处理。发现个别缺页时由 AI 手动往对应 topics/ 补一行(重跑会丢失,属可接受损耗)
  • 不改用户环境:不写 gitignore、不提交、不注册到任何需求管理系统;如需入 git 由用户决定
  • 不做反爬对抗:不用代理池、不伪造 UA 重试、不绕过登录
  • 与 dependency-docs 分工:dependency-docs 管"需求里的第三方依赖 × 结构化字段"(接口清单 / 认证 / 限流 / 配额),本 skill 管"一个网站的页面路由 × 反复查阅"。设计阶段要依赖的深度字段时用前者,不要用索引代替(反之亦然,两者产物互不冲突)
  • 与 frontend-index 分工(防抢触发):本 skill 的对象是外部网站(需要 web_fetch 抓远端页面,产物 .web-index/);本地前端代码的「页面 ↔ 接口」双向映射走 frontend-index(扫源码,产物 .fe-index/)——用户说"给前端项目建索引"时用后者,别去 fetch 本地代码

被其它 skill 集成(调用契约 · SSOT)

本 skill 的主要用法不是独立触发,而是被其它 skill 在"需要参考外部站点"时调用。调用方按本节判定,不要无脑建索引。

规模判断:值不值得建

维度 直接查(不建) 建索引
查阅次数 1 次,本轮用完即止 预计 ≥2 次,或要跨阶段/跨会话复用
站点规模 单页 / 1-3 页 / 无结构可言 多页文档站,有 llms.txt 或 sitemap
需求成熟度 需求尚未确认(可能不成立) 需求已确认,后续设计/编码/测试都要参考
已有索引 已在 INDEX.md 在册 → 消费模式,不重建 未收录且满足上述条件 → 建造模式

判定的三种输出(不只是建/不建两种):

  1. 不建 → 直接 web_fetch / web_search,不产出文件
  2. 值得建但当前阶段太早 → 只登记"待建站点清单",把建造推迟到确定会用的阶段(如设计阶段由 dependency-docs 接管)。需求没立住就先把文档收集一遍,是典型的白做功
  3. 现在就建 → 走建造模式(阶段 0-5)

调用方式

情况 怎么调
目标站点已在 INDEX.md 消费模式:读 INDEX.md → 命中分区 → web_fetch。不跑脚本
未收录且判定要建 建造模式:阶段 0 → 阶段 5
判定不建 什么都不调,按原流程直接查

调用方只需在流程里写清"何时调用 + 上面这张判定表的指针",判定规则本身不复制——规则改了只改本文件(与 ki-memory-lookup 的 SSOT 约定一致)。

已知调用方

调用方 调用时机 索引落点
topic-teach Step 1.4:大纲定稿后按主题收集官方站(速览默认不做) 教程目录内 {topic-slug}/web-index/(覆盖本文件默认的 .web-index/,落点以调用方为准;教程产物要入库,不适用"默认不入库"的建议)
module-teach Phase 1.5:知识范围含 [通用] 时收集(纯专用 / 变更类精简模式跳过) 项目根(与 .teach/ 同级)

本表只用于双向发现(知道谁在用、索引在哪),不含规则——判定规则以本文件为准,调用方的时机与落点以其 SKILL.md 为准。新增调用方时在此加一行。

已知集成方(新增集成方时在此补一行,并确认它声明了发现钩子):

集成方 位置 该阶段的默认口径
requirement-mining Step 5.5.3 依赖可行性 登记待建为主(需求未定,不急着建)
dependency-docs 阶段 2.0(分发子任务之前) 主 agent 先建 / 复用索引再分发,避免 N 个子 agent 重复探索

两处默认口径不同是故意的:需求阶段方案未定 → 先登记;设计阶段需求已确认且要并行收集 → 先建再用。


更多资源

  • 地图抓取四级链细节、脚本完整参数与退出码、分区拆分算法、llms.txt / sitemap.xml 解析约定 → reference.md
  • 确定性抓取脚本(Python 3 标准库,零依赖)→ scripts/fetch_site_map.py