Files
reader/docs/notes/reading-pipeline-design-notes.md

11 KiB
Raw Permalink Blame History

阅读流方案讨论纪要

参考来源

1. 当前目标

本项目的目标不是直接复刻文章里的整套实现,而是先按下面这条链路,逐步做出一套接近文章效果的阅读流系统:

  1. 通过一层 RSS 聚合获取文章
  2. 通过一个 skill 或 mcp 获取文章摘要
  3. 基于规则对摘要结果进行过滤
  4. 将过滤后的内容推送到知识库或其他文档组件
  5. 完成消息推送
  6. 最后再考虑与 OpenClaw 结合

这里的 skill / mcp 只是整条链路中的一个组件,当前讨论的重点是第 2 步“页面摘要能力”的设计,而不是一次性把整套系统全部落地。


2. 内容来源分类

为了便于后续实现,内容来源建议按两个维度分类:

  • 按来源类型分类:这个内容来自什么渠道
  • 按接入方式分类:系统用什么技术手段把它纳入统一流水线

这样做的原因是:

  • 同一种来源类型,可能有不同接入方式
  • 同一种接入方式,可能服务多种来源
  • 后面的摘要、过滤、入库更适合依赖标准化后的 source schema,而不是依赖渠道名称

2.1 按来源类型分类

建议定义以下几类:

  • feed

    • 原生 RSS / Atom 源
    • 典型例子:博客、新闻站、技术周刊、文档更新
  • converted_feed

    • 原本不是 RSS,但通过第三方或自建转换后变成 feed
    • 典型例子:微信公众号、部分社区栏目、社交平台账号流
  • event_feed

    • 更偏事件流而不是传统文章流
    • 典型例子:GitHub Releases、Commits、Discussions、Changelog
  • page_watch

    • 没有现成 feed,需要定时轮询某个页面的更新
    • 典型例子:专题页、导航页、榜单页、产品更新页
  • custom_source

    • 无法直接归类,需要为特定站点写专门抓取逻辑
    • 典型例子:结构特殊的网站、内部页面、非标准内容源

2.2 按接入方式分类

建议定义以下几类:

  • feed_direct

    • 直接消费 RSS / Atom
  • feed_converted

    • 通过 RSSHub、wewe-rss、RSS-Bridge 等方式先转成 feed,再统一消费
  • api_backed

    • 通过平台 API 获取内容,再标准化成内部 item
  • html_scraped

    • 直接抓取 HTML 页面,自己解析列表页和正文页
  • hybrid

    • 先消费 feed 元信息,再按需回源抓正文

2.3 你当前关心的几类内容如何归档

  • RSS 文章

    • 来源类型:feed
    • 接入方式:feed_direct
    • 优先级:最高
  • 微信文章

    • 来源类型:converted_feed
    • 接入方式:通常是 feed_converted
    • 优先级:高
  • 其他文章

    • 如果是社区栏目、论坛专题:通常归到 converted_feed 或 page_watch
    • 如果是普通网站更新页:通常归到 page_watch
    • 如果是 GitHub 项目更新:通常归到 event_feed
    • 如果是特殊站点:归到 custom_source

结论:

“其他文章”不应作为最终系统里的正式分类,因为它过于宽泛,后续规则过滤会很难维护。

2.4 建议的实现级分类

如果进入实现阶段,建议系统内部只保留下面这 5 类 source type:

  • feed
  • converted_feed
  • event_feed
  • page_watch
  • custom_source

同时再给每个 source item 增加一个 content_kind 字段,用来表达内容形态:

  • article
  • thread
  • release
  • changelog
  • video
  • mixed

这样可以把“来源渠道”和“内容形态”拆开,后面的摘要与过滤规则会更稳定。

2.5 当前阶段建议先支持的来源

为了降低复杂度,第一阶段建议只支持两类:

  • feed
  • converted_feed

原因:

  • 它们最接近当前目标链路
  • 接入成本最低
  • 最容易验证第 2 步摘要和第 3 步过滤是否成立
  • 暂时不需要引入复杂的页面轮询和定制抓取逻辑

