Skill Seekers RSS 技能生成:SKILL.md 金标输出结构与截断规范解析
Skill Seekers RSS 技能生成:SKILL.md 金标输出结构与截断规范解析
导读
本文以 Skill Seekers 仓库中 tests/golden/phase2/rss/SKILL.md 金标(golden)输出文件为骨架,完整解析 RSS/Atom 订阅源(Feed)被转换为 Claude AI Skill 后生成的 SKILL.md 结构规范:从前置元数据、Feed 信息块、文章概览到标签溢出与截断规则,并逐一对应到 RSS 抓取器源码 与 金标测试用例 的实现细节。读完本文,你将掌握 Skill Seekers 生成 RSS 技能的文件布局、字段约定、边界条件处理方式,以及如何用一条命令把一个技术博客的订阅源变成可被 Claude 直接引用的结构化技能。
一、金标文件的定位:什么是 RSS 技能的 SKILL.md
tests/golden/phase2/rss/SKILL.md 不是一篇普通文档,而是一份金标输出(golden output)——它是 Skill Seekers 在测试阶段对 RSS 抓取器产物做的“快照基准”。测试代码在 tests/test_phase2_golden_rss.py 顶部有明确说明:
The golden trees under
tests/golden/phase2/rss*were captured from the PRE-DocumentSkillBuilder code; these tests prove the port is byte-identical.
也就是说,这份 SKILL.md 与同目录下的 references/ 子目录一起,构成一棵金标目录树,用于证明重构后的 RSS 构建路径与旧代码逐字节一致(byte-identical)。它同时是一份极具参考价值的“成品规格”:展示了当用户运行 skill-seekers rss 抓取一个真实 Feed 后,生成的技能入口文件应该长什么样。
这份金标文件围绕一个虚构的测试订阅源 https://example.com/feed.xml(标题 "Example Engineering Blog",类型 RSS 2.0,由 ExampleCMS 2.0 生成)构建,包含 4 篇文章、2 位作者、55 个标签。所有 URL 均为测试占位符,切勿视为真实数据。
二、RSS 技能的整体产物布局
根据金标目录树 tests/golden/phase2/rss/,一个 RSS 技能的完整产物结构如下:
rss/
├── SKILL.md # 技能入口:Feed 概览 + 导航
└── references/
├── index.md # 分类索引 + 统计信息
├── dev_ops.md # 按标签归类的文章参考文件
├── python.md
├── uncategorized.md
└── unnamed.md # 全符号标签(★★★)的兜底文件名
这个结构由 RssToSkillConverter 负责生成。它继承自 DocumentSkillBuilder 的 build_skill 编排逻辑,但针对 RSS 数据“以文章(articles)+ 标签(tags)而非页面(pages)+ 标题(headings)为形态”的特点,重写了分类、参考文件生成、索引生成与 SKILL.md 生成四个环节(源码类注释对此有明确说明)。
index.md 的生成逻辑见 _generate_index,SKILL.md 的生成逻辑见 _generate_skill_md。下面逐区块拆解 SKILL.md 的构成。
三、YAML 前置元数据:name 与 description 的规范化
金标 SKILL.md 的开头是标准的 YAML frontmatter:
---
name: golden-rss
description: Use when testing the rss golden build
---
对应源码逻辑位于 _generate_skill_md:
- name:取用户传入的
config["name"],统一转为小写、下划线与空格替换为连字符、截断到 64 字符。因此配置名golden_rss最终变成golden-rss。 - description:若用户未显式提供,会由 _infer_description_from_feed 根据 Feed 元数据自动推断——优先用 Feed 的 description(超过 150 字符时截断到 147 字符加省略号),其次用 Feed 标题拼出
Use when referencing articles from {title};最终写入 frontmatter 前还会被截断到 1024 字符以内。
description 是 Claude/Agent 判定“何时使用该技能”的关键信号,因此生成器始终以 Use when... 句式输出,保证语义一致性。
四、📡 Feed Information 区块:订阅源元数据的完整呈现
金标文件在这一区块输出了 7 个字段,覆盖 Feed 级元数据的全部关键维度:
| 字段 | 金标示例值 | 数据来源(feedparser 字段) |
|---|---|---|
| Feed Title | Example Engineering Blog | feed.title |
| Feed Type | RSS 2.0 | 由 parsed.version 检测(见下) |
| Website | https://example.com | feed.link |
| Language | en-us | feed.language |
| Description | 长描述截断至 300 字符 | feed.subtitle 或 feed.description |
| Generator | ExampleCMS 2.0 | feed.generator |
| Rights | © Example Inc. | feed.rights |
Feed 类型检测在 _detect_feed_type 中完成,支持四种取值:RSS 2.0、RSS 1.0 (RDF)、Atom、Unknown。检测优先级是:先看 feedparser 的 version 字段(含 "atom"、"rss20"、"rss10/rdf" 等关键词),再退回启发式判断(检查 xmlns 命名空间或 rss_version 字段)。
Description 的 300 字符截断是本区块最值得注意的规范:金标测试特意构造了一个超长描述(见测试文件中的 LONG_FEED_DESCRIPTION),源码中对应的处理是:
if len(feed_desc) > 300:
feed_desc = feed_desc[:297] + "..."
即超过 300 字符时,保留前 297 字符并以省略号结尾,保证信息块在技能入口文件中保持紧凑。
五、💡 When to Use 与 📖 Article Overview:技能的用途声明与内容盘点
When to Use This Skill 区块是生成器固定的 5 条“何时使用”清单,由源码逐行写入(_generate_skill_md):
- Reference articles and content from Example Engineering Blog
- Look up specific topics covered in the feed
- Find author perspectives and expert analysis
- Review recent posts and updates on the subject
- Explore categorized content by tags or topics
紧随其后的 Article Overview 区块输出文章总数与分类分布,分类分布来自 categorize_content() 的返回结果(_categorize_content),其核心逻辑是:
- 取每篇文章的
categories(由 feedparser 的tags字段提取); - 文章没有标签时落入
uncategorized桶; - 分类键经
_sanitize_filename清洗后作为去重与文件名依据; - 若整个 Feed 一篇文章都没有,则回退为单一的
all_articles桶(金标树 tests/golden/phase2/rss_empty/SKILL.md 演示了空 Feed 场景)。
金标示例的分类分布为:Dev Ops 1 篇、Python 1 篇、uncategorized 1 篇、★★★ 1 篇,与 4 篇总数严格对应。
六、📰 Recent Articles 区块:摘要的 200 字符截断与元数据行
这是 SKILL.md 的信息密度核心。金标示例展示了 4 篇文章的三种元数据形态:
### Continuous Delivery in Practice
**Published:** Mon, 01 Jan 2024 10:00:00 GMT | **Author:** Jane Doe
This is a deliberately long summary that keeps going well past the two hundred character truncation threshold...(截断效果)
摘要截断规则:源码对每篇文章的 summary 做 summary<a href="https://link.gitcode.com/i/472b7b1432a11c94284dde5f08b6dd23" target="_blank">:200] + "..." 处理([_generate_skill_md),即超过 200 字符截断并追加省略号。金标测试特意把第一篇文章的摘要写得远超 200 字符,用于验证此分支。
元数据行组装规则:Published 与 Author 用 | 连接成一行,但两者均可选——无发布日期的文章(如 "An Uncategorized Note")只显示作者,无作者的文章(如 "Symbols Only")只显示发布时间。每条文章末尾输出 Read more,无链接(如 "An Uncategorized Note")则不输出。
Recent 列表上限:取文章列表的前 10 篇(articles[:10]),对于超大 Feed,SKILL.md 只展示最新 10 篇,其余内容全部沉淀到 references 参考文件中,保证入口文件不至于膨胀。
七、✍️ Authors、🏷️ Tags 与 📊 Feed Statistics:统计维度的三个区块
Authors:由 _count_authors 统计每篇文章的 author 字段并按文章数降序排列,SKILL.md 展示前 15 位,索引文件展示前 20 位。金标示例为 Jane Doe 2 篇、John Roe 1 篇。
Tags:展示全部唯一标签,最多列出前 50 个,超出部分以 ... and N more 结尾:
`Dev Ops`, `Python`, `dev-ops`, `tag00`, ..., `tag46` ... and 5 more
金标测试用 55 个标签专门验证了这条溢出分支(tag00~tag50 共 51 个,加 4 个主题标签共 55 个,多出的 5 个触发 and 5 more)。注意这里不截断标签内容,只截断数量,与摘要/描述的字符截断形成对照。
Feed Statistics:汇总输出 6 项统计,其中 Full Content Scraped 直接反映 follow_links 配置:
- Total Articles / Feed Type / Categories-Tags / Authors / Full Content Scraped(Yes/No)/ Date Range
Date Range 由 _get_date_range 计算:取全部文章 published_iso 的最小值与最大值(仅取日期部分 [:10])。金标示例为 2024-01-01 to 2024-03-15。
八、🗺️ Navigation 区块与 references 参考文件体系
SKILL.md 的收尾区块是指向参考文件的导航清单,金标示例:
**Reference Files:**
- `references/dev_ops.md` - Dev Ops (1 articles)
- `references/python.md` - Python (1 articles)
- `references/uncategorized.md` - uncategorized (1 articles)
- `references/unnamed.md` - ★★★ (1 articles)
See `references/index.md` for complete feed structure.
这里隐藏着 RSS 构建路径的两个关键边界处理,也正是金标测试重点覆盖的场景:
8.1 重叠归一化键的去重("Dev Ops" 与 "dev-ops")
categorize_content 中,分类名 Dev Ops 与 dev-ops 经 _sanitize_filename 清洗后都变成 dev_ops,会落入同一个分类桶。源码通过维护已加入文章的 id 集合来避免同一篇文章被重复收录(_categorize_content)。金标测试的第一篇文章故意携带 <a href="https://link.gitcode.com/i/ca3abb936b19056417e24212fc36a51e" target="_blank">"Dev Ops", "dev-ops"] 两个标签来触发此守卫。查看 [references/dev_ops.md 可确认该文章只出现一次,且 Tags 行完整保留了原始双标签 Dev Ops, dev-ops。
8.2 全符号标签的 "unnamed" 兜底("★★★")
_sanitize_filename 会把非字母数字字符剥离:★★★ 清洗后得到空字符串。源码的 _sanitize_filename 以 return safe or "unnamed" 兜底,确保不产生空文件名——这正是 references/unnamed.md 的由来,其内容见 references/unnamed.md。
8.3 参考文件内部结构
每个分类参考文件(如 references/python.md)按“分类标题 → 文章数 → 每篇文章的元数据块(Author / Published / Link / Tags)→ Summary → Content → Full Article”的固定顺序排版。三个内容来源有明确优先级与条件:
- Summary:总是输出;
- Content:仅当 Feed 内联正文(
content)存在且与 summary 不同才输出(金标测试第二篇文章 content == summary,专门验证该分支被跳过); - Full Article:仅当
follow_links抓取到完整页面文本(full_text)时输出,见 references/uncategorized.md 中由 "An Uncategorized Note" 展示的### Full Article区块。
index.md 则聚合全部分类链接与统计信息,格式见 references/index.md。
九、金标验证:如何保证字节级一致
金标树不是静态展示,而是由测试动态校验的。核心测试为 test_phase2_golden_rss.py 中的 test_rss_build_matches_golden:
converter = RssToSkillConverter({
"name": "golden_rss",
"description": "Use when testing the rss golden build",
"feed_url": "https://example.com/feed.xml",
"output_dir": str(tmp_path / "skill"),
})
converter.extracted_data = _extracted_data()
assert_matches_golden(build_snapshot(converter), "rss")
测试直接注入 _extracted_data() 构造的 4 篇文章(覆盖:双标签去重、无标签文章、无链接/日期/作者文章、纯符号标签、55 个标签溢出、长摘要、长 Feed 描述),调用转换器生成快照,与金标树逐字节比对。配套的 test_rss_empty_feed_matches_golden 则用空 Feed 验证 all_articles 兜底与 Full Content Scraped: No 统计分支。
这意味着你看到的这份金标 SKILL.md 的每一个字符,包括省略号、空格、连字符,都是可回归测试的“契约”,任何重构都必须保持逐字节不变。
十、从金标到实战:如何生成自己的 RSS 技能
金标文件对应的是完整抓取流水线的“输出端”。输入端由 RssToSkillConverter 的 extract_feed() 驱动,CLI 用法(见 rss_scraper.py 模块 docstring):
# 从远程 Feed URL 抓取(默认跟随文章链接抓取全文)
skill-seekers rss --feed-url https://example.com/feed.xml --name myblog
# 从本地 Feed XML 文件解析
skill-seekers rss --feed-path ./feed.xml --name myblog
# 不跟随文章链接,仅用 Feed 内的摘要与内联正文
skill-seekers rss --feed-url https://example.com/rss --no-follow-links --name myblog
# 复用已抽取的中间 JSON 继续构建
skill-seekers rss --from-json myblog_extracted.json
# 等价于直接调用模块
python3 -m skill_seekers.cli.rss_scraper --feed-url https://example.com/atom.xml --name myblog
可配置项及其默认值(来自 _init):
| 配置项 | 默认值 | 说明 |
|---|---|---|
feed_url / feed_path |
必选其一 | 远程 URL 或本地 XML 文件 |
follow_links |
True |
是否跟随文章链接抓取全文(对应金标中 Full Content Scraped: Yes) |
max_articles |
50 |
最多处理文章数(entries[:max_articles]) |
description |
自动推断 | 覆盖自动生成的 Use when 描述 |
两个值得注意的运行时保护:抓取全文时每篇文章请求超时 15 秒、请求间固定间隔 1 秒(_REQUEST_DELAY),并设有 180 秒总时间预算(_FOLLOW_TIME_BUDGET),慢速 Feed 不会无限阻塞构建(_extract_feed);单篇文章正文上限 50000 字符,超出截断并追加 [Content truncated]。此外,RSS 功能依赖可选依赖 feedparser,未安装时会明确提示 pip install "skill-seekers[rss]"。
结语:金标文件是一份可执行的输出规范
tests/golden/phase2/rss/SKILL.md 的价值远超“测试样本”:它完整定义了 Skill Seekers 将 RSS/Atom 订阅源转化为 Claude 技能时的入口文件规范——frontmatter 的命名与描述约定、Feed 元数据的 7 字段呈现、300/200/1024 字符与 50 标签的四类截断边界、uncategorized/unnamed/all_articles 三种兜底分类,以及 references 参考文件体系的排版规则。结合 RSS 抓取器源码、金标测试 与 references 目录 相互印证,读者既可以把这份文件当作格式参考来审查自己生成的技能,也可以把它当作理解整个 RSS→Skill 管线的入口地图。