web-index
给需反复查阅的网站 / 文档站建本地网页索引(.web-index/{site}/):抓 llms.txt / sitemap.xml / 导航,产出「要做什么 → 去哪一页(含锚点)」的路由表;已索引站点按路由表直接查(消费模式),只做链接索引、不镜像正文。触发:"给这个网站建个索引"、"整理一下这个文档的链接"、"网页索引"、"查一下网页索引"、"web index"、"这站要反复参考";只查
Files3
View on GitHubSKILL.mdskills/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进消费模式,而不是重头建一遍
核心原则
- 路由表,不是链接收藏:每条必须有任务视角的「我要…」列。只给链接等于没索引——AI 拿到一堆 URL 仍不知道跳哪页。
- 只索引,不镜像:不抓正文、不抄代码示例。正文留给
web_fetch现取,否则立刻过期且上下文爆炸。 - 一手地图优先:
llms.txt>sitemap.xml> 站点导航 >web_search。能用地图就不用搜索引擎——后者结果随机、不可复现。 - 范围闸门 + 反门槛:不设 scope 与上限会对着上千页失控;只查一次的站禁止建索引(见阶段 0)。
- 不臆造链接:URL 必须来自站点实际返回。禁止按路径规律拼链接、凭记忆写 URL;拿不准的标
[待确认]。 - 快照制(只建不管):产物是一次性快照,元信息记录生成日期 / scope / 条目数供新鲜度判断。不提供自动刷新与版本 diff,失效即整站重跑覆盖重建。
- 可见性由集成方负责:产物落在隐藏目录,本 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)
- 读
.web-index/INDEX.md→ 拿到 slug - 读
.web-index/{slug}/index.md,按「我要…」列或分区索引定位条目 - 命中分区时只读该
topics/{分区}.md,不读全部分区(省上下文) web_fetch目标 URL(带锚点)取正文作答- 没命中才现场查找;确认是常用页后,可手动往对应 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(Linuxtimeout 30s/ Macgtimeout 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)时的备选:
web_fetch起始 URL,让 AI 列出导航中的链接与其文案- 有
/sitemap-index.xml、/sitemap_index.xml、根/sitemap.txt可再试一次--sitemap <url>手动指定 - 仍无解且站点不大 → 逐页 fetch 收集(每次只提取链接、不读正文),控制在 5 页以内
- 站点极大且无结构 → 回到阶段 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:落盘
- 检查目标目录
{落点}/{slug}/是否已存在(落点默认.web-index/;被集成时以调用方指定位置为准,见「已知调用方」表):存在则先告知用户"将整站覆盖重建"(快照制没有增量合并),得到确认再写 - 同步更新
{落点}/INDEX.md(新增或覆盖该站那一行)。缺这步,后续会话的 AI 发现不了这份索引 - 分区拆分规则:
- ≤15 条 → 全部进
index.md,不建topics/ - >15 条 → 按导航一级分支拆到
topics/{分区}.md - 单分区 >60 条 → 按二级分支再拆(
security-tls.md/security-kms.md) - 分区名为空 → 先按页面名前缀人工归并再分组;空名分区会生成
topics/.md这种损坏产物,绝不允许出现
- ≤15 条 → 全部进
index.md的「高频直达」取 5-10 条用户最可能问起的任务(宁少勿多,它是目录不是索引主体)- 写入完成后自检:所有 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 在册 → 消费模式,不重建 |
未收录且满足上述条件 → 建造模式 |
判定的三种输出(不只是建/不建两种):
- 不建 → 直接
web_fetch/web_search,不产出文件 - 值得建但当前阶段太早 → 只登记"待建站点清单",把建造推迟到确定会用的阶段(如设计阶段由
dependency-docs接管)。需求没立住就先把文档收集一遍,是典型的白做功 - 现在就建 → 走建造模式(阶段 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