Add FreshRSS ingestion and rule filtering
This commit is contained in:
@@ -0,0 +1,59 @@
|
||||
# 文档索引
|
||||
|
||||
## 当前推荐阅读顺序
|
||||
|
||||
1. `context-reset-brief.md`
|
||||
- 当前真实进度与下一步入口
|
||||
2. `summary-mcp-service-design.md`
|
||||
- 当前 MCP 服务的职责、接口和边界
|
||||
3. `filter-rule-engine-design.md`
|
||||
- 过滤层的输入输出、规则结构与当前实现
|
||||
4. `source-schema-design.md`
|
||||
- `source -> item -> document` 的对象设计
|
||||
5. `reading-pipeline-design-notes.md`
|
||||
- 更上层的阅读流方案与阶段划分
|
||||
6. `summary-loop-explained.md`
|
||||
- 当前 LLM 摘要校验闭环的解释
|
||||
|
||||
## 当前文档分层
|
||||
|
||||
### 1. 当前状态与导航
|
||||
|
||||
- `README.md`
|
||||
- 仓库入口与脚本运行方式
|
||||
- `TODO.md`
|
||||
- 当前优先级、已完成项、下一阶段任务
|
||||
- `docs/context-reset-brief.md`
|
||||
- 当前阶段状态的最短摘要
|
||||
- `docs/README.md`
|
||||
- 文档索引与阅读顺序
|
||||
|
||||
### 2. 当前实现设计
|
||||
|
||||
- `docs/summary-mcp-service-design.md`
|
||||
- 当前内容提取 MCP 的真实设计
|
||||
- `docs/summary-core-interface-design.md`
|
||||
- 摘要/提取内核的接口抽象
|
||||
- `docs/source-schema-design.md`
|
||||
- `source`、`item`、`document` 三层 schema
|
||||
- `docs/summary-loop-explained.md`
|
||||
- 提取 JSON -> LLM 摘要 JSON -> 校验 的闭环说明
|
||||
- `docs/filter-rule-engine-design.md`
|
||||
- 第一版规则过滤引擎设计与落地位置
|
||||
|
||||
### 3. 上下游方案设计
|
||||
|
||||
- `docs/reading-pipeline-design-notes.md`
|
||||
- 整体阅读流、规则、sink、push 的方案笔记
|
||||
|
||||
### 4. 历史归档
|
||||
|
||||
- `docs/content-extract-mcp-mvp-archive.md`
|
||||
- MVP 阶段归档,部分状态已被后续进展覆盖
|
||||
|
||||
## 当前文档维护原则
|
||||
|
||||
- `context-reset-brief.md` 记录当前最新状态
|
||||
- `TODO.md` 记录任务优先级与下一步
|
||||
- `content-extract-mcp-mvp-archive.md` 只当历史快照,不再作为最新事实来源
|
||||
- 新增阶段性进展,优先更新 `README.md`、`TODO.md`、`context-reset-brief.md`
|
||||
@@ -7,9 +7,10 @@
|
||||
- 只负责内容提取
|
||||
- 不负责摘要、分类、价值判断
|
||||
- 已完成 Python MCP 骨架
|
||||
- 已实现两个 tool:
|
||||
- 已实现三个 tool:
|
||||
- `extract_url_content`
|
||||
- `extract_item_content`
|
||||
- `filter_summary_result`
|
||||
- 已完成真实 URL 提取验证
|
||||
- 已完成 LLM 摘要 prompt
|
||||
- 已完成 LLM 摘要结果 schema 校验器
|
||||
@@ -17,6 +18,12 @@
|
||||
- 已完成 LLM 摘要校验 skill 封装
|
||||
- 已清理旧的启发式 `summarizer.py`
|
||||
- 已将旧的 MCP 设计文档更新为当前“Content Extract MCP”语义
|
||||
- 已完成 FreshRSS `greader` API 接入
|
||||
- 已完成 FreshRSS entry -> `item` 映射
|
||||
- 已产出真实 `item` 样例文件
|
||||
- 已跑通 `FreshRSS -> item -> content extraction` 单条链路
|
||||
- 已定义过滤层输入输出 schema
|
||||
- 已完成第一版规则引擎、本地脚本和 MCP tool
|
||||
|
||||
## 当前关键文件
|
||||
|
||||
@@ -28,12 +35,34 @@
|
||||
- `src/summary_mcp/models/llm_result.py`
|
||||
- LLM 校验器:
|
||||
- `src/summary_mcp/validators/llm_result.py`
|
||||
- 过滤模型:
|
||||
- `src/summary_mcp/models/filtering.py`
|
||||
- 过滤引擎:
|
||||
- `src/summary_mcp/filters/engine.py`
|
||||
- 默认过滤规则:
|
||||
- `configs/filter_rules.json`
|
||||
- 校验 CLI:
|
||||
- `src/summary_mcp/validate_llm_result.py`
|
||||
- 最小闭环脚本:
|
||||
- `scripts/run_summary_loop.py`
|
||||
- FreshRSS 拉取脚本:
|
||||
- `scripts/pull_freshrss_items.py`
|
||||
- FreshRSS 提取脚本:
|
||||
- `scripts/run_freshrss_extract.py`
|
||||
- 过滤脚本:
|
||||
- `scripts/run_filter_rules.py`
|
||||
- 当前提示词:
|
||||
- `outputs/llm-summary-prompt.txt`
|
||||
- FreshRSS 原始响应样例:
|
||||
- `outputs/freshrss.raw.json`
|
||||
- FreshRSS item 样例:
|
||||
- `outputs/freshrss.items.json`
|
||||
- FreshRSS 提取结果:
|
||||
- `outputs/freshrss.extracted.json`
|
||||
- 过滤结果样例:
|
||||
- `outputs/filter-decision.json`
|
||||
- 文档索引:
|
||||
- `docs/README.md`
|
||||
- MVP 归档:
|
||||
- `docs/content-extract-mcp-mvp-archive.md`
|
||||
- 当前 TODO:
|
||||
@@ -45,21 +74,26 @@
|
||||
- LLM 可根据提取结果生成摘要 JSON
|
||||
- validator 可校验摘要 JSON
|
||||
- 最小闭环脚本可直接调用 LLM 接口并产出通过校验的结果
|
||||
- FreshRSS API 可拉取真实 entry
|
||||
- 真实 entry 可映射为标准化 `item`
|
||||
- 标准化 `item` 可继续进入内容提取流程
|
||||
- 规则引擎可对结构化摘要结果输出 `keep / drop / review` 决策
|
||||
- MCP tool 可承接“由上层 LLM/Agent 调用过滤”的模式
|
||||
|
||||
## 当前未开始的下一阶段
|
||||
|
||||
- 让 FreshRSS 作为主聚合池
|
||||
- 设计 FreshRSS entry -> `item` 的映射
|
||||
- 准备真实 `item` 样例
|
||||
- 开始定义规则过滤层 schema
|
||||
- 设计知识库入库格式
|
||||
- 设计 webhook / 推送格式
|
||||
- 把 FreshRSS 拉取与提取流程进一步批量化/调度化
|
||||
- 迭代更细的过滤规则与个性化上下文
|
||||
|
||||
## 收束后建议从这里继续
|
||||
|
||||
优先从这两个问题继续:
|
||||
|
||||
1. FreshRSS 的 entry 字段如何映射成 `item`
|
||||
2. 先做一个真实 `item` 样例文件,再讨论规则过滤
|
||||
1. 先设计知识库 sink 的输入输出格式
|
||||
2. 再决定先接 webhook / 推送还是继续细化过滤规则
|
||||
|
||||
## 一句话结论
|
||||
|
||||
当前 MVP 已完成,下一阶段不再是继续打磨 MCP,而是开始接入 FreshRSS 上游并建立 `item` 标准化入口。
|
||||
当前 MVP 已完成,FreshRSS 上游和第一版规则过滤层都已接通,下一阶段应转向下游 sink 与推送设计。
|
||||
|
||||
@@ -0,0 +1,225 @@
|
||||
# 规则过滤引擎设计
|
||||
|
||||
## 1. 目标
|
||||
|
||||
当前过滤层的定位是:
|
||||
|
||||
- 不让 LLM 直接做最终过滤决策
|
||||
- 让 LLM 只产出结构化信号
|
||||
- 由规则引擎输出最终 `keep / drop / review` 决策
|
||||
|
||||
当前链路是:
|
||||
|
||||
`item -> content extraction -> llm summary -> filter rule engine`
|
||||
|
||||
## 2. 输入输出
|
||||
|
||||
### 2.1 FilterInput
|
||||
|
||||
过滤层统一读取四类输入:
|
||||
|
||||
- `item`
|
||||
- `article`
|
||||
- `summary`
|
||||
- `context`
|
||||
|
||||
其中:
|
||||
|
||||
- `item` 表示上游标准化候选条目
|
||||
- `article` 表示正文提取结果
|
||||
- `summary` 表示结构化 LLM 摘要结果
|
||||
- `context` 表示额外的用户偏好或运行时上下文
|
||||
|
||||
### 2.2 FilterDecisionResult
|
||||
|
||||
过滤结果统一输出:
|
||||
|
||||
- `decision`
|
||||
- `keep`
|
||||
- `drop`
|
||||
- `review`
|
||||
- `matched_rules`
|
||||
- `reasons`
|
||||
- `labels`
|
||||
- `priority`
|
||||
- `matches`
|
||||
|
||||
这样后续的知识库 sink、推送层或人工审核都可以稳定消费。
|
||||
|
||||
## 3. 规则结构
|
||||
|
||||
当前规则文件位置:
|
||||
|
||||
- `configs/filter_rules.json`
|
||||
|
||||
单条规则结构为:
|
||||
|
||||
```json
|
||||
{
|
||||
"rule_id": "keep-worth-keeping-method",
|
||||
"enabled": true,
|
||||
"stop_on_match": false,
|
||||
"conditions_all": [
|
||||
{ "field": "summary.worth_keeping", "op": "eq", "value": true },
|
||||
{ "field": "summary.category", "op": "in", "value": ["方法论", "工具实践"] }
|
||||
],
|
||||
"action": {
|
||||
"decision": "keep",
|
||||
"reason": "Structured summary marked the content as worth keeping in a durable category.",
|
||||
"labels": ["summary", "durable"],
|
||||
"priority": 80
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## 4. 当前支持的操作符
|
||||
|
||||
- `eq`
|
||||
- `ne`
|
||||
- `in`
|
||||
- `not_in`
|
||||
- `contains`
|
||||
- `overlap`
|
||||
- `gte`
|
||||
- `lte`
|
||||
- `exists`
|
||||
|
||||
当前条件组合方式:
|
||||
|
||||
- `conditions_all`
|
||||
- `conditions_any`
|
||||
|
||||
## 5. 动态上下文字段
|
||||
|
||||
规则支持从其他字段动态取值,例如:
|
||||
|
||||
```json
|
||||
{ "field": "summary.topics", "op": "overlap", "value": { "from_field": "context.interest_topics" } }
|
||||
```
|
||||
|
||||
这允许上层 Agent 在调用 `filter_summary_result` 时,把当前关注主题动态注入,而不必把偏好硬编码在规则文件里。
|
||||
|
||||
## 6. 当前默认规则思路
|
||||
|
||||
当前默认规则分为三类:
|
||||
|
||||
- 质量拦截
|
||||
- 低质量正文直接 `drop`
|
||||
- 疑似截断或付费墙进入 `review`
|
||||
- 摘要价值判断
|
||||
- `资讯 + worth_keeping=false` 直接 `drop`
|
||||
- `方法论/工具实践 + worth_keeping=true` 直接 `keep`
|
||||
- 个性化补充信号
|
||||
- `summary.topics` 与 `context.interest_topics` 重叠时提升为 `keep`
|
||||
- 其他 `worth_keeping=true` 的结果默认进入 `review`
|
||||
|
||||
## 7. 规则执行流程
|
||||
|
||||
当前过滤流程按以下顺序执行:
|
||||
|
||||
1. 上层先产出结构化 `summary`
|
||||
2. 可选附带 `item`、`article` 与 `context`
|
||||
3. 规则引擎按 `priority` 从高到低遍历规则
|
||||
4. 每条规则根据 `conditions_all` / `conditions_any` 判断是否命中
|
||||
5. 命中的规则被收集为 `matches`
|
||||
6. 最终根据命中结果收敛为 `keep / drop / review`
|
||||
|
||||
当前决策收敛规则是:
|
||||
|
||||
- 只要命中任意 `drop`,最终结果就是 `drop`
|
||||
- 否则只要命中任意 `keep`,最终结果就是 `keep`
|
||||
- 否则如果命中任意 `review`,最终结果就是 `review`
|
||||
- 如果没有任何规则命中,默认回落到 `review`
|
||||
|
||||
这样设计的原因是:
|
||||
|
||||
- `drop` 应该拥有最高约束力
|
||||
- `keep` 只在没有硬性淘汰时生效
|
||||
- 默认不自动放行未知内容
|
||||
|
||||
## 8. 为什么让 LLM 调用规则 tool,而不是直接裁决
|
||||
|
||||
当前架构故意拆成两层:
|
||||
|
||||
- LLM 负责生成结构化信号
|
||||
- 规则引擎负责输出最终过滤决策
|
||||
|
||||
原因是:
|
||||
|
||||
- LLM 适合做语义理解、归类、摘要和价值信号提取
|
||||
- 规则引擎适合做稳定、可复现、可审计的最终判断
|
||||
|
||||
因此推荐的调用方式是:
|
||||
|
||||
1. LLM 先调用提取 tool
|
||||
2. LLM 或本地脚本产出 `summary_result`
|
||||
3. LLM 再调用 `filter_summary_result`
|
||||
4. 后续根据过滤结果决定是否入库、推送或人工审核
|
||||
|
||||
这意味着:
|
||||
|
||||
- LLM 是编排者
|
||||
- rule engine 是裁决器
|
||||
|
||||
而不是让 LLM 在过滤阶段再次自由发挥。
|
||||
|
||||
## 9. 调用示例
|
||||
|
||||
### 9.1 本地脚本
|
||||
|
||||
```bash
|
||||
python scripts/run_filter_rules.py ^
|
||||
--summary outputs/result.json ^
|
||||
--extracted outputs/read-flow-2026.extracted.json ^
|
||||
--output outputs/filter-decision.json
|
||||
```
|
||||
|
||||
### 9.2 带上下文的调用
|
||||
|
||||
```json
|
||||
{
|
||||
"interest_topics": ["个人信息管理", "阅读工作流"]
|
||||
}
|
||||
```
|
||||
|
||||
将这份上下文作为 `--context` 传入后,规则就可以根据当前关注主题做加权。
|
||||
|
||||
### 9.3 MCP tool
|
||||
|
||||
`filter_summary_result` 接收:
|
||||
|
||||
- `summary_result`
|
||||
- 可选 `extracted_article`
|
||||
- 可选 `item`
|
||||
- 可选 `context`
|
||||
|
||||
返回:
|
||||
|
||||
- `decision`
|
||||
- `matched_rules`
|
||||
- `reasons`
|
||||
- `labels`
|
||||
- `priority`
|
||||
- `matches`
|
||||
|
||||
## 10. 当前落地位置
|
||||
|
||||
- 过滤模型:
|
||||
- `src/summary_mcp/models/filtering.py`
|
||||
- 规则引擎:
|
||||
- `src/summary_mcp/filters/engine.py`
|
||||
- 默认规则:
|
||||
- `configs/filter_rules.json`
|
||||
- 本地运行脚本:
|
||||
- `scripts/run_filter_rules.py`
|
||||
- MCP tool:
|
||||
- `filter_summary_result`
|
||||
|
||||
## 11. 当前阶段的设计结论
|
||||
|
||||
第一版过滤层采用“规则主导,LLM 提供信号”的架构:
|
||||
|
||||
- LLM 不直接做最终裁决
|
||||
- 上层 Agent 可以决定是否调用过滤 tool
|
||||
- 真正的过滤决策由规则引擎输出
|
||||
- 灰区内容后续再考虑是否引入第二层 LLM 辅助判断
|
||||
Reference in New Issue
Block a user