Files
reader/docs/design/daily-keyword-index-design.md
T
root a06f2a1d08 chore: update term configs, skill docs and Python 3.10 compat
- term_change_log: record watch term add history
- term_watchlist: add initial watch terms from cleanup review
- term_aliases: minor update
- filter_context.personal: reorganize interest keywords
- keyword-cleanup-review skill: clarify JSON as formal artifact, markdown as temp review copy
- openclaw_delivery: add Python <3.11 UTC import compat
- daily-keyword-index-design: update suggestion artifact semantics
2026-04-14 09:51:57 +08:00

11 KiB

日报级词元库与词元清洗 Skill 设计

1. 设计目标

当前项目已经具备:

FreshRSS -> extraction -> LLM summary -> rule engine -> OpenClaw payload

下一阶段希望新增“词元库”能力,目标不是做全文级检索索引,而是解决两件事:

  1. 为后续规则配置提供稳定、轻量、可读的词元来源
  2. 为周期性的词元清洗、合并和兴趣词补充提供数据基础

因此这套设计的核心原则是:

  • 词元来源轻量化
  • 数据粒度日报化
  • 主链路程序化维护
  • 清洗治理由独立 skill 周期性执行
  • LLM 不直接修改规则或兴趣词配置

2. 为什么不用逐篇词元库

逐篇记录每篇文章的词元事件,虽然可追溯,但当前阶段成本过高,收益不足:

  • 生成文件会很多
  • 存储和调试负担更大
  • 后续真正调规则时,用户更关心“最近日报里反复出现什么词”,而不是“某一篇文章具体抽到了什么词”
  • 当前目标是服务日报与规则配置,不是做文章级分析平台

所以本项目不采用:

article -> term event -> term store

而采用:

daily digest -> keyword aggregate -> daily term index -> global term stats

3. 为什么只保留 keywords

当前 LLM 摘要结果里已经有两个候选字段:

  • keywords
  • topics

本设计只使用 keywords 进入词元库,不使用 topics 作为主来源。

原因:

  • keywords 更具体,适合后续规则配置
    • 例如 Java、Go、Python、MCP、RAG、Kafka
  • topics 更宽泛,适合摘要展示,不适合作为精确规则命中基础
    • 例如“后端工程”“AI Agent”“前沿科技”过于宽泛
  • 只保留一个字段可以显著控制词元库规模
  • 当前项目的真实需求是“词元可配置”,不是“主题聚类”

结论:

  • keywords 进入词元库
  • topics 继续保留在单篇摘要结果中,但不纳入词元统计主流程

4. 词元库的上游边界

词元库不直接读取所有候选文章,而只读取“最终进入日报”的内容。

也就是说,真正的词元来源是:

  • DailyDigest
  • 或等价的“已被日报选中”的 candidate 集合

不纳入词元库的内容:

  • 被 drop 的内容
  • 仅在中间候选层出现、但未进入日报的内容
  • 调试产物中的临时摘要结果

这样做的好处是:

  • 词元库只反映真正进入日级产物的内容
  • 高频词更接近长期兴趣,而不是临时噪声
  • 数据量更可控

5. 总体链路

目标链路调整为:

DailyDigest -> keyword normalization -> daily term index -> global term stats -> cleaning skill review -> human confirm -> config update

职责拆分如下:

5.1 程序负责

  • 从日报中提取 keywords
  • 归一化词元
  • 应用别名映射
  • 应用停用词过滤
  • 生成每日词频
  • 更新全局累计统计

5.2 Skill 负责

  • 周期性读取词频结果
  • 识别重复词、近义词、大小写变体
  • 识别泛词、噪声词、低价值词
  • 建议哪些词应合并、停用、加入兴趣词配置

5.3 人工负责

  • 审核 skill 输出的建议
  • 决定是否更新:
    • term_aliases
    • term_stopwords
    • filter_context.personal.json

6. 数据文件设计