3. 系统边界的核心结论

当前最重要的不是先决定做 Skill 还是 MCP,而是先定义一个可复用的“摘要内核”。

建议的能力分层:

RSS 聚合 -> summary-core -> rule-engine -> sink -> push -> OpenClaw 编排

其中:

  • summary-core:负责抓取页面、抽取正文、生成结构化摘要
  • rule-engine:负责根据规则和评分过滤内容
  • sink:负责将结果写入知识库或文档系统
  • push:负责消息通知
  • OpenClaw:最后作为编排层或自动化入口接入

结论:先做“能力内核”,再决定用 MCP 还是 Skill 进行封装。


4. Skill 和 MCP 的定位

Skill

适合:

  • 人工触发
  • 代理式工作流
  • 提示词编排
  • 让 Agent 在上下文里决定何时调用摘要流程

优点:

  • 实现快
  • 适合探索和半自动流程

缺点:

  • 不适合做稳定的批处理基础设施
  • 不适合承载缓存、重试、队列、状态管理

结论:

Skill 更像“编排层”,不适合作为底层基础能力的唯一实现。

MCP

适合:

  • 将摘要能力标准化成可调用工具
  • 给 OpenClaw、ChatGPT、Claude 等 Agent 统一接入
  • 为后续自动化编排预留稳定接口

优点:

  • 接口标准化
  • 易于被 Agent 调用
  • 后续接 OpenClaw 更自然

缺点:

  • 仍然需要自己实现抓取、抽取、摘要、缓存等能力

结论:

MCP 适合作为“能力接口层”。

当前建议

推荐顺序:

  1. 先做 summary-core
  2. 再暴露成 MCP
  3. 最后根据需要加 Skill

不建议一开始只做 Skill。


5. 页面摘要能力应输出什么

页面摘要不要只输出一段自然语言摘要,而应该输出结构化结果,方便后面的过滤、入库和推送。

建议输出结构:

{
  "url": "https://example.com/article",
  "title": "文章标题",
  "source": "站点名",
  "author": "作者",
  "published_at": "2026-03-23T08:00:00Z",
  "language": "zh",
  "summary": "3-5句摘要",
  "highlights": ["要点1", "要点2", "要点3"],
  "keywords": ["rss", "mcp", "knowledge-base"],
  "topics": ["AI tools", "workflow"],
  "quality_flags": {
    "is_paywalled": false,
    "is_truncated": false,
    "is_low_content": false
  },
  "scores": {
    "readability": 0.84,
    "novelty": 0.72,
    "relevance": 0.91
  },
  "content_hash": "xxx"
}

这样做的价值:

  • 规则过滤直接使用结构化字段
  • 知识库入库更稳定
  • 推送内容可按场景裁剪
  • 后续可以追踪质量、去重和打分

6. 第 2 步“页面摘要能力”的技术拆分

页面摘要不是单一步骤,而是 3 个子能力:

  1. 获取页面内容
  2. 抽取正文
  3. 生成摘要

5.1 获取页面内容

有两条常见路径:

  • 直接使用 RSS item 里的 content:encoded 或 summary
  • 根据 RSS item 的 link 回源抓取页面

建议策略:

  • 先使用 RSS 已提供的内容
  • 如果内容过短、质量不够,再回源抓页面正文

这样能平衡速度和完整度。

5.2 正文抽取

这是稳定性的关键环节。

候选技术:

  • trafilatura

    • 对博客、新闻、文档类页面较稳
    • Python 生态成熟
  • readability-lxml

    • 经典轻量方案
    • 覆盖面广
  • Playwright + Readability

    • 适合 JS 动态页面
    • 成本最高,但兜底能力最强

建议组合:

  • 第一层:httpx/requests + trafilatura
  • 第二层:Playwright 作为兜底方案

不建议一开始就默认使用 Playwright。

5.3 摘要生成

