462 lines
10 KiB
Markdown
462 lines
10 KiB
Markdown
# 日报级词元库与词元清洗 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`
|
|
|
|
建议结构:
|
|
|
|
```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`
|
|
|
|
建议结构:
|
|
|
|
```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` 做归一。
|
|
|
|
示例:
|
|
|
|
```json
|
|
{
|
|
"Agent": "AI Agent",
|
|
"智能体": "AI Agent",
|
|
"Postgres": "PostgreSQL",
|
|
"Model Context Protocol": "MCP"
|
|
}
|
|
```
|
|
|
|
### 9.3 停用词过滤
|
|
|
|
通过 `configs/term_stopwords.json` 过滤过泛词和噪声词。
|
|
|
|
示例:
|
|
|
|
```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.md`
|
|
- `outputs/term_index/review/term-cleanup-suggestions-YYYY-MM-DD.json`
|
|
|
|
低复杂治理层建议补充三类输入:
|
|
|
|
- `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 文件结构如下:
|
|
|
|
```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 输出建议
|
|
6. 人工确认后再更新配置文件
|
|
|
|
## 14. 与规则引擎的关系
|
|
|
|
这套词元库设计不是规则引擎的替代品,而是规则配置的辅助层。
|
|
|
|
关系如下:
|
|
|
|
- `keywords`
|
|
- 是词元库来源
|
|
- `term_stats`
|
|
- 是观察与调优依据
|
|
- `filter_context.personal.json`
|
|
- 是真正给规则引擎使用的兴趣词配置
|
|
- `filter_rules.json`
|
|
- 是最终裁决逻辑
|
|
|
|
也就是说:
|
|
|
|
`日报词元统计 -> 清洗建议 -> 人工确认 -> 更新 interest_keywords -> 规则引擎命中`
|
|
|
|
而不是:
|
|
|
|
`日报词元统计 -> 自动改规则`
|
|
|
|
## 15. 分阶段落地建议
|
|
|
|
### Phase 1
|
|
|
|
先做最小可用版本:
|
|
|
|
- 只读取日报中的 `keywords`
|
|
- 生成每日词元文件
|
|
- 生成全局累计词频文件
|
|
- 支持 `term_aliases` 和 `term_stopwords`
|
|
|
|
### Phase 2
|
|
|
|
再补治理层:
|
|
|
|
- 增加词元清洗 skill
|
|
- 输出建议文件
|
|
- 人工确认后更新配置
|
|
|
|
### Phase 3
|
|
|
|
最后再考虑增强:
|
|
|
|
- 增加趋势分析
|
|
- 增加最近 7 天热点词视图
|
|
- 增加“建议加入兴趣词”的自动排序
|
|
|
|
## 16. 一句话结论
|
|
|
|
这套设计选择“只统计日报中的 `keywords`,由程序维护轻量词元库,再由独立 skill 周期性做清洗建议”,目的是在控制数据规模的前提下,为规则配置和长期兴趣演化提供稳定、可审计、可扩展的基础设施。
|