建议新增以下文件:

  • data/term_index/daily/YYYY-MM-DD.json
    • 某一天日报的词元聚合结果
  • data/term_index/term_stats.json
    • 全局累计词元统计
  • configs/term_aliases.json
    • 词元别名归一配置
  • configs/term_stopwords.json
    • 词元停用词配置
  • configs/term_cleanup_policy.json
    • 清洗阈值与治理策略配置
  • configs/term_watchlist.json
    • 当前处于观察状态的词元列表
  • configs/term_change_log.json
    • 已确认生效的词元治理变更记录

说明:

  • 不新增逐篇 term_events.jsonl
  • 不新增文章级明细文件
  • 默认只保留“日报聚合结果 + 全局统计结果”

7. 每日词元文件结构

文件路径示例:

  • data/term_index/daily/2026-03-26.json

建议结构:

{
  "date": "2026-03-26",
  "source": "daily_digest",
  "digest_id": "digest-2026-03-26",
  "generated_at": "2026-03-26T21:30:00+08:00",
  "candidate_count": 8,
  "terms": [
    {
      "term": "AI Agent",
      "normalized_term": "AI Agent",
      "count": 4
    },
    {
      "term": "MCP",
      "normalized_term": "MCP",
      "count": 3
    },
    {
      "term": "RAG",
      "normalized_term": "RAG",
      "count": 2
    }
  ]
}

字段说明:

  • date
    • 日报日期
  • source
    • 固定标记为 daily_digest
  • digest_id
    • 日报对象唯一标识
  • generated_at
    • 该词元文件生成时间
  • candidate_count
    • 当天日报包含的条目数
  • terms[]
    • 当天词元聚合结果

其中单条 terms[] 只保留:

  • term
  • normalized_term
  • count

不保留:

  • 逐篇文章来源列表
  • 逐条命中明细
  • 本地文件路径

8. 全局统计文件结构

文件路径:

  • data/term_index/term_stats.json

建议结构:

{
  "schema_version": "v1",
  "generated_at": "2026-03-26T21:30:00+08:00",
  "terms": [
    {
      "term": "AI Agent",
      "total_count": 18,
      "days_seen": 6,
      "first_seen": "2026-03-20",
      "last_seen": "2026-03-26"
    },
    {
      "term": "MCP",
      "total_count": 12,
      "days_seen": 5,
      "first_seen": "2026-03-21",
      "last_seen": "2026-03-26"
    }
  ]
}

字段说明:

  • term
    • 最终归一后的词元
  • total_count
    • 累计出现次数
  • days_seen
    • 出现过的天数
  • first_seen
    • 首次出现日期
  • last_seen
    • 最近出现日期

当前阶段不额外记录:

  • 各 category 分桶统计
  • keep/review/drop 分桶统计
  • 文章级来源列表

原因是:日报级词元库的第一目标是轻量稳定,不是分析平台。

9. 标准化与归一规则

程序在写入日报词元前,应先做标准化。

9.1 基础标准化

  • 去除首尾空白
  • 保留中英文大小写风格中的稳定写法
  • 去重
  • 过滤空字符串

9.2 别名映射

通过 configs/term_aliases.json 做归一。

示例:

{
  "Agent": "AI Agent",
  "智能体": "AI Agent",
  "Postgres": "PostgreSQL",
  "Model Context Protocol": "MCP"
}

9.3 停用词过滤

通过 configs/term_stopwords.json 过滤过泛词和噪声词。

示例:

[
  "技术",
  "系统",
  "方案",
  "实践",
  "文章"
]

10. 为什么不让 LLM 直接维护词元库

LLM 可以帮助做清洗建议,但不适合直接维护主词元库。

原因:

  • 主词元库更新应该稳定、低成本、可复现
  • 词频统计属于纯程序逻辑,没必要消耗模型调用
  • 如果让 LLM 直接写词元库,会引入不稳定和难审计问题

因此主流程固定为:

  • LLM 只负责在摘要结果里输出 keywords
  • 程序负责归一、聚合、统计

11. 词元清洗 Skill 设计

新增一个周期性清洗 skill,定位是“治理器”,不是“实时生产者”。

11.1 Skill 输入