有两类方向:

  • 抽取式摘要

    • 成本低
    • 稳定
    • 可读性通常一般
  • 生成式摘要

    • 更接近最终想要的“知识流”效果
    • 可读性更好
    • 需要更严格的结构化约束

建议:

  • 采用生成式摘要
  • 强制模型输出 JSON Schema
  • 不允许自由散文式输出

这样后续流程会稳定很多。


7. 过滤层设计

过滤层不要完全依赖 LLM 的自由判断,建议采用“两层过滤”。

第一层:确定性规则

例如:

  • 来源白名单 / 黑名单
  • 关键词规则
  • 主题规则
  • 语言过滤
  • 最低字数要求
  • 重复检测
  • 发布时间窗口
  • relevance 阈值

第二层:可选的 LLM 判断

例如:

  • 是否值得进入知识库
  • 更偏资讯还是方法论
  • 是否符合个人关注主题
  • 是否值得推送

结论:

先规则,后智能,不要反过来。


8. 知识库与推送层设计

第 4、5 步可以统一抽象为 sink 和 push。

第一阶段建议优先做的 sink

  • Markdown sink

    • 输出到本地目录或 Git 仓库
    • 适合第一版
    • 可审计、易迁移
  • Webhook sink

    • 推送到 Telegram、企业微信、飞书、OpenClaw 或其他自动化入口
    • 扩展性最好

后续可扩展的 sink

  • Notion
  • Obsidian Vault
  • Logseq
  • 数据库

结论:

第一版不建议直接绑死在单一平台上,优先本地 Markdown + Webhook。


9. 现在真正该先定义的接口

摘要内核建议先定义统一接口,而不是先定义 UI 或 Agent 提示词。

建议输入:

  • url
  • 可选 raw_html
  • 可选 rss_content
  • 可选 user_profile
  • 可选 summary_style

建议输出:

  • 结构化摘要 JSON
  • 原始正文文本
  • 元信息
  • 错误状态

只要这个接口稳定:

  • CLI 可以调用
  • HTTP 服务可以调用
  • MCP 可以调用
  • OpenClaw Skill 也可以调用

这一步是整个系统里最关键的抽象。


10. 推荐的演进路线

建议按下面顺序推进:

  1. RSS 聚合
    • 先通过 FreshRSS 或现有聚合器获取文章链接
  2. summary-core
    • 输入 URL,输出结构化摘要
  3. rule-engine
    • 对摘要 JSON 执行过滤规则
  4. sink
    • 先落 Markdown,再做 webhook 推送
  5. MCP server
    • 暴露 summarize_url、filter_summary、store_note 等工具
  6. OpenClaw Skill
    • 让 OpenClaw 负责编排、人工确认或附加动作
  7. OpenClaw 集成
    • 最后再接入完整自动化流程

这样每一层都可以独立测试,不会过早被某个平台或代理框架绑定。


11. 当前阶段的明确判断

不建议的方向

  • 一开始只做 Skill
  • 一开始把 OpenClaw 当成底层依赖
  • 一开始就直接绑死 Notion 一类单一知识库
  • 让过滤完全依赖 LLM 自由发挥

建议优先做的方向

  • 先定义 summary-core 的输入输出
  • 摘要结果必须结构化
  • 过滤规则优先基于确定性逻辑
  • 入库优先选择 Markdown
  • 对外优先暴露成 MCP,而不是先做纯 Skill

12. 后续讨论建议

后面可以基于这份文档继续讨论以下问题:

  1. summary-core 的最小可用接口如何定义
  2. MCP 版和 Skill 版分别暴露哪些能力
  3. 正文抽取链路是否需要分层回退
  4. 规则引擎使用配置文件还是代码实现
  5. Markdown sink 的目录结构怎么设计
  6. Webhook / 推送层先接哪一个目标
  7. OpenClaw 在整条链路里承担“调度器”还是“人工审核入口”

13. 当前阶段的一句话结论

当前阶段最合理的方向是:先把“页面摘要”做成一个独立、结构化、可复用的能力内核,再优先封装为 MCP,最后再用 Skill 和 OpenClaw 做编排与集成。