建议输入:

  • data/term_index/term_stats.json
  • 最近 N 天的 data/term_index/daily/*.json
  • configs/term_aliases.json
  • configs/term_stopwords.json
  • configs/filter_context.personal.json

11.2 Skill 输出

skill 不直接修改配置文件,而是生成建议文件,例如:

  • outputs/term_index/review/term-cleanup-suggestions-YYYY-MM-DD.json
  • outputs/term_index/review/term-cleanup-suggestions-YYYY-MM-DD.md

其中建议语义为:

  • JSON 是 review / apply 之间的唯一正式建议产物
  • Markdown 是人工临时审阅展示稿,不是长期真相来源

低复杂治理层建议补充三类输入:

  • term_cleanup_policy
    • 用来定义 watch 和 interest 的最小证据阈值
  • term_watchlist
    • 用来记录“先观察、暂不升级”的词元
  • term_change_log
    • 用来记录已经确认落地的配置变更,避免后续遗忘上下文

建议项包括:

  • 建议合并的别名词
  • 建议新增的停用词
  • 建议加入 interest_keywords 的候选词
  • 建议降权观察的热点词

11.3 Skill 允许做什么

  • 发现重复词
  • 发现大小写变体
  • 发现中英文混用的近义词
  • 发现持续高频但尚未进入兴趣配置的词
  • 发现明显过泛的词

11.4 Skill 不允许做什么

  • 直接改 filter_rules.json
  • 直接改 filter_context.personal.json
  • 直接覆盖 term_stats.json
  • 在无人工确认的情况下自动生效

12. 建议的清洗建议文件结构

建议 JSON 文件结构如下:

{
  "date": "2026-03-26",
  "based_on_days": 7,
  "alias_suggestions": [
    {
      "from": "Agent",
      "to": "AI Agent",
      "reason": "和现有高频词语义一致,建议归并。"
    }
  ],
  "stopword_suggestions": [
    {
      "term": "系统",
      "reason": "出现频繁但语义过泛,难以作为规则命中词。"
    }
  ],
  "interest_keyword_suggestions": [
    {
      "term": "MCP",
      "reason": "最近多日持续高频,且符合当前 AI Agent 学习方向。"
    }
  ]
}

13. 周期与触发方式

建议触发周期:

  • 词元统计更新:每天一次,跟随日报生成
  • skill 清洗:每周一次,或人工手动触发

推荐流程:

  1. 当天日报生成完成
  2. 程序更新 daily/YYYY-MM-DD.json
  3. 程序更新 term_stats.json
  4. 每周或人工触发一次词元清洗 skill
  5. skill 生成 suggestions JSON(正式建议产物)
  6. 如需要人工阅读,再临时生成 Markdown 展示稿
  7. 人工确认后再更新配置文件

14. 与规则引擎的关系

这套词元库设计不是规则引擎的替代品,而是规则配置的辅助层。

关系如下:

  • keywords
    • 是词元库来源
  • term_stats
    • 是观察与调优依据
  • filter_context.personal.json
    • 是真正给规则引擎使用的兴趣词配置
  • filter_rules.json
    • 是最终裁决逻辑

也就是说:

日报词元统计 -> 清洗建议 -> 人工确认 -> 更新 interest_keywords -> 规则引擎命中

而不是:

日报词元统计 -> 自动改规则

15. 分阶段落地建议

Phase 1

先做最小可用版本:

  • 只读取日报中的 keywords
  • 生成每日词元文件
  • 生成全局累计词频文件
  • 支持 term_aliases 和 term_stopwords

Phase 2

再补治理层:

  • 增加词元清洗 skill
  • 输出建议文件(以 JSON 为正式产物)
  • Markdown 仅作为按需生成的人工展示层
  • 人工确认后更新配置

Phase 3

最后再考虑增强:

  • 增加趋势分析
  • 增加最近 7 天热点词视图
  • 增加“建议加入兴趣词”的自动排序

16. 一句话结论

这套设计选择“只统计日报中的 keywords,由程序维护轻量词元库,再由独立 skill 周期性做清洗建议”,目的是在控制数据规模的前提下,为规则配置和长期兴趣演化提供稳定、可审计、可扩展的基础设施。

补充的产物策略是:

  • facts/state 长期保留
  • suggestions JSON 作为正式建议产物短期保留
  • review bundle 与 Markdown 展示稿降级为临时工作文件 / 展